Skip to content

Commit e9482f0

Browse files
author
fuyoo
committed
feat(tray): Implement system tray functionality and optimize related logic
- Add system tray icon and menu functions, support left-click to show/hide the main window - Implement the function of exiting the application from the tray - Optimize the tray construction logic, distinguish the icon processing between macOS and other platforms - Remove duplicate window close event listening logic - Adjust the Tauri configuration file, add compilation optimization options for development and release versions - Update component declaration files, remove unused Naive UI component references - Add internationalization support for the new connection button - Implement the new form function for ZSet data type - Improve the existence check logic for keys of various data types to avoid duplicate creation - Optimize the data display interface for Hash and Set types, add search, reset and other functions - Fix the issue where list-type data was not refreshed in time after deletion - Supplement and improve Chinese and English internationalization copy content
1 parent 97d0d91 commit e9482f0

File tree

24 files changed

+867
-150
lines changed

24 files changed

+867
-150
lines changed

components.d.ts

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,11 +12,8 @@ declare module 'vue' {
1212
NAlert: typeof import('naive-ui')['NAlert']
1313
NBadge: typeof import('naive-ui')['NBadge']
1414
NButton: typeof import('naive-ui')['NButton']
15-
NCard: typeof import('naive-ui')['NCard']
1615
NConfigProvider: typeof import('naive-ui')['NConfigProvider']
1716
NDataTable: typeof import('naive-ui')['NDataTable']
18-
NDescription: typeof import('naive-ui')['NDescription']
19-
NDescriptionItem: typeof import('naive-ui')['NDescriptionItem']
2017
NDescriptions: typeof import('naive-ui')['NDescriptions']
2118
NDescriptionsItem: typeof import('naive-ui')['NDescriptionsItem']
2219
NDialogProvider: typeof import('naive-ui')['NDialogProvider']
@@ -26,26 +23,20 @@ declare module 'vue' {
2623
NEmpty: typeof import('naive-ui')['NEmpty']
2724
NForm: typeof import('naive-ui')['NForm']
2825
NFormItem: typeof import('naive-ui')['NFormItem']
29-
NH1: typeof import('naive-ui')['NH1']
30-
NH3: typeof import('naive-ui')['NH3']
3126
NH4: typeof import('naive-ui')['NH4']
3227
NInput: typeof import('naive-ui')['NInput']
3328
NInputNumber: typeof import('naive-ui')['NInputNumber']
3429
NPopconfirm: typeof import('naive-ui')['NPopconfirm']
3530
NPopselect: typeof import('naive-ui')['NPopselect']
36-
NRadio: typeof import('naive-ui')['NRadio']
3731
NRadioButton: typeof import('naive-ui')['NRadioButton']
3832
NRadioGroup: typeof import('naive-ui')['NRadioGroup']
3933
NScrollbar: typeof import('naive-ui')['NScrollbar']
4034
NSelect: typeof import('naive-ui')['NSelect']
4135
NSpace: typeof import('naive-ui')['NSpace']
4236
NSplit: typeof import('naive-ui')['NSplit']
43-
NSwitch: typeof import('naive-ui')['NSwitch']
4437
NTab: typeof import('naive-ui')['NTab']
45-
NTabPane: typeof import('naive-ui')['NTabPane']
4638
NTabs: typeof import('naive-ui')['NTabs']
4739
NTag: typeof import('naive-ui')['NTag']
48-
NTest: typeof import('naive-ui')['NTest']
4940
NText: typeof import('naive-ui')['NText']
5041
NTree: typeof import('naive-ui')['NTree']
5142
RouterLink: typeof import('vue-router')['RouterLink']

src-tauri/Cargo.toml

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,3 +32,13 @@ tauri-plugin-window-state = "2"
3232
[features]
3333
# This feature is used for production builds or when a dev server is not specified, DO NOT REMOVE!!
3434
custom-protocol = ["tauri/custom-protocol"]
35+
36+
[profile.dev]
37+
incremental = true # Compile your binary in smaller steps.
38+
39+
[profile.release]
40+
codegen-units = 1 # Allows LLVM to perform better optimization.
41+
lto = true # Enables link-time-optimizations.
42+
opt-level = "s" # Prioritizes small binary size. Use `3` if you prefer speed.
43+
panic = "abort" # Higher performance by disabling panic handlers.
44+
strip = true # Ensures debug symbols are removed.

src-tauri/icons/logo.png

7.81 KB
Loading

src-tauri/src/api/mod.rs

Lines changed: 73 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,12 @@ use crate::api::rdb::{ConnectionImpl, RedisClientImpl};
55
use crate::api::resp::Response;
66
use redis::{cmd, Value};
77
use serde::{Deserialize, Serialize};
8-
use tauri::{Emitter, Manager, Result, command};
8+
use tauri::{command, Emitter, Manager, Result};
99
pub mod rdb;
1010
pub mod resp;
1111
use crate::{r_404, r_error, r_ok};
12+
use tauri::menu::{Menu, MenuItem};
13+
use tauri::tray::{MouseButton, TrayIconBuilder, TrayIconEvent};
1214

1315
async fn route<T: serde::Serialize>(f: impl Future<Output = Result<Response<T>>>) -> String {
1416
match f.await {
@@ -83,14 +85,77 @@ async fn do_query(connection_info: ConnectionImpl, data: &str) -> Result<Respons
8385
Ok(r_ok!(rdb::convert_to_string(resp)?, None))
8486
}
8587

86-
#[derive(Serialize,Clone, Debug)]
88+
#[derive(Serialize, Clone, Debug)]
8789
pub struct Evt {
88-
pub evt: String,
89-
pub data: String,
90+
pub evt: String,
91+
pub data: String,
9092
}
9193

9294
#[command]
93-
pub async fn emit_event(app: tauri::AppHandle,evt: String, data: String) -> Result<Response<()>> {
94-
app.app_handle().emit("emit-event",Evt{evt,data})?;
95-
Ok(r_ok!((), None))
96-
}
95+
pub async fn emit_event(app: tauri::AppHandle, evt: String, data: String) -> Result<Response<()>> {
96+
app.app_handle().emit("emit-event", Evt { evt, data })?;
97+
Ok(r_ok!((), None))
98+
}
99+
100+
#[command]
101+
pub async fn quit(app: tauri::AppHandle) -> Result<Response<()>> {
102+
app.app_handle().exit(0);
103+
Ok(r_ok!((), None))
104+
}
105+
#[command]
106+
pub async fn init_tray(app: tauri::AppHandle, text: String) -> Result<Response<()>> {
107+
let app = app.app_handle();
108+
let quit_i = MenuItem::with_id(app, "quit", text, true, None::<&str>)?;
109+
let menu = Menu::with_items(app, &[&quit_i])?;
110+
if let Some(tray) = app.tray_by_id("1") {
111+
tray.set_menu(Some(menu))?;
112+
return Ok(r_ok!((), None));
113+
}
114+
let _tray = TrayIconBuilder::new()
115+
.menu(&menu)
116+
.on_menu_event(|app, event| match event.id.as_ref() {
117+
"quit" => {
118+
app.exit(0);
119+
}
120+
_ => {}
121+
})
122+
.show_menu_on_left_click(false)
123+
.on_tray_icon_event(|tray, event| match event {
124+
TrayIconEvent::Click { button, .. } => match button {
125+
MouseButton::Left => {
126+
#[cfg(target_os = "macos")]
127+
let _ = tauri::AppHandle::show(tray.app_handle());
128+
#[cfg(not(target_os = "macos"))]
129+
{
130+
let win = tray
131+
.app_handle()
132+
.get_webview_window("main")
133+
.expect("no main window");
134+
win.show().expect("failed to show window");
135+
let _ = win.set_focus();
136+
let _ = win.unminimize();
137+
}
138+
}
139+
_ => {}
140+
},
141+
_ => {}
142+
});
143+
println!("{:?}", _tray.id());
144+
// 设置图标
145+
#[cfg(target_os = "macos")]
146+
let icon = include_bytes!("../../icons/template.png");
147+
#[cfg(target_os = "macos")]
148+
let img = tauri::image::Image::from_bytes(icon)?;
149+
#[cfg(target_os = "macos")]
150+
let _tray = _tray.icon(img);
151+
#[cfg(target_os = "macos")]
152+
let _tray = _tray.icon_as_template(true);
153+
#[cfg(not(target_os = "macos"))]
154+
let icon = include_bytes!("../../icons/logo.png");
155+
#[cfg(not(target_os = "macos"))]
156+
let img = tauri::image::Image::from_bytes(icon)?;
157+
#[cfg(not(target_os = "macos"))]
158+
let _tray = _tray.icon(img);
159+
_tray.build(app)?;
160+
Ok(r_ok!((), None))
161+
}

src-tauri/src/lib.rs

Lines changed: 25 additions & 82 deletions
Original file line numberDiff line numberDiff line change
@@ -5,63 +5,6 @@ use std::sync::Mutex;
55
use tauri::webview::PageLoadEvent;
66
use tauri::Manager;
77
use tauri::RunEvent;
8-
use tauri::menu::{Menu, MenuItem};
9-
use tauri::tray::{TrayIconBuilder, TrayIconEvent, MouseButton};
10-
fn build_try(app: &mut tauri::App) -> Result<(), Box<dyn std::error::Error>> {
11-
let quit_i = MenuItem::with_id(app, "quit", "关闭", true, None::<&str>)?;
12-
let menu = Menu::with_items(app, &[&quit_i])?;
13-
14-
let _tray = TrayIconBuilder::new()
15-
.menu(&menu)
16-
.on_menu_event(|app, event| match event.id.as_ref() {
17-
"quit" => {
18-
println!("quit menu item was clicked");
19-
app.exit(0);
20-
}
21-
_ => {
22-
println!("menu item {:?} not handled", event.id);
23-
}
24-
})
25-
.show_menu_on_left_click(false)
26-
.on_tray_icon_event(|tray, event| match event {
27-
TrayIconEvent::Click { button, .. } => match button {
28-
MouseButton::Left => {
29-
#[cfg(target_os = "macos")]
30-
let _ = tauri::AppHandle::show(tray.app_handle());
31-
#[cfg(not(target_os = "macos"))]
32-
{
33-
let win = tray.app_handle()
34-
.get_webview_window("main")
35-
.expect("no main window");
36-
win.show()
37-
.expect("failed to show window");
38-
let _ = win.set_focus();
39-
let _ = win.unminimize();
40-
}
41-
42-
}
43-
_ => {}
44-
},
45-
_ => {}
46-
});
47-
// 设置图标
48-
#[cfg(target_os = "macos")]
49-
let icon = include_bytes!("../icons/template.png");
50-
#[cfg(target_os = "macos")]
51-
let img = tauri::image::Image::from_bytes(icon)?;
52-
#[cfg(target_os = "macos")]
53-
let _tray = _tray.icon(img);
54-
#[cfg(target_os = "macos")]
55-
let _tray = _tray.icon_as_template(true);
56-
#[cfg(not(target_os = "macos"))]
57-
let icon = include_bytes!("../icons/icon.png");
58-
#[cfg(not(target_os = "macos"))]
59-
let img = tauri::image::Image::from_bytes(icon)?;
60-
#[cfg(not(target_os = "macos"))]
61-
let _tray = _tray.icon(img);
62-
_tray.build(app)?;
63-
Ok(())
64-
}
658
pub fn run() -> Result<(), Box<dyn std::error::Error>> {
669
let mut app = tauri::Builder::default();
6710
// Access the system shell. Allows you to spawn child processes
@@ -80,20 +23,6 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
8023
)
8124
.build(),
8225
);
83-
// listen window event
84-
app = app.on_window_event(|win, evt| match evt {
85-
tauri::WindowEvent::CloseRequested { api, .. } => match win.label() {
86-
"main" => {
87-
api.prevent_close();
88-
#[cfg(target_os = "macos")]
89-
let _ = tauri::AppHandle::hide(win.app_handle());
90-
#[cfg(not(target_os = "macos"))]
91-
let _ = win.hide();
92-
}
93-
_ => {}
94-
},
95-
_ => {}
96-
});
9726
app = app.plugin(tauri_plugin_single_instance::init(|app, _args, _cwd| {
9827
let win = app.get_webview_window("main").expect("no main window");
9928
let _ = win.show();
@@ -109,21 +38,35 @@ pub fn run() -> Result<(), Box<dyn std::error::Error>> {
10938
Some(win) => {
11039
let _ = win.set_decorations(false);
11140
}
112-
}
113-
build_try(_app)?;
41+
};
11442

11543
Ok(())
11644
});
11745

118-
app = app
119-
.manage(Mutex::new(Vec::<tabs::Tab>::new()))
120-
.invoke_handler(tauri::generate_handler![
121-
api::request,
122-
tabs::tab_list,
123-
tabs::tab_change,
124-
tabs::tab_close,
125-
api::emit_event
126-
]);
46+
// listen window event
47+
app = app.on_window_event(|win, evt| match evt {
48+
tauri::WindowEvent::CloseRequested { api, .. } => match win.label() {
49+
"main" => {
50+
api.prevent_close();
51+
#[cfg(target_os = "macos")]
52+
let _ = tauri::AppHandle::hide(win.app_handle());
53+
#[cfg(not(target_os = "macos"))]
54+
let _ = win.hide();
55+
}
56+
_ => {}
57+
},
58+
_ => {}
59+
});
60+
app = app.manage(Mutex::new(Vec::<tabs::Tab>::new()));
61+
app = app.invoke_handler(tauri::generate_handler![
62+
api::request,
63+
tabs::tab_list,
64+
tabs::tab_change,
65+
tabs::tab_close,
66+
api::emit_event,
67+
api::quit,
68+
api::init_tray,
69+
]);
12770
let app = app.on_page_load(|wb, evt| match evt.event() {
12871
PageLoadEvent::Finished => {
12972
let win = wb.window();

src/App.vue

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,14 @@
22
import { RouterView } from 'vue-router'
33
import { useLocate } from '@/i18n'
44
import { useTheme } from './hooks/life';
5+
import { buildTray } from './tools/tray';
56
const { theme, initThemeMode, listenChange } = useTheme()
67
provide('theme', theme)
78
const { locate, listenLocateChange } = useLocate()
89
initThemeMode()
910
listenChange()
1011
listenLocateChange()
12+
buildTray()
1113
</script>
1214

1315
<template>

src/pages/host/components/CoKeys/actions.tsx renamed to src/hooks/actions.tsx

Lines changed: 31 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,39 @@
11
import NewStringForm from '@/pages/host/components/CoKeys/compoents/NewStringForm.vue'
22
import NewSetForm from '@/pages/host/components/CoKeys/compoents/NewSetForm.vue'
3+
import NewZSetForm from '@/pages/host/components/CoKeys/compoents/NewZSetForm.vue'
34
import NewListForm from '@/pages/host/components/CoKeys/compoents/NewListForm.vue'
45
import NewHashForm from '@/pages/host/components/CoKeys/compoents/NewHashForm.vue'
56
import type { DialogApiInjection } from 'naive-ui/es/dialog/src/DialogProvider'
7+
import { useReqStore } from '@/stores/req'
8+
import { useI18n } from 'vue-i18n'
9+
import { message } from '@/tools'
10+
import { useRoute, useRouter } from 'vue-router'
611

712
export const useActions = (dialog: DialogApiInjection) => {
13+
const req = useReqStore()
14+
const { t } = useI18n()
15+
const router = useRouter()
16+
const route = useRoute()
17+
const checkKeyIsExist = async (key: string, hideMsg?: boolean, jump?: boolean) => {
18+
const resp = await req.reqWithHost({
19+
path: `/cmd`,
20+
data: ['exists', key],
21+
})
22+
if (resp.data === '0') {
23+
// if key is not exist and jump is true, jump to new key page
24+
if (jump) {
25+
await router.replace(`/tab/${route.params.id}/main/database/none/${btoa(key)}`)
26+
return
27+
}
28+
return Promise.resolve(false)
29+
}
30+
if (!hideMsg) {
31+
message.destroyAll()
32+
message.warning(t('tips.7', { key }))
33+
}
34+
35+
return Promise.reject(t('tips.7', { key }))
36+
}
837
const options = [
938
{
1039
label: 'string',
@@ -75,7 +104,7 @@ export const useActions = (dialog: DialogApiInjection) => {
75104
dialog.create({
76105
title: title ?? 'New Key',
77106
content: () => {
78-
return <div>good job</div>
107+
return <NewZSetForm></NewZSetForm>
79108
},
80109
draggable: true,
81110
})
@@ -88,5 +117,6 @@ export const useActions = (dialog: DialogApiInjection) => {
88117
addHashKey,
89118
addSetKey,
90119
addZSetKey,
120+
checkKeyIsExist,
91121
}
92122
}

0 commit comments

Comments
 (0)