diff --git a/.changes/dialog-3-buttons.md b/.changes/dialog-3-buttons.md
new file mode 100644
index 0000000000..e2b7645465
--- /dev/null
+++ b/.changes/dialog-3-buttons.md
@@ -0,0 +1,6 @@
+---
+"dialog": "minor"
+"dialog-js": "minor"
+---
+
+Add support for showing a message dialog with 3 buttons.
\ No newline at end of file
diff --git a/examples/api/src/views/Dialog.svelte b/examples/api/src/views/Dialog.svelte
index 462eecff7e..5aadad5a94 100644
--- a/examples/api/src/views/Dialog.svelte
+++ b/examples/api/src/views/Dialog.svelte
@@ -44,6 +44,13 @@
await message("Tauri is awesome!");
}
+ async function msgCustom(result) {
+ const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
+ await message(`Tauri is: `, { buttons })
+ .then((res) => onMessage(`Tauri is ${res}`))
+ .catch(onMessage);
+ }
+
function openDialog() {
open({
title: "My wonderful open dialog",
@@ -136,12 +143,17 @@
-
-
-
-
-
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/plugins/dialog/android/src/main/java/DialogPlugin.kt b/plugins/dialog/android/src/main/java/DialogPlugin.kt
index af0467d894..a815e1baa2 100644
--- a/plugins/dialog/android/src/main/java/DialogPlugin.kt
+++ b/plugins/dialog/android/src/main/java/DialogPlugin.kt
@@ -38,6 +38,7 @@ class MessageOptions {
var title: String? = null
lateinit var message: String
var okButtonLabel: String? = null
+ var noButtonLabel: String? = null
var cancelButtonLabel: String? = null
}
@@ -169,9 +170,8 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
return
}
- val handler = { cancelled: Boolean, value: Boolean ->
+ val handler = { value: String ->
val ret = JSObject()
- ret.put("cancelled", cancelled)
ret.put("value", value)
invoke.resolve(ret)
}
@@ -183,24 +183,34 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
if (args.title != null) {
builder.setTitle(args.title)
}
+
+ val okButtonLabel = args.okButtonLabel ?: "Ok"
+
builder
.setMessage(args.message)
- .setPositiveButton(
- args.okButtonLabel ?: "OK"
- ) { dialog, _ ->
+ .setPositiveButton(okButtonLabel) { dialog, _ ->
dialog.dismiss()
- handler(false, true)
+ handler(okButtonLabel)
}
.setOnCancelListener { dialog ->
dialog.dismiss()
- handler(true, false)
+ handler(args.cancelButtonLabel ?: "Cancel")
+ }
+
+ if (args.noButtonLabel != null) {
+ builder.setNeutralButton(args.noButtonLabel) { dialog, _ ->
+ dialog.dismiss()
+ handler(args.noButtonLabel!!)
}
+ }
+
if (args.cancelButtonLabel != null) {
builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ ->
dialog.dismiss()
- handler(false, false)
+ handler(args.cancelButtonLabel!!)
}
}
+
val dialog = builder.create()
dialog.show()
}
diff --git a/plugins/dialog/api-iife.js b/plugins/dialog/api-iife.js
index c2e0870c82..a357f2c0bd 100644
--- a/plugins/dialog/api-iife.js
+++ b/plugins/dialog/api-iife.js
@@ -1 +1 @@
-if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,yesButtonLabel:i?.okLabel?.toString(),noButtonLabel:i?.cancelLabel?.toString()})},t.confirm=async function(t,e){const i="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),cancelButtonLabel:i?.cancelLabel?.toString()})},t.message=async function(t,e){const i="string"==typeof e?{title:e}:e;await n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString()})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
+if("__TAURI__"in window){var __TAURI_PLUGIN_DIALOG__=function(t){"use strict";async function n(t,n={},e){return window.__TAURI_INTERNALS__.invoke(t,n,e)}function e(t){if(void 0!==t)return"string"==typeof t?t:"ok"in t&&"cancel"in t?{OkCancelCustom:[t.ok,t.cancel]}:"yes"in t&&"no"in t&&"cancel"in t?{YesNoCancelCustom:[t.yes,t.no,t.cancel]}:"ok"in t?{OkCustom:t.ok}:void 0}return"function"==typeof SuppressedError&&SuppressedError,t.ask=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|ask",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,yesButtonLabel:o?.okLabel?.toString(),noButtonLabel:o?.cancelLabel?.toString()})},t.confirm=async function(t,e){const o="string"==typeof e?{title:e}:e;return await n("plugin:dialog|confirm",{message:t.toString(),title:o?.title?.toString(),kind:o?.kind,okButtonLabel:o?.okLabel?.toString(),cancelButtonLabel:o?.cancelLabel?.toString()})},t.message=async function(t,o){const i="string"==typeof o?{title:o}:o;return n("plugin:dialog|message",{message:t.toString(),title:i?.title?.toString(),kind:i?.kind,okButtonLabel:i?.okLabel?.toString(),buttons:e(i?.buttons)})},t.open=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|open",{options:t})},t.save=async function(t={}){return"object"==typeof t&&Object.freeze(t),await n("plugin:dialog|save",{options:t})},t}({});Object.defineProperty(window.__TAURI__,"dialog",{value:__TAURI_PLUGIN_DIALOG__})}
diff --git a/plugins/dialog/guest-js/index.ts b/plugins/dialog/guest-js/index.ts
index 150be95a00..2130ec8987 100644
--- a/plugins/dialog/guest-js/index.ts
+++ b/plugins/dialog/guest-js/index.ts
@@ -77,6 +77,72 @@ interface SaveDialogOptions {
canCreateDirectories?: boolean
}
+/**
+ * Default buttons for a message dialog.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogDefaultButtons =
+ | 'Ok'
+ | 'OkCancel'
+ | 'YesNo'
+ | 'YesNoCancel'
+
+/**
+ * The Yes, No and Cancel buttons of a message dialog.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogButtonsYesNoCancel = {
+ /** The Yes button. */
+ yes: string
+ /** The No button. */
+ no: string
+ /** The Cancel button. */
+ cancel: string
+}
+
+/**
+ * The Ok and Cancel buttons of a message dialog.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogButtonsOkCancel = {
+ /** The Ok button. */
+ ok: string
+ /** The Cancel button. */
+ cancel: string
+}
+
+/**
+ * The Ok button of a message dialog.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogButtonsOk = {
+ /** The Ok button. */
+ ok: string
+}
+
+/**
+ * Custom buttons for a message dialog.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogCustomButtons =
+ | MessageDialogButtonsYesNoCancel
+ | MessageDialogButtonsOkCancel
+ | MessageDialogButtonsOk
+
+/**
+ * The buttons of a message dialog.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogButtons =
+ | MessageDialogDefaultButtons
+ | MessageDialogCustomButtons
+
/**
* @since 2.0.0
*/
@@ -85,8 +151,41 @@ interface MessageDialogOptions {
title?: string
/** The kind of the dialog. Defaults to `info`. */
kind?: 'info' | 'warning' | 'error'
- /** The label of the confirm button. */
+ /**
+ * The label of the Ok button.
+ *
+ * @deprecated Use {@linkcode MessageDialogOptions.buttons} instead.
+ */
okLabel?: string
+ /**
+ * The buttons of the dialog.
+ *
+ * @since 2.3.0
+ */
+ buttons?: MessageDialogButtons
+}
+
+/**
+ * Internal function to convert the buttons to the Rust type.
+ */
+function buttonsToRust(buttons: MessageDialogButtons | undefined) {
+ if (buttons === undefined) {
+ return undefined
+ }
+
+ if (typeof buttons === 'string') {
+ return buttons
+ } else if ('ok' in buttons && 'cancel' in buttons) {
+ return { OkCancelCustom: [buttons.ok, buttons.cancel] }
+ } else if ('yes' in buttons && 'no' in buttons && 'cancel' in buttons) {
+ return {
+ YesNoCancelCustom: [buttons.yes, buttons.no, buttons.cancel]
+ }
+ } else if ('ok' in buttons) {
+ return { OkCustom: buttons.ok }
+ }
+
+ return undefined
}
interface ConfirmDialogOptions {
@@ -202,6 +301,16 @@ async function save(options: SaveDialogOptions = {}): Promise {
return await invoke('plugin:dialog|save', { options })
}
+/**
+ * The result of a message dialog.
+ *
+ * The result is a string if the dialog has custom buttons,
+ * otherwise it is one of the default buttons.
+ *
+ * @since 2.3.0
+ */
+export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
+
/**
* Shows a message dialog with an `Ok` button.
* @example
@@ -222,13 +331,15 @@ async function save(options: SaveDialogOptions = {}): Promise {
async function message(
message: string,
options?: string | MessageDialogOptions
-): Promise {
+): Promise {
const opts = typeof options === 'string' ? { title: options } : options
- await invoke('plugin:dialog|message', {
+
+ return invoke('plugin:dialog|message', {
message: message.toString(),
title: opts?.title?.toString(),
kind: opts?.kind,
- okButtonLabel: opts?.okLabel?.toString()
+ okButtonLabel: opts?.okLabel?.toString(),
+ buttons: buttonsToRust(opts?.buttons)
})
}
diff --git a/plugins/dialog/ios/Sources/DialogPlugin.swift b/plugins/dialog/ios/Sources/DialogPlugin.swift
index b3f7e7da6e..710fd0bb25 100644
--- a/plugins/dialog/ios/Sources/DialogPlugin.swift
+++ b/plugins/dialog/ios/Sources/DialogPlugin.swift
@@ -20,6 +20,7 @@ struct MessageDialogOptions: Decodable {
var title: String?
let message: String
var okButtonLabel: String?
+ var noButtonLabel: String?
var cancelButtonLabel: String?
}
@@ -200,36 +201,38 @@ class DialogPlugin: Plugin {
let alert = UIAlertController(
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
- let cancelButtonLabel = args.cancelButtonLabel ?? ""
- if !cancelButtonLabel.isEmpty {
+ if let cancelButtonLabel = args.cancelButtonLabel {
alert.addAction(
UIAlertAction(
title: cancelButtonLabel, style: UIAlertAction.Style.default,
handler: { (_) -> Void in
- Logger.error("cancel")
-
- invoke.resolve([
- "value": false,
- "cancelled": false,
- ])
- }))
+ invoke.resolve(["value": cancelButtonLabel])
+ }
+ )
+ )
}
- let okButtonLabel = args.okButtonLabel ?? (cancelButtonLabel.isEmpty ? "OK" : "")
- if !okButtonLabel.isEmpty {
+ if let noButtonLabel = args.noButtonLabel {
alert.addAction(
UIAlertAction(
- title: okButtonLabel, style: UIAlertAction.Style.default,
+ title: noButtonLabel, style: UIAlertAction.Style.default,
handler: { (_) -> Void in
- Logger.error("ok")
-
- invoke.resolve([
- "value": true,
- "cancelled": false,
- ])
- }))
+ invoke.resolve(["value": noButtonLabel])
+ }
+ )
+ )
}
+ let okButtonLabel = args.okButtonLabel ?? "Ok"
+ alert.addAction(
+ UIAlertAction(
+ title: okButtonLabel, style: UIAlertAction.Style.default,
+ handler: { (_) -> Void in
+ invoke.resolve(["value": okButtonLabel])
+ }
+ )
+ )
+
manager.viewController?.present(alert, animated: true, completion: nil)
}
}
diff --git a/plugins/dialog/src/commands.rs b/plugins/dialog/src/commands.rs
index c3caf027fb..5298de9d07 100644
--- a/plugins/dialog/src/commands.rs
+++ b/plugins/dialog/src/commands.rs
@@ -9,8 +9,8 @@ use tauri::{command, Manager, Runtime, State, Window};
use tauri_plugin_fs::FsExt;
use crate::{
- Dialog, FileDialogBuilder, FilePath, MessageDialogButtons, MessageDialogKind, Result, CANCEL,
- NO, OK, YES,
+ Dialog, FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogButtons,
+ MessageDialogKind, MessageDialogResult, Result, CANCEL, NO, OK, YES,
};
#[derive(Serialize)]
@@ -248,7 +248,7 @@ fn message_dialog(
message: String,
kind: Option,
buttons: MessageDialogButtons,
-) -> bool {
+) -> MessageDialogBuilder {
let mut builder = dialog.message(message);
builder = builder.buttons(buttons);
@@ -266,7 +266,7 @@ fn message_dialog(
builder = builder.kind(kind);
}
- builder.blocking_show()
+ builder
}
#[command]
@@ -277,19 +277,15 @@ pub(crate) async fn message(
message: String,
kind: Option,
ok_button_label: Option,
-) -> Result {
- Ok(message_dialog(
- window,
- dialog,
- title,
- message,
- kind,
- if let Some(ok_button_label) = ok_button_label {
- MessageDialogButtons::OkCustom(ok_button_label)
- } else {
- MessageDialogButtons::Ok
- },
- ))
+ buttons: Option,
+) -> Result {
+ let buttons = buttons.unwrap_or(if let Some(ok_button_label) = ok_button_label {
+ MessageDialogButtons::OkCustom(ok_button_label)
+ } else {
+ MessageDialogButtons::Ok
+ });
+
+ Ok(message_dialog(window, dialog, title, message, kind, buttons).blocking_show_with_result())
}
#[command]
@@ -302,7 +298,7 @@ pub(crate) async fn ask(
yes_button_label: Option,
no_button_label: Option,
) -> Result {
- Ok(message_dialog(
+ let dialog = message_dialog(
window,
dialog,
title,
@@ -318,7 +314,9 @@ pub(crate) async fn ask(
} else {
MessageDialogButtons::YesNo
},
- ))
+ );
+
+ Ok(dialog.blocking_show())
}
#[command]
@@ -331,7 +329,7 @@ pub(crate) async fn confirm(
ok_button_label: Option,
cancel_button_label: Option,
) -> Result {
- Ok(message_dialog(
+ let dialog = message_dialog(
window,
dialog,
title,
@@ -347,5 +345,7 @@ pub(crate) async fn confirm(
} else {
MessageDialogButtons::OkCancel
},
- ))
+ );
+
+ Ok(dialog.blocking_show())
}
diff --git a/plugins/dialog/src/desktop.rs b/plugins/dialog/src/desktop.rs
index d1a3e8b21a..732e81ec8a 100644
--- a/plugins/dialog/src/desktop.rs
+++ b/plugins/dialog/src/desktop.rs
@@ -13,7 +13,7 @@ use rfd::{AsyncFileDialog, AsyncMessageDialog};
use serde::de::DeserializeOwned;
use tauri::{plugin::PluginApi, AppHandle, Runtime};
-use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder, OK};
+use crate::{models::*, FileDialogBuilder, FilePath, MessageDialogBuilder};
pub fn init(
app: &AppHandle,
@@ -115,6 +115,10 @@ impl From for rfd::MessageButtons {
MessageDialogButtons::YesNo => Self::YesNo,
MessageDialogButtons::OkCustom(ok) => Self::OkCustom(ok),
MessageDialogButtons::OkCancelCustom(ok, cancel) => Self::OkCancelCustom(ok, cancel),
+ MessageDialogButtons::YesNoCancel => Self::YesNoCancel,
+ MessageDialogButtons::YesNoCancelCustom(yes, no, cancel) => {
+ Self::YesNoCancelCustom(yes, no, cancel)
+ }
}
}
}
@@ -208,24 +212,11 @@ pub fn save_file) + Send + 'static>(
}
/// Shows a message dialog
-pub fn show_message_dialog(
+pub fn show_message_dialog(
dialog: MessageDialogBuilder,
- f: F,
+ callback: F,
) {
- use rfd::MessageDialogResult;
-
- let ok_label = match &dialog.buttons {
- MessageDialogButtons::OkCustom(ok) => Some(ok.clone()),
- MessageDialogButtons::OkCancelCustom(ok, _) => Some(ok.clone()),
- _ => None,
- };
- let f = move |res| {
- f(match res {
- MessageDialogResult::Ok | MessageDialogResult::Yes => true,
- MessageDialogResult::Custom(s) => ok_label.map_or(s == OK, |ok_label| ok_label == s),
- _ => false,
- });
- };
+ let f = move |res: rfd::MessageDialogResult| callback(res.into());
let handle = dialog.dialog.app_handle().to_owned();
let _ = handle.run_on_main_thread(move || {
diff --git a/plugins/dialog/src/lib.rs b/plugins/dialog/src/lib.rs
index 2ef1c1eade..17d9a829d4 100644
--- a/plugins/dialog/src/lib.rs
+++ b/plugins/dialog/src/lib.rs
@@ -216,6 +216,7 @@ pub(crate) struct MessageDialogPayload<'a> {
message: &'a String,
kind: &'a MessageDialogKind,
ok_button_label: Option<&'a str>,
+ no_button_label: Option<&'a str>,
cancel_button_label: Option<&'a str>,
}
@@ -238,13 +239,17 @@ impl MessageDialogBuilder {
#[cfg(mobile)]
pub(crate) fn payload(&self) -> MessageDialogPayload<'_> {
- let (ok_button_label, cancel_button_label) = match &self.buttons {
- MessageDialogButtons::Ok => (Some(OK), None),
- MessageDialogButtons::OkCancel => (Some(OK), Some(CANCEL)),
- MessageDialogButtons::YesNo => (Some(YES), Some(NO)),
- MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), Some(CANCEL)),
+ let (ok_button_label, no_button_label, cancel_button_label) = match &self.buttons {
+ MessageDialogButtons::Ok => (Some(OK), None, None),
+ MessageDialogButtons::OkCancel => (Some(OK), None, Some(CANCEL)),
+ MessageDialogButtons::YesNo => (Some(YES), Some(NO), None),
+ MessageDialogButtons::YesNoCancel => (Some(YES), Some(NO), Some(CANCEL)),
+ MessageDialogButtons::OkCustom(ok) => (Some(ok.as_str()), None, None),
MessageDialogButtons::OkCancelCustom(ok, cancel) => {
- (Some(ok.as_str()), Some(cancel.as_str()))
+ (Some(ok.as_str()), None, Some(cancel.as_str()))
+ }
+ MessageDialogButtons::YesNoCancelCustom(yes, no, cancel) => {
+ (Some(yes.as_str()), Some(no.as_str()), Some(cancel.as_str()))
}
};
MessageDialogPayload {
@@ -252,6 +257,7 @@ impl MessageDialogBuilder {
message: &self.message,
kind: &self.kind,
ok_button_label,
+ no_button_label,
cancel_button_label,
}
}
@@ -295,16 +301,55 @@ impl MessageDialogBuilder {
}
/// Shows a message dialog
+ ///
+ /// Returns `true` if the user pressed the OK/Yes button,
pub fn show(self, f: F) {
+ let ok_label = match &self.buttons {
+ MessageDialogButtons::OkCustom(ok) => Some(ok.clone()),
+ MessageDialogButtons::OkCancelCustom(ok, _) => Some(ok.clone()),
+ MessageDialogButtons::YesNoCancelCustom(yes, _, _) => Some(yes.clone()),
+ _ => None,
+ };
+
+ show_message_dialog(self, move |res| {
+ let sucess = match res {
+ MessageDialogResult::Ok | MessageDialogResult::Yes => true,
+ MessageDialogResult::Custom(s) => {
+ ok_label.map_or(s == OK, |ok_label| ok_label == s)
+ }
+ _ => false,
+ };
+
+ f(sucess)
+ })
+ }
+
+ /// Shows a message dialog and returns the button that was pressed.
+ ///
+ /// Returns a [`MessageDialogResult`] enum that indicates which button was pressed.
+ pub fn show_with_result(self, f: F) {
show_message_dialog(self, f)
}
/// Shows a message dialog.
+ ///
+ /// Returns `true` if the user pressed the OK/Yes button,
+ ///
/// This is a blocking operation,
/// and should *NOT* be used when running on the main thread context.
pub fn blocking_show(self) -> bool {
blocking_fn!(self, show)
}
+
+ /// Shows a message dialog and returns the button that was pressed.
+ ///
+ /// Returns a [`MessageDialogResult`] enum that indicates which button was pressed.
+ ///
+ /// This is a blocking operation,
+ /// and should *NOT* be used when running on the main thread context.
+ pub fn blocking_show_with_result(self) -> MessageDialogResult {
+ blocking_fn!(self, show_with_result)
+ }
}
#[derive(Debug, Serialize)]
pub(crate) struct Filter {
diff --git a/plugins/dialog/src/mobile.rs b/plugins/dialog/src/mobile.rs
index b73def4f98..46ea3a2769 100644
--- a/plugins/dialog/src/mobile.rs
+++ b/plugins/dialog/src/mobile.rs
@@ -8,7 +8,7 @@ use tauri::{
AppHandle, Runtime,
};
-use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder};
+use crate::{FileDialogBuilder, FilePath, MessageDialogBuilder, MessageDialogResult};
#[cfg(target_os = "android")]
const PLUGIN_IDENTIFIER: &str = "app.tauri.dialog";
@@ -107,13 +107,11 @@ pub fn save_file) + Send + 'static>(
#[derive(Debug, Deserialize)]
struct ShowMessageDialogResponse {
- #[allow(dead_code)]
- cancelled: bool,
- value: bool,
+ value: String,
}
/// Shows a message dialog
-pub fn show_message_dialog(
+pub fn show_message_dialog(
dialog: MessageDialogBuilder,
f: F,
) {
@@ -122,6 +120,8 @@ pub fn show_message_dialog(
.dialog
.0
.run_mobile_plugin::("showMessageDialog", dialog.payload());
- f(res.map(|r| r.value).unwrap_or_default())
+
+ let res = res.map(|res| res.value.into());
+ f(res.unwrap_or_default())
});
}
diff --git a/plugins/dialog/src/models.rs b/plugins/dialog/src/models.rs
index d6452bce7d..0b2de2c9a3 100644
--- a/plugins/dialog/src/models.rs
+++ b/plugins/dialog/src/models.rs
@@ -52,7 +52,7 @@ impl Serialize for MessageDialogKind {
/// Set of button that will be displayed on the dialog
#[non_exhaustive]
-#[derive(Debug, Default, Clone)]
+#[derive(Debug, Default, Clone, Serialize, Deserialize)]
pub enum MessageDialogButtons {
#[default]
/// A single `Ok` button with OS default dialog text
@@ -61,8 +61,49 @@ pub enum MessageDialogButtons {
OkCancel,
/// 2 buttons `Yes` and `No` with OS default dialog texts
YesNo,
+ /// 3 buttons `Yes`, `No` and `Cancel` with OS default dialog texts
+ YesNoCancel,
/// A single `Ok` button with custom text
OkCustom(String),
/// 2 buttons `Ok` and `Cancel` with custom texts
OkCancelCustom(String, String),
+ /// 3 buttons `Yes`, `No` and `Cancel` with custom texts
+ YesNoCancelCustom(String, String, String),
+}
+
+/// Result of a message dialog
+#[derive(Debug, Default, Clone, PartialEq, Eq, Deserialize, Serialize)]
+pub enum MessageDialogResult {
+ Yes,
+ No,
+ Ok,
+ #[default]
+ Cancel,
+ #[serde(untagged)]
+ Custom(String),
+}
+
+#[cfg(desktop)]
+impl From for MessageDialogResult {
+ fn from(result: rfd::MessageDialogResult) -> Self {
+ match result {
+ rfd::MessageDialogResult::Yes => Self::Yes,
+ rfd::MessageDialogResult::No => Self::No,
+ rfd::MessageDialogResult::Ok => Self::Ok,
+ rfd::MessageDialogResult::Cancel => Self::Cancel,
+ rfd::MessageDialogResult::Custom(s) => Self::Custom(s),
+ }
+ }
+}
+
+impl From for MessageDialogResult {
+ fn from(value: String) -> Self {
+ match value.as_str() {
+ "Yes" => Self::Yes,
+ "No" => Self::No,
+ "Ok" => Self::Ok,
+ "Cancel" => Self::Cancel,
+ _ => Self::Custom(value),
+ }
+ }
}