添加显示图片和视频功能

This commit is contained in:
2026-07-08 17:38:56 +08:00
parent 7ee990f7a2
commit a719b70156
6 changed files with 303 additions and 4 deletions

78
src-tauri/Cargo.lock generated
View File

@@ -1011,6 +1011,15 @@ dependencies = [
"percent-encoding",
]
[[package]]
name = "fsevent-sys"
version = "4.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "76ee7a02da4d231650c7cea31349b889be2f45ddb3ef3032d2ec8185f6313fd2"
dependencies = [
"libc",
]
[[package]]
name = "futures-channel"
version = "0.3.32"
@@ -1695,6 +1704,26 @@ dependencies = [
"cfb",
]
[[package]]
name = "inotify"
version = "0.11.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dd854a95a4ac672fed8c054136039fd32c22cf039ff09ead7280afe920486483"
dependencies = [
"bitflags 2.13.0",
"inotify-sys",
"libc",
]
[[package]]
name = "inotify-sys"
version = "0.1.8"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c033f80b2c113cdf91ab7a33faa9cbc014726dcad99880c8609af2a370edf37d"
dependencies = [
"libc",
]
[[package]]
name = "ipnet"
version = "2.12.0"
@@ -1837,6 +1866,26 @@ dependencies = [
"unicode-segmentation",
]
[[package]]
name = "kqueue"
version = "1.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "273c0752728918e0ac4976f2b275b6fefb9ecd400585dec929419f3844cd87b5"
dependencies = [
"kqueue-sys",
"libc",
]
[[package]]
name = "kqueue-sys"
version = "1.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "07293a4e297ac234359b510362495713f75ea345d5307140414f20c69ffeb087"
dependencies = [
"bitflags 2.13.0",
"libc",
]
[[package]]
name = "libappindicator"
version = "0.9.0"
@@ -1971,6 +2020,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "02bd0af71c67b473010cbbc60715ee815645a4dc942899111f494b4b737d6fda"
dependencies = [
"libc",
"log",
"wasi",
"windows-sys 0.61.2",
]
@@ -2026,6 +2076,33 @@ version = "1.0.6"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "650eef8c711430f1a879fdd01d4745a7deea475becfb90269c06775983bbf086"
[[package]]
name = "notify"
version = "8.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "4d3d07927151ff8575b7087f245456e549fea62edf0ec4e565a5ee50c8402bc3"
dependencies = [
"bitflags 2.13.0",
"fsevent-sys",
"inotify",
"kqueue",
"libc",
"log",
"mio",
"notify-types",
"walkdir",
"windows-sys 0.60.2",
]
[[package]]
name = "notify-types"
version = "2.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "42b8cfee0e339a0337359f3c88165702ac6e600dc01c0cc9579a92d62b08477a"
dependencies = [
"bitflags 2.13.0",
]
[[package]]
name = "num-conv"
version = "0.2.2"
@@ -4853,6 +4930,7 @@ dependencies = [
name = "yurou"
version = "0.1.0"
dependencies = [
"notify",
"serde",
"serde_json",
"tauri",

View File

@@ -24,4 +24,5 @@ tauri-plugin-opener = "2"
serde = { version = "1", features = ["derive"] }
serde_json = "1"
time = ">=0.3.0, <0.3.47"
notify = "8.2.0"

View File

@@ -1,5 +1,8 @@
// Learn more about Tauri commands at https://tauri.app/develop/calling-rust/
use notify::{RecursiveMode, Watcher};
use std::fs;
use std::path::PathBuf;
use std::sync::Mutex;
use tauri::menu::{MenuBuilder, MenuItemBuilder, SubmenuBuilder};
use tauri::{Emitter, Manager};
use tauri_plugin_dialog::DialogExt;
@@ -11,6 +14,24 @@ struct DirEntry {
is_dir: bool,
}
#[derive(Default)]
struct WorkspaceWatcherState {
watcher: Mutex<Option<notify::RecommendedWatcher>>,
}
#[derive(Debug, Clone, serde::Serialize)]
struct WorkspaceChangedPayload {
root: String,
paths: Vec<String>,
kind: String,
}
#[derive(Debug, Clone, serde::Serialize)]
struct WorkspaceWatchErrorPayload {
root: String,
message: String,
}
fn is_hidden_entry(entry: &fs::DirEntry) -> bool {
let name = entry.file_name();
let is_dot_hidden = name.to_string_lossy().starts_with('.');
@@ -94,6 +115,73 @@ fn write_file(path: String, content: String) -> Result<(), String> {
fs::write(&path, &content).map_err(|e| format!("无法保存文件: {}", e))
}
#[tauri::command]
fn watch_workspace(
app: tauri::AppHandle,
state: tauri::State<'_, WorkspaceWatcherState>,
path: String,
) -> Result<(), String> {
let watch_path = PathBuf::from(&path);
if !watch_path.is_dir() {
return Err("工作目录不存在或不是文件夹".to_string());
}
let root = watch_path.to_string_lossy().to_string();
let event_root = root.clone();
let error_root = root.clone();
let app_handle = app.clone();
let mut watcher =
notify::recommended_watcher(move |result: notify::Result<notify::Event>| match result {
Ok(event) => {
if event.kind.is_access() {
return;
}
let payload = WorkspaceChangedPayload {
root: event_root.clone(),
paths: event
.paths
.iter()
.map(|path| path.to_string_lossy().to_string())
.collect(),
kind: format!("{:?}", event.kind),
};
let _ = app_handle.emit("workspace-changed", payload);
}
Err(error) => {
let _ = app_handle.emit(
"workspace-watch-error",
WorkspaceWatchErrorPayload {
root: error_root.clone(),
message: error.to_string(),
},
);
}
})
.map_err(|e| format!("无法监听工作目录: {}", e))?;
watcher
.watch(&watch_path, RecursiveMode::Recursive)
.map_err(|e| format!("无法监听工作目录: {}", e))?;
let mut current = state
.watcher
.lock()
.map_err(|_| "无法更新工作目录监听状态".to_string())?;
*current = Some(watcher);
Ok(())
}
#[tauri::command]
fn unwatch_workspace(state: tauri::State<'_, WorkspaceWatcherState>) -> Result<(), String> {
let mut current = state
.watcher
.lock()
.map_err(|_| "无法更新工作目录监听状态".to_string())?;
*current = None;
Ok(())
}
#[tauri::command]
fn pick_save_file(app: tauri::AppHandle) -> Option<String> {
app.dialog()
@@ -112,12 +200,15 @@ pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_dialog::init())
.manage(WorkspaceWatcherState::default())
.invoke_handler(tauri::generate_handler![
greet,
pick_folder,
read_dir,
read_file,
write_file,
watch_workspace,
unwatch_workspace,
pick_save_file
])
.setup(|app| {