Prechádzať zdrojové kódy

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

Co-authored-by: Lucas Nogueira <lucas@tauri.studio>
Bo 2 rokov pred
rodič
commit
00e1efaa9b

+ 2 - 0
.cargo/config

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

+ 5 - 0
.changes/custom-buttons-api.md

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

+ 5 - 0
.changes/custom-buttons.md

@@ -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.

+ 1 - 1
core/tauri/Cargo.toml

@@ -87,7 +87,7 @@ ico = { version = "0.2.0", optional = true }
 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]
-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 }
 
 [target."cfg(any(target_os = \"linux\", target_os = \"dragonfly\", target_os = \"freebsd\", target_os = \"openbsd\", target_os = \"netbsd\"))".dependencies]

+ 14 - 0
core/tauri/Windows Manifest.xml

@@ -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>

+ 29 - 0
core/tauri/build.rs

@@ -141,6 +141,18 @@ fn main() {
     CHECKED_FEATURES.get().unwrap().lock().unwrap().join(","),
   )
   .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.
@@ -170,3 +182,20 @@ fn alias_module(module: &str, apis: &[&str], api_all: bool) {
 
   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");
+}

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
core/tauri/scripts/bundle.global.js


Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
core/tauri/scripts/bundle.js


+ 9 - 1
core/tauri/src/api/dialog.rs

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

+ 30 - 5
core/tauri/src/endpoints/dialog.rs

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

Rozdielové dáta súboru neboli zobrazené, pretože súbor je príliš veľký
+ 0 - 0
examples/api/dist/assets/index.js


+ 22 - 2
examples/api/src-tauri/src/desktop.rs

@@ -1,7 +1,11 @@
 use std::sync::atomic::{AtomicBool, Ordering};
 use tauri::{
-  api::dialog::ask, CustomMenuItem, GlobalShortcutManager, Manager, RunEvent, SystemTray,
-  SystemTrayEvent, SystemTrayMenu, WindowBuilder, WindowEvent, WindowUrl,
+  api::{
+    dialog::{ask, MessageDialogBuilder, MessageDialogButtons},
+    shell,
+  },
+  CustomMenuItem, GlobalShortcutManager, Manager, RunEvent, SystemTray, SystemTrayEvent,
+  SystemTrayMenu, WindowBuilder, WindowEvent, WindowUrl,
 };
 
 pub fn main() {
@@ -71,6 +75,7 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> {
 
   tray_menu1 = tray_menu1
     .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("destroy", "Destroy"));
 
@@ -78,6 +83,7 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> {
     .add_item(CustomMenuItem::new("toggle", "Toggle"))
     .add_item(CustomMenuItem::new("new", "New window"))
     .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("destroy", "Destroy"));
   let is_menu1 = AtomicBool::new(true);
@@ -161,6 +167,20 @@ fn create_tray(app: &tauri::App) -> tauri::Result<()> {
                 .unwrap();
               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();
+                  }
+                });
+            }
             _ => {}
           }
         }

+ 29 - 6
tooling/api/src/dialog.ts

@@ -97,6 +97,19 @@ interface MessageDialogOptions {
   title?: string
   /** The type of the dialog. Defaults to `info`. */
   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',
       message: message.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(
   message: string,
-  options?: string | MessageDialogOptions
+  options?: string | ConfirmDialogOptions
 ): Promise<boolean> {
   const opts = typeof options === 'string' ? { title: options } : options
   return invokeTauriCommand({
@@ -265,7 +279,11 @@ async function ask(
       cmd: 'askDialog',
       message: message.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(
   message: string,
-  options?: string | MessageDialogOptions
+  options?: string | ConfirmDialogOptions
 ): Promise<boolean> {
   const opts = typeof options === 'string' ? { title: options } : options
   return invokeTauriCommand({
@@ -297,7 +315,11 @@ async function confirm(
       cmd: 'confirmDialog',
       message: message.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,
   OpenDialogOptions,
   SaveDialogOptions,
-  MessageDialogOptions
+  MessageDialogOptions,
+  ConfirmDialogOptions
 }
 
 export { open, save, message, ask, confirm }

Niektoré súbory nie sú zobrazené, pretože je v týchto rozdielových dátach zmenené mnoho súborov