support events
This commit is contained in:
81
src-tauri/Cargo.lock
generated
81
src-tauri/Cargo.lock
generated
@@ -673,6 +673,7 @@ dependencies = [
|
||||
"base64 0.22.1",
|
||||
"chrono",
|
||||
"image",
|
||||
"rusqlite",
|
||||
"serde",
|
||||
"serde_json",
|
||||
"tauri",
|
||||
@@ -1078,7 +1079,7 @@ version = "0.5.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ab8ecd87370524b461f8557c119c405552c396ed91fc0a8eec68679eab26f94a"
|
||||
dependencies = [
|
||||
"libloading 0.7.4",
|
||||
"libloading 0.8.9",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -1337,6 +1338,18 @@ dependencies = [
|
||||
"zune-inflate",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fallible-iterator"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2acce4a10f12dc2fb14a218589d4f1f62ef011b2d0cc4b3cb1bba8e94da14649"
|
||||
|
||||
[[package]]
|
||||
name = "fallible-streaming-iterator"
|
||||
version = "0.1.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7360491ce676a36bf9bb3c56c1aa791658183a54d2744120f27285738d90465a"
|
||||
|
||||
[[package]]
|
||||
name = "fastrand"
|
||||
version = "2.3.0"
|
||||
@@ -1944,6 +1957,18 @@ name = "hashbrown"
|
||||
version = "0.16.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "841d1cc9bed7f9236f321df977030373f4a4163ae1a7dbfe1a51a2c1a51d9100"
|
||||
dependencies = [
|
||||
"foldhash 0.2.0",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "hashlink"
|
||||
version = "0.11.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "ea0b22561a9c04a7cb1a302c013e0259cd3b4bb619f145b32f72b8b4bcbed230"
|
||||
dependencies = [
|
||||
"hashbrown 0.16.1",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "heck"
|
||||
@@ -2627,6 +2652,17 @@ dependencies = [
|
||||
"system-deps 7.0.7",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libsqlite3-sys"
|
||||
version = "0.37.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "b1f111c8c41e7c61a49cd34e44c7619462967221a6443b0ec299e0ac30cfb9b1"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
"vcpkg",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "libwayshot-xcap"
|
||||
version = "0.3.2"
|
||||
@@ -4234,6 +4270,31 @@ version = "0.8.53"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "47b34b781b31e5d73e9fbc8689c70551fd1ade9a19e3e28cfec8580a79290cc4"
|
||||
|
||||
[[package]]
|
||||
name = "rsqlite-vfs"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a8a1f2315036ef6b1fbacd1972e8ee7688030b0a2121edfc2a6550febd41574d"
|
||||
dependencies = [
|
||||
"hashbrown 0.16.1",
|
||||
"thiserror 2.0.18",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rusqlite"
|
||||
version = "0.39.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "a0d2b0146dd9661bf67bb107c0bb2a55064d556eeb3fc314151b957f313bcd4e"
|
||||
dependencies = [
|
||||
"bitflags 2.11.0",
|
||||
"fallible-iterator",
|
||||
"fallible-streaming-iterator",
|
||||
"hashlink",
|
||||
"libsqlite3-sys",
|
||||
"smallvec",
|
||||
"sqlite-wasm-rs",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
@@ -4691,6 +4752,18 @@ dependencies = [
|
||||
"system-deps 6.2.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sqlite-wasm-rs"
|
||||
version = "0.5.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2f4206ed3a67690b9c29b77d728f6acc3ce78f16bf846d83c94f76400320181b"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"js-sys",
|
||||
"rsqlite-vfs",
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "stable_deref_trait"
|
||||
version = "1.2.1"
|
||||
@@ -5741,6 +5814,12 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "vcpkg"
|
||||
version = "0.2.15"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426"
|
||||
|
||||
[[package]]
|
||||
name = "version-compare"
|
||||
version = "0.2.1"
|
||||
|
||||
@@ -31,6 +31,7 @@ chrono = "0.4.44"
|
||||
tokio = { version = "1.50.0", features = ["rt-multi-thread", "macros", "time"] }
|
||||
anyhow = "1.0.102"
|
||||
base64 = "0.22.1"
|
||||
rusqlite = { version = "0.39.0", features = ["bundled"] }
|
||||
|
||||
[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies]
|
||||
tauri-plugin-autostart = "2"
|
||||
|
||||
135
src-tauri/src/db.rs
Normal file
135
src-tauri/src/db.rs
Normal file
@@ -0,0 +1,135 @@
|
||||
use rusqlite::{params, Connection};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::PathBuf;
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Tag {
|
||||
pub id: i64,
|
||||
pub name: String,
|
||||
pub parent_id: Option<i64>,
|
||||
pub color: String,
|
||||
}
|
||||
|
||||
#[derive(Serialize, Deserialize, Clone)]
|
||||
pub struct Event {
|
||||
pub id: i64,
|
||||
pub date: String,
|
||||
pub start_minute: i32,
|
||||
pub end_minute: i32,
|
||||
pub main_tag_id: i64,
|
||||
pub sub_tag_id: Option<i64>,
|
||||
pub content: String,
|
||||
}
|
||||
|
||||
pub fn init_db(path: &str) -> anyhow::Result<()> {
|
||||
let conn = Connection::open(path)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS tags (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
name TEXT NOT NULL,
|
||||
parent_id INTEGER,
|
||||
color TEXT NOT NULL,
|
||||
FOREIGN KEY(parent_id) REFERENCES tags(id)
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
conn.execute(
|
||||
"CREATE TABLE IF NOT EXISTS events (
|
||||
id INTEGER PRIMARY KEY AUTOINCREMENT,
|
||||
date TEXT NOT NULL,
|
||||
start_minute INTEGER NOT NULL,
|
||||
end_minute INTEGER NOT NULL,
|
||||
main_tag_id INTEGER NOT NULL,
|
||||
sub_tag_id INTEGER,
|
||||
content TEXT,
|
||||
FOREIGN KEY(main_tag_id) REFERENCES tags(id),
|
||||
FOREIGN KEY(sub_tag_id) REFERENCES tags(id)
|
||||
)",
|
||||
[],
|
||||
)?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_tags(path: &str) -> anyhow::Result<Vec<Tag>> {
|
||||
let conn = Connection::open(path)?;
|
||||
let mut stmt = conn.prepare("SELECT id, name, parent_id, color FROM tags")?;
|
||||
let tag_iter = stmt.query_map([], |row| {
|
||||
Ok(Tag {
|
||||
id: row.get(0)?,
|
||||
name: row.get(1)?,
|
||||
parent_id: row.get(2)?,
|
||||
color: row.get(3)?,
|
||||
})
|
||||
})?;
|
||||
|
||||
let mut results = Vec::new();
|
||||
for tag in tag_iter {
|
||||
results.push(tag?);
|
||||
}
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub fn add_tag(path: &str, name: &str, parent_id: Option<i64>, color: &str) -> anyhow::Result<i64> {
|
||||
let conn = Connection::open(path)?;
|
||||
conn.execute(
|
||||
"INSERT INTO tags (name, parent_id, color) VALUES (?1, ?2, ?3)",
|
||||
params![name, parent_id, color],
|
||||
)?;
|
||||
Ok(conn.last_insert_rowid())
|
||||
}
|
||||
|
||||
pub fn delete_tag(path: &str, id: i64) -> anyhow::Result<()> {
|
||||
let conn = Connection::open(path)?;
|
||||
// Also delete child tags
|
||||
conn.execute("DELETE FROM tags WHERE parent_id = ?1", params![id])?;
|
||||
conn.execute("DELETE FROM tags WHERE id = ?1", params![id])?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub fn get_events(path: &str, date: &str) -> anyhow::Result<Vec<Event>> {
|
||||
let conn = Connection::open(path)?;
|
||||
let mut stmt = conn.prepare("SELECT id, date, start_minute, end_minute, main_tag_id, sub_tag_id, content FROM events WHERE date = ?1")?;
|
||||
let event_iter = stmt.query_map(params![date], |row| {
|
||||
Ok(Event {
|
||||
id: row.get(0)?,
|
||||
date: row.get(1)?,
|
||||
start_minute: row.get(2)?,
|
||||
end_minute: row.get(3)?,
|
||||
main_tag_id: row.get(4)?,
|
||||
sub_tag_id: row.get(5)?,
|
||||
content: row.get(6)?,
|
||||
})
|
||||
})?;
|
||||
|
||||
let mut results = Vec::new();
|
||||
for event in event_iter {
|
||||
results.push(event?);
|
||||
}
|
||||
Ok(results)
|
||||
}
|
||||
|
||||
pub fn save_event(path: &str, event: Event) -> anyhow::Result<i64> {
|
||||
let conn = Connection::open(path)?;
|
||||
if event.id > 0 {
|
||||
conn.execute(
|
||||
"UPDATE events SET date=?1, start_minute=?2, end_minute=?3, main_tag_id=?4, sub_tag_id=?5, content=?6 WHERE id=?7",
|
||||
params![event.date, event.start_minute, event.end_minute, event.main_tag_id, event.sub_tag_id, event.content, event.id],
|
||||
)?;
|
||||
Ok(event.id)
|
||||
} else {
|
||||
conn.execute(
|
||||
"INSERT INTO events (date, start_minute, end_minute, main_tag_id, sub_tag_id, content) VALUES (?1, ?2, ?3, ?4, ?5, ?6)",
|
||||
params![event.date, event.start_minute, event.end_minute, event.main_tag_id, event.sub_tag_id, event.content],
|
||||
)?;
|
||||
Ok(conn.last_insert_rowid())
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_event(path: &str, id: i64) -> anyhow::Result<()> {
|
||||
let conn = Connection::open(path)?;
|
||||
conn.execute("DELETE FROM events WHERE id = ?1", params![id])?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -11,9 +11,60 @@ use tauri_plugin_store::StoreExt;
|
||||
pub struct AppState {
|
||||
pub is_paused: Arc<AtomicBool>,
|
||||
pub capture_interval_secs: std::sync::atomic::AtomicU64,
|
||||
pub db_path: std::sync::Mutex<Option<String>>,
|
||||
pub toggle_menu_item: std::sync::Mutex<Option<tauri::menu::MenuItem<tauri::Wry>>>,
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn update_db_path(state: tauri::State<'_, AppState>, path: String) -> Result<(), String> {
|
||||
crate::db::init_db(&path).map_err(|e| e.to_string())?;
|
||||
let mut db_path = state.db_path.lock().unwrap();
|
||||
*db_path = Some(path);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_tags(state: tauri::State<'_, AppState>) -> Result<Vec<crate::db::Tag>, String> {
|
||||
let path = state.db_path.lock().unwrap();
|
||||
let path = path.as_ref().ok_or("Database path not set")?;
|
||||
crate::db::get_tags(path).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn add_tag(state: tauri::State<'_, AppState>, name: String, parent_id: Option<i64>, color: String) -> Result<i64, String> {
|
||||
let path = state.db_path.lock().unwrap();
|
||||
let path = path.as_ref().ok_or("Database path not set")?;
|
||||
crate::db::add_tag(path, &name, parent_id, &color).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn delete_tag(state: tauri::State<'_, AppState>, id: i64) -> Result<(), String> {
|
||||
let path = state.db_path.lock().unwrap();
|
||||
let path = path.as_ref().ok_or("Database path not set")?;
|
||||
crate::db::delete_tag(path, id).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn get_events(state: tauri::State<'_, AppState>, date: String) -> Result<Vec<crate::db::Event>, String> {
|
||||
let path = state.db_path.lock().unwrap();
|
||||
let path = path.as_ref().ok_or("Database path not set")?;
|
||||
crate::db::get_events(path, &date).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn save_event(state: tauri::State<'_, AppState>, event: crate::db::Event) -> Result<i64, String> {
|
||||
let path = state.db_path.lock().unwrap();
|
||||
let path = path.as_ref().ok_or("Database path not set")?;
|
||||
crate::db::save_event(path, event).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn delete_event(state: tauri::State<'_, AppState>, id: i64) -> Result<(), String> {
|
||||
let path = state.db_path.lock().unwrap();
|
||||
let path = path.as_ref().ok_or("Database path not set")?;
|
||||
crate::db::delete_event(path, id).map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub fn update_interval(state: tauri::State<'_, AppState>, seconds: u64) {
|
||||
state.capture_interval_secs.store(seconds, Ordering::SeqCst);
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
mod db;
|
||||
mod engine;
|
||||
mod tray;
|
||||
|
||||
@@ -21,12 +22,20 @@ pub fn run() {
|
||||
engine::get_pause_state,
|
||||
engine::get_timeline,
|
||||
engine::get_image_base64,
|
||||
engine::update_interval
|
||||
engine::update_interval,
|
||||
engine::update_db_path,
|
||||
engine::get_tags,
|
||||
engine::add_tag,
|
||||
engine::delete_tag,
|
||||
engine::get_events,
|
||||
engine::save_event,
|
||||
engine::delete_event
|
||||
])
|
||||
.setup(|app| {
|
||||
app.manage(engine::AppState {
|
||||
is_paused: Arc::new(AtomicBool::new(false)),
|
||||
capture_interval_secs: std::sync::atomic::AtomicU64::new(30),
|
||||
db_path: std::sync::Mutex::new(None),
|
||||
toggle_menu_item: std::sync::Mutex::new(None),
|
||||
});
|
||||
tray::create_tray(app.handle())?;
|
||||
|
||||
Reference in New Issue
Block a user