feat: customize button texts of message dialog (#4383)

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
This commit is contained in:
Bo 2022-12-28 05:15:53 +08:00 committed by GitHub
parent 7a8d570db7
commit 00e1efaa9b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
13 changed files with 167 additions and 35 deletions

2
.cargo/config Normal file
View File

@ -0,0 +1,2 @@
[env]
__TAURI_WORKSPACE__ = "true"

View File

@ -0,0 +1,5 @@
---
"api": minor
---
Allow setting the text of the dialog buttons.

View File

@ -0,0 +1,5 @@
---
"tauri": minor
---
Added `OkWithLabel` and `OkCancelWithLabels` variants to the `api::dialog::MessageDialogButtons` enum to set the text of the dialog buttons.

View File

@ -87,7 +87,7 @@ ico = { version = "0.2.0", optional = true }
encoding_rs = "0.8.31" encoding_rs = "0.8.31"
[target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"macos\", windows, target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]
rfd = { version = "0.10", optional = true } rfd = { version = "0.10", optional = true, features=["gtk3", "common-controls-v6"] }
notify-rust = { version = "4.5", default-features = false, features = [ "d" ], optional = true } notify-rust = { version = "4.5", default-features = false, features = [ "d" ], optional = true }
[target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies] [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]

View File

@ -0,0 +1,14 @@
<assembly xmlns="urn:schemas-microsoft-com:asm.v1" manifestVersion="1.0">
<dependency>
<dependentAssembly>
<assemblyIdentity
type="win32"
name="Microsoft.Windows.Common-Controls"
version="6.0.0.0"
processorArchitecture="*"
publicKeyToken="6595b64144ccf1df"
language="*"
/>
</dependentAssembly>
</dependency>
</assembly>

View File

@ -141,6 +141,18 @@ fn main() {
CHECKED_FEATURES.get().unwrap().lock().unwrap().join(","), CHECKED_FEATURES.get().unwrap().lock().unwrap().join(","),
) )
.expect("failed to write checked_features file"); .expect("failed to write checked_features file");
// workaround needed to preven `STATUS_ENTRYPOINT_NOT_FOUND` error
// see https://github.com/tauri-apps/tauri/pull/4383#issuecomment-1212221864
let target_os = std::env::var("CARGO_CFG_TARGET_OS");
let target_env = std::env::var("CARGO_CFG_TARGET_ENV");
let is_tauri_workspace = std::env::var("__TAURI_WORKSPACE__").map_or(false, |v| v == "true");
if is_tauri_workspace
&& Ok("windows") == target_os.as_deref()
&& Ok("msvc") == target_env.as_deref()
{
add_manifest();
}
} }
// create aliases for the given module with its apis. // create aliases for the given module with its apis.
@ -170,3 +182,20 @@ fn alias_module(module: &str, apis: &[&str], api_all: bool) {
alias(&format!("{}_any", AsSnakeCase(module)), any); alias(&format!("{}_any", AsSnakeCase(module)), any);
} }
fn add_manifest() {
static WINDOWS_MANIFEST_FILE: &str = "Windows Manifest.xml";
let mut manifest = std::env::current_dir().unwrap();
manifest.push(WINDOWS_MANIFEST_FILE);
println!("cargo:rerun-if-changed={}", WINDOWS_MANIFEST_FILE);
// Embed the Windows application manifest file.
println!("cargo:rustc-link-arg=/MANIFEST:EMBED");
println!(
"cargo:rustc-link-arg=/MANIFESTINPUT:{}",
manifest.to_str().unwrap()
);
// Turn linker warnings into errors.
println!("cargo:rustc-link-arg=/WX");
}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -171,7 +171,7 @@ macro_rules! message_dialog_builder {
/// Options for action buttons on message dialogs. /// Options for action buttons on message dialogs.
#[non_exhaustive] #[non_exhaustive]
#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] #[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MessageDialogButtons { pub enum MessageDialogButtons {
/// Ok button. /// Ok button.
Ok, Ok,
@ -179,6 +179,10 @@ pub enum MessageDialogButtons {
OkCancel, OkCancel,
/// Yes and No buttons. /// Yes and No buttons.
YesNo, YesNo,
/// OK button with customized text.
OkWithLabel(String),
/// Ok and Cancel buttons with customized text.
OkCancelWithLabels(String, String),
} }
impl From<MessageDialogButtons> for rfd::MessageButtons { impl From<MessageDialogButtons> for rfd::MessageButtons {
@ -187,6 +191,10 @@ impl From<MessageDialogButtons> for rfd::MessageButtons {
MessageDialogButtons::Ok => Self::Ok, MessageDialogButtons::Ok => Self::Ok,
MessageDialogButtons::OkCancel => Self::OkCancel, MessageDialogButtons::OkCancel => Self::OkCancel,
MessageDialogButtons::YesNo => Self::YesNo, MessageDialogButtons::YesNo => Self::YesNo,
MessageDialogButtons::OkWithLabel(ok_text) => Self::OkCustom(ok_text),
MessageDialogButtons::OkCancelWithLabels(ok_text, cancel_text) => {
Self::OkCancelCustom(ok_text, cancel_text)
}
} }
} }
} }

View File

@ -14,19 +14,21 @@ use tauri_macros::{command_enum, module_command_handler, CommandModule};
use std::path::PathBuf; use std::path::PathBuf;
macro_rules! message_dialog { macro_rules! message_dialog {
($fn_name: ident, $allowlist: ident, $buttons: expr) => { ($fn_name: ident, $allowlist: ident, $button_labels_type: ty, $buttons: expr) => {
#[module_command_handler($allowlist)] #[module_command_handler($allowlist)]
fn $fn_name<R: Runtime>( fn $fn_name<R: Runtime>(
context: InvokeContext<R>, context: InvokeContext<R>,
title: Option<String>, title: Option<String>,
message: String, message: String,
level: Option<MessageDialogType>, level: Option<MessageDialogType>,
button_labels: $button_labels_type,
) -> super::Result<bool> { ) -> super::Result<bool> {
let determine_button = $buttons;
let mut builder = crate::api::dialog::blocking::MessageDialogBuilder::new( let mut builder = crate::api::dialog::blocking::MessageDialogBuilder::new(
title.unwrap_or_else(|| context.window.app_handle.package_info().name.clone()), title.unwrap_or_else(|| context.window.app_handle.package_info().name.clone()),
message, message,
) )
.buttons($buttons); .buttons(determine_button(button_labels));
#[cfg(any(windows, target_os = "macos"))] #[cfg(any(windows, target_os = "macos"))]
{ {
builder = builder.parent(&context.window); builder = builder.parent(&context.window);
@ -139,6 +141,8 @@ pub enum Cmd {
message: String, message: String,
#[serde(rename = "type")] #[serde(rename = "type")]
level: Option<MessageDialogType>, level: Option<MessageDialogType>,
#[serde(rename = "buttonLabel")]
button_label: Option<String>,
}, },
#[cmd(dialog_ask, "dialog > ask")] #[cmd(dialog_ask, "dialog > ask")]
AskDialog { AskDialog {
@ -146,6 +150,8 @@ pub enum Cmd {
message: String, message: String,
#[serde(rename = "type")] #[serde(rename = "type")]
level: Option<MessageDialogType>, level: Option<MessageDialogType>,
#[serde(rename = "buttonLabels")]
button_label: Option<(String, String)>,
}, },
#[cmd(dialog_confirm, "dialog > confirm")] #[cmd(dialog_confirm, "dialog > confirm")]
ConfirmDialog { ConfirmDialog {
@ -153,6 +159,8 @@ pub enum Cmd {
message: String, message: String,
#[serde(rename = "type")] #[serde(rename = "type")]
level: Option<MessageDialogType>, level: Option<MessageDialogType>,
#[serde(rename = "buttonLabels")]
button_labels: Option<(String, String)>,
}, },
} }
@ -255,19 +263,36 @@ impl Cmd {
message_dialog!( message_dialog!(
message_dialog, message_dialog,
dialog_message, dialog_message,
crate::api::dialog::MessageDialogButtons::Ok Option<String>,
|label: Option<String>| {
label
.map(crate::api::dialog::MessageDialogButtons::OkWithLabel)
.unwrap_or(crate::api::dialog::MessageDialogButtons::Ok)
}
); );
message_dialog!( message_dialog!(
ask_dialog, ask_dialog,
dialog_ask, dialog_ask,
crate::api::dialog::MessageDialogButtons::YesNo Option<(String, String)>,
|labels: Option<(String, String)>| {
labels
.map(|(yes, no)| crate::api::dialog::MessageDialogButtons::OkCancelWithLabels(yes, no))
.unwrap_or(crate::api::dialog::MessageDialogButtons::YesNo)
}
); );
message_dialog!( message_dialog!(
confirm_dialog, confirm_dialog,
dialog_confirm, dialog_confirm,
crate::api::dialog::MessageDialogButtons::OkCancel Option<(String, String)>,
|labels: Option<(String, String)>| {
labels
.map(|(ok, cancel)| {
crate::api::dialog::MessageDialogButtons::OkCancelWithLabels(ok, cancel)
})
.unwrap_or(crate::api::dialog::MessageDialogButtons::OkCancel)
}
); );
} }

File diff suppressed because one or more lines are too long

View File

@ -1,7 +1,11 @@
use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::atomic::{AtomicBool, Ordering};
use tauri::{ use tauri::{
api::dialog::ask, CustomMenuItem, GlobalShortcutManager, Manager, RunEvent, SystemTray, api::{
SystemTrayEvent, SystemTrayMenu, WindowBuilder, WindowEvent, WindowUrl, dialog::{ask, MessageDialogBuilder, MessageDialogButtons},
shell,
},
CustomMenuItem, GlobalShortcutManager, Manager, RunEvent, SystemTray, SystemTrayEvent,
SystemTrayMenu, WindowBuilder, WindowEvent, WindowUrl,
}; };
pub fn main() { pub fn main() {
@ -71,6 +75,7 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> {
tray_menu1 = tray_menu1 tray_menu1 = tray_menu1
.add_item(CustomMenuItem::new("switch_menu", "Switch Menu")) .add_item(CustomMenuItem::new("switch_menu", "Switch Menu"))
.add_item(CustomMenuItem::new("about", "About"))
.add_item(CustomMenuItem::new("exit_app", "Quit")) .add_item(CustomMenuItem::new("exit_app", "Quit"))
.add_item(CustomMenuItem::new("destroy", "Destroy")); .add_item(CustomMenuItem::new("destroy", "Destroy"));
@ -78,6 +83,7 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> {
.add_item(CustomMenuItem::new("toggle", "Toggle")) .add_item(CustomMenuItem::new("toggle", "Toggle"))
.add_item(CustomMenuItem::new("new", "New window")) .add_item(CustomMenuItem::new("new", "New window"))
.add_item(CustomMenuItem::new("switch_menu", "Switch Menu")) .add_item(CustomMenuItem::new("switch_menu", "Switch Menu"))
.add_item(CustomMenuItem::new("about", "About"))
.add_item(CustomMenuItem::new("exit_app", "Quit")) .add_item(CustomMenuItem::new("exit_app", "Quit"))
.add_item(CustomMenuItem::new("destroy", "Destroy")); .add_item(CustomMenuItem::new("destroy", "Destroy"));
let is_menu1 = AtomicBool::new(true); let is_menu1 = AtomicBool::new(true);
@ -161,6 +167,20 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> {
.unwrap(); .unwrap();
is_menu1.store(!flag, Ordering::Relaxed); is_menu1.store(!flag, Ordering::Relaxed);
} }
"about" => {
let window = handle.get_window("main").unwrap();
MessageDialogBuilder::new("About app", "Tauri demo app")
.parent(&window)
.buttons(MessageDialogButtons::OkCancelCustom(
"Homepage".into(),
"know it".into(),
))
.show(move |ok| {
if ok {
shell::open(&window.shell_scope(), "https://tauri.app/", None).unwrap();
}
});
}
_ => {} _ => {}
} }
} }

View File

@ -97,6 +97,19 @@ interface MessageDialogOptions {
title?: string title?: string
/** The type of the dialog. Defaults to `info`. */ /** The type of the dialog. Defaults to `info`. */
type?: 'info' | 'warning' | 'error' type?: 'info' | 'warning' | 'error'
/** The label of the confirm button. */
okLabel?: string
}
interface ConfirmDialogOptions {
/** The title of the dialog. Defaults to the app name. */
title?: string
/** The type of the dialog. Defaults to `info`. */
type?: 'info' | 'warning' | 'error'
/** The label of the confirm button. */
okLabel?: string
/** The label of the cancel button. */
cancelLabel?: string
} }
/** /**
@ -233,7 +246,8 @@ async function message(
cmd: 'messageDialog', cmd: 'messageDialog',
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
type: opts?.type type: opts?.type,
buttonLabel: opts?.okLabel?.toString()
} }
}) })
} }
@ -256,7 +270,7 @@ async function message(
*/ */
async function ask( async function ask(
message: string, message: string,
options?: string | MessageDialogOptions options?: string | ConfirmDialogOptions
): Promise<boolean> { ): Promise<boolean> {
const opts = typeof options === 'string' ? { title: options } : options const opts = typeof options === 'string' ? { title: options } : options
return invokeTauriCommand({ return invokeTauriCommand({
@ -265,7 +279,11 @@ async function ask(
cmd: 'askDialog', cmd: 'askDialog',
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
type: opts?.type type: opts?.type,
buttonLabels: [
opts?.okLabel?.toString() ?? 'Yes',
opts?.cancelLabel?.toString() ?? 'No'
]
} }
}) })
} }
@ -288,7 +306,7 @@ async function ask(
*/ */
async function confirm( async function confirm(
message: string, message: string,
options?: string | MessageDialogOptions options?: string | ConfirmDialogOptions
): Promise<boolean> { ): Promise<boolean> {
const opts = typeof options === 'string' ? { title: options } : options const opts = typeof options === 'string' ? { title: options } : options
return invokeTauriCommand({ return invokeTauriCommand({
@ -297,7 +315,11 @@ async function confirm(
cmd: 'confirmDialog', cmd: 'confirmDialog',
message: message.toString(), message: message.toString(),
title: opts?.title?.toString(), title: opts?.title?.toString(),
type: opts?.type type: opts?.type,
buttonLabels: [
opts?.okLabel?.toString() ?? 'Ok',
opts?.cancelLabel?.toString() ?? 'Cancel'
]
} }
}) })
} }
@ -306,7 +328,8 @@ export type {
DialogFilter, DialogFilter,
OpenDialogOptions, OpenDialogOptions,
SaveDialogOptions, SaveDialogOptions,
MessageDialogOptions MessageDialogOptions,
ConfirmDialogOptions
} }
export { open, save, message, ask, confirm } export { open, save, message, ask, confirm }