Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions .changes/dialog-3-buttons.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
---
"dialog": "minor"
"dialog-js": "minor"
---

Add support for showing a message dialog with 3 buttons.
30 changes: 21 additions & 9 deletions examples/api/src/views/Dialog.svelte
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -136,12 +143,17 @@
<label for="dialog-directory">Directory</label>
</div>
<br />
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
<button class="btn" id="save-dialog" on:click={saveDialog}
>Open save dialog</button
>
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
>Prompt (custom)</button
>
<button class="btn" id="message-dialog" on:click={msg}>Message</button>

<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0">
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
<button class="btn" id="save-dialog" on:click={saveDialog}
>Open save dialog</button
>
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
>Prompt (custom)</button
>
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
<button class="btn" id="message-dialog" on:click={msgCustom}>Message (custom)</button>

</div>
26 changes: 18 additions & 8 deletions plugins/dialog/android/src/main/java/DialogPlugin.kt
Original file line number Diff line number Diff line change
Expand Up @@ -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
}

Expand Down Expand Up @@ -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)
}
Expand All @@ -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()
}
Expand Down
2 changes: 1 addition & 1 deletion plugins/dialog/api-iife.js

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

133 changes: 129 additions & 4 deletions plugins/dialog/guest-js/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,68 @@ interface SaveDialogOptions {
canCreateDirectories?: boolean
}

/**
* Default buttons for a message dialog.
*
* @since 2.3.0
*/
export type MessageDialogDefaultButtons = 'Ok' | 'OkCancel' | 'YesNo'

/**
* 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
*/
Expand All @@ -85,8 +147,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 {
Expand Down Expand Up @@ -202,6 +297,32 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
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 & {})

type MessageDialogResultRust =
| 'Yes'
| 'No'
| 'Ok'
| 'Cancel'
| { Custom: string }

/** Internal function to convert the result to JS. */
function resultToJS(res: MessageDialogResultRust): MessageDialogResult {
if (typeof res === 'string') {
return res
} else {
return res.Custom
}
}

/**
* Shows a message dialog with an `Ok` button.
* @example
Expand All @@ -222,14 +343,18 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
async function message(
message: string,
options?: string | MessageDialogOptions
): Promise<void> {
): Promise<MessageDialogResult> {
const opts = typeof options === 'string' ? { title: options } : options
await invoke('plugin:dialog|message', {

const res = await invoke<MessageDialogResultRust>('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)
})

return resultToJS(res)
}

/**
Expand Down
41 changes: 22 additions & 19 deletions plugins/dialog/ios/Sources/DialogPlugin.swift
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ struct MessageDialogOptions: Decodable {
var title: String?
let message: String
var okButtonLabel: String?
var noButtonLabel: String?
var cancelButtonLabel: String?
}

Expand Down Expand Up @@ -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)
}
}
Expand Down
Loading
Loading