Skip to content

Commit 660031d

Browse files
committed
调整代码结构
1 parent 4819157 commit 660031d

File tree

5 files changed

+206
-196
lines changed

5 files changed

+206
-196
lines changed

src-tauri/src/api/launcher_api.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ use anyhow::Result;
22
use rand::{Rng, distributions::Alphanumeric};
33
use serde::Deserialize;
44
use tauri::{AppHandle, State};
5+
use tauri_plugin_opener::OpenerExt;
56
use tracing::info;
67

78
use crate::{
@@ -18,7 +19,6 @@ use crate::{
1819
LauncherLaunchedPayload,
1920
},
2021
},
21-
open_using_default_program,
2222
};
2323

2424
/// 创建新的启动器
@@ -324,3 +324,19 @@ pub fn launch_resources(app: &AppHandle, resources: &[LauncherResource]) {
324324
}
325325
}
326326
}
327+
328+
/// 使用系统默认的程序打开指定的文件或 URL。
329+
///
330+
/// # 参数
331+
/// - `app`: 应用程序状态的引用,用于访问 Tauri 的应用句柄。
332+
/// - `path`: 表示文件路径或 URL 的字符串切片。
333+
///
334+
/// # 返回值
335+
/// - `Ok(())` 表示操作成功。
336+
/// - `Err(OneClickLaunchError)` 表示操作失败。
337+
pub fn open_using_default_program(app: &AppHandle, path: &str) -> Result<(), OneClickLaunchError> {
338+
app.opener()
339+
.open_path(path, None::<&str>)
340+
.map_err(|e| OneClickLaunchError::ExecutionError(e.to_string()))?;
341+
Ok(())
342+
}

src-tauri/src/api/setting_api.rs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
use sqlx::{Executor, Sqlite};
12
use tauri::{AppHandle, State};
23

34
use crate::{
@@ -50,3 +51,17 @@ pub async fn read_all_setting(
5051
let setting = settings::read_all(&db.pool).await?;
5152
Ok(setting)
5253
}
54+
55+
pub async fn check_launch_then_exit<'a, E>(executor: E) -> Result<bool, OneClickLaunchError>
56+
where
57+
E: Executor<'a, Database = Sqlite>,
58+
{
59+
match settings::read(executor, "launch_then_exit").await {
60+
Ok(Some(setting)) => Ok(string_to_bool(&setting.value)),
61+
_ => Ok(false),
62+
}
63+
}
64+
65+
fn string_to_bool(s: &str) -> bool {
66+
matches!(s.trim().to_lowercase().as_str(), "true")
67+
}

src-tauri/src/api/window_api.rs

Lines changed: 165 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
1+
use std::{sync::Mutex, time::Instant};
2+
3+
use anyhow::Result;
14
use tauri::{
2-
AppHandle, Manager, State, Theme,
5+
AppHandle, DragDropEvent, Manager, State, Theme,
36
menu::{MenuBuilder, MenuItem},
7+
tray::{MouseButton, MouseButtonState, TrayIconBuilder, TrayIconEvent},
8+
};
9+
use tracing::{debug, info};
10+
11+
use crate::{
12+
DatabaseManager, WindowContext,
13+
constants::{self, WINDOW_MIN_HEIGHT, WINDOW_MIN_WIDTH},
14+
db::launcher,
15+
error::OneClickLaunchError,
16+
events::{
17+
EventDispatcher,
18+
types::{DragDropResource, DragDropResourcePaylod},
19+
},
420
};
521

6-
use crate::{DatabaseManager, WindowContext, db::launcher, error::OneClickLaunchError};
22+
use super::{launcher_api, setting_api};
723

824
pub fn hide_window(app: &AppHandle) -> Result<(), OneClickLaunchError> {
925
let window = app.get_webview_window("main").unwrap();
@@ -50,3 +66,150 @@ pub fn change_windows_theme(app: &AppHandle, theme: &str) -> Result<(), OneClick
5066
}
5167
Ok(())
5268
}
69+
70+
pub fn handle_window_event(window: &tauri::Window, event: &tauri::WindowEvent) {
71+
match event {
72+
tauri::WindowEvent::CloseRequested { api, .. } => {
73+
api.prevent_close();
74+
let _ = window.hide();
75+
76+
let app_handle = window.app_handle().clone();
77+
tauri::async_runtime::spawn(async move {
78+
let db = app_handle.state::<DatabaseManager>();
79+
let setting = setting_api::read_setting(db, constants::CLOSE_MAIN_PANEL_KEY).await;
80+
81+
match setting {
82+
Ok(Some(setting)) if constants::CLOSE_MAIN_PANEL_EXIT == setting.value => {
83+
app_handle.exit(0);
84+
}
85+
_ => {}
86+
}
87+
});
88+
}
89+
tauri::WindowEvent::ScaleFactorChanged {
90+
scale_factor,
91+
new_inner_size,
92+
..
93+
} => {
94+
print!(
95+
"ScaleFactorChanged scale_factor: {}, new_inner_size: {:?}",
96+
scale_factor, new_inner_size
97+
);
98+
99+
let now = Instant::now();
100+
let state = window.state::<ScaleFactorChangedState>();
101+
let mut lock = state.last_reset.try_lock();
102+
103+
if let Ok(ref mut last_reset) = lock {
104+
// 500ms防抖间隔
105+
if last_reset.map_or(true, |t| now.duration_since(t).as_millis() > 500) {
106+
if let Ok(physical_size) = window.inner_size() {
107+
// 如果窗口大小异常,强制调整到正常大小
108+
if physical_size.width != WINDOW_MIN_WIDTH
109+
|| physical_size.height != WINDOW_MIN_HEIGHT
110+
{
111+
let _ = window.set_size(tauri::Size::Logical(tauri::LogicalSize {
112+
width: WINDOW_MIN_WIDTH as f64,
113+
height: WINDOW_MIN_HEIGHT as f64,
114+
}));
115+
**last_reset = Some(now);
116+
debug!("DPI发生变化,触发窗口大小重置");
117+
}
118+
}
119+
} else {
120+
debug!("DPI重置窗口防抖生效");
121+
}
122+
}
123+
}
124+
tauri::WindowEvent::DragDrop(drag_drop_event) => match drag_drop_event {
125+
DragDropEvent::Drop { paths, .. } if !paths.is_empty() => {
126+
let _ = EventDispatcher::<DragDropResource>::send_event(
127+
window.app_handle(),
128+
DragDropResourcePaylod {
129+
paths: paths.clone(),
130+
},
131+
);
132+
}
133+
_ => {}
134+
},
135+
tauri::WindowEvent::Resized(physical_size) => {
136+
if physical_size.width == 0 && physical_size.height == 0 {
137+
// 页面最小化时忽略
138+
return;
139+
}
140+
// 如果窗口大小过小,强制调整到正常大小
141+
if physical_size.width < WINDOW_MIN_WIDTH || physical_size.height < WINDOW_MIN_HEIGHT {
142+
let _ = window.set_size(tauri::Size::Logical(tauri::LogicalSize {
143+
width: WINDOW_MIN_WIDTH as f64,
144+
height: WINDOW_MIN_HEIGHT as f64,
145+
}));
146+
debug!("窗口大小过小,触发窗口大小重置: ps: {:?}", physical_size);
147+
}
148+
}
149+
_ => {}
150+
}
151+
}
152+
153+
/// 初始化窗口
154+
pub fn setup_tray(app: &AppHandle) -> Result<()> {
155+
let tray_icon = TrayIconBuilder::new()
156+
// 设置系统托盘的提示,鼠标悬浮时会显示
157+
.tooltip(constants::APPLICATION_NAME)
158+
// 左键系统托盘时不显示菜单
159+
.show_menu_on_left_click(false)
160+
// 使用主窗口的icon作为系统托盘的图标
161+
.icon(app.default_window_icon().unwrap().clone())
162+
// 系统托盘的点击事件
163+
.on_tray_icon_event(|tray, event| match event {
164+
TrayIconEvent::Click {
165+
button: MouseButton::Left,
166+
button_state: MouseButtonState::Up,
167+
..
168+
} => {
169+
// 当用户点击系统托盘时使应用程序取消最小化,显示并聚焦
170+
let app = tray.app_handle();
171+
if let Some(window) = app.get_webview_window("main") {
172+
let _ = window.unminimize();
173+
let _ = window.show();
174+
let _ = window.set_focus();
175+
}
176+
}
177+
_ => {
178+
debug!("unhandled event {event:?}");
179+
}
180+
})
181+
.on_menu_event(|app, event| match event.id.as_ref() {
182+
"quit" => {
183+
// 退出应用程序
184+
info!("quit menu item was clicked");
185+
app.exit(0);
186+
}
187+
id if id.starts_with("launch_") => {
188+
// 系统托盘的菜单id由"launch_"与启动器id拼接而成, 点击菜单后通过解析id,找到要启动的启动器触发启动
189+
let id = &id["launch_".len()..];
190+
if let Ok(launcher_id) = id.parse::<i64>() {
191+
let app_cloned = app.clone();
192+
tauri::async_runtime::spawn(async move {
193+
let inner_app = app_cloned.clone();
194+
let db = inner_app.state();
195+
launcher_api::launch(app_cloned, db, launcher_id).await
196+
});
197+
}
198+
}
199+
_ => {
200+
tracing::error!("menu item {:?} not handled", event.id);
201+
}
202+
})
203+
.build(app)?;
204+
205+
let window_context = WindowContext { tray_icon };
206+
207+
app.manage(window_context);
208+
209+
Ok(())
210+
}
211+
212+
/// 用于保存上次处理分辨率变更事件的时间
213+
pub struct ScaleFactorChangedState {
214+
pub last_reset: Mutex<Option<Instant>>,
215+
}

src-tauri/src/events/system_listeners.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,7 @@ use tracing::{debug, error};
33

44
use crate::{
55
DatabaseManager,
6-
api::{launcher_api, window_api},
7-
check_launch_then_exit,
6+
api::{launcher_api, setting_api::check_launch_then_exit, window_api},
87
constants::{AUTO_START_FLAG, THEME_KEY},
98
db::{launcher_resource, settings},
109
events::EventDispatcher,

0 commit comments

Comments
 (0)