Skip to content

Commit 519cd12

Browse files
committed
事件组件
1 parent a2ac1b3 commit 519cd12

File tree

14 files changed

+281
-19
lines changed

14 files changed

+281
-19
lines changed

components.d.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,9 @@ export {}
88
/* prettier-ignore */
99
declare module 'vue' {
1010
export interface GlobalComponents {
11+
ElHelp: typeof import('element-plus/es')['ElHelp']
1112
ElOption: typeof import('element-plus/es')['ElOption']
1213
ElSelect: typeof import('element-plus/es')['ElSelect']
14+
ElTooltip: typeof import('element-plus/es')['ElTooltip']
1315
}
1416
}

package-lock.json

Lines changed: 13 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
},
1212
"dependencies": {
1313
"@fortawesome/fontawesome-free": "^6.7.2",
14+
"@icon-park/vue-next": "^1.4.2",
1415
"@tauri-apps/api": "^2.2.0",
1516
"@tauri-apps/plugin-autostart": "^2.2.0",
1617
"@tauri-apps/plugin-dialog": "^2.2.0",

src-tauri/src/api/launcher_api.rs

Lines changed: 49 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,25 @@
11
use anyhow::Result;
22
use rand::{Rng, distributions::Alphanumeric};
3-
use tauri::{AppHandle, Emitter, State};
4-
use tracing::info;
3+
use tauri::{AppHandle, Emitter, Manager, State};
4+
use tracing::{debug, info};
55

66
use crate::{
7-
DatabaseManager,
7+
DatabaseManager, check_launch_then_exit,
88
db::{
99
launcher,
1010
launcher_resource::{self, LauncherResource},
1111
},
1212
error::OneClickLaunchError,
13+
events::{
14+
payloads::{LauncherLaunched, LauncherLaunchedPayload},
15+
types::{EventDispatcher, EventSystem},
16+
},
1317
open_using_default_program,
1418
};
1519

20+
pub const LAUNCHER_LAUNCHED_EVENT: &str = "launcher_launched";
21+
pub const LAUNCHER_BASIC_INFO_UPDATED_EVENT: &str = "launcher_basic_info_updated";
22+
1623
/// 创建新的启动器
1724
#[tauri::command]
1825
pub async fn craete_launcher(
@@ -22,7 +29,7 @@ pub async fn craete_launcher(
2229
) -> Result<i64, OneClickLaunchError> {
2330
let name = name.unwrap_or_else(generate_default_launcher_name);
2431
let launcher_id = launcher::create(&db.pool, &name, None).await?;
25-
let _ = app.emit("launcher_basic_info_updated", "");
32+
let _ = app.emit(LAUNCHER_BASIC_INFO_UPDATED_EVENT, "");
2633
Ok(launcher_id)
2734
}
2835

@@ -50,7 +57,7 @@ pub async fn modify_launcher_name(
5057
name: String,
5158
) -> Result<(), OneClickLaunchError> {
5259
launcher::modify_launcher_name(&db.pool, launcher_id, &name).await?;
53-
let _ = app.emit("launcher_basic_info_updated", "");
60+
let _ = app.emit(LAUNCHER_BASIC_INFO_UPDATED_EVENT, "");
5461
Ok(())
5562
}
5663

@@ -79,7 +86,7 @@ pub async fn copy_launcher(
7986

8087
tx.commit().await?;
8188

82-
let _ = app.emit("launcher_basic_info_updated", "");
89+
let _ = app.emit(LAUNCHER_BASIC_INFO_UPDATED_EVENT, "");
8390

8491
Ok(new_launcher_id)
8592
}
@@ -147,7 +154,7 @@ pub async fn delete_launcher(
147154

148155
tx.commit().await?;
149156

150-
let _ = app.emit("launcher_basic_info_updated", "");
157+
let _ = app.emit(LAUNCHER_BASIC_INFO_UPDATED_EVENT, "");
151158

152159
Ok(())
153160
}
@@ -173,7 +180,7 @@ pub async fn modify_launcher_sort(
173180

174181
tx.commit().await?;
175182

176-
let _ = app.emit("launcher_basic_info_updated", "");
183+
let _ = app.emit(LAUNCHER_BASIC_INFO_UPDATED_EVENT, "");
177184

178185
Ok(())
179186
}
@@ -236,6 +243,13 @@ pub async fn launch(
236243

237244
launch_launcher_resources(&app, &resources);
238245

246+
// app.emit(
247+
// LAUNCHER_LAUNCHED_EVENT,
248+
// LauncherLaunchedPayload { launcher_id },
249+
// )?;
250+
251+
EventDispatcher::<LauncherLaunched>::send_event(&app, LauncherLaunchedPayload { launcher_id })?;
252+
239253
Ok(())
240254
}
241255

@@ -249,3 +263,30 @@ pub fn launch_launcher_resources(app: &AppHandle, resources: &[LauncherResource]
249263
}
250264
}
251265
}
266+
267+
pub fn de(app: AppHandle) {
268+
// 监听 `event-name`(无论其在什么窗口中触发)
269+
let app_handle = app; // 获取 AppHandle
270+
271+
EventSystem::register_listener(&app_handle.clone(), LauncherLaunched, move |_payload| {
272+
let inner_app_handle = app_handle.clone();
273+
tauri::async_runtime::spawn(async move {
274+
let db = inner_app_handle.state::<DatabaseManager>();
275+
if let Ok(_exit @ true) = check_launch_then_exit(&db.pool).await {
276+
debug!("监听到启动器启动完成事件, 已设置启动后退出, 正在退出程序.");
277+
inner_app_handle.exit(0);
278+
}
279+
});
280+
});
281+
282+
// let _id = app.listen(launcher_api::LAUNCHER_LAUNCHED_EVENT, move |_event| {
283+
// let inner_app_handle = app_handle.clone();
284+
// tauri::async_runtime::spawn(async move {
285+
// let db = inner_app_handle.state::<DatabaseManager>();
286+
// if let Ok(_exit @ true) = check_launch_then_exit(&db.pool).await {
287+
// debug!("监听到启动器启动完成事件, 已设置启动后退出, 正在退出程序.");
288+
// inner_app_handle.exit(0);
289+
// }
290+
// });
291+
// });
292+
}

src-tauri/src/error.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ pub enum OneClickLaunchError {
1818

1919
#[error("{0}")]
2020
TauriError(#[from] tauri::Error),
21+
22+
#[error("Unable to convert from {0} to Event")]
23+
EventConvertError(String),
2124
}
2225

2326
// we must manually implement serde::Serialize

src-tauri/src/events.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
pub mod payloads;
2+
pub mod types;

src-tauri/src/events/payloads.rs

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
use serde::{Deserialize, Serialize};
2+
3+
use super::types::Event;
4+
5+
pub struct LauncherLaunched;
6+
#[derive(Serialize, Deserialize, Clone)]
7+
pub struct LauncherLaunchedPayload {
8+
pub launcher_id: i64,
9+
}
10+
11+
impl Event for LauncherLaunched {
12+
type Payload = LauncherLaunchedPayload;
13+
14+
fn name() -> &'static str {
15+
"launcher_launched"
16+
}
17+
}

src-tauri/src/events/types.rs

Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
use std::marker::PhantomData;
2+
3+
use serde::{Deserialize, Serialize};
4+
use tauri::{AppHandle, Emitter, Listener};
5+
use tracing::error;
6+
7+
use crate::error::OneClickLaunchError;
8+
9+
// #[derive(serde::Deserialize, serde::Serialize, Debug, Clone)]
10+
// pub enum Event {
11+
// LauncherLaunched { launcher_id: i64 },
12+
// LauncherBasicInfoUpdated { launcher_id: i64 },
13+
// }
14+
15+
// impl Event {
16+
// pub fn name(&self) -> &'static str {
17+
// match self {
18+
// Event::LauncherLaunched { .. } => "launcher_launched",
19+
// Event::LauncherBasicInfoUpdated { .. } => "launcher_basic_info_updated",
20+
// }
21+
// }
22+
// }
23+
24+
pub trait Event {
25+
type Payload: Serialize + for<'a> Deserialize<'a> + Clone;
26+
27+
fn name() -> &'static str;
28+
}
29+
30+
// 事件发送器
31+
pub struct EventDispatcher<E: Event> {
32+
_marker: PhantomData<E>,
33+
}
34+
35+
impl<E: Event> EventDispatcher<E> {
36+
pub fn send_event(app: &AppHandle, payload: E::Payload) -> Result<(), OneClickLaunchError> {
37+
app.emit(E::name(), payload)?;
38+
Ok(())
39+
}
40+
}
41+
42+
// 事件监听器注册系统
43+
pub struct EventSystem;
44+
45+
impl EventSystem {
46+
pub fn register_listener<E, F>(app: &AppHandle, _event: E, callback: F)
47+
where
48+
E: Event + 'static,
49+
F: Fn(E::Payload) + Send + 'static,
50+
{
51+
app.listen(E::name(), move |e| {
52+
if let Ok(payload) = serde_json::from_str(e.payload()) {
53+
callback(payload);
54+
} else {
55+
error!("{}事件payload反序列化失败.原始数据: {}", "", e.payload());
56+
}
57+
});
58+
}
59+
}

src-tauri/src/lib.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,24 @@
11
use crate::error::OneClickLaunchError;
22
use anyhow::Result;
3+
use api::launcher_api::de;
34
use api::{launcher_api, setting_api, window_api};
45
use db::{launcher, launcher_resource, settings};
56
use lazy_static::lazy_static;
7+
use sqlx::{Executor, Sqlite};
68
use sqlx::{SqlitePool, sqlite::SqlitePoolOptions};
79
use std::path::PathBuf;
810
use std::sync::Mutex;
911
use std::{env, fs};
10-
use tauri::Emitter;
1112
use tauri::tray::{MouseButton, MouseButtonState, TrayIcon, TrayIconEvent};
1213
use tauri::{AppHandle, Manager, tray::TrayIconBuilder};
14+
use tauri::{Emitter, Listener};
1315
use tauri_plugin_autostart::MacosLauncher;
1416
use tauri_plugin_opener::OpenerExt;
1517
use tracing::{debug, info};
1618
mod api;
1719
mod db;
1820
pub mod error;
21+
mod events;
1922

2023
lazy_static! {
2124
static ref AUTO_START_FLAG: String = "--auto".to_string();
@@ -72,7 +75,7 @@ fn get_db_path() -> Result<PathBuf> {
7275
if !db_path.exists() {
7376
// 创建空的数据库文件
7477
fs::File::create(&db_path)?;
75-
println!("Database file created at {:?}", db_path);
78+
info!("Database file created at {:?}", db_path);
7679
}
7780

7881
Ok(db_path)
@@ -116,6 +119,20 @@ async fn query_auto_start_launcher_ids(
116119
Mutex::new(auto_start_resources)
117120
}
118121

122+
async fn check_launch_then_exit<'a, E>(executor: E) -> Result<bool, OneClickLaunchError>
123+
where
124+
E: Executor<'a, Database = Sqlite>,
125+
{
126+
match settings::read(executor, "launch_then_exit").await {
127+
Ok(Some(setting)) => Ok(string_to_bool(&setting.value)),
128+
_ => Ok(false),
129+
}
130+
}
131+
132+
fn string_to_bool(s: &str) -> bool {
133+
matches!(s.trim().to_lowercase().as_str(), "true")
134+
}
135+
119136
#[cfg_attr(mobile, tauri::mobile_entry_point)]
120137
pub async fn run() -> Result<()> {
121138
let db_manager = init_db().await?;
@@ -150,7 +167,7 @@ pub async fn run() -> Result<()> {
150167
}
151168
}
152169
_ => {
153-
// println!("unhandled event {event:?}");
170+
debug!("unhandled event {event:?}");
154171
}
155172
})
156173
.on_menu_event(|app, event| match event.id.as_ref() {
@@ -173,6 +190,20 @@ pub async fn run() -> Result<()> {
173190

174191
app.manage(window_context);
175192

193+
// 监听 `event-name`(无论其在什么窗口中触发)
194+
let app_handle = app.handle().clone(); // 获取 AppHandle
195+
de(app_handle);
196+
// let _id = app.listen(launcher_api::LAUNCHER_LAUNCHED_EVENT, move |_event| {
197+
// let inner_app_handle = app_handle.clone();
198+
// tauri::async_runtime::spawn(async move {
199+
// let db = inner_app_handle.state::<DatabaseManager>();
200+
// if let Ok(_exit @ true) = check_launch_then_exit(&db.pool).await {
201+
// debug!("监听到启动器启动完成事件, 已设置启动后退出, 正在退出程序.");
202+
// inner_app_handle.exit(0);
203+
// }
204+
// });
205+
// });
206+
176207
// 检查是否包含 `--auto` 参数
177208
if args.contains(&AUTO_START_FLAG) {
178209
if let Ok(mut data) = auto_start_resources.lock() {

src/App.vue

Lines changed: 50 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,4 +58,54 @@ export default defineComponent({
5858
color: rgba(188, 190, 196);
5959
}
6060
61+
.dark .el-select-dropdown {
62+
background-color: rgba(30, 31, 34);
63+
color: rgba(188, 190, 196);
64+
}
65+
66+
.dark .el-select-dropdown__item.is-hovering {
67+
background-color: #020913;
68+
}
69+
70+
.dark .el-tag {
71+
background-color: rgba(30, 31, 34);
72+
color: rgba(188, 190, 196);
73+
}
74+
75+
/* 公共样式 */
76+
input[type="checkbox"] {
77+
width: 16px;
78+
height: 16px;
79+
border: 1px solid #ccc;
80+
border-radius: 3px;
81+
background-color: #f0f0f0;
82+
cursor: pointer;
83+
outline: none;
84+
}
85+
86+
/* 勾选标记 */
87+
input[type="checkbox"]:checked::after,
88+
.dark input[type="checkbox"]:checked::after {
89+
content: "";
90+
display: block;
91+
text-align: center;
92+
color: #fff;
93+
font-size: 12px;
94+
line-height: 16px;
95+
}
96+
97+
/* 深色主题样式 */
98+
.dark input[type="checkbox"] {
99+
appearance: none;
100+
-webkit-appearance: none;
101+
-moz-appearance: none;
102+
border-color: #bcbec4;
103+
background-color: #1e1f22;
104+
}
105+
106+
.dark input[type="checkbox"]:checked {
107+
background-color: #ccc;
108+
border-color: #ccc;
109+
}
110+
61111
</style>

0 commit comments

Comments
 (0)