Mountain/Track/Effect/CreateEffectForRequest/
WindowUI.rs1use std::sync::Arc;
7
8use serde_json::{Value, json};
9use tauri::Runtime;
10
11use crate::{
12 ApplicationState::State::ApplicationState::ApplicationState,
13 RunTime::ApplicationRunTime::ApplicationRunTime,
14 Track::Effect::{
15 CreateEffectForRequest::Utilities::Params::{array_unwrap, ensure_array},
16 MappedEffectType::MappedEffect,
17 },
18 dev_log,
19};
20
21pub fn CreateEffect<R:Runtime>(MethodName:&str, Parameters:Value) -> Option<Result<MappedEffect, String>> {
22 match MethodName {
23 "Window.ShowMessage" => {
24 crate::effect!(run_time, {
25 use std::sync::atomic::{AtomicU64, Ordering as AO};
26
27 use tauri::Emitter;
28
29 let AppHandle = run_time.Environment.ApplicationHandle.clone();
30
31 let Payload = array_unwrap(Parameters);
32
33 let Message = Payload.get("message").and_then(Value::as_str).unwrap_or("").to_string();
34
35 let Level = Payload.get("level").and_then(Value::as_str).unwrap_or("info").to_string();
36
37 let Items = Payload.get("items").and_then(Value::as_array).cloned().unwrap_or_default();
38
39 let Options = Payload.get("options").cloned().unwrap_or(json!({}));
40
41 if Items.is_empty() {
42 let _ = AppHandle.emit(
44 "sky://notification/show",
45 json!({
46 "message": Message,
47 "severity": Level,
48 "actions": [],
49 "options": Options,
50 }),
51 );
52
53 return Ok(Value::Null);
54 }
55
56 static UI_MSG_SEQ:AtomicU64 = AtomicU64::new(1);
60
61 let Nonce = format!("msg-{}", UI_MSG_SEQ.fetch_add(1, AO::Relaxed));
62
63 let (tx, rx) = tokio::sync::oneshot::channel();
64
65 run_time.Environment.ApplicationState.UI.AddPendingRequest(Nonce.clone(), tx);
66
67 let Actions:Vec<serde_json::Value> = Items
68 .iter()
69 .map(|Item| if Item.is_string() { json!({ "title": Item }) } else { Item.clone() })
70 .collect();
71
72 if let Err(Error) = AppHandle.emit(
73 "sky://ui/show-message-request",
74 json!({
75 "RequestIdentifier": Nonce,
76 "Payload": {
77 "Severity": Level,
78 "Message": Message,
79 "Options": { "Actions": Actions },
80 },
81 }),
82 ) {
83 run_time.Environment.ApplicationState.UI.RemovePendingRequest(&Nonce);
84
85 dev_log!("notification", "warn: [Window.ShowMessage] emit failed: {}", Error);
86
87 return Ok(Value::Null);
88 }
89
90 match rx.await {
91 Ok(Ok(Value)) => Ok(Value),
92 _ => Ok(Value::Null),
93 }
94 })
95 },
96
97 "Window.ShowQuickPick" | "Window.ShowInputBox" | "Window.ShowOpenDialog" | "Window.ShowSaveDialog" => {
98 let MethodNameOwned = MethodName.to_string();
99
100 crate::effect!(run_time, {
101 use tauri::Emitter;
102
103 let Args = ensure_array(Parameters);
104
105 let Channel = match MethodNameOwned.as_str() {
106 "Window.ShowQuickPick" => "sky://quickpick/show",
107 "Window.ShowInputBox" => "sky://input-box/show",
108 "Window.ShowOpenDialog" => "sky://dialog/open",
109 "Window.ShowSaveDialog" => "sky://dialog/save",
110 _ => "sky://quickpick/show",
111 };
112
113 use std::sync::atomic::{AtomicU64, Ordering as AO};
114
115 static UI_SEQ:AtomicU64 = AtomicU64::new(1);
116
117 let Nonce = format!("ui-{}", UI_SEQ.fetch_add(1, AO::Relaxed));
118
119 let (tx, rx) = tokio::sync::oneshot::channel();
122
123 run_time.Environment.ApplicationState.UI.AddPendingRequest(Nonce.clone(), tx);
124
125 let AppHandle = run_time.Environment.ApplicationHandle.clone();
126
127 if let Err(Error) = AppHandle.emit(Channel, json!({ "nonce": Nonce, "args": Args })) {
128 run_time.Environment.ApplicationState.UI.RemovePendingRequest(&Nonce.clone());
131
132 dev_log!("ipc", "warn: [{}] {} emit failed: {}", MethodNameOwned, Channel, Error);
133
134 return Err(format!("[{}] emit failed: {}", MethodNameOwned, Error));
135 }
136
137 match rx.await {
141 Ok(Ok(Value)) => Ok(Value),
142 Ok(Err(CommonError)) => Err(CommonError.to_string()),
143 Err(_RecvError) => {
144 dev_log!("ipc", "[{}] dialog dismissed (nonce dropped)", MethodNameOwned);
149
150 Ok(Value::Null)
151 },
152 }
153 })
154 },
155
156 _ => None,
157 }
158}