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