1use reactive_graph::{
2 effect::Effect,
3 owner::LocalStorage,
4 signal::{WriteSignal, signal},
5 traits::{Get as _, GetUntracked as _, Set as _, UpdateUntracked as _},
6 wrappers::read::Signal,
7};
8use serde::{Deserialize, Serialize};
9use std::path::PathBuf;
10
11use crate::{UseTauriError, UseTauriWithReturn, use_invoke_with_args, use_invoke_with_options};
12
13pub fn use_ask_dialog<T>() -> UseDialogReturn<ConfirmDialogOpions, T>
14where
15 T: Clone + Send + Sync + 'static,
16{
17 let (transfer, set_transfer) = signal(None::<T>);
18 let (dialog_options, set_dialog_options) = signal(None::<(ConfirmDialogOpions, T)>);
19
20 let UseTauriWithReturn {
21 data,
22 error,
23 trigger,
24 } = use_invoke_with_args::<ConfirmDialogOpions, bool>("plugin:dialog|ask");
25
26 Effect::new(move || {
27 if let Some((options, _)) = dialog_options.get() {
28 trigger.set(Some(options));
29 }
30 });
31
32 Effect::new(move || {
33 if let Some(b) = data.get() {
34 if b {
35 set_transfer.set(Some(dialog_options.get_untracked().unwrap().1));
36 }
37 set_dialog_options.update_untracked(|v| *v = None);
38 }
39 });
40
41 Effect::new(move || {
42 if let Some(_) = error.get() {
43 set_dialog_options.update_untracked(|v| *v = None);
44 }
45 });
46
47 UseDialogReturn {
48 transfer: transfer.into(),
49 error: error.into(),
50 set_dialog_options,
51 }
52}
53
54pub fn use_confirm_dialog<T>() -> UseDialogReturn<ConfirmDialogOpions, T>
55where
56 T: Clone + Send + Sync + 'static,
57{
58 let (transfer, set_transfer) = signal(None::<T>);
59 let (dialog_options, set_dialog_options) = signal(None::<(ConfirmDialogOpions, T)>);
60
61 let UseTauriWithReturn {
62 data,
63 error,
64 trigger,
65 } = use_invoke_with_args::<ConfirmDialogOpions, bool>("plugin:dialog|confirm");
66
67 Effect::new(move || {
68 if let Some((options, _)) = dialog_options.get() {
69 trigger.set(Some(options));
70 }
71 });
72
73 Effect::new(move || {
74 if let Some(b) = data.get() {
75 if b {
76 set_transfer.set(Some(dialog_options.get_untracked().unwrap().1));
77 }
78 set_dialog_options.update_untracked(|v| *v = None);
79 }
80 });
81
82 Effect::new(move || {
83 if let Some(_) = error.get() {
84 set_dialog_options.update_untracked(|v| *v = None);
85 }
86 });
87
88 UseDialogReturn {
89 transfer: transfer.into(),
90 error: error.into(),
91 set_dialog_options,
92 }
93}
94
95pub fn use_message_dialog<T>() -> UseDialogReturn<MessageDialogOpions, T>
96where
97 T: Clone + Send + Sync + 'static,
98{
99 let (transfer, set_transfer) = signal(None::<T>);
100 let (dialog_options, set_dialog_options) = signal(None::<(MessageDialogOpions, T)>);
101
102 let UseTauriWithReturn {
103 data,
104 error,
105 trigger,
106 } = use_invoke_with_args::<MessageDialogOpions, ()>("plugin:dialog|message");
107
108 Effect::new(move || {
109 if let Some((options, _)) = dialog_options.get() {
110 trigger.set(Some(options));
111 }
112 });
113
114 Effect::new(move || {
115 if let Some(()) = data.get() {
116 set_transfer.set(Some(dialog_options.get_untracked().unwrap().1));
117 set_dialog_options.update_untracked(|v| *v = None);
118 }
119 });
120
121 Effect::new(move || {
122 if let Some(_) = error.get() {
123 set_dialog_options.update_untracked(|v| *v = None);
124 }
125 });
126
127 UseDialogReturn {
128 transfer: transfer.into(),
129 error: error.into(),
130 set_dialog_options,
131 }
132}
133
134pub fn use_open_dialog() -> UseTauriWithReturn<OpenDialogOptions, Option<OpenDialogReturn>> {
135 #[derive(Clone, Serialize)]
136 struct OptionsWrapper {
137 options: OpenDialogOptions,
138 }
139
140 let (args_wrapper, set_args_wrapper) = signal(None::<OpenDialogOptions>);
141
142 let UseTauriWithReturn {
143 data,
144 error,
145 trigger,
146 } = use_invoke_with_args::<OptionsWrapper, Option<OpenDialogReturn>>("plugin:dialog|open");
147
148 Effect::new(move || {
149 if let Some(options) = args_wrapper.get() {
150 trigger.set(Some(OptionsWrapper { options }));
151 set_args_wrapper.update_untracked(|v| *v = None);
152 }
153 });
154
155 UseTauriWithReturn {
156 data: data.into(),
157 error: error.into(),
158 trigger: set_args_wrapper,
159 }
160}
161
162pub fn use_save_dialog() -> UseTauriWithReturn<SaveDialogOptions, Option<PathBuf>> {
163 use_invoke_with_options::<SaveDialogOptions, Option<PathBuf>>("plugin:dialog|save")
164}
165
166pub struct UseDialogReturn<O, T>
167where
168 O: serde::Serialize + Clone + 'static,
169 T: Clone + Send + Sync + 'static,
170{
171 pub transfer: Signal<Option<T>>,
172 pub error: Signal<Option<UseTauriError>, LocalStorage>,
173 pub set_dialog_options: WriteSignal<Option<(O, T)>>,
174}
175
176#[derive(Clone, Deserialize)]
177#[serde(untagged)]
178pub enum OpenDialogReturn {
179 Files(Vec<String>),
180 File(String),
181}
182
183#[derive(Clone, Default, Serialize)]
184#[serde(rename = "camelCase")]
185pub struct ConfirmDialogOpions {
186 pub message: String,
187 #[serde(skip_serializing_if = "Option::is_none")]
188 pub title: Option<&'static str>,
189 #[serde(skip_serializing_if = "Option::is_none")]
190 pub kind: Option<MessageDialogKind>,
191 #[serde(skip_serializing_if = "Option::is_none")]
192 pub ok_label: Option<&'static str>,
193 #[serde(skip_serializing_if = "Option::is_none")]
194 pub cancel_label: Option<&'static str>,
195}
196
197impl ConfirmDialogOpions {
198 pub fn new(msg: &str) -> Self {
199 Self {
200 message: msg.to_string(),
201 ..Default::default()
202 }
203 }
204}
205
206#[derive(Clone, Default, Serialize)]
207#[serde(rename = "camelCase")]
208pub struct MessageDialogOpions {
209 pub message: String,
210 #[serde(skip_serializing_if = "Option::is_none")]
211 pub title: Option<&'static str>,
212 #[serde(skip_serializing_if = "Option::is_none")]
213 pub kind: Option<MessageDialogKind>,
214 #[serde(skip_serializing_if = "Option::is_none")]
215 pub ok_label: Option<&'static str>,
216}
217
218impl MessageDialogOpions {
219 pub fn new(msg: &str) -> Self {
220 Self {
221 message: msg.to_string(),
222 ..Default::default()
223 }
224 }
225}
226
227#[derive(Clone, Default, Serialize)]
228#[serde(untagged, rename = "camelCase")]
229pub enum MessageDialogKind {
230 #[default]
231 Info,
232 Warning,
233 Error,
234}
235
236#[derive(Clone, Default, Serialize)]
237#[serde(rename = "camelCase")]
238pub struct DialogFilter {
239 pub name: String,
240 pub extensions: Vec<String>,
241}
242
243#[derive(Clone, Default, Serialize)]
244#[serde(rename = "camelCase")]
245pub struct OpenDialogOptions {
246 pub title: Option<String>,
247 pub filters: Vec<DialogFilter>,
248 pub multiple: bool,
249 pub directory: bool,
250 pub default_path: Option<PathBuf>,
251 pub recursive: bool,
252 pub can_create_directories: bool,
253}
254
255#[derive(Clone, Default, Serialize)]
256#[serde(rename = "camelCase")]
257pub struct SaveDialogOptions {
258 pub title: Option<String>,
259 pub filters: Vec<DialogFilter>,
260 pub default_path: Option<PathBuf>,
261 pub can_create_directories: bool,
262}