Skip to content

Commit 509eba8

Browse files
amrbashirLegend-Masterlucasfernog
authored
feat: support message dialogs with 3 buttons (#2641)
* feat: support message dialogs with 3 buttons * change file * From<String> * untagged & YesNoCancel * revert package.json * Update plugins/dialog/src/desktop.rs Co-authored-by: Tony <[email protected]> * no optional * Update desktop.rs * Update plugins/dialog/src/models.rs Co-authored-by: Tony <[email protected]> * change to an enum * convert back into union * regen * update @SInCE * map buttons for linux * enhance type * Add examples --------- Co-authored-by: Tony <[email protected]> Co-authored-by: Lucas Nogueira <[email protected]> Co-authored-by: Tony <[email protected]>
1 parent 9ac5fe8 commit 509eba8

File tree

11 files changed

+368
-93
lines changed

11 files changed

+368
-93
lines changed

.changes/dialog-3-buttons.md

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
---
2+
"dialog": "minor"
3+
"dialog-js": "minor"
4+
---
5+
6+
Add support for showing a message dialog with 3 buttons.

examples/api/src/views/Dialog.svelte

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,13 @@
4444
await message("Tauri is awesome!");
4545
}
4646
47+
async function msgCustom(result) {
48+
const buttons = { yes: "awesome", no: "amazing", cancel: "stunning" };
49+
await message(`Tauri is: `, { buttons })
50+
.then((res) => onMessage(`Tauri is ${res}`))
51+
.catch(onMessage);
52+
}
53+
4754
function openDialog() {
4855
open({
4956
title: "My wonderful open dialog",
@@ -136,12 +143,17 @@
136143
<label for="dialog-directory">Directory</label>
137144
</div>
138145
<br />
139-
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
140-
<button class="btn" id="save-dialog" on:click={saveDialog}
141-
>Open save dialog</button
142-
>
143-
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
144-
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
145-
>Prompt (custom)</button
146-
>
147-
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
146+
147+
<div class="flex flex-wrap flex-col md:flex-row gap-2 children:flex-shrink-0">
148+
<button class="btn" id="open-dialog" on:click={openDialog}>Open dialog</button>
149+
<button class="btn" id="save-dialog" on:click={saveDialog}
150+
>Open save dialog</button
151+
>
152+
<button class="btn" id="prompt-dialog" on:click={prompt}>Prompt</button>
153+
<button class="btn" id="custom-prompt-dialog" on:click={promptCustom}
154+
>Prompt (custom)</button
155+
>
156+
<button class="btn" id="message-dialog" on:click={msg}>Message</button>
157+
<button class="btn" id="message-dialog" on:click={msgCustom}>Message (custom)</button>
158+
159+
</div>

plugins/dialog/android/src/main/java/DialogPlugin.kt

Lines changed: 18 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ class MessageOptions {
3838
var title: String? = null
3939
lateinit var message: String
4040
var okButtonLabel: String? = null
41+
var noButtonLabel: String? = null
4142
var cancelButtonLabel: String? = null
4243
}
4344

@@ -139,9 +140,8 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
139140
return
140141
}
141142

142-
val handler = { cancelled: Boolean, value: Boolean ->
143+
val handler = { value: String ->
143144
val ret = JSObject()
144-
ret.put("cancelled", cancelled)
145145
ret.put("value", value)
146146
invoke.resolve(ret)
147147
}
@@ -153,24 +153,34 @@ class DialogPlugin(private val activity: Activity): Plugin(activity) {
153153
if (args.title != null) {
154154
builder.setTitle(args.title)
155155
}
156+
157+
val okButtonLabel = args.okButtonLabel ?: "Ok"
158+
156159
builder
157160
.setMessage(args.message)
158-
.setPositiveButton(
159-
args.okButtonLabel ?: "OK"
160-
) { dialog, _ ->
161+
.setPositiveButton(okButtonLabel) { dialog, _ ->
161162
dialog.dismiss()
162-
handler(false, true)
163+
handler(okButtonLabel)
163164
}
164165
.setOnCancelListener { dialog ->
165166
dialog.dismiss()
166-
handler(true, false)
167+
handler(args.cancelButtonLabel ?: "Cancel")
168+
}
169+
170+
if (args.noButtonLabel != null) {
171+
builder.setNeutralButton(args.noButtonLabel) { dialog, _ ->
172+
dialog.dismiss()
173+
handler(args.noButtonLabel!!)
167174
}
175+
}
176+
168177
if (args.cancelButtonLabel != null) {
169178
builder.setNegativeButton( args.cancelButtonLabel) { dialog, _ ->
170179
dialog.dismiss()
171-
handler(false, false)
180+
handler(args.cancelButtonLabel!!)
172181
}
173182
}
183+
174184
val dialog = builder.create()
175185
dialog.show()
176186
}

plugins/dialog/api-iife.js

Lines changed: 1 addition & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

plugins/dialog/guest-js/index.ts

Lines changed: 140 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -77,6 +77,80 @@ interface SaveDialogOptions {
7777
canCreateDirectories?: boolean
7878
}
7979

80+
/**
81+
* Default buttons for a message dialog.
82+
*
83+
* @since 2.4.0
84+
*/
85+
export type MessageDialogDefaultButtons =
86+
| 'Ok'
87+
| 'OkCancel'
88+
| 'YesNo'
89+
| 'YesNoCancel'
90+
91+
/** All possible button keys. */
92+
type ButtonKey = 'ok' | 'cancel' | 'yes' | 'no'
93+
94+
/** Ban everything except a set of keys. */
95+
type BanExcept<Allowed extends ButtonKey> = Partial<
96+
Record<Exclude<ButtonKey, Allowed>, never>
97+
>
98+
99+
/**
100+
* The Yes, No and Cancel buttons of a message dialog.
101+
*
102+
* @since 2.4.0
103+
*/
104+
export type MessageDialogButtonsYesNoCancel = {
105+
/** The Yes button. */
106+
yes: string
107+
/** The No button. */
108+
no: string
109+
/** The Cancel button. */
110+
cancel: string
111+
} & BanExcept<'yes' | 'no' | 'cancel'>
112+
113+
/**
114+
* The Ok and Cancel buttons of a message dialog.
115+
*
116+
* @since 2.4.0
117+
*/
118+
export type MessageDialogButtonsOkCancel = {
119+
/** The Ok button. */
120+
ok: string
121+
/** The Cancel button. */
122+
cancel: string
123+
} & BanExcept<'ok' | 'cancel'>
124+
125+
/**
126+
* The Ok button of a message dialog.
127+
*
128+
* @since 2.4.0
129+
*/
130+
export type MessageDialogButtonsOk = {
131+
/** The Ok button. */
132+
ok: string
133+
} & BanExcept<'ok'>
134+
135+
/**
136+
* Custom buttons for a message dialog.
137+
*
138+
* @since 2.4.0
139+
*/
140+
export type MessageDialogCustomButtons =
141+
| MessageDialogButtonsYesNoCancel
142+
| MessageDialogButtonsOkCancel
143+
| MessageDialogButtonsOk
144+
145+
/**
146+
* The buttons of a message dialog.
147+
*
148+
* @since 2.4.0
149+
*/
150+
export type MessageDialogButtons =
151+
| MessageDialogDefaultButtons
152+
| MessageDialogCustomButtons
153+
80154
/**
81155
* @since 2.0.0
82156
*/
@@ -85,8 +159,58 @@ interface MessageDialogOptions {
85159
title?: string
86160
/** The kind of the dialog. Defaults to `info`. */
87161
kind?: 'info' | 'warning' | 'error'
88-
/** The label of the confirm button. */
162+
/**
163+
* The label of the Ok button.
164+
*
165+
* @deprecated Use {@linkcode MessageDialogOptions.buttons} instead.
166+
*/
89167
okLabel?: string
168+
/**
169+
* The buttons of the dialog.
170+
*
171+
* @example
172+
*
173+
* ```ts
174+
* // Use system default buttons texts
175+
* await message('Hello World!', { buttons: 'Ok' })
176+
* await message('Hello World!', { buttons: 'OkCancel' })
177+
*
178+
* // Or with custom button texts
179+
* await message('Hello World!', { buttons: { ok: 'Yes!' } })
180+
* await message('Take on the task?', {
181+
* buttons: { ok: 'Accept', cancel: 'Cancel' }
182+
* })
183+
* await message('Show the file content?', {
184+
* buttons: { yes: 'Show content', no: 'Show in folder', cancel: 'Cancel' }
185+
* })
186+
* ```
187+
*
188+
* @since 2.4.0
189+
*/
190+
buttons?: MessageDialogButtons
191+
}
192+
193+
/**
194+
* Internal function to convert the buttons to the Rust type.
195+
*/
196+
function buttonsToRust(buttons: MessageDialogButtons | undefined) {
197+
if (buttons === undefined) {
198+
return undefined
199+
}
200+
201+
if (typeof buttons === 'string') {
202+
return buttons
203+
} else if ('ok' in buttons && 'cancel' in buttons) {
204+
return { OkCancelCustom: [buttons.ok, buttons.cancel] }
205+
} else if ('yes' in buttons && 'no' in buttons && 'cancel' in buttons) {
206+
return {
207+
YesNoCancelCustom: [buttons.yes, buttons.no, buttons.cancel]
208+
}
209+
} else if ('ok' in buttons) {
210+
return { OkCustom: buttons.ok }
211+
}
212+
213+
return undefined
90214
}
91215

92216
interface ConfirmDialogOptions {
@@ -202,6 +326,16 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
202326
return await invoke('plugin:dialog|save', { options })
203327
}
204328

329+
/**
330+
* The result of a message dialog.
331+
*
332+
* The result is a string if the dialog has custom buttons,
333+
* otherwise it is one of the default buttons.
334+
*
335+
* @since 2.4.0
336+
*/
337+
export type MessageDialogResult = 'Yes' | 'No' | 'Ok' | 'Cancel' | (string & {})
338+
205339
/**
206340
* Shows a message dialog with an `Ok` button.
207341
* @example
@@ -222,13 +356,15 @@ async function save(options: SaveDialogOptions = {}): Promise<string | null> {
222356
async function message(
223357
message: string,
224358
options?: string | MessageDialogOptions
225-
): Promise<void> {
359+
): Promise<MessageDialogResult> {
226360
const opts = typeof options === 'string' ? { title: options } : options
227-
await invoke('plugin:dialog|message', {
361+
362+
return invoke<MessageDialogResult>('plugin:dialog|message', {
228363
message: message.toString(),
229364
title: opts?.title?.toString(),
230365
kind: opts?.kind,
231-
okButtonLabel: opts?.okLabel?.toString()
366+
okButtonLabel: opts?.okLabel?.toString(),
367+
buttons: buttonsToRust(opts?.buttons)
232368
})
233369
}
234370

plugins/dialog/ios/Sources/DialogPlugin.swift

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ struct MessageDialogOptions: Decodable {
2020
var title: String?
2121
let message: String
2222
var okButtonLabel: String?
23+
var noButtonLabel: String?
2324
var cancelButtonLabel: String?
2425
}
2526

@@ -200,36 +201,38 @@ class DialogPlugin: Plugin {
200201
let alert = UIAlertController(
201202
title: args.title, message: args.message, preferredStyle: UIAlertController.Style.alert)
202203

203-
let cancelButtonLabel = args.cancelButtonLabel ?? ""
204-
if !cancelButtonLabel.isEmpty {
204+
if let cancelButtonLabel = args.cancelButtonLabel {
205205
alert.addAction(
206206
UIAlertAction(
207207
title: cancelButtonLabel, style: UIAlertAction.Style.default,
208208
handler: { (_) -> Void in
209-
Logger.error("cancel")
210-
211-
invoke.resolve([
212-
"value": false,
213-
"cancelled": false,
214-
])
215-
}))
209+
invoke.resolve(["value": cancelButtonLabel])
210+
}
211+
)
212+
)
216213
}
217214

218-
let okButtonLabel = args.okButtonLabel ?? (cancelButtonLabel.isEmpty ? "OK" : "")
219-
if !okButtonLabel.isEmpty {
215+
if let noButtonLabel = args.noButtonLabel {
220216
alert.addAction(
221217
UIAlertAction(
222-
title: okButtonLabel, style: UIAlertAction.Style.default,
218+
title: noButtonLabel, style: UIAlertAction.Style.default,
223219
handler: { (_) -> Void in
224-
Logger.error("ok")
225-
226-
invoke.resolve([
227-
"value": true,
228-
"cancelled": false,
229-
])
230-
}))
220+
invoke.resolve(["value": noButtonLabel])
221+
}
222+
)
223+
)
231224
}
232225

226+
let okButtonLabel = args.okButtonLabel ?? "Ok"
227+
alert.addAction(
228+
UIAlertAction(
229+
title: okButtonLabel, style: UIAlertAction.Style.default,
230+
handler: { (_) -> Void in
231+
invoke.resolve(["value": okButtonLabel])
232+
}
233+
)
234+
)
235+
233236
manager.viewController?.present(alert, animated: true, completion: nil)
234237
}
235238
}

0 commit comments

Comments
 (0)