From dbe15eb94f5fc8f2d9f268f1a810c887dc868192 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 10:05:34 +0800 Subject: [PATCH 01/28] User setting store --- src-tauri/src/main.rs | 1 + src-tauri/src/user_setting.rs | 109 ++++++++++++++++++++++++++++++++++ 2 files changed, 110 insertions(+) create mode 100644 src-tauri/src/user_setting.rs diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 5119051..f87d38f 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -20,6 +20,7 @@ mod utils; mod walk_exec; mod walk_metrics; mod watch_exec; +mod user_setting; use crate::idx_store::IdxStore; use crate::kv_store::KvStore; diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs new file mode 100644 index 0000000..77c098c --- /dev/null +++ b/src-tauri/src/user_setting.rs @@ -0,0 +1,109 @@ +use log::set_logger_racy; +use serde::{Deserialize, Serialize}; +use serde_json::{Result, Value}; + +use crate::kv_store::KvStore; +use crate::utils; + +#[derive(Serialize, Deserialize, Debug)] +pub enum Theme { + Light, + Dark, +} +#[derive(Serialize, Deserialize, Debug)] +pub struct UserConf { + theme: Theme, + exclude_index_path: Vec, + +} + +impl Default for UserConf { + fn default() -> Self { + UserConf{ theme: Theme::Light, exclude_index_path: vec![] } + } +} + +impl UserConf { + pub fn set_theme(&mut self, theme: Theme) { + self.theme = theme; + } + pub fn set_exclude_index_path(&mut self, exclude_index_path: Vec) { + self.exclude_index_path = exclude_index_path; + } + + pub fn theme(&self) -> &Theme { + &self.theme + } + pub fn exclude_index_path(&self) -> &Vec { + &self.exclude_index_path + } +} + +pub struct UserSetting<'a> { + store: KvStore<'a>, + user_conf: UserConf, +} + +impl UserSetting<'_> { + pub fn set_theme(&mut self, theme: Theme) { + self.user_conf.set_theme(theme); + self.save(); + } + pub fn set_exclude_index_path(&mut self, exclude_index_path: Vec) { + self.user_conf.set_exclude_index_path(exclude_index_path); + self.save(); + } + pub fn theme(&self) -> &Theme { + &self.user_conf.theme + } + pub fn exclude_index_path(&self) -> &Vec { + &self.user_conf.exclude_index_path + } + fn save(&self) { + self.store.put_str("user_setting".to_string(), serde_json::to_string(&self.user_conf).unwrap()) + } +} + +impl Default for UserSetting<'_> { + fn default() -> Self { + let dir = utils::data_dir(); + let user_setting = format!("{}{}", dir, "/orangecachedata/user_setting"); + let store = KvStore::new(&user_setting); + + return match store.get_str("user_setting".to_string()) { + None => { + let user_conf = UserConf::default(); + let setting = UserSetting { + store, + user_conf + }; + setting.save(); + setting + } + Some(x) => { + let user_conf: UserConf = serde_json::from_str(&x).unwrap(); + UserSetting{ store, user_conf } + } + }; + + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[test] + fn t2() { + let mut setting = UserSetting::default(); + setting.set_theme(Theme::Dark); + } + #[test] + fn t1() { + let setting = UserSetting::default(); + println!("{:?}", setting.user_conf); + } +} + + + + From 80746af5c668bef24607016b90222fa85d6b9a6d Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 10:12:43 +0800 Subject: [PATCH 02/28] Item overflow fix --- src/index.css | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/index.css b/src/index.css index d41ce30..58e9380 100644 --- a/src/index.css +++ b/src/index.css @@ -50,6 +50,9 @@ div.ms-Callout-container > div { .items { height: calc(100vh - 125px); } +.items div{ + overflow: hidden; +} .ms-DetailsHeader { border: none !important; From a92114b34290b324eee2045ab6e62c02901142ff Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 14:14:42 +0800 Subject: [PATCH 03/28] User setting --- src-tauri/src/user_setting.rs | 162 +++++++++++++++++----------------- src-tauri/src/utils.rs | 1 - 2 files changed, 82 insertions(+), 81 deletions(-) diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs index 77c098c..4e43dd5 100644 --- a/src-tauri/src/user_setting.rs +++ b/src-tauri/src/user_setting.rs @@ -1,3 +1,7 @@ +use core::fmt; +use std::error::Error; +use std::fmt::{Display, Formatter}; + use log::set_logger_racy; use serde::{Deserialize, Serialize}; use serde_json::{Result, Value}; @@ -7,103 +11,101 @@ use crate::utils; #[derive(Serialize, Deserialize, Debug)] pub enum Theme { - Light, - Dark, + Light, + Dark, } -#[derive(Serialize, Deserialize, Debug)] -pub struct UserConf { - theme: Theme, - exclude_index_path: Vec, +#[derive(Debug)] +struct UserSettingError { + details: String, } -impl Default for UserConf { - fn default() -> Self { - UserConf{ theme: Theme::Light, exclude_index_path: vec![] } - } +impl UserSettingError { + pub fn new(details: String) -> Self { + UserSettingError { details } + } } -impl UserConf { - pub fn set_theme(&mut self, theme: Theme) { - self.theme = theme; - } - pub fn set_exclude_index_path(&mut self, exclude_index_path: Vec) { - self.exclude_index_path = exclude_index_path; - } +impl Display for UserSettingError { + fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result { + write!(f, "{}", self.details) + } +} - pub fn theme(&self) -> &Theme { - &self.theme - } - pub fn exclude_index_path(&self) -> &Vec { - &self.exclude_index_path - } +impl Error for UserSettingError { + fn description(&self) -> &str { + self.details.as_str() + } } -pub struct UserSetting<'a> { - store: KvStore<'a>, - user_conf: UserConf, +#[derive(Debug, Serialize, Deserialize)] +pub struct UserSetting { + theme: Theme, + exclude_index_path: Vec, } -impl UserSetting<'_> { - pub fn set_theme(&mut self, theme: Theme) { - self.user_conf.set_theme(theme); - self.save(); - } - pub fn set_exclude_index_path(&mut self, exclude_index_path: Vec) { - self.user_conf.set_exclude_index_path(exclude_index_path); - self.save(); - } - pub fn theme(&self) -> &Theme { - &self.user_conf.theme - } - pub fn exclude_index_path(&self) -> &Vec { - &self.user_conf.exclude_index_path - } - fn save(&self) { - self.store.put_str("user_setting".to_string(), serde_json::to_string(&self.user_conf).unwrap()) +impl UserSetting { + pub fn set_theme(&mut self, theme: Theme) { + self.theme = theme; + self.store(); + } + pub fn set_exclude_index_path( + &mut self, + exclude_index_path: Vec, + ) -> std::result::Result<(), UserSettingError> { + for path in &exclude_index_path { + if std::fs::metadata(path).is_err() { + return Err(UserSettingError::new(path.to_string())); + } } + self.exclude_index_path = exclude_index_path; + self.store(); + Ok(()) + } } -impl Default for UserSetting<'_> { - fn default() -> Self { - let dir = utils::data_dir(); - let user_setting = format!("{}{}", dir, "/orangecachedata/user_setting"); - let store = KvStore::new(&user_setting); - - return match store.get_str("user_setting".to_string()) { - None => { - let user_conf = UserConf::default(); - let setting = UserSetting { - store, - user_conf - }; - setting.save(); - setting - } - Some(x) => { - let user_conf: UserConf = serde_json::from_str(&x).unwrap(); - UserSetting{ store, user_conf } - } - }; +const PREFERENCE_FILE: &'static str = "/preference.json"; + +impl UserSetting { + fn store(&self) { + let path = UserSetting::build_conf_path(); + let contents = serde_json::to_string_pretty(self).unwrap(); + let _ = std::fs::write(path, contents); + } + + fn load() -> std::result::Result> { + let path = UserSetting::build_conf_path(); + let string = std::fs::read_to_string(path)?; + Ok(serde_json::from_str(&string).expect("deserialize error")) + } + + fn build_conf_path() -> String { + let path = format!("{}{}", utils::data_dir(), PREFERENCE_FILE); + path + } +} - } +impl Default for UserSetting { + fn default() -> Self { + UserSetting::load().unwrap_or_else(|_| { + let setting = UserSetting { + theme: Theme::Light, + exclude_index_path: vec![], + }; + setting.store(); + setting + }) + } } #[cfg(test)] mod tests { - use super::*; - #[test] - fn t2() { - let mut setting = UserSetting::default(); - setting.set_theme(Theme::Dark); - } - #[test] - fn t1() { - let setting = UserSetting::default(); - println!("{:?}", setting.user_conf); - } + use super::*; + + #[test] + fn t1() { + let mut setting = UserSetting::default(); + // setting.set_theme(Theme::Dark); + println!("{:?}", setting); + } } - - - - diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index d1d89dc..65fc4b9 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -88,7 +88,6 @@ pub fn open_file_path_in_terminal(path: &str) { } pub fn data_dir() -> String { - // return "/Users/jeff/IdeaProjects/orange2/src-tauri/target".to_string(); let project_dir = ProjectDirs::from("com", "github", "Orange").unwrap(); project_dir.data_dir().to_str().unwrap().to_string() } From 217f544cfbc516e1f281a124f3e0a4547bf170ae Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 14:53:08 +0800 Subject: [PATCH 04/28] Clean code --- src-tauri/Cargo.lock | 1 + src-tauri/Cargo.toml | 2 +- src-tauri/src/fs_watcher.rs | 32 ++----- src-tauri/src/idx_store.rs | 29 ++++--- src-tauri/src/indexing.rs | 75 ++++++---------- src-tauri/src/kv_store.rs | 9 +- src-tauri/src/main.rs | 156 +++------------------------------- src-tauri/src/ui.rs | 110 ++++++++++++++++++++++++ src-tauri/src/user_setting.rs | 14 +++ src-tauri/src/utils.rs | 13 +-- src-tauri/src/walk_exec.rs | 61 ++++++------- src-tauri/src/watch_exec.rs | 22 ++--- src/Items.js | 1 - src/SearchBox.js | 12 +-- src/index.css | 1 + src/utils.js | 21 +++-- 16 files changed, 255 insertions(+), 304 deletions(-) create mode 100644 src-tauri/src/ui.rs diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 12f42b7..3ee85d7 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -67,6 +67,7 @@ dependencies = [ "jwalk", "kernel32-sys", "kv", + "lazy_static", "libc", "log", "log4rs", diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 70364ec..6503eb2 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -43,7 +43,7 @@ pinyin = "0.9" directories = "4.0" jwalk = "0.6.0" convert_case = "0.1.0" - +lazy_static = "1.4.0" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/fs_watcher.rs b/src-tauri/src/fs_watcher.rs index 08cc572..66c1779 100644 --- a/src-tauri/src/fs_watcher.rs +++ b/src-tauri/src/fs_watcher.rs @@ -1,6 +1,7 @@ extern crate notify; use crate::idx_store::IdxStore; +use crate::idx_store::IDX_STORE; use crate::utils; use crate::utils::subs; use log::{error, info}; @@ -17,13 +18,12 @@ use std::sync::mpsc::channel; use std::sync::Arc; pub struct FsWatcher { - index_store: Arc, path: String, } impl FsWatcher { - pub fn new(index_store: Arc, path: String) -> FsWatcher { - FsWatcher { index_store, path } + pub fn new(path: String) -> FsWatcher { + FsWatcher { path } } pub fn start(&mut self) { @@ -49,14 +49,13 @@ impl FsWatcher { continue; } if Op::REMOVE & op == Op::REMOVE { - self.index_store._del(path_str.to_string()) + IDX_STORE._del(path_str.to_string()) }; let result = path.metadata(); match result { Ok(meta) => { - let abs_path = path.to_str().unwrap().to_string(); - - let name = Self::get_filename(&path); + let abs_path = path.to_str().unwrap_or("").to_string(); + let name = utils::path2name(abs_path.clone()); #[cfg(windows)] let _size = meta.file_size(); @@ -76,9 +75,7 @@ impl FsWatcher { } let name0 = name.clone(); let ext = utils::file_ext(&name0); - self - .index_store - .add(name, abs_path, meta.is_dir(), ext.to_string()) + IDX_STORE.add(name, abs_path, meta.is_dir(), ext.to_string()) } Err(_) => {} } @@ -102,21 +99,10 @@ impl FsWatcher { if let Ok(meta) = sub_path.metadata() { let name0 = name.clone(); let ext = utils::file_ext(&name0); - self - .index_store - .add(name, sub.clone(), meta.is_dir(), ext.to_string()); + IDX_STORE.add(name, sub.clone(), meta.is_dir(), ext.to_string()); } } } - - fn get_filename(path: &PathBuf) -> String { - let name = path - .file_name() - .map(|x| x.to_str().unwrap()) - .unwrap_or_default() - .to_string(); - name - } } #[cfg(test)] @@ -199,6 +185,6 @@ fn t4() { let idx_path = format!("{}{}", utils::data_dir(), "/orangecachedata/idx"); let idx_store = Arc::new(IdxStore::new(&idx_path)); - let mut watcher = FsWatcher::new(idx_store, "/".to_string()); + let mut watcher = FsWatcher::new("/".to_string()); watcher.start(); } diff --git a/src-tauri/src/idx_store.rs b/src-tauri/src/idx_store.rs index 8f72cd0..e334988 100644 --- a/src-tauri/src/idx_store.rs +++ b/src-tauri/src/idx_store.rs @@ -1,28 +1,32 @@ use std::collections::HashSet; - use std::fs; - #[cfg(unix)] use std::os::unix::fs::MetadataExt; #[cfg(windows)] use std::os::windows::fs::MetadataExt; +use std::sync::{Arc, Mutex}; +use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use convert_case::{Case, Casing}; +use jieba_rs::Jieba; +use pinyin::ToPinyin; use tantivy::collector::TopDocs; +use tantivy::merge_policy::NoMergePolicy; use tantivy::query::{BooleanQuery, FuzzyTermQuery, Occur, Query, QueryParser, TermQuery}; use tantivy::schema::*; - use tantivy::{doc, Index, IndexReader, IndexWriter, ReloadPolicy}; use crate::file_doc::FileDoc; use crate::file_view::FileView; use crate::utils; use crate::utils::is_ascii_alphanumeric; -use convert_case::{Case, Casing}; -use jieba_rs::Jieba; -use pinyin::ToPinyin; -use std::sync::{Arc, Mutex}; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; -use tantivy::merge_policy::NoMergePolicy; + +lazy_static! { + pub static ref IDX_STORE: IdxStore = { + let idx_path = format!("{}{}", utils::data_dir(), "/orangecachedata/idx"); + IdxStore::new(&idx_path) + }; +} pub struct IdxStore { pub writer: Arc>, @@ -201,7 +205,7 @@ impl IdxStore { .map(|x| { return FileView { abs_path: "".to_string(), - name: utils::path2name(utils::norm(&x)).unwrap_or("".to_string()), + name: utils::path2name(x), created_at: 0, mod_at: 0, size: 0, @@ -287,7 +291,7 @@ impl IdxStore { file_views.push(FileView { abs_path: utils::norm(&path), - name: utils::path2name(utils::norm(&path)).unwrap_or("".to_string()), + name: utils::path2name(path), created_at: meta .created() .unwrap_or(SystemTime::now()) @@ -423,9 +427,10 @@ impl IdxStore { #[cfg(test)] mod tests { - use super::*; use std::thread::sleep; + use super::*; + #[test] fn t1() { let path = "./tmp"; diff --git a/src-tauri/src/indexing.rs b/src-tauri/src/indexing.rs index 1739793..9a3cd39 100644 --- a/src-tauri/src/indexing.rs +++ b/src-tauri/src/indexing.rs @@ -1,4 +1,6 @@ -use crate::{utils, walk_exec, watch_exec, CONF_STORE, IDX_STORE}; +use crate::idx_store::IDX_STORE; +use crate::kv_store::CONF_STORE; +use crate::{utils, walk_exec, watch_exec}; use log::{error, info}; #[cfg(windows)] use std::sync::mpsc; @@ -25,66 +27,47 @@ const VERSION: &'static str = "0.4.0"; const LAST_INDEX_TS: &'static str = "last_index_ts"; pub fn run() { - let conf_path = format!("{}{}", utils::data_dir(), "/orangecachedata/conf"); - let idx_path = format!("{}{}", utils::data_dir(), "/orangecachedata/idx"); + housekeeping(); - let conf_store = Arc::new(KvStore::new(&conf_path)); - housekeeping(conf_store.clone()); - - let idx_store = Arc::new(IdxStore::new(&idx_path)); - - unsafe { - IDX_STORE = Some(idx_store.clone()); - } - unsafe { - CONF_STORE = Some(conf_store.clone()); - } - - let reindex = need_reindex(conf_store.clone()); + let reindex = need_reindex(); info!("need reindex: {}", reindex); if reindex { - let conf_store_bro = conf_store.clone(); - let idx_store_bro = idx_store.clone(); - walk_exec::run(conf_store_bro, idx_store_bro); - conf_store.put_str(LAST_INDEX_TS.to_string(), curr_ts().to_string()); + walk_exec::run(); + CONF_STORE.put_str(LAST_INDEX_TS.to_string(), curr_ts().to_string()); info!("walk exec done"); }; - let idx_store_bro = idx_store.clone(); - idx_store_bro.disable_full_indexing(); + IDX_STORE.disable_full_indexing(); info!("start fs watch"); #[cfg(windows)] - win_watch(idx_store_bro); + win_watch(); #[cfg(unix)] - watch_exec::run(idx_store_bro); + watch_exec::run(); } #[cfg(windows)] -fn win_watch(idx_store_bro: Arc) { +fn win_watch() { let success = unsafe { maybe_usn_watch() }; if success { info!("usn success"); } else { info!("usn err, use watch"); - watch_exec::run(idx_store_bro); + watch_exec::run(); } } pub fn reindex() { unsafe { - CONF_STORE - .clone() - .unwrap() - .put_str("reindex".to_string(), "1".to_string()); + CONF_STORE.put_str("reindex".to_string(), "1".to_string()); } } -fn need_reindex(kv_store: Arc) -> bool { +fn need_reindex() -> bool { let key = LAST_INDEX_TS.to_string(); - return match kv_store.get_str(key.clone()) { + return match CONF_STORE.get_str(key.clone()) { None => true, Some(val) => { let ts = val.parse::().unwrap(); @@ -104,30 +87,30 @@ fn curr_ts() -> u64 { curr_ts } -pub fn housekeeping(kv_store: Arc) { +pub fn housekeeping() { info!("housekeeping..."); - let reidx_opt = kv_store.get_str("reindex".to_string()); + let reidx_opt = CONF_STORE.get_str("reindex".to_string()); match reidx_opt { None => { info!("no need to reindex"); } Some(_) => { - clear(&kv_store); + clear(); info!("detect reindex sign"); return; } } - let version_opt = kv_store.get_str("version".to_string()); + let version_opt = CONF_STORE.get_str("version".to_string()); match version_opt { None => { - clear(&kv_store); + clear(); info!("init version {}", VERSION); } Some(version) => { if !version.eq(VERSION) { - clear(&kv_store); + clear(); info!("clean old version cachedata"); } else { info!("no need to clean, current version:{}", VERSION); @@ -136,10 +119,10 @@ pub fn housekeeping(kv_store: Arc) { } } -fn clear(kv_store: &Arc) { +fn clear() { let _ = std::fs::remove_dir_all(&format!("{}{}", utils::data_dir(), "/orangecachedata/idx")); - kv_store.clear(); - kv_store.put_str("version".to_string(), VERSION.to_string()); + CONF_STORE.clear(); + CONF_STORE.put_str("version".to_string(), VERSION.to_string()); } #[cfg(windows)] @@ -162,9 +145,8 @@ unsafe fn start_usn_watch<'a>(no: String, volume_path: String, tx_clone: Sender< info!("start_usn_watch {}", volume_path); std::thread::spawn(move || { - let kv_store = CONF_STORE.clone().unwrap(); let key = format!("usn#next_usn#{}", volume_path.clone()); - let next_usn = kv_store + let next_usn = CONF_STORE .get_str(key.clone()) .unwrap_or("0".to_string()) .parse() @@ -211,13 +193,10 @@ unsafe fn start_usn_watch<'a>(no: String, volume_path: String, tx_clone: Sender< let name0 = file_name.clone(); let ext = utils::file_ext(&name0); - IDX_STORE - .clone() - .unwrap() - .add(file_name, abs_path.clone(), is_dir, ext.to_string()); + IDX_STORE.add(file_name, abs_path.clone(), is_dir, ext.to_string()); } - kv_store.put_str(key.clone(), usn_no); + CONF_STORE.put_str(key.clone(), usn_no); } } }); diff --git a/src-tauri/src/kv_store.rs b/src-tauri/src/kv_store.rs index 24ba9ad..27d986c 100644 --- a/src-tauri/src/kv_store.rs +++ b/src-tauri/src/kv_store.rs @@ -1,10 +1,15 @@ +use crate::utils; use kv::*; - #[derive(Clone)] pub struct KvStore<'a> { bucket: Bucket<'a, String, String>, } - +lazy_static! { + pub static ref CONF_STORE: KvStore<'static> = { + let conf_path = format!("{}{}", utils::data_dir(), "/orangecachedata/conf"); + KvStore::new(&conf_path) + }; +} impl KvStore<'_> { pub fn new<'a>(path: &str) -> KvStore<'a> { let cfg = Config::new(path); diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index f87d38f..a3b720a 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,10 +3,11 @@ windows_subsystem = "windows" )] -use crate::file_view::FileView; -use tauri::{App, Manager}; -use tauri::{SystemTray, SystemTrayEvent}; -use tauri::{Window, Wry}; +use crate::idx_store::IdxStore; +use crate::kv_store::KvStore; +use crate::user_setting::{Theme, UserSetting}; +use std::sync::{Arc, Mutex, RwLock}; +use std::time::Duration; mod file_doc; mod file_view; @@ -14,154 +15,19 @@ mod fs_watcher; mod idx_store; mod indexing; mod kv_store; +mod ui; +mod user_setting; #[cfg(windows)] mod usn_journal_watcher; mod utils; mod walk_exec; mod walk_metrics; mod watch_exec; -mod user_setting; - -use crate::idx_store::IdxStore; -use crate::kv_store::KvStore; -use crate::walk_metrics::WalkMatrixView; -use std::sync::{Arc, RwLock}; -use std::time::Duration; -use tauri::{CustomMenuItem, SystemTrayMenu}; - -static mut IDX_STORE: Option> = None; -static mut CONF_STORE: Option> = None; -static mut APP: Option> = None; -static mut WINDOW: Option> = None; - -#[derive(serde::Serialize)] -struct CustomResponse { - message: String, - file_views: Vec, -} - -#[derive(Clone, serde::Serialize)] -struct Payload { - message: String, -} - -#[tauri::command] -fn walk_metrics() -> WalkMatrixView { - unsafe { walk_exec::get_walk_matrix() } -} - -#[tauri::command] -async fn my_custom_command( - _window: Window, - number: usize, - mut kw: String, - is_dir_opt: Option, - ext_opt: Option, - parent_dirs_opt: Option, -) -> Result { - return match number { - // open file - 1 => { - utils::open_file_path(kw.as_str()); - Ok(CustomResponse { - message: "".to_string(), - file_views: vec![], - }) - } - - // search - 0 => unsafe { - if IDX_STORE.is_none() { - Ok(CustomResponse { - message: "".to_string(), - file_views: vec![], - }) - } else { - let arc = IDX_STORE.clone().unwrap(); - if kw.eq("") { - kw = "*".to_string(); - } - let vec = arc.search_with_filter(kw, 100, is_dir_opt, ext_opt, parent_dirs_opt); - // let vec = arc.search(kw, 100); - Ok(CustomResponse { - message: "".to_string(), - file_views: vec, - }) - } - }, - // suggest - 2 => unsafe { - let arc = IDX_STORE.clone().unwrap(); - let vec = arc.suggest(kw, 20); - Ok(CustomResponse { - message: "".to_string(), - file_views: vec, - }) - }, - - // open file in terminal - 3 => { - utils::open_file_path_in_terminal(kw.as_str()); - Ok(CustomResponse { - message: "".to_string(), - file_views: vec![], - }) - } - - _ => Ok(CustomResponse { - message: "".to_string(), - file_views: vec![], - }), - }; -} +#[macro_use] +extern crate lazy_static; fn main() { utils::init_log(); - - std::thread::spawn(|| { - std::thread::sleep(Duration::from_secs(1)); - indexing::run(); - }); - - show(); -} - -fn show() { - let quit = CustomMenuItem::new("quit".to_string(), "Quit"); - let reindex = CustomMenuItem::new("reindex".to_string(), "Reindex"); - let tray_menu = SystemTrayMenu::new().add_item(reindex).add_item(quit); - let tray = SystemTray::new().with_menu(tray_menu); - - tauri::Builder::default() - .setup(|x| { - let option = x.get_window("main"); - unsafe { - WINDOW = option; - } - Ok(()) - }) - .invoke_handler(tauri::generate_handler![my_custom_command, walk_metrics]) - .system_tray(tray) - .on_system_tray_event(|_app, event| match event { - SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { - "quit" => { - std::process::exit(0); - } - "reindex" => { - unsafe { - WINDOW.clone().unwrap().emit( - "reindex", - Payload { - message: "".to_string(), - }, - ); - } - indexing::reindex(); - } - _ => {} - }, - _ => {} - }) - .run(tauri::generate_context!()) - .expect("error while running tauri application"); + indexing::run(); + ui::show(); } diff --git a/src-tauri/src/ui.rs b/src-tauri/src/ui.rs new file mode 100644 index 0000000..2e2e8b7 --- /dev/null +++ b/src-tauri/src/ui.rs @@ -0,0 +1,110 @@ +use crate::file_view::FileView; +use crate::idx_store::IdxStore; +use crate::idx_store::IDX_STORE; +use crate::kv_store::KvStore; +use crate::walk_metrics::WalkMatrixView; +use crate::{indexing, utils, walk_exec}; +use std::sync::{Arc, RwLock}; +use std::time::Duration; +use tauri::{App, Manager}; +use tauri::{CustomMenuItem, SystemTrayMenu}; +use tauri::{SystemTray, SystemTrayEvent}; +use tauri::{Window, Wry}; + +static mut WINDOW: Option> = None; + +#[derive(Clone, serde::Serialize)] +struct Payload { + message: String, +} + +#[tauri::command] +fn walk_metrics() -> WalkMatrixView { + unsafe { walk_exec::get_walk_matrix() } +} + +#[tauri::command] +async fn suggest(kw: String) -> Vec { + unsafe { IDX_STORE.suggest(kw, 20) } +} + +#[tauri::command] +async fn search( + mut kw: String, + is_dir_opt: Option, + ext_opt: Option, +) -> Vec { + unsafe { + if kw.eq("") { + kw = "*".to_string(); + } + IDX_STORE.search_with_filter(kw, 100, is_dir_opt, ext_opt, None) + } +} + +#[tauri::command] +fn open_file_in_terminal(kw: String) { + utils::open_file_path_in_terminal(kw.as_str()); +} + +#[tauri::command] +fn open_file_path(kw: String) { + utils::open_file_path(kw.as_str()); +} + +fn init_window(x: &mut App) { + let option = x.get_window("main"); + unsafe { + WINDOW = option; + } +} + +fn handle_tray_event(event: SystemTrayEvent) { + match event { + SystemTrayEvent::MenuItemClick { id, .. } => match id.as_str() { + "quit" => { + std::process::exit(0); + } + "reindex" => { + unsafe { + WINDOW.clone().unwrap().emit( + "reindex", + Payload { + message: "".to_string(), + }, + ); + } + indexing::reindex(); + } + _ => {} + }, + _ => {} + } +} + +fn build_tray() -> SystemTray { + let quit = CustomMenuItem::new("quit".to_string(), "Quit"); + let reindex = CustomMenuItem::new("reindex".to_string(), "Reindex"); + let tray_menu = SystemTrayMenu::new().add_item(reindex).add_item(quit); + let tray = SystemTray::new().with_menu(tray_menu); + tray +} + +pub fn show() { + tauri::Builder::default() + .setup(|x| { + init_window(x); + Ok(()) + }) + .invoke_handler(tauri::generate_handler![ + open_file_path, + open_file_in_terminal, + search, + suggest, + walk_metrics + ]) + .system_tray(build_tray()) + .on_system_tray_event(|_, event| handle_tray_event(event)) + .run(tauri::generate_context!()) + .expect("error while running tauri application"); +} diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs index 4e43dd5..09dc223 100644 --- a/src-tauri/src/user_setting.rs +++ b/src-tauri/src/user_setting.rs @@ -1,6 +1,7 @@ use core::fmt; use std::error::Error; use std::fmt::{Display, Formatter}; +use std::sync::RwLock; use log::set_logger_racy; use serde::{Deserialize, Serialize}; @@ -9,6 +10,10 @@ use serde_json::{Result, Value}; use crate::kv_store::KvStore; use crate::utils; +lazy_static! { + pub static ref USER_SETTING: RwLock = RwLock::new(UserSetting::default()); +} + #[derive(Serialize, Deserialize, Debug)] pub enum Theme { Light, @@ -44,6 +49,15 @@ pub struct UserSetting { exclude_index_path: Vec, } +impl UserSetting { + pub fn theme(&self) -> &Theme { + &self.theme + } + pub fn exclude_index_path(&self) -> &Vec { + &self.exclude_index_path + } +} + impl UserSetting { pub fn set_theme(&mut self, theme: Theme) { self.theme = theme; diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 65fc4b9..1c4499c 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -92,19 +92,14 @@ pub fn data_dir() -> String { project_dir.data_dir().to_str().unwrap().to_string() } -// pub fn parse_ts(time: SystemTime) -> u64 { -// let created_at = time -// .duration_since(SystemTime::UNIX_EPOCH) -// .unwrap() -// .as_secs() as u64; -// created_at -// } -pub fn path2name(x: String) -> Option { - x.as_str() +pub fn path2name(x: String) -> String { + norm(&x) + .as_str() .split("/") .into_iter() .last() .map(|x| x.to_string()) + .unwrap_or("".to_string()) } pub fn file_ext(file_name: &str) -> &str { if !file_name.contains(".") { diff --git a/src-tauri/src/walk_exec.rs b/src-tauri/src/walk_exec.rs index 4181b77..94b6980 100644 --- a/src-tauri/src/walk_exec.rs +++ b/src-tauri/src/walk_exec.rs @@ -5,8 +5,10 @@ use std::ops::Deref; #[cfg(windows)] use crate::utils::get_win32_ready_drives; -use crate::{indexing, utils, IDX_STORE}; +use crate::{indexing, utils}; +use crate::idx_store::IDX_STORE; +use crate::kv_store::CONF_STORE; use crate::walk_metrics::{WalkMatrixView, WalkMetrics}; use jwalk::{DirEntry, WalkDir}; use log::info; @@ -22,38 +24,34 @@ pub fn home_dir() -> String { } pub unsafe fn get_walk_matrix() -> WalkMatrixView { - let idx_store = IDX_STORE.clone(); - if idx_store.is_none() { - return WalkMatrixView::default(); - } - if WALK_METRICS.is_none() && !idx_store.clone().unwrap().is_full_indexing() { - return WalkMatrixView::new(100, idx_store.clone().unwrap().num_docs()); + if WALK_METRICS.is_none() && !IDX_STORE.is_full_indexing() { + return WalkMatrixView::new(100, IDX_STORE.num_docs()); } WALK_METRICS .clone() .unwrap() .lock() .unwrap() - .view(move || idx_store.clone().unwrap().num_docs()) + .view(move || IDX_STORE.num_docs()) } -pub fn run(conf_store: Arc, idx_store: Arc) { +pub fn run() { init_walk_matrix(); let home = utils::norm(&home_dir()); start_walk_home_matrix(); info!("start walk home {}", home); - walk_home(conf_store.clone(), idx_store.clone(), &home); + walk_home(&home); end_walk_home_matrix(); info!("start walk root {}", home); #[cfg(windows)] - win_walk_root(conf_store, idx_store, home); + win_walk_root(home); #[cfg(unix)] - unix_walk_root(conf_store, idx_store, home); + unix_walk_root(home); } fn end_walk_home_matrix() { @@ -77,20 +75,20 @@ fn init_walk_matrix() { } #[cfg(unix)] -fn unix_walk_root(conf_store: Arc, idx_store: Arc, home: String) { +fn unix_walk_root(home: String) { let subs = utils::subs("/"); let sz = subs.len(); for (i, sub) in subs.iter().enumerate() { inc_root_walk_metrics(sz, i); let key = format!("walk:stat:{}", &sub); - let opt = conf_store.get_str(key.clone()); + let opt = CONF_STORE.get_str(key.clone()); if opt.is_some() { info!("{} walked", sub); continue; } - walk(idx_store.clone(), &sub, Some(home.to_string())); - conf_store.put_str(key, "1".to_string()); + walk(&sub, Some(home.to_string())); + CONF_STORE.put_str(key, "1".to_string()); } } @@ -121,14 +119,14 @@ fn win_walk_root(conf_store: Arc, idx_store: Arc, home: Strin idx += 1; let key = format!("walk:stat:{}", &sub); - let opt = conf_store.get_str(key.clone()); + let opt = CONF_STORE.get_str(key.clone()); if opt.is_some() { info!("{} walked", sub); continue; } walk(idx_store.clone(), &sub, Some(home.to_string())); - conf_store.put_str(key, "1".to_string()); + CONF_STORE.put_str(key, "1".to_string()); } } } @@ -145,21 +143,21 @@ fn win_subs_len() -> usize { sz } -fn walk_home(conf_store: Arc, idx_store: Arc, home: &String) { +fn walk_home(home: &String) { let key = format!("walk:stat:{}", home); - let opt = conf_store.get_str(key.clone()); + let opt = CONF_STORE.get_str(key.clone()); if opt.is_some() { info!("home walked {}", home); return; } - let home_name = utils::path2name(home.as_str().to_string()).unwrap_or("".to_string()); - idx_store.add(home_name, home.clone().to_string(), true, "".to_string()); - walk(idx_store, &home, None); - conf_store.put_str(key, "1".to_string()); + let home_name = utils::path2name(home.to_string()); + IDX_STORE.add(home_name, home.clone().to_string(), true, "".to_string()); + walk(&home, None); + CONF_STORE.put_str(key, "1".to_string()); } -fn walk(store: Arc, path: &String, skip_path_opt: Option) { +fn walk(path: &String, skip_path_opt: Option) { let start = SystemTime::now(); info!("start travel {}", path); let mut cnt = 0; @@ -167,7 +165,7 @@ fn walk(store: Arc, path: &String, skip_path_opt: Option) { let mut generic = WalkDir::new(&path); if skip_path_opt.is_some() { let skip_path = skip_path_opt.unwrap(); - let home_name = utils::path2name(skip_path.clone()).unwrap_or("".to_string()); + let home_name = utils::path2name(skip_path.clone()); generic = generic.process_read_dir(move |_depth, _path, _read_dir_state, children| { children.iter_mut().for_each(|dir_entry_result| { if let Ok(dir_entry) = dir_entry_result { @@ -195,10 +193,10 @@ fn walk(store: Arc, path: &String, skip_path_opt: Option) { let path = buf.to_str().unwrap(); let name = en.file_name().to_str().unwrap(); let ext = utils::file_ext(name); - store.add(name.to_string(), path.to_string(), is_dir, ext.to_string()); + IDX_STORE.add(name.to_string(), path.to_string(), is_dir, ext.to_string()); } let end = SystemTime::now(); - store.commit(); + IDX_STORE.commit(); info!( "cost {} s, total {} files", end.duration_since(start).unwrap().as_secs(), @@ -220,11 +218,8 @@ fn t1() { let conf_path = format!("{}{}", dir, "/orangecachedata/conf"); let idx_path = format!("{}{}", dir, "/orangecachedata/idx"); - let conf_store = Arc::new(KvStore::new(&conf_path)); - let idx_store = Arc::new(IdxStore::new(&idx_path)); - - run(conf_store, idx_store.clone()); - idx_store.commit(); + run(); + IDX_STORE.commit(); } #[test] diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index da855b3..8c881f3 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -1,25 +1,25 @@ -use crate::idx_store::IdxStore; -#[cfg(windows)] -use crate::utils::get_win32_ready_drives; +use std::sync::Arc; use crate::fs_watcher::FsWatcher; +use crate::idx_store::IdxStore; use crate::utils; -use std::sync::Arc; +#[cfg(windows)] +use crate::utils::get_win32_ready_drives; -pub fn run(idx_store: Arc) { +pub fn run() { #[cfg(windows)] - win_run(idx_store); + win_run(); #[cfg(target_os = "linux")] - linux_run(idx_store); + linux_run(); #[cfg(target_os = "macos")] - macos_run(idx_store); + macos_run(); } #[cfg(target_os = "macos")] -fn macos_run(idx_store: Arc) { - let mut watcher = FsWatcher::new(idx_store.clone(), "/".to_string()); +fn macos_run() { + let mut watcher = FsWatcher::new("/".to_string()); std::thread::spawn(move || { watcher.start(); }); @@ -37,7 +37,7 @@ fn linux_run(idx_store: Arc) { } #[cfg(windows)] -fn win_run(idx_store: Arc) { +fn win_run() { let drives = unsafe { get_win32_ready_drives() }; for driv in drives { let mut watcher = FsWatcher::new(idx_store.clone(), driv); diff --git a/src/Items.js b/src/Items.js index fa3cb49..3d63024 100644 --- a/src/Items.js +++ b/src/Items.js @@ -201,7 +201,6 @@ function Items({items, setItems}) { setKey="none" layoutMode={DetailsListLayoutMode.justified} isHeaderVisible={true} - // onItemInvoked={this._onItemInvoked} /> diff --git a/src/SearchBox.js b/src/SearchBox.js index f5e1f6f..3ca74bf 100644 --- a/src/SearchBox.js +++ b/src/SearchBox.js @@ -1,22 +1,18 @@ import React, {useEffect, useState} from 'react'; import {TagPicker} from "@fluentui/react"; -import {invoke} from "@tauri-apps/api"; import * as R from "ramda"; -import {search} from "./utils"; +import {search, suggest} from "./utils"; function top6(json) { return R.take(6)(json); } async function filterSuggestedTags(filter, selectedItems) { - let res = await invoke('my_custom_command', { - number: 2, - kw: filter - }); + let res = await suggest(filter); let titles = R.map(x => ({name: x, key: x}))(R.uniq(R.map( x => (x.name) - )(res.file_views))); + )(res))); if (titles[0]) { if (titles[0].name !== filter) { @@ -43,7 +39,7 @@ const SearchBox = ({setItems, kw, setKw, selectedKey}) => { setInit(true) } - }, 1000); + }, 200); setHandler(number); }, [init]) diff --git a/src/index.css b/src/index.css index 58e9380..77a5135 100644 --- a/src/index.css +++ b/src/index.css @@ -4,6 +4,7 @@ body { padding: 10px 10px; + user-select: none; } .ms-FocusZone { diff --git a/src/utils.js b/src/utils.js index bb99b2a..540b41f 100644 --- a/src/utils.js +++ b/src/utils.js @@ -5,7 +5,11 @@ const fileType2ext = { 3: "mp4 mov avi flv f4v mkv", 2: "doc txt pdf ppt pptx docx xlsx xls", } - +export async function suggest(kw) { + return await invoke('suggest', { + kw: kw + }); +} export async function search(kw, no) { let ext = fileType2ext[no]; let dirOpt = undefined; @@ -14,27 +18,22 @@ export async function search(kw, no) { dirOpt = true; } } - let res = await invoke('my_custom_command', { - number: 0, + return await invoke('search', { kw: kw, isDirOpt: dirOpt, extOpt: ext, - parentDirsOpt: undefined, }); - return res.file_views; } export function open_file_location_in_terminal(row) { - invoke('my_custom_command', { - number: 3, + let _ = invoke('open_file_in_terminal', { kw: row.abs_path - }) + }); } export function open_file_location(row) { - invoke('my_custom_command', { - number: 1, + let _ = invoke('open_file_path', { kw: row.abs_path - }) + }); } \ No newline at end of file From fe1b6fd9e1a795c37ffc334e43a07e3eef850066 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 20:06:29 +0800 Subject: [PATCH 05/28] Add exclude path component --- src-tauri/src/walk_exec.rs | 4 +-- src-tauri/src/watch_exec.rs | 2 +- src/App.js | 38 ++++++--------------- src/Tab.js | 68 +++++++++++++++++++++++++++++++++++++ src/index.css | 24 +++++++++++++ 5 files changed, 105 insertions(+), 31 deletions(-) create mode 100644 src/Tab.js diff --git a/src-tauri/src/walk_exec.rs b/src-tauri/src/walk_exec.rs index 94b6980..9f76f3a 100644 --- a/src-tauri/src/walk_exec.rs +++ b/src-tauri/src/walk_exec.rs @@ -104,7 +104,7 @@ fn inc_root_walk_metrics(sz: usize, i: usize) { } #[cfg(windows)] -fn win_walk_root(conf_store: Arc, idx_store: Arc, home: String) { +fn win_walk_root(home: String) { let len = win_subs_len(); let drives = unsafe { get_win32_ready_drives() }; @@ -125,7 +125,7 @@ fn win_walk_root(conf_store: Arc, idx_store: Arc, home: Strin continue; } - walk(idx_store.clone(), &sub, Some(home.to_string())); + walk(&sub, Some(home.to_string())); CONF_STORE.put_str(key, "1".to_string()); } } diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index 8c881f3..c50554b 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -40,7 +40,7 @@ fn linux_run(idx_store: Arc) { fn win_run() { let drives = unsafe { get_win32_ready_drives() }; for driv in drives { - let mut watcher = FsWatcher::new(idx_store.clone(), driv); + let mut watcher = FsWatcher::new( driv); watcher.start(); } } diff --git a/src/App.js b/src/App.js index f9b71a4..bd42d33 100644 --- a/src/App.js +++ b/src/App.js @@ -4,12 +4,12 @@ import './App.css'; import Items from "./Items"; import {Scrollbars} from 'react-custom-scrollbars'; import SearchBox from "./SearchBox"; -import {Pivot, PivotItem, PrimaryButton} from "@fluentui/react"; +import {IconButton, Pivot, PivotItem, PrimaryButton} from "@fluentui/react"; import {search} from "./utils"; -import { appWindow } from '@tauri-apps/api/window' -import { Dialog, DialogType, DialogFooter } from '@fluentui/react/lib/Dialog'; -import { useId, useBoolean } from '@fluentui/react-hooks'; - +import {appWindow} from '@tauri-apps/api/window' +import {Dialog, DialogType, DialogFooter} from '@fluentui/react/lib/Dialog'; +import {useId, useBoolean} from '@fluentui/react-hooks'; +import Tab from "./Tab"; const dialogContentProps = { @@ -24,8 +24,8 @@ const App = () => { const [items, setItems] = useState([]); const [kw, setKw] = useState(''); const [selectedKey, setSelectedKey] = useState(0); - const [hideDialog, { toggle: toggleHideDialog }] = useBoolean(true); - let [init,setInit] = useState(false); + const [hideDialog, {toggle: toggleHideDialog}] = useBoolean(true); + let [init, setInit] = useState(false); useEffect(() => { if (!init) { @@ -36,7 +36,7 @@ const App = () => { }) setInit(true); } - }, [init,hideDialog]); + }, [init, hideDialog]); return (
@@ -46,29 +46,11 @@ const App = () => { dialogContentProps={dialogContentProps} > - + {/**/} - { - let key = event.key.substr(1); - setSelectedKey(key) - search(kw, key).then(value => { - setItems(value) - }) - }}> - {/*https://uifabricicons.azurewebsites.net/?help*/} - - - - - - - - - - - +
diff --git a/src/Tab.js b/src/Tab.js new file mode 100644 index 0000000..f023955 --- /dev/null +++ b/src/Tab.js @@ -0,0 +1,68 @@ +import React from 'react'; +import { + ContextualMenu, + FontWeights, + getTheme, + IconButton, Label, + mergeStyleSets, + Modal, Panel, + Pivot, + PivotItem, PrimaryButton, TextField +} from "@fluentui/react"; +import {search} from "./utils"; +import {useBoolean, useId} from "@fluentui/react-hooks"; + + +const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { + const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false); + + + return ( +
+ +
+ +
+ + +
+
+ +
+
+
+ + { + let key = event.key.substr(1); + setSelectedKey(key) + search(kw, key).then(value => { + setItems(value) + }) + }}> + {/*https://uifabricicons.azurewebsites.net/?help*/} + + + + + + + + + + + +
+ +
+
+ ); +}; + +export default Tab; \ No newline at end of file diff --git a/src/index.css b/src/index.css index 77a5135..2f8af65 100644 --- a/src/index.css +++ b/src/index.css @@ -85,4 +85,28 @@ ul.right-menu-list.theme-mac li { body { overflow: hidden; +} +.tabs{ + display: flex; + justify-content:space-between; +} +.tabs>.menu{ + display: flex; + flex-direction: column-reverse; + justify-content: center; + width: 40px; +} +.ms-layer{ + display: none; +} +.setting-item{ + padding: 10px 0 ; +} +.setting-item .add{ + margin: 2px 0 0 0 !important; +} + +.setting-item .added { + display: flex; + margin: 2px 0 0 0 !important; } \ No newline at end of file From 6f4493aba4e2b5dfb469bf0da1334d65bd448ba5 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 20:49:09 +0800 Subject: [PATCH 06/28] Highlight --- package.json | 2 ++ src/App.js | 2 +- src/Items.js | 17 ++++++++++++----- src/index.css | 17 +++++++++++++---- yarn.lock | 10 ++++++++++ 5 files changed, 38 insertions(+), 10 deletions(-) diff --git a/package.json b/package.json index 7bc5196..68db529 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "af-virtual-scroll": "2.7.9", "copy-to-clipboard": "^3.3.1", "lodash": "^4.17.21", + "mark.js": "^8.11.1", "moment": "^2.29.1", "office-ui-fabric-react": "^7.183.1", "ramda": "^0.27.1", @@ -21,6 +22,7 @@ "react-custom-scrollbars": "^4.2.1", "react-dom": "^17.0.2", "react-file-icon": "1.1.0", + "react-mark.js": "^3.1.16", "react-modern-drawer": "^1.0.2", "react-scripts": "5.0.0", "styled-components": "^5.3.3", diff --git a/src/App.js b/src/App.js index bd42d33..4011a8c 100644 --- a/src/App.js +++ b/src/App.js @@ -58,7 +58,7 @@ const App = () => { - + diff --git a/src/Items.js b/src/Items.js index 3d63024..c4655ef 100644 --- a/src/Items.js +++ b/src/Items.js @@ -7,7 +7,7 @@ import moment from "moment"; import copy from "copy-to-clipboard"; import {open_file_location, open_file_location_in_terminal} from "./utils"; import RightMenu from '@right-menu/react' - +import { Marker } from "react-mark.js"; initializeFileTypeIcons(undefined); function bytesToSize(bytes) { @@ -100,13 +100,19 @@ const columns = [ { key: "column2", name: "Name", - fieldName: "name", minWidth: 50, maxWidth: 200, isRowHeader: true, isResizable: true, data: "string", - isPadded: true + isPadded: true, + onRender: (item) => { + return + + {item.name} + + ; + }, }, { key: "column3", @@ -178,7 +184,7 @@ function options(row) { ] } -function Items({items, setItems}) { +function Items({kw,items, setItems}) { return ( @@ -186,8 +192,9 @@ function Items({items, setItems}) { { let row = props.item; + row.kw = kw; return -
open_file_location(row)}> +
; diff --git a/src/index.css b/src/index.css index 2f8af65..a49e800 100644 --- a/src/index.css +++ b/src/index.css @@ -51,7 +51,8 @@ div.ms-Callout-container > div { .items { height: calc(100vh - 125px); } -.items div{ +/*todo*/ +.items>div{ overflow: hidden; } @@ -73,14 +74,14 @@ ul.right-menu-list.theme-mac { ul.right-menu-list.theme-mac :hover { background: #f3f2f1; color: #21201f; - cursor: pointer; + /*cursor: pointer;*/ } ul.right-menu-list.theme-mac li { padding: 0 8px !important; font-family: "Segoe UI", "Segoe UI Web (West European)", "Segoe UI", -apple-system, BlinkMacSystemFont, Roboto, "Helvetica Neue", sans-serif; - height: 36px !important; - line-height: 36px !important; + height: 30px !important; + line-height: 30px !important; } body { @@ -109,4 +110,12 @@ body { .setting-item .added { display: flex; margin: 2px 0 0 0 !important; +} + + div.menu > button > span{ + color: black; + } +.marker{ + background: lightyellow; + /*background: lightgoldenrodyellow;*/ } \ No newline at end of file diff --git a/yarn.lock b/yarn.lock index 0575948..352c27e 100644 --- a/yarn.lock +++ b/yarn.lock @@ -7917,6 +7917,11 @@ map-obj@^1.0.0, map-obj@^1.0.1: resolved "https://registry.yarnpkg.com/map-obj/-/map-obj-1.0.1.tgz#d933ceb9205d82bdcf4886f6742bdc2b4dea146d" integrity sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0= +mark.js@^8.11.1: + version "8.11.1" + resolved "https://registry.yarnpkg.com/mark.js/-/mark.js-8.11.1.tgz#180f1f9ebef8b0e638e4166ad52db879beb2ffc5" + integrity sha1-GA8fnr74sOY45BZq1S24eb6y/8U= + matcher@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/matcher/-/matcher-3.0.0.tgz#bd9060f4c5b70aa8041ccc6f80368760994f30ca" @@ -9741,6 +9746,11 @@ react-is@^17.0.1: resolved "https://registry.yarnpkg.com/react-is/-/react-is-17.0.2.tgz#e691d4a8e9c789365655539ab372762b0efb54f0" integrity sha512-w2GsyukL62IJnlaff/nRegPQR94C/XXamvMWmSHRJ4y7Ts/4ocGRmTHvOs8PSE6pB3dWOrD/nueuU5sduBsQ4w== +react-mark.js@^3.1.16: + version "3.1.16" + resolved "https://registry.yarnpkg.com/react-mark.js/-/react-mark.js-3.1.16.tgz#64ddc171df2844696287e56948a5bf142814b02e" + integrity sha512-vxZ4Ac9YeH5fAwlOWxxvEQlzqzZVYdwKalfN3OJMJXdft9ejEOOSOSiqWA2DVSgTOvUmFa+Fb8aNvzh+VKXBwA== + react-modern-drawer@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/react-modern-drawer/-/react-modern-drawer-1.0.2.tgz#0847ed43c14f6fc6bf6f2bf61af2554fc34d213f" From ee79703c5e17ba4980c6812ff7aed82e9c350d7b Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 21:00:06 +0800 Subject: [PATCH 07/28] Add Upgrade SystemTrayMenu --- src-tauri/Cargo.lock | 42 ++++++++++++++++++++++++++++++++++++++++++ src-tauri/Cargo.toml | 1 + src-tauri/src/ui.rs | 6 +++++- src-tauri/src/utils.rs | 6 ++++++ src/Tab.js | 2 +- 5 files changed, 55 insertions(+), 2 deletions(-) diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 3ee85d7..244a3b3 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -79,6 +79,7 @@ dependencies = [ "tauri", "tauri-build", "walkdir", + "webbrowser", "windows 0.29.0", "winres", ] @@ -435,6 +436,12 @@ version = "0.4.0" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "5927edd8345aef08578bcbb4aea7314f340d80c7f4931f99fbeb40b99d8f5060" +[[package]] +name = "cesu8" +version = "1.1.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "6d43a04d8753f35258c91f8ec639f792891f748a1edbd759cf1dcea3382ad83c" + [[package]] name = "cfb" version = "0.4.0" @@ -555,6 +562,7 @@ version = "4.6.3" source = "registry+/~https://github.com/rust-lang/crates.io-index" checksum = "50b727aacc797f9fc28e355d21f34709ac4fc9adecfe470ad07b8f4464f53062" dependencies = [ + "bytes", "memchr", ] @@ -1867,6 +1875,20 @@ dependencies = [ "regex", ] +[[package]] +name = "jni" +version = "0.19.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "c6df18c2e3db7e453d3c6ac5b3e9d5182664d28788126d39b91f2d1e22b017ec" +dependencies = [ + "cesu8", + "combine", + "jni-sys", + "log", + "thiserror", + "walkdir", +] + [[package]] name = "jni-sys" version = "0.3.0" @@ -4497,6 +4519,20 @@ dependencies = [ "wasm-bindgen", ] +[[package]] +name = "webbrowser" +version = "0.6.0" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "f9c28b6b6a78440b02647358625e3febc90724126480b9da6a967b5f674b3554" +dependencies = [ + "jni", + "ndk-glue", + "url", + "web-sys", + "widestring", + "winapi 0.3.9", +] + [[package]] name = "webkit2gtk" version = "0.17.1" @@ -4589,6 +4625,12 @@ dependencies = [ "cc", ] +[[package]] +name = "widestring" +version = "0.5.1" +source = "registry+/~https://github.com/rust-lang/crates.io-index" +checksum = "17882f045410753661207383517a6f62ec3dbeb6a4ed2acce01f0728238d1983" + [[package]] name = "wildmatch" version = "2.1.0" diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 6503eb2..52fdade 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -44,6 +44,7 @@ directories = "4.0" jwalk = "0.6.0" convert_case = "0.1.0" lazy_static = "1.4.0" +webbrowser = "0.6.0" [features] # by default Tauri runs in production mode diff --git a/src-tauri/src/ui.rs b/src-tauri/src/ui.rs index 2e2e8b7..8bcaec7 100644 --- a/src-tauri/src/ui.rs +++ b/src-tauri/src/ui.rs @@ -76,6 +76,9 @@ fn handle_tray_event(event: SystemTrayEvent) { } indexing::reindex(); } + "upgrade"=>{ + webbrowser::open("/~https://github.com/naaive/orange/releases"); + } _ => {} }, _ => {} @@ -85,7 +88,8 @@ fn handle_tray_event(event: SystemTrayEvent) { fn build_tray() -> SystemTray { let quit = CustomMenuItem::new("quit".to_string(), "Quit"); let reindex = CustomMenuItem::new("reindex".to_string(), "Reindex"); - let tray_menu = SystemTrayMenu::new().add_item(reindex).add_item(quit); + let upgrade = CustomMenuItem::new("upgrade".to_string(), "Upgrade"); + let tray_menu = SystemTrayMenu::new().add_item(upgrade).add_item(reindex).add_item(quit); let tray = SystemTray::new().with_menu(tray_menu); tray } diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 1c4499c..43b4085 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -229,3 +229,9 @@ fn t6() { let string = "FilterFieldNamesProvidingStoredFieldsVisitor.java".to_case(Case::Title); println!("{}", string); } +use webbrowser; + +#[test] +fn t7() { + let result = webbrowser::open("/~https://github.com/naaive/orange/releases"); +} \ No newline at end of file diff --git a/src/Tab.js b/src/Tab.js index f023955..4485cce 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -51,7 +51,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { - + From 53d5928750ec1bc69937bfaff0fdd2f0abc53178 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 21:18:09 +0800 Subject: [PATCH 08/28] Spawn thread while indexing --- src-tauri/src/indexing.rs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/src-tauri/src/indexing.rs b/src-tauri/src/indexing.rs index 9a3cd39..4fb6172 100644 --- a/src-tauri/src/indexing.rs +++ b/src-tauri/src/indexing.rs @@ -27,6 +27,12 @@ const VERSION: &'static str = "0.4.0"; const LAST_INDEX_TS: &'static str = "last_index_ts"; pub fn run() { + std::thread::spawn(|| { + do_run(); + }); +} + +fn do_run() { housekeeping(); let reindex = need_reindex(); @@ -41,10 +47,10 @@ pub fn run() { info!("start fs watch"); #[cfg(windows)] - win_watch(); + win_watch(); #[cfg(unix)] - watch_exec::run(); + watch_exec::run(); } #[cfg(windows)] From a42c284f8b428a7bc297ffc30c9b3e03b67c7793 Mon Sep 17 00:00:00 2001 From: Jeff Date: Thu, 31 Mar 2022 21:23:27 +0800 Subject: [PATCH 09/28] CSS --- src/index.css | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/index.css b/src/index.css index a49e800..a34a0f9 100644 --- a/src/index.css +++ b/src/index.css @@ -51,8 +51,8 @@ div.ms-Callout-container > div { .items { height: calc(100vh - 125px); } -/*todo*/ -.items>div{ + +.items>div>div div{ overflow: hidden; } From 4146bc4498f8d61dce0b861d73c374c3f8d7d4a1 Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 1 Apr 2022 10:30:58 +0800 Subject: [PATCH 10/28] I18n --- package.json | 2 + src/App.js | 2 + src/Items.js | 323 ++++++++++++++++++++++++++------------------------- src/Tab.js | 20 ++-- src/index.js | 47 ++++++++ yarn.lock | 37 +++++- 6 files changed, 261 insertions(+), 170 deletions(-) diff --git a/package.json b/package.json index 68db529..eaed94a 100644 --- a/package.json +++ b/package.json @@ -13,6 +13,7 @@ "@testing-library/user-event": "^13.2.1", "af-virtual-scroll": "2.7.9", "copy-to-clipboard": "^3.3.1", + "i18next": "^21.6.14", "lodash": "^4.17.21", "mark.js": "^8.11.1", "moment": "^2.29.1", @@ -22,6 +23,7 @@ "react-custom-scrollbars": "^4.2.1", "react-dom": "^17.0.2", "react-file-icon": "1.1.0", + "react-i18next": "^11.16.2", "react-mark.js": "^3.1.16", "react-modern-drawer": "^1.0.2", "react-scripts": "5.0.0", diff --git a/src/App.js b/src/App.js index 4011a8c..98ffa35 100644 --- a/src/App.js +++ b/src/App.js @@ -10,6 +10,7 @@ import {appWindow} from '@tauri-apps/api/window' import {Dialog, DialogType, DialogFooter} from '@fluentui/react/lib/Dialog'; import {useId, useBoolean} from '@fluentui/react-hooks'; import Tab from "./Tab"; +import {useTranslation} from "react-i18next"; const dialogContentProps = { @@ -26,6 +27,7 @@ const App = () => { const [selectedKey, setSelectedKey] = useState(0); const [hideDialog, {toggle: toggleHideDialog}] = useBoolean(true); let [init, setInit] = useState(false); + const { t } = useTranslation(); useEffect(() => { if (!init) { diff --git a/src/Items.js b/src/Items.js index c4655ef..fea3a1b 100644 --- a/src/Items.js +++ b/src/Items.js @@ -8,184 +8,187 @@ import copy from "copy-to-clipboard"; import {open_file_location, open_file_location_in_terminal} from "./utils"; import RightMenu from '@right-menu/react' import { Marker } from "react-mark.js"; +import {useTranslation} from "react-i18next"; initializeFileTypeIcons(undefined); -function bytesToSize(bytes) { - const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; - if (bytes === 0) return '0 Byte'; - const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); - return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; -} -function tsFmt(mod_at) { - return moment.unix(mod_at).format("YYYY/MM/DD"); -} +function Items({kw,items, setItems}) { -function _getKey(item, index) { - return item.key; -} + const { t } = useTranslation(); -const classNames = mergeStyleSets({ - fileIconHeaderIcon: { - padding: 0, - fontSize: "12px" - }, - fileIconCell: { - textAlign: "center", - selectors: { - "&:before": { - content: ".", - display: "inline-block", - verticalAlign: "middle", - height: "100%", - width: "0px", - visibility: "hidden" - } - } - }, - fileIconImg: { - verticalAlign: "middle", - maxHeight: "16px", - maxWidth: "16px" - }, - controlWrapper: { - display: "flex", - flexWrap: "wrap" - }, - exampleToggle: { - display: "inline-block", - marginBottom: "10px", - marginRight: "30px" - }, - selectionDetails: { - marginBottom: "20px" + function bytesToSize(bytes) { + const sizes = ['Bytes', 'KB', 'MB', 'GB', 'TB']; + if (bytes === 0) return '0 Byte'; + const i = parseInt(Math.floor(Math.log(bytes) / Math.log(1024))); + return Math.round(bytes / Math.pow(1024, i), 2) + ' ' + sizes[i]; } -}); - -const columns = [ - { - key: "column1", - name: "File Type", - className: classNames.fileIconCell, - iconClassName: classNames.fileIconHeaderIcon, - ariaLabel: - "Column operations for File type, Press to sort on File type", - iconName: "Page", - isIconOnly: true, - fieldName: "name", - minWidth: 16, - maxWidth: 16, - - onRender: (item) => { - let isDir = R.prop('is_dir')(item); - let name = R.prop("name")(item); - const extSplit = R.split('.'); - let ext = R.last(extSplit(name)); - // let ext = "exe"; - // item.name - return ( -
- { - isDir ? : - - } -
- ); - } - }, - { - key: "column2", - name: "Name", - minWidth: 50, - maxWidth: 200, - isRowHeader: true, - isResizable: true, - data: "string", - isPadded: true, - onRender: (item) => { - return - - {item.name} - - ; + + function tsFmt(mod_at) { + return moment.unix(mod_at).format("YYYY/MM/DD"); + } + + function _getKey(item, index) { + return item.key; + } + + const classNames = mergeStyleSets({ + fileIconHeaderIcon: { + padding: 0, + fontSize: "12px" + }, + fileIconCell: { + textAlign: "center", + selectors: { + "&:before": { + content: ".", + display: "inline-block", + verticalAlign: "middle", + height: "100%", + width: "0px", + visibility: "hidden" + } + } + }, + fileIconImg: { + verticalAlign: "middle", + maxHeight: "16px", + maxWidth: "16px" }, - }, - { - key: "column3", - name: "Last Modified", - fieldName: "mod_at", - minWidth: 70, - maxWidth: 90, - isResizable: true, - data: "number", - onRender: (item) => { - return {tsFmt(item.mod_at)}; + controlWrapper: { + display: "flex", + flexWrap: "wrap" }, - isPadded: true - }, - { - key: "column4", - name: "Size", - fieldName: "size", - minWidth: 40, - maxWidth: 60, - isSorted: false, - isResizable: true, - isCollapsible: true, - data: "string", - onRender: (item) => { - return {bytesToSize(item.size)}; + exampleToggle: { + display: "inline-block", + marginBottom: "10px", + marginRight: "30px" }, - isPadded: true - }, - { - key: "column5", - name: "Path", - fieldName: "abs_path", - minWidth: 70, - isSorted: false, - isResizable: true, - isCollapsible: true, - data: "number", - onRender: (item) => { - return {item.abs_path}; + selectionDetails: { + marginBottom: "20px" } - } -]; - -function options(row) { + }); - return [ + const columns = [ { - type: 'li', - text: 'Open', - callback: () => { - open_file_location(row) + key: "column1", + name: "File Type", + className: classNames.fileIconCell, + iconClassName: classNames.fileIconHeaderIcon, + ariaLabel: + "Column operations for File type, Press to sort on File type", + iconName: "Page", + isIconOnly: true, + fieldName: "name", + minWidth: 16, + maxWidth: 16, + + onRender: (item) => { + let isDir = R.prop('is_dir')(item); + let name = R.prop("name")(item); + const extSplit = R.split('.'); + let ext = R.last(extSplit(name)); + // let ext = "exe"; + // item.name + return ( +
+ { + isDir ? : + + } +
+ ); } }, - // { - type: 'li', - text: 'Copy Path', - callback: () => copy(row.abs_path) + key: "column2", + name: t("name"), + minWidth: 50, + maxWidth: 200, + isRowHeader: true, + isResizable: true, + data: "string", + isPadded: true, + onRender: (item) => { + return + + {item.name} + + ; + }, }, - { - type: 'li', - text: 'Open in Terminal', - callback: () => { - open_file_location_in_terminal(row) - } + key: "column3", + name: t("last-modified"), + fieldName: "mod_at", + minWidth: 70, + maxWidth: 90, + isResizable: true, + data: "number", + onRender: (item) => { + return {tsFmt(item.mod_at)}; + }, + isPadded: true }, - ] -} - -function Items({kw,items, setItems}) { - + { + key: "column4", + name: t("size"), + fieldName: "size", + minWidth: 40, + maxWidth: 60, + isSorted: false, + isResizable: true, + isCollapsible: true, + data: "string", + onRender: (item) => { + return {bytesToSize(item.size)}; + }, + isPadded: true + }, + { + key: "column5", + name: t("path"), + fieldName: "abs_path", + minWidth: 70, + isSorted: false, + isResizable: true, + isCollapsible: true, + data: "number", + onRender: (item) => { + return {item.abs_path}; + } + } + ]; + + function options(row) { + + return [ + { + type: 'li', + text: 'Open', + callback: () => { + open_file_location(row) + } + }, + // + { + type: 'li', + text: 'Copy Path', + callback: () => copy(row.abs_path) + }, + + { + type: 'li', + text: 'Open in Terminal', + callback: () => { + open_file_location_in_terminal(row) + } + }, + ] + } return (
diff --git a/src/Tab.js b/src/Tab.js index 4485cce..d9d0a6c 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -11,30 +11,32 @@ import { } from "@fluentui/react"; import {search} from "./utils"; import {useBoolean, useId} from "@fluentui/react-hooks"; +import {useTranslation} from "react-i18next"; const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false); + const { t } = useTranslation(); return (
- +
- +
@@ -47,19 +49,19 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { }) }}> {/*https://uifabricicons.azurewebsites.net/?help*/} - + - + - + - + - +
- +
); diff --git a/src/index.js b/src/index.js index 42e2ba5..6dd9113 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,8 @@ import * as ReactDOM from 'react-dom'; import './index.css' import App from "./App"; import {mergeStyles, ThemeProvider, initializeIcons} from '@fluentui/react'; +import i18n from "i18next"; +import { useTranslation, initReactI18next } from "react-i18next"; initializeIcons() // Inject some global styles @@ -13,6 +15,51 @@ mergeStyles({ height: '100vh', }, }); +const lang = navigator.language || navigator.userLanguage; +let _ = i18n + .use(initReactI18next) + .init({ + resources: { + "en": { + translation: { + "setting-header": "Setting", + "exclude-path-label":"Exclude Path", + "add":"Add", + "all":"All", + "photo":"Add", + "video":"Video", + "document":"Document", + "folder":"Folder", + "name":"Name", + "last-modified":"Last Modified", + "size":"Size", + "path":"Path", + + } + }, + "zh-CN":{ + translation: { + "setting-header": "设置", + "exclude-path-label":"排除路径", + "add":"添加", + "all":"所有", + "photo":"图片", + "video":"视频", + "document":"文档", + "folder":"文件夹", + "name":"名称", + "last-modified":"上次修改", + "size":"大小", + "path":"路径", + } + } + }, + lng: "zh-CN", + fallbackLng: "en", + interpolation: { + escapeValue: false + } + }); ReactDOM.render(<> diff --git a/yarn.lock b/yarn.lock index 352c27e..1a0d113 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1036,6 +1036,13 @@ dependencies: regenerator-runtime "^0.13.4" +"@babel/runtime@^7.14.5", "@babel/runtime@^7.17.2": + version "7.17.8" + resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.8.tgz#3e56e4aff81befa55ac3ac6a0967349fd1c5bca2" + integrity sha512-dQpEpK0O9o6lj6oPu0gRDbbnk+4LeHlNcBpspf6Olzt3GIX4P1lWF1gS+pHLDFlaJvbR6q7jCfQ08zA4QJBnmA== + dependencies: + regenerator-runtime "^0.13.4" + "@babel/runtime@^7.14.8", "@babel/runtime@^7.7.2": version "7.17.2" resolved "https://registry.yarnpkg.com/@babel/runtime/-/runtime-7.17.2.tgz#66f68591605e59da47523c631416b18508779941" @@ -6291,7 +6298,7 @@ html-entities@^2.1.0, html-entities@^2.3.2: resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.3.2.tgz#760b404685cb1d794e4f4b744332e3b00dcfe488" integrity sha512-c3Ab/url5ksaT0WyleslpBEthOzWhrjQbg75y7XUsfSzi3Dgzt0l8w5e7DylRn15MTlMMD58dTfzddNS2kcAjQ== -html-escaper@^2.0.0: +html-escaper@^2.0.0, html-escaper@^2.0.2: version "2.0.2" resolved "https://registry.yarnpkg.com/html-escaper/-/html-escaper-2.0.2.tgz#dfd60027da36a36dfcbe236262c00a5822681453" integrity sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg== @@ -6309,6 +6316,13 @@ html-minifier-terser@^6.0.2: relateurl "^0.2.7" terser "^5.10.0" +html-parse-stringify@^3.0.1: + version "3.0.1" + resolved "https://registry.yarnpkg.com/html-parse-stringify/-/html-parse-stringify-3.0.1.tgz#dfc1017347ce9f77c8141a507f233040c59c55d2" + integrity sha512-KknJ50kTInJ7qIScF3jeaFRpMpE8/lfiTdzf/twXyPBLAGrLRTmkz3AdTnKeh40X8k9L2fdYwEp/42WGXIRGcg== + dependencies: + void-elements "3.1.0" + html-webpack-plugin@^5.5.0: version "5.5.0" resolved "https://registry.yarnpkg.com/html-webpack-plugin/-/html-webpack-plugin-5.5.0.tgz#c3911936f57681c1f9f4d8b68c158cd9dfe52f50" @@ -6421,6 +6435,13 @@ human-signals@^2.1.0: resolved "https://registry.yarnpkg.com/human-signals/-/human-signals-2.1.0.tgz#dc91fcba42e4d06e4abaed33b3e7a3c02f514ea0" integrity sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw== +i18next@^21.6.14: + version "21.6.14" + resolved "https://registry.yarnpkg.com/i18next/-/i18next-21.6.14.tgz#2bc199fba7f4da44b5952d7df0a3814a6e5c3943" + integrity sha512-XL6WyD+xlwQwbieXRlXhKWoLb/rkch50/rA+vl6untHnJ+aYnkQ0YDZciTWE78PPhOpbi2gR0LTJCJpiAhA+uQ== + dependencies: + "@babel/runtime" "^7.17.2" + iconv-lite@0.4.24, iconv-lite@^0.4.24: version "0.4.24" resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" @@ -9736,6 +9757,15 @@ react-file-icon@1.1.0: prop-types "^15.7.2" tinycolor2 "^1.4.2" +react-i18next@^11.16.2: + version "11.16.2" + resolved "https://registry.yarnpkg.com/react-i18next/-/react-i18next-11.16.2.tgz#650b18c12a624057ee2651ba4b4a989b526be554" + integrity sha512-1iuZduvARUelL5ux663FvIoDZExwFO+9QtRAAt4uvs1/aun4cUZt8XBrVg7iiDgNls9cOSORAhE7Ri5KA9RMvg== + dependencies: + "@babel/runtime" "^7.14.5" + html-escaper "^2.0.2" + html-parse-stringify "^3.0.1" + react-is@^16.13.1, react-is@^16.7.0: version "16.13.1" resolved "https://registry.yarnpkg.com/react-is/-/react-is-16.13.1.tgz#789729a4dc36de2999dc156dd6c1d9c18cea56a4" @@ -11577,6 +11607,11 @@ vary@~1.1.2: resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= +void-elements@3.1.0: + version "3.1.0" + resolved "https://registry.yarnpkg.com/void-elements/-/void-elements-3.1.0.tgz#614f7fbf8d801f0bb5f0661f5b2f5785750e4f09" + integrity sha1-YU9/v42AHwu18GYfWy9XhXUOTwk= + w3c-hr-time@^1.0.2: version "1.0.2" resolved "https://registry.yarnpkg.com/w3c-hr-time/-/w3c-hr-time-1.0.2.tgz#0a89cdf5cc15822df9c360543676963e0cc308cd" From 4979c06a5073ff45a162b6fe529beae3099525ef Mon Sep 17 00:00:00 2001 From: Jeff Date: Fri, 1 Apr 2022 17:03:33 +0800 Subject: [PATCH 11/28] Theme --- src-tauri/src/user_setting.rs | 16 ++++++++++++++-- src/App.js | 2 +- src/index.css | 4 +++- src/index.js | 32 ++++++++++++++++++++++++++++---- 4 files changed, 46 insertions(+), 8 deletions(-) diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs index 09dc223..b7c7fe5 100644 --- a/src-tauri/src/user_setting.rs +++ b/src-tauri/src/user_setting.rs @@ -46,10 +46,14 @@ impl Error for UserSettingError { #[derive(Debug, Serialize, Deserialize)] pub struct UserSetting { theme: Theme, + lang: String, exclude_index_path: Vec, } impl UserSetting { + pub fn lang(&self) -> &str { + &self.lang + } pub fn theme(&self) -> &Theme { &self.theme } @@ -59,6 +63,10 @@ impl UserSetting { } impl UserSetting { + pub fn set_lang(&mut self, lang: String) { + self.lang = lang; + self.store(); + } pub fn set_theme(&mut self, theme: Theme) { self.theme = theme; self.store(); @@ -87,10 +95,11 @@ impl UserSetting { let _ = std::fs::write(path, contents); } - fn load() -> std::result::Result> { + fn load() -> std::result::Result> { let path = UserSetting::build_conf_path(); let string = std::fs::read_to_string(path)?; - Ok(serde_json::from_str(&string).expect("deserialize error")) + let result1: Result = serde_json::from_str(&string); + result1.map_err(|x| x.to_string().into()) } fn build_conf_path() -> String { @@ -104,6 +113,7 @@ impl Default for UserSetting { UserSetting::load().unwrap_or_else(|_| { let setting = UserSetting { theme: Theme::Light, + lang: "en".to_string(), exclude_index_path: vec![], }; setting.store(); @@ -119,6 +129,8 @@ mod tests { #[test] fn t1() { let mut setting = UserSetting::default(); + // let string = "zh".into(); + // setting.set_lang(string); // setting.set_theme(Theme::Dark); println!("{:?}", setting); } diff --git a/src/App.js b/src/App.js index 98ffa35..03bd781 100644 --- a/src/App.js +++ b/src/App.js @@ -41,7 +41,7 @@ const App = () => { }, [init, hideDialog]); return ( -
+
); diff --git a/src/Tab.js b/src/Tab.js index aa324b7..021ac8d 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -1,35 +1,125 @@ -import React from 'react'; +import React, {useEffect, useState} from 'react'; import { - ContextualMenu, Dropdown, - FontWeights, - getTheme, - IconButton, Label, - mergeStyleSets, - Modal, Panel, + ContextualMenu, + DefaultButton, + Dropdown, hiddenContentStyle, + IconButton, + Label, mergeStyles, + MessageBar, MessageBarType, + Panel, Pivot, - PivotItem, PrimaryButton, TextField + PivotItem, + PrimaryButton, + TextField } from "@fluentui/react"; -import {search} from "./utils"; +import {add_exclude_path, change_lang, get_exclude_paths, reindex, remove_exclude_path, search} from "./utils"; import {useBoolean, useId} from "@fluentui/react-hooks"; import {useTranslation} from "react-i18next"; +import i18next from "i18next"; +import { Dialog, DialogType, DialogFooter, Toggle} from "@fluentui/react"; + +const dialogStyles = { main: { maxWidth: 450 } }; +const dragOptions = { + moveMenuItemText: 'Move', + closeMenuItemText: 'Close', + menu: ContextualMenu, + keepInBounds: true, +}; const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { - const [isOpen, { setTrue: openPanel, setFalse: dismissPanel }] = useBoolean(false); - const { t } = useTranslation(); + const [isOpen, {setTrue: openPanel, setFalse: dismissPanel}] = useBoolean(false); + const {t} = useTranslation(); + let [excludePath, setExcludePath] = useState(); + let [show, setShow] = useState(false); + let [toastText, setToastText] = useState(''); + let [excludePaths, setExcludePaths] = useState([]); - const options = [ - { key: 'fruitsHeader', text: 'EN'}, - { key: 'apple', text: '中文' }, + const [hideDialog, { toggle: toggleHideDialog }] = useBoolean(true); + const [isDraggable, { toggle: toggleIsDraggable }] = useBoolean(false); + const labelId = useId('dialogLabel'); + const subTextId = useId('subTextLabel'); + + const dialogContentProps = { + type: DialogType.normal, + title: t('reindex'), + closeButtonAriaLabel: 'Close', + subText: t("reindex-dialog"), + }; + + function toast(txt) { + setToastText(txt); + setShow(true); + setTimeout(() => setShow(false), 2000); + } + useEffect(async () => { + setExcludePaths(await get_exclude_paths()) + }, [excludePaths]) + const options = [ + {key: 'en', text: 'EN'}, + {key: 'zh-CN', text: '中文'}, ]; const dropdownStyles = { - dropdown: { width: 300 }, + dropdown: {width: 300}, }; + + async function handleAddExcludePath(){ + if (await add_exclude_path(excludePath) === 1) { + toast(t("add_exclude_path_err")); + + } else { + setExcludePath(""); + setExcludePaths(await get_exclude_paths()); + } + } + async function handleRemoveExcludePath(path){ + await remove_exclude_path(path) + setExcludePaths(await get_exclude_paths()); + } + + function handle_reindex() { + toggleHideDialog(); + reindex(); + } + + function handle_lang_change(_,item) { + let key = item.key; + setSelectedKey(key); + change_lang(key); + i18next.changeLanguage(key, (err, t) => { + if (err) return console.log('something went wrong loading', err); + t('key'); // -> same as i18next.t + }); + } + + const modalProps = React.useMemo( + () => ({ + titleAriaId: labelId, + subtitleAriaId: subTextId, + isBlocking: false, + styles: dialogStyles, + dragOptions: isDraggable ? dragOptions : undefined, + }), + [isDraggable, labelId, subTextId], + ); + return (
+ + { // You MUST provide this prop! Otherwise screen readers will just say "button" with no label. closeButtonAriaLabel="Close" > + { + show? + {toastText} + :"" + }
-
- -
- - -
-
- - -
-
+
+ + setExcludePath(e.target.value)} /> +
+ { + excludePaths.map(x =>
+ + handleRemoveExcludePath(x)}/> +
) + } + +
+
+ + +
+ +
{ @@ -79,7 +182,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => {
- +
); diff --git a/src/index.css b/src/index.css index 7c7af78..0006a6a 100644 --- a/src/index.css +++ b/src/index.css @@ -106,18 +106,22 @@ body { padding: 10px 0 ; } .setting-item .add{ - margin: 2px 0 0 0 !important; + margin: 10px 0 0 0 !important; display: flex; } .setting-item .add button{ margin: 0 0 20px 0; } - -.setting-item .added { +.setting-item .added{ display: flex; - margin: 2px 0 0 0 !important; } - +.setting-item .added .added-item{ + display: flex; + margin: 0 8px 0 0 !important; +} +.add button{ + margin-right: 10px !important; +} /*div.menu > button > span{*/ /* color: black;*/ /*}*/ @@ -126,4 +130,7 @@ body { /*color: white;*/ /*background: lightslategray;*/ /*background: lightgoldenrodyellow;*/ -} \ No newline at end of file +} +.ms-Dropdown{ + width: 290px !important; +} diff --git a/src/index.js b/src/index.js index c6aa9ed..cb3bcdf 100644 --- a/src/index.js +++ b/src/index.js @@ -2,9 +2,12 @@ import * as React from 'react'; import * as ReactDOM from 'react-dom'; import './index.css' import App from "./App"; -import {mergeStyles, ThemeProvider, initializeIcons, createTheme} from '@fluentui/react'; +import {createTheme, initializeIcons, mergeStyles, ThemeProvider} from '@fluentui/react'; import i18n from "i18next"; -import { useTranslation, initReactI18next } from "react-i18next"; +import {initReactI18next} from "react-i18next"; +import {change_lang, get_lang} from "./utils"; +import i18next from "i18next"; + initializeIcons() // Inject some global styles @@ -15,7 +18,7 @@ mergeStyles({ height: '100vh', }, }); -const lang = navigator.language || navigator.userLanguage; +let lang= navigator.language || navigator.userLanguage; let _ = i18n .use(initReactI18next) .init({ @@ -26,7 +29,7 @@ let _ = i18n "exclude-path-label":"Exclude Path", "add":"Add", "all":"All", - "photo":"Add", + "photo":"Photo", "video":"Video", "document":"Document", "folder":"Folder", @@ -34,6 +37,11 @@ let _ = i18n "last-modified":"Last Modified", "size":"Size", "path":"Path", + "lang":"Language", + "reindex":"Reindex", + "reindex-dialog":"Do you want to Reindex? It will take effect on next reboot.", + "remove":"Remove", + "add_exclude_path_err":"Invalid path", } }, @@ -51,6 +59,11 @@ let _ = i18n "last-modified":"上次修改", "size":"大小", "path":"路径", + "lang":"语言", + "reindex":"重索引", + "reindex-dialog":"您确认要重新索引吗?它将在下一次重启时生效。", + "remove":"删除", + "add_exclude_path_err":"非法路径", } } }, @@ -62,6 +75,9 @@ let _ = i18n }); + + + const myTheme = createTheme({ palette: { themePrimary: '#1a2a3a', @@ -94,3 +110,4 @@ ReactDOM.render(<> , document.getElementById('root')); + diff --git a/src/utils.js b/src/utils.js index 540b41f..26a4148 100644 --- a/src/utils.js +++ b/src/utils.js @@ -1,4 +1,5 @@ import {invoke} from "@tauri-apps/api"; +import i18next from "i18next"; const fileType2ext = { 4: "bmp jpg gif png jpeg", @@ -36,4 +37,52 @@ export function open_file_location(row) { let _ = invoke('open_file_path', { kw: row.abs_path }); +} +export async function get_lang() { + return await invoke('get_lang', { + }); +} + +export function change_lang(lang) { + let _ = invoke('change_lang', { + lang: lang + }); + +} + +export async function get_theme() { + return await invoke('get_theme', { + }); +} + +export function change_theme(theme) { + let _ = invoke('change_theme', { + theme: theme + }); +} +export async function add_exclude_path(path) { + + return await invoke('add_exclude_path', { + path: path + }); +} + +export async function remove_exclude_path(path) { + return await invoke('remove_exclude_path', { + path: path + }); +} + +export function upgrade() { + let _ = invoke('upgrade', { + }); +} + +export function reindex() { + let _ = invoke('reindex', { + }); +} + +export async function get_exclude_paths() { + return await invoke('get_exclude_paths', {}); } \ No newline at end of file From c22f411293a0b1efe4864e012c3ee93875d90153 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 14:52:14 +0800 Subject: [PATCH 16/28] Skip exclude path when walk --- src-tauri/src/ui.rs | 14 +++++++++++++- src-tauri/src/walk_exec.rs | 30 +++++++++++++++++++++++++++--- src/Tab.js | 38 ++++++++++++++++++++++---------------- src/index.css | 4 +++- src/index.js | 8 ++++++-- 5 files changed, 71 insertions(+), 23 deletions(-) diff --git a/src-tauri/src/ui.rs b/src-tauri/src/ui.rs index 32e1a6d..fc6bfa7 100644 --- a/src-tauri/src/ui.rs +++ b/src-tauri/src/ui.rs @@ -44,7 +44,19 @@ fn change_lang(lang: String) { } #[tauri::command] fn add_exclude_path(path: String) -> u8 { - println!("{}", path); + if path.eq("/") { + return 1; + } + if USER_SETTING + .read() + .unwrap() + .exclude_index_path() + .iter() + .any(|x| x.eq(&path)) + { + return 1; + } + match USER_SETTING.write().unwrap().add_exclude_index_path(path) { Ok(_) => 0, Err(_) => 1, diff --git a/src-tauri/src/walk_exec.rs b/src-tauri/src/walk_exec.rs index 9f76f3a..a03e59f 100644 --- a/src-tauri/src/walk_exec.rs +++ b/src-tauri/src/walk_exec.rs @@ -9,6 +9,7 @@ use crate::{indexing, utils}; use crate::idx_store::IDX_STORE; use crate::kv_store::CONF_STORE; +use crate::user_setting::UserSetting; use crate::walk_metrics::{WalkMatrixView, WalkMetrics}; use jwalk::{DirEntry, WalkDir}; use log::info; @@ -34,15 +35,21 @@ pub unsafe fn get_walk_matrix() -> WalkMatrixView { .unwrap() .view(move || IDX_STORE.num_docs()) } - +use crate::user_setting::{UserSettingError, USER_SETTING}; pub fn run() { init_walk_matrix(); let home = utils::norm(&home_dir()); start_walk_home_matrix(); - info!("start walk home {}", home); - walk_home(&home); + let need = need_skip_home(&home); + + if need { + info!("skip walk home {}", home); + } else { + info!("start walk home {}", home); + walk_home(&home); + } end_walk_home_matrix(); @@ -54,6 +61,17 @@ pub fn run() { unix_walk_root(home); } +fn need_skip_home(home: &String) -> bool { + let guard = USER_SETTING.read().unwrap(); + let exclude_path = guard.exclude_index_path(); + for path in exclude_path { + if home.starts_with(path) { + return true; + } + } + return false; +} + fn end_walk_home_matrix() { unsafe { let mut walk_matrix0 = WALK_METRICS.clone().unwrap(); @@ -170,10 +188,16 @@ fn walk(path: &String, skip_path_opt: Option) { children.iter_mut().for_each(|dir_entry_result| { if let Ok(dir_entry) = dir_entry_result { let curr_path = utils::norm(dir_entry.path().to_str().unwrap_or("")); + + let guard = USER_SETTING.read().unwrap(); + let exclude_path = guard.exclude_index_path(); + if curr_path.eq(skip_path.as_str()) || curr_path.eq("/proc") + || exclude_path.iter().any(|x| x.starts_with(&curr_path)) || curr_path.eq(&format!("/System/Volumes/Data/Users/{}", home_name)) { + info!("skip path {}", curr_path); dir_entry.read_children_path = None; } } diff --git a/src/Tab.js b/src/Tab.js index 021ac8d..1e4cb78 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -2,10 +2,14 @@ import React, {useEffect, useState} from 'react'; import { ContextualMenu, DefaultButton, - Dropdown, hiddenContentStyle, + Dialog, + DialogFooter, + DialogType, + Dropdown, IconButton, - Label, mergeStyles, - MessageBar, MessageBarType, + Label, + MessageBar, + MessageBarType, Panel, Pivot, PivotItem, @@ -16,9 +20,8 @@ import {add_exclude_path, change_lang, get_exclude_paths, reindex, remove_exclud import {useBoolean, useId} from "@fluentui/react-hooks"; import {useTranslation} from "react-i18next"; import i18next from "i18next"; -import { Dialog, DialogType, DialogFooter, Toggle} from "@fluentui/react"; -const dialogStyles = { main: { maxWidth: 450 } }; +const dialogStyles = {main: {maxWidth: 450}}; const dragOptions = { moveMenuItemText: 'Move', closeMenuItemText: 'Close', @@ -36,8 +39,8 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { let [toastText, setToastText] = useState(''); let [excludePaths, setExcludePaths] = useState([]); - const [hideDialog, { toggle: toggleHideDialog }] = useBoolean(true); - const [isDraggable, { toggle: toggleIsDraggable }] = useBoolean(false); + const [hideDialog, {toggle: toggleHideDialog}] = useBoolean(true); + const [isDraggable, {toggle: toggleIsDraggable}] = useBoolean(false); const labelId = useId('dialogLabel'); const subTextId = useId('subTextLabel'); @@ -66,7 +69,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { dropdown: {width: 300}, }; - async function handleAddExcludePath(){ + async function handleAddExcludePath() { if (await add_exclude_path(excludePath) === 1) { toast(t("add_exclude_path_err")); @@ -75,7 +78,8 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { setExcludePaths(await get_exclude_paths()); } } - async function handleRemoveExcludePath(path){ + + async function handleRemoveExcludePath(path) { await remove_exclude_path(path) setExcludePaths(await get_exclude_paths()); } @@ -85,7 +89,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { reindex(); } - function handle_lang_change(_,item) { + function handle_lang_change(_, item) { let key = item.key; setSelectedKey(key); change_lang(key); @@ -116,8 +120,8 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { modalProps={modalProps} > - - + + { closeButtonAriaLabel="Close" > { - show? + show ? {toastText} - :"" + : "" }
{
- setExcludePath(e.target.value)} /> + setExcludePath(e.target.value)}/>
{ excludePaths.map(x =>
- handleRemoveExcludePath(x)}/> + handleRemoveExcludePath(x)}/>
) } diff --git a/src/index.css b/src/index.css index 0006a6a..c8fd19e 100644 --- a/src/index.css +++ b/src/index.css @@ -110,10 +110,12 @@ body { display: flex; } .setting-item .add button{ - margin: 0 0 20px 0; + margin: 0 0 10px 0; } .setting-item .added{ display: flex; + flex-wrap: wrap; + } .setting-item .added .added-item{ display: flex; diff --git a/src/index.js b/src/index.js index cb3bcdf..0f87402 100644 --- a/src/index.js +++ b/src/index.js @@ -39,8 +39,10 @@ let _ = i18n "path":"Path", "lang":"Language", "reindex":"Reindex", - "reindex-dialog":"Do you want to Reindex? It will take effect on next reboot.", + "reindex-dialog":"Do you want to Reindex? It will take effect on next reboot!", "remove":"Remove", + "confirm":"Confirm", + "cancel":"Cancel", "add_exclude_path_err":"Invalid path", } @@ -61,8 +63,10 @@ let _ = i18n "path":"路径", "lang":"语言", "reindex":"重索引", - "reindex-dialog":"您确认要重新索引吗?它将在下一次重启时生效。", + "reindex-dialog":"您确认要重新索引吗?它将在下一次重启时生效!", "remove":"删除", + "confirm":"确认", + "cancel":"取消", "add_exclude_path_err":"非法路径", } } From 2c60c4861da63bfc86cf3691d9d98ac7cff755a1 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 15:05:12 +0800 Subject: [PATCH 17/28] Upgrade --- src/Tab.js | 12 +++++++++++- src/index.js | 4 ++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/src/Tab.js b/src/Tab.js index 1e4cb78..90da2c1 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -1,4 +1,6 @@ import React, {useEffect, useState} from 'react'; +import {app} from "@tauri-apps/api"; + import { ContextualMenu, DefaultButton, @@ -37,6 +39,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { let [excludePath, setExcludePath] = useState(); let [show, setShow] = useState(false); let [toastText, setToastText] = useState(''); + let [version, setVersion] = useState(''); let [excludePaths, setExcludePaths] = useState([]); const [hideDialog, {toggle: toggleHideDialog}] = useBoolean(true); @@ -58,7 +61,9 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { } useEffect(async () => { - setExcludePaths(await get_exclude_paths()) + setExcludePaths(await get_exclude_paths()); + let version = await app.getVersion(); + setVersion(version); }, [excludePaths]) const options = [ {key: 'en', text: 'EN'}, @@ -146,6 +151,10 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { styles={dropdownStyles} />
+
+ + +
{
+
{ diff --git a/src/index.js b/src/index.js index 0f87402..bf15771 100644 --- a/src/index.js +++ b/src/index.js @@ -44,6 +44,8 @@ let _ = i18n "confirm":"Confirm", "cancel":"Cancel", "add_exclude_path_err":"Invalid path", + "upgrade":"Upgrade", + "version":"Version V" } }, @@ -68,6 +70,8 @@ let _ = i18n "confirm":"确认", "cancel":"取消", "add_exclude_path_err":"非法路径", + "upgrade":"升级", + "version":"版本 V" } } }, From 42ae4ea2b1da7d59ab4667aead3cd1f2ae5cf806 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 15:48:02 +0800 Subject: [PATCH 18/28] Theme --- src-tauri/src/ui.rs | 6 +-- src-tauri/src/user_setting.rs | 10 ++-- src/App.js | 4 +- src/Tab.js | 38 ++++++++++++-- src/Theme.js | 99 +++++++++++++++++++++++++++++++++++ src/index.js | 39 ++++---------- 6 files changed, 155 insertions(+), 41 deletions(-) create mode 100644 src/Theme.js diff --git a/src-tauri/src/ui.rs b/src-tauri/src/ui.rs index fc6bfa7..0c51917 100644 --- a/src-tauri/src/ui.rs +++ b/src-tauri/src/ui.rs @@ -24,13 +24,13 @@ fn walk_metrics() -> WalkMatrixView { } use crate::user_setting::{UserSettingError, USER_SETTING}; #[tauri::command] -fn change_theme(theme: String) { +fn change_theme(theme: u8) { USER_SETTING.write().unwrap().set_theme(theme); } #[tauri::command] -fn get_theme(theme: String) -> String { - USER_SETTING.read().unwrap().theme().to_string() +fn get_theme() -> u8 { + USER_SETTING.read().unwrap().theme() } #[tauri::command] diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs index c643067..41fc23d 100644 --- a/src-tauri/src/user_setting.rs +++ b/src-tauri/src/user_setting.rs @@ -40,7 +40,7 @@ impl Error for UserSettingError { #[derive(Debug, Serialize, Deserialize)] pub struct UserSetting { - theme: String, + theme: u8, lang: String, exclude_index_path: Vec, ext: HashMap, @@ -50,8 +50,8 @@ impl UserSetting { pub fn lang(&self) -> &str { &self.lang } - pub fn theme(&self) -> &String { - &self.theme + pub fn theme(&self) -> u8 { + self.theme } pub fn exclude_index_path(&self) -> &Vec { &self.exclude_index_path @@ -71,7 +71,7 @@ impl UserSetting { self.lang = lang; self.store(); } - pub fn set_theme(&mut self, theme: String) { + pub fn set_theme(&mut self, theme: u8) { self.theme = theme; self.store(); } @@ -129,7 +129,7 @@ impl Default for UserSetting { fn default() -> Self { UserSetting::load().unwrap_or_else(|_| { let setting = UserSetting { - theme: "light".to_string(), + theme: 1, lang: "en".to_string(), exclude_index_path: vec![], ext: Default::default(), diff --git a/src/App.js b/src/App.js index 240b6fe..ce368e1 100644 --- a/src/App.js +++ b/src/App.js @@ -21,7 +21,7 @@ const dialogContentProps = { }; -const App = () => { +const App = ({setTheme,theme}) => { const [items, setItems] = useState([]); const [kw, setKw] = useState(''); @@ -68,7 +68,7 @@ const App = () => { {/**/} - +
diff --git a/src/Tab.js b/src/Tab.js index 90da2c1..5d998e1 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -18,7 +18,15 @@ import { PrimaryButton, TextField } from "@fluentui/react"; -import {add_exclude_path, change_lang, get_exclude_paths, reindex, remove_exclude_path, search} from "./utils"; +import { + add_exclude_path, + change_lang, + change_theme, + get_exclude_paths, + reindex, + remove_exclude_path, + search, upgrade +} from "./utils"; import {useBoolean, useId} from "@fluentui/react-hooks"; import {useTranslation} from "react-i18next"; import i18next from "i18next"; @@ -32,7 +40,7 @@ const dragOptions = { }; -const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { +const Tab = ({setSelectedKey, selectedKey, kw, setItems,setTheme,theme}) => { const [isOpen, {setTrue: openPanel, setFalse: dismissPanel}] = useBoolean(false); const {t} = useTranslation(); @@ -70,6 +78,12 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { {key: 'zh-CN', text: '中文'}, ]; + const themes = [ + {key: 0, text: t("theme-default")}, + {key: 1, text: t("theme-light-purple")}, + {key: 2, text: t("theme-light-blue")}, + ]; + const dropdownStyles = { dropdown: {width: 300}, }; @@ -94,6 +108,15 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { reindex(); } + function handle_theme_change(_, item) { + let key = item.key; + setTheme(key); + change_theme(key); + } + + function handle_upgrade() { + upgrade() + } function handle_lang_change(_, item) { let key = item.key; setSelectedKey(key); @@ -151,9 +174,18 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems}) => { styles={dropdownStyles} />
+
+ +
- +
diff --git a/src/Theme.js b/src/Theme.js new file mode 100644 index 0000000..2f864c7 --- /dev/null +++ b/src/Theme.js @@ -0,0 +1,99 @@ +import React, {useEffect, useState} from 'react'; +import {createTheme, ThemeProvider} from "@fluentui/react"; +import App from "./App"; +import {get_theme} from "./utils"; + + +const default_theme = createTheme({ + palette: { + themePrimary: '#1a2a3a', + themeLighterAlt: '#d8e0e7', + themeLighter: '#b7c5d2', + themeLight: '#99abbc', + themeTertiary: '#7d92a7', + themeSecondary: '#647b91', + themeDarkAlt: '#4e657b', + themeDark: '#3a5066', + themeDarker: '#293d50', + neutralLighterAlt: '#faf9f8', + neutralLighter: '#f3f2f1', + neutralLight: '#edebe9', + neutralQuaternaryAlt: '#e1dfdd', + neutralQuaternary: '#d0d0d0', + neutralTertiaryAlt: '#c8c6c4', + neutralTertiary: '#a19f9d', + neutralSecondary: '#605e5c', + neutralPrimaryAlt: '#3b3a39', + neutralPrimary: '#323130', + neutralDark: '#201f1e', + black: '#000000', + white: '#ffffff', + }}); +const light_purple = createTheme({ + palette: { + themePrimary: '#562992', + themeLighterAlt: '#f7f3fb', + themeLighter: '#ded2ed', + themeLight: '#c3aede', + themeTertiary: '#8f6bbd', + themeSecondary: '#663a9f', + themeDarkAlt: '#4d2583', + themeDark: '#411f6e', + themeDarker: '#301751', + neutralLighterAlt: '#f2f1f3', + neutralLighter: '#eeedef', + neutralLight: '#e4e3e5', + neutralQuaternaryAlt: '#d5d4d6', + neutralQuaternary: '#cbcacc', + neutralTertiaryAlt: '#c3c2c4', + neutralTertiary: '#a19f9d', + neutralSecondary: '#605e5c', + neutralPrimaryAlt: '#3b3a39', + neutralPrimary: '#323130', + neutralDark: '#201f1e', + black: '#000000', + white: '#f9f8fa', + }}); +const light_blue = createTheme({ + palette: { + themePrimary: '#3566b9', + themeLighterAlt: '#f5f8fc', + themeLighter: '#d8e2f4', + themeLight: '#b8cbea', + themeTertiary: '#7b9cd6', + themeSecondary: '#4975c2', + themeDarkAlt: '#315ca8', + themeDark: '#294e8d', + themeDarker: '#1e3968', + neutralLighterAlt: '#eef1f3', + neutralLighter: '#eaedef', + neutralLight: '#e1e3e5', + neutralQuaternaryAlt: '#d1d4d6', + neutralQuaternary: '#c8cacc', + neutralTertiaryAlt: '#c0c2c4', + neutralTertiary: '#a19f9d', + neutralSecondary: '#605e5c', + neutralPrimaryAlt: '#3b3a39', + neutralPrimary: '#323130', + neutralDark: '#201f1e', + black: '#000000', + white: '#f7f9fb', + }}); +const themes = [default_theme, light_purple,light_blue]; +const Theme = () => { + let [theme,setTheme] = useState(0); + useEffect(async ()=>{ + let newVar = await get_theme(); + console.log(newVar) + setTheme(newVar) + },[]) + return ( +
+ + + +
+ ); +}; + +export default Theme; \ No newline at end of file diff --git a/src/index.js b/src/index.js index bf15771..d95ca26 100644 --- a/src/index.js +++ b/src/index.js @@ -7,6 +7,7 @@ import i18n from "i18next"; import {initReactI18next} from "react-i18next"; import {change_lang, get_lang} from "./utils"; import i18next from "i18next"; +import Theme from "./Theme"; initializeIcons() @@ -38,6 +39,10 @@ let _ = i18n "size":"Size", "path":"Path", "lang":"Language", + "theme":"Theme", + "theme-default":"Default", + "theme-light-purple":"Light Purple", + "theme-light-blue":"Light Blue", "reindex":"Reindex", "reindex-dialog":"Do you want to Reindex? It will take effect on next reboot!", "remove":"Remove", @@ -64,6 +69,10 @@ let _ = i18n "size":"大小", "path":"路径", "lang":"语言", + "theme":"主题", + "theme-default":"默认", + "theme-light-purple":"浅紫色", + "theme-light-blue":"浅蓝色", "reindex":"重索引", "reindex-dialog":"您确认要重新索引吗?它将在下一次重启时生效!", "remove":"删除", @@ -86,35 +95,9 @@ let _ = i18n -const myTheme = createTheme({ - palette: { - themePrimary: '#1a2a3a', - themeLighterAlt: '#d8e0e7', - themeLighter: '#b7c5d2', - themeLight: '#99abbc', - themeTertiary: '#7d92a7', - themeSecondary: '#647b91', - themeDarkAlt: '#4e657b', - themeDark: '#3a5066', - themeDarker: '#293d50', - neutralLighterAlt: '#faf9f8', - neutralLighter: '#f3f2f1', - neutralLight: '#edebe9', - neutralQuaternaryAlt: '#e1dfdd', - neutralQuaternary: '#d0d0d0', - neutralTertiaryAlt: '#c8c6c4', - neutralTertiary: '#a19f9d', - neutralSecondary: '#605e5c', - neutralPrimaryAlt: '#3b3a39', - neutralPrimary: '#323130', - neutralDark: '#201f1e', - black: '#000000', - white: '#ffffff', - }}); + ReactDOM.render(<> - - - + , document.getElementById('root')); From 99789070a32abc21b7d959929a03eb98ad64a686 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 18:01:00 +0800 Subject: [PATCH 19/28] Remove useless import --- src-tauri/src/file_doc.rs | 2 - src-tauri/src/fs_watcher.rs | 14 +++--- src-tauri/src/idx_store.rs | 14 +++--- src-tauri/src/indexing.rs | 14 ++---- src-tauri/src/main.rs | 6 --- src-tauri/src/ui.rs | 19 ++++---- src-tauri/src/user_setting.rs | 6 +-- src-tauri/src/utils.rs | 86 ++++++++++++++++++----------------- src-tauri/src/walk_exec.rs | 80 ++++++++++++++++---------------- src-tauri/src/walk_metrics.rs | 5 +- src-tauri/src/watch_exec.rs | 5 +- 11 files changed, 114 insertions(+), 137 deletions(-) diff --git a/src-tauri/src/file_doc.rs b/src-tauri/src/file_doc.rs index 4c4796d..1d6d841 100644 --- a/src-tauri/src/file_doc.rs +++ b/src-tauri/src/file_doc.rs @@ -1,7 +1,5 @@ use crate::utils; use jwalk::DirEntry; -use std::fs::Metadata; -use std::path::PathBuf; #[derive(Debug)] pub struct FileDoc { diff --git a/src-tauri/src/fs_watcher.rs b/src-tauri/src/fs_watcher.rs index 66c1779..90356b0 100644 --- a/src-tauri/src/fs_watcher.rs +++ b/src-tauri/src/fs_watcher.rs @@ -1,6 +1,5 @@ extern crate notify; -use crate::idx_store::IdxStore; use crate::idx_store::IDX_STORE; use crate::utils; use crate::utils::subs; @@ -13,9 +12,8 @@ use std::os::unix::fs::MetadataExt; #[cfg(target_os = "windows")] use std::os::windows::fs::MetadataExt; use std::path; -use std::path::PathBuf; + use std::sync::mpsc::channel; -use std::sync::Arc; pub struct FsWatcher { path: String, @@ -108,7 +106,9 @@ impl FsWatcher { #[cfg(test)] mod tests { use super::*; + use crate::idx_store::IdxStore; use notify::watcher; + use std::sync::Arc; use std::time::Duration; #[test] @@ -162,8 +162,8 @@ mod tests { match rx.recv() { Ok(RawEvent { path: Some(path), - op: Ok(op), - cookie, + op: Ok(_op), + cookie: _, }) => { let x = path.to_str().unwrap(); if x.contains("orangecachedata") { @@ -181,10 +181,10 @@ mod tests { #[test] fn t4() { - let conf_path = format!("{}{}", utils::data_dir(), "/orangecachedata/conf"); + let _conf_path = format!("{}{}", utils::data_dir(), "/orangecachedata/conf"); let idx_path = format!("{}{}", utils::data_dir(), "/orangecachedata/idx"); - let idx_store = Arc::new(IdxStore::new(&idx_path)); + let _idx_store = Arc::new(IdxStore::new(&idx_path)); let mut watcher = FsWatcher::new("/".to_string()); watcher.start(); } diff --git a/src-tauri/src/idx_store.rs b/src-tauri/src/idx_store.rs index 32933e4..de155af 100644 --- a/src-tauri/src/idx_store.rs +++ b/src-tauri/src/idx_store.rs @@ -12,11 +12,10 @@ use jieba_rs::Jieba; use pinyin::ToPinyin; use tantivy::collector::TopDocs; use tantivy::merge_policy::NoMergePolicy; -use tantivy::query::{BooleanQuery, FuzzyTermQuery, Occur, Query, QueryParser, TermQuery}; +use tantivy::query::{BooleanQuery, FuzzyTermQuery, Occur, QueryParser, TermQuery}; use tantivy::schema::*; use tantivy::{doc, Index, IndexReader, IndexWriter, ReloadPolicy}; -use crate::file_doc::FileDoc; use crate::file_view::FileView; use crate::utils; use crate::utils::is_ascii_alphanumeric; @@ -49,7 +48,7 @@ impl IdxStore { } let space = " "; let hans = hans.replace("-", space).replace("_", space); - let mut words = self.tokenizer.cut(&hans, false); + let words = self.tokenizer.cut(&hans, false); let mut token_text: HashSet = vec![].into_iter().collect(); @@ -72,7 +71,7 @@ impl IdxStore { } let space = " "; let hans = hans.replace("-", space).replace("_", space); - let mut words = self.tokenizer.cut(&hans, false); + let words = self.tokenizer.cut(&hans, false); let mut token_text: HashSet = vec![].into_iter().collect(); @@ -117,7 +116,7 @@ impl IdxStore { } pub fn search(&self, kw: String, limit: usize) -> Vec { - let mut paths = self.search_paths(self.search_tokenize(kw.clone()), limit); + let paths = self.search_paths(self.search_tokenize(kw.clone()), limit); // if paths.is_empty() { // paths = self.suggest_path(kw, limit); // } @@ -133,7 +132,6 @@ impl IdxStore { limit: usize, is_dir_opt: Option, ext_opt: Option, - parent_dirs_opt: Option, ) -> Vec { let searcher = self.reader.searcher(); @@ -366,7 +364,7 @@ impl IdxStore { .unwrap(); let mut query_parser = QueryParser::for_index(&index, vec![name_field]); - let mut ext_query_parser = QueryParser::for_index(&index, vec![ext_field]); + let ext_query_parser = QueryParser::for_index(&index, vec![ext_field]); // let mut parent_dirs_query_parser = QueryParser::for_index(&index, vec![parent_dirs_field]); query_parser.set_field_boost(name_field, 4.0f32); let mut jieba = Jieba::new(); @@ -435,7 +433,7 @@ mod tests { fn t1() { let path = "./tmp"; let _ = fs::remove_dir_all(path); - let mut store = IdxStore::new(path); + let store = IdxStore::new(path); let vec1 = vec![ "jack rose", diff --git a/src-tauri/src/indexing.rs b/src-tauri/src/indexing.rs index ce9b562..bf48d4b 100644 --- a/src-tauri/src/indexing.rs +++ b/src-tauri/src/indexing.rs @@ -1,26 +1,20 @@ use crate::idx_store::IDX_STORE; use crate::kv_store::CONF_STORE; use crate::{utils, walk_exec, watch_exec}; -use log::{error, info}; +use log::info; #[cfg(windows)] use std::sync::mpsc; #[cfg(windows)] use std::sync::mpsc::Sender; -use std::sync::Arc; + #[cfg(windows)] use std::time::Duration; use std::time::SystemTime; use std::time::UNIX_EPOCH; -use crate::kv_store::KvStore; - -use crate::idx_store::IdxStore; - #[cfg(windows)] use crate::usn_journal_watcher::Watcher; -const STORE_PATH: &'static str = "orangecachedata"; - #[cfg(windows)] const RECYCLE_PATH: &'static str = "$RECYCLE.BIN"; const VERSION: &'static str = "0.4.0"; @@ -65,9 +59,7 @@ fn win_watch() { } pub fn reindex() { - unsafe { - CONF_STORE.put_str("reindex".to_string(), "1".to_string()); - } + CONF_STORE.put_str("reindex".to_string(), "1".to_string()); } fn need_reindex() -> bool { diff --git a/src-tauri/src/main.rs b/src-tauri/src/main.rs index 7417fd0..25139f7 100644 --- a/src-tauri/src/main.rs +++ b/src-tauri/src/main.rs @@ -3,12 +3,6 @@ windows_subsystem = "windows" )] -use crate::idx_store::IdxStore; -use crate::kv_store::KvStore; -use crate::user_setting::UserSetting; -use std::sync::{Arc, Mutex, RwLock}; -use std::time::Duration; - mod file_doc; mod file_view; mod fs_watcher; diff --git a/src-tauri/src/ui.rs b/src-tauri/src/ui.rs index 0c51917..fc0aa75 100644 --- a/src-tauri/src/ui.rs +++ b/src-tauri/src/ui.rs @@ -1,11 +1,10 @@ use crate::file_view::FileView; -use crate::idx_store::IdxStore; + use crate::idx_store::IDX_STORE; -use crate::kv_store::KvStore; + use crate::walk_metrics::WalkMatrixView; use crate::{indexing, utils, walk_exec}; -use std::sync::{Arc, RwLock}; -use std::time::Duration; + use tauri::{App, Manager}; use tauri::{CustomMenuItem, SystemTrayMenu}; use tauri::{SystemTray, SystemTrayEvent}; @@ -22,7 +21,7 @@ struct Payload { fn walk_metrics() -> WalkMatrixView { unsafe { walk_exec::get_walk_matrix() } } -use crate::user_setting::{UserSettingError, USER_SETTING}; +use crate::user_setting::USER_SETTING; #[tauri::command] fn change_theme(theme: u8) { USER_SETTING.write().unwrap().set_theme(theme); @@ -86,7 +85,7 @@ fn upgrade() { } #[tauri::command] async fn suggest(kw: String) -> Vec { - unsafe { IDX_STORE.suggest(kw, 20) } + IDX_STORE.suggest(kw, 20) } #[tauri::command] @@ -95,12 +94,10 @@ async fn search( is_dir_opt: Option, ext_opt: Option, ) -> Vec { - unsafe { - if kw.eq("") { - kw = "*".to_string(); - } - IDX_STORE.search_with_filter(kw, 100, is_dir_opt, ext_opt, None) + if kw.eq("") { + kw = "*".to_string(); } + IDX_STORE.search_with_filter(kw, 100, is_dir_opt, ext_opt) } #[tauri::command] diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs index 41fc23d..5549252 100644 --- a/src-tauri/src/user_setting.rs +++ b/src-tauri/src/user_setting.rs @@ -1,14 +1,10 @@ -use core::fmt; use std::collections::HashMap; use std::error::Error; use std::fmt::{Display, Formatter}; use std::sync::RwLock; -use log::set_logger_racy; use serde::{Deserialize, Serialize}; -use serde_json::{Result, Value}; -use crate::kv_store::KvStore; use crate::utils; lazy_static! { @@ -146,7 +142,7 @@ mod tests { #[test] fn t1() { - let mut setting = UserSetting::default(); + let setting = UserSetting::default(); // let string = "zh".into(); // setting.set_lang(string); // setting.set_theme("dark".to_string()); diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 6ad3f91..02024cd 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -1,11 +1,10 @@ use directories::ProjectDirs; #[cfg(windows)] use std::ffi::CString; -use std::path::{Path, PathBuf}; extern crate chrono; use chrono::Local; -use convert_case::{Case, Casing}; + use log::LevelFilter; use log4rs::append::console::ConsoleAppender; use log4rs::append::file::FileAppender; @@ -189,49 +188,54 @@ pub unsafe fn get_win32_ready_drive_nos() -> Vec { pub unsafe fn build_volume_path(str: &str) -> String { str::replace("\\\\?\\$:", "$", str) } +#[cfg(test)] +mod tests { + use super::*; -#[cfg(windows)] -#[test] -fn t1() { - let str = "c"; - let string = unsafe { build_volume_path(str) }; - println!("{}", string); -} -#[test] -fn t2() { - println!("{}", data_dir()); -} + use convert_case::{Case, Casing}; -#[test] -fn t3() { - let chines = is_ascii_alphanumeric("j dsadal"); - println!("{:?}", chines); -} + #[cfg(windows)] + #[test] + fn t1() { + let str = "c"; + let string = unsafe { build_volume_path(str) }; + println!("{}", string); + } + #[test] + fn t2() { + println!("{}", data_dir()); + } -#[test] -fn t4() { - open_file_path_in_terminal("/home/jeff/CLionProjects/orange") - // use std::process::Command; - // Command::new("cmd") - // .args(&["/c", "start", "cmd"]) - // .spawn() - // .unwrap(); -} + #[test] + fn t3() { + let chines = is_ascii_alphanumeric("j dsadal"); + println!("{:?}", chines); + } -#[test] -fn t5() { - let ext = file_ext("java"); - println!("{}", ext); -} + #[test] + fn t4() { + open_file_path_in_terminal("/home/jeff/CLionProjects/orange") + // use std::process::Command; + // Command::new("cmd") + // .args(&["/c", "start", "cmd"]) + // .spawn() + // .unwrap(); + } -#[test] -fn t6() { - let string = "FilterFieldNamesProvidingStoredFieldsVisitor.java".to_case(Case::Title); - println!("{}", string); -} -use webbrowser; + #[test] + fn t5() { + let ext = file_ext("java"); + println!("{}", ext); + } + + #[test] + fn t6() { + let string = "FilterFieldNamesProvidingStoredFieldsVisitor.java".to_case(Case::Title); + println!("{}", string); + } -#[test] -fn t7() { - let result = webbrowser::open("/~https://github.com/naaive/orange/releases"); + #[test] + fn t7() { + let _result = webbrowser::open("/~https://github.com/naaive/orange/releases"); + } } diff --git a/src-tauri/src/walk_exec.rs b/src-tauri/src/walk_exec.rs index a03e59f..a18b89c 100644 --- a/src-tauri/src/walk_exec.rs +++ b/src-tauri/src/walk_exec.rs @@ -1,21 +1,16 @@ -use crate::file_doc::FileDoc; -use crate::idx_store::IdxStore; -use crate::kv_store::KvStore; -use std::ops::Deref; - +use crate::utils; #[cfg(windows)] use crate::utils::get_win32_ready_drives; -use crate::{indexing, utils}; use crate::idx_store::IDX_STORE; use crate::kv_store::CONF_STORE; -use crate::user_setting::UserSetting; + use crate::walk_metrics::{WalkMatrixView, WalkMetrics}; use jwalk::{DirEntry, WalkDir}; use log::info; -use std::sync::{Arc, Mutex, RwLock}; -use std::thread; -use std::time::{Duration, SystemTime, UNIX_EPOCH}; +use std::sync::{Arc, Mutex}; + +use std::time::SystemTime; static mut WALK_METRICS: Option>> = None; @@ -35,7 +30,8 @@ pub unsafe fn get_walk_matrix() -> WalkMatrixView { .unwrap() .view(move || IDX_STORE.num_docs()) } -use crate::user_setting::{UserSettingError, USER_SETTING}; + +use crate::user_setting::USER_SETTING; pub fn run() { init_walk_matrix(); let home = utils::norm(&home_dir()); @@ -74,14 +70,14 @@ fn need_skip_home(home: &String) -> bool { fn end_walk_home_matrix() { unsafe { - let mut walk_matrix0 = WALK_METRICS.clone().unwrap(); + let walk_matrix0 = WALK_METRICS.clone().unwrap(); walk_matrix0.lock().unwrap().end_home(); } } fn start_walk_home_matrix() { unsafe { - let mut walk_matrix0 = WALK_METRICS.clone().unwrap(); + let walk_matrix0 = WALK_METRICS.clone().unwrap(); walk_matrix0.lock().unwrap().start_home(); } } @@ -227,36 +223,42 @@ fn walk(path: &String, skip_path_opt: Option) { cnt ); } -use crate::utils::init_log; -#[test] -fn t1() { - let dir = utils::data_dir(); +#[cfg(test)] +mod tests { + use super::*; + use crate::kv_store::KvStore; + use std::time::UNIX_EPOCH; - let string = format!("{}/orangecachedata", dir); - println!("{}", string); - let dir_all = std::fs::remove_dir_all(string); - init_log(); + #[test] + fn t1() { + let dir = utils::data_dir(); - let dir = utils::data_dir(); - let conf_path = format!("{}{}", dir, "/orangecachedata/conf"); - let idx_path = format!("{}{}", dir, "/orangecachedata/idx"); + let string = format!("{}/orangecachedata", dir); + println!("{}", string); + let _dir_all = std::fs::remove_dir_all(string); + utils::init_log(); - run(); - IDX_STORE.commit(); -} + let dir = utils::data_dir(); + let _conf_path = format!("{}{}", dir, "/orangecachedata/conf"); + let _idx_path = format!("{}{}", dir, "/orangecachedata/idx"); -#[test] -fn disable_walk() { - init_log(); + run(); + IDX_STORE.commit(); + } - let dir = utils::data_dir(); - let conf_path = format!("{}{}", dir, "/orangecachedata/conf"); - let conf_store = Arc::new(KvStore::new(&conf_path)); - let curr_ts = SystemTime::now() - .duration_since(UNIX_EPOCH) - .unwrap() - .as_secs(); - conf_store.put_str("version".to_string(), "0.3.0".to_string()); - conf_store.put_str("last_index_ts".to_string(), curr_ts.to_string()); + #[test] + fn disable_walk() { + utils::init_log(); + + let dir = utils::data_dir(); + let conf_path = format!("{}{}", dir, "/orangecachedata/conf"); + let conf_store = Arc::new(KvStore::new(&conf_path)); + let curr_ts = SystemTime::now() + .duration_since(UNIX_EPOCH) + .unwrap() + .as_secs(); + conf_store.put_str("version".to_string(), "0.3.0".to_string()); + conf_store.put_str("last_index_ts".to_string(), curr_ts.to_string()); + } } diff --git a/src-tauri/src/walk_metrics.rs b/src-tauri/src/walk_metrics.rs index 1f04f0b..77ec3cd 100644 --- a/src-tauri/src/walk_metrics.rs +++ b/src-tauri/src/walk_metrics.rs @@ -1,8 +1,7 @@ -use crate::IdxStore; use serde::{Deserialize, Serialize}; -use std::ops::{Deref, DerefMut}; + use std::sync::atomic::{AtomicBool, Ordering}; -use std::sync::{Arc, Mutex, RwLock}; +use std::sync::{Arc, RwLock}; use std::thread; use std::time::Duration; diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index f864735..ec1a72b 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -1,8 +1,5 @@ -use std::sync::Arc; - use crate::fs_watcher::FsWatcher; -use crate::idx_store::IdxStore; -use crate::utils; + #[cfg(windows)] use crate::utils::get_win32_ready_drives; From 5cea4836e651fcaa148b51eda3db2f9a1ae2ee40 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 18:08:35 +0800 Subject: [PATCH 20/28] Fix on linux --- src-tauri/src/watch_exec.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index ec1a72b..debb942 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -26,7 +26,7 @@ fn macos_run() { fn linux_run(idx_store: Arc) { let sub_root = utils::subs("/"); for sub in sub_root { - let mut watcher = FsWatcher::new(idx_store.clone(), sub); + let mut watcher = FsWatcher::new(sub); std::thread::spawn(move || { watcher.start(); }); From b6d21cef205b2740e1d4e85c0ab91d5d7c463593 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 19:31:09 +0800 Subject: [PATCH 21/28] Fix on win --- src-tauri/src/indexing.rs | 5 +++++ src-tauri/src/watch_exec.rs | 2 +- 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/indexing.rs b/src-tauri/src/indexing.rs index bf48d4b..0e83d05 100644 --- a/src-tauri/src/indexing.rs +++ b/src-tauri/src/indexing.rs @@ -2,6 +2,9 @@ use crate::idx_store::IDX_STORE; use crate::kv_store::CONF_STORE; use crate::{utils, walk_exec, watch_exec}; use log::info; + +#[cfg(windows)] +use log::error; #[cfg(windows)] use std::sync::mpsc; #[cfg(windows)] @@ -15,6 +18,8 @@ use std::time::UNIX_EPOCH; #[cfg(windows)] use crate::usn_journal_watcher::Watcher; +#[cfg(windows)] +const STORE_PATH: &'static str = "orangecachedata"; #[cfg(windows)] const RECYCLE_PATH: &'static str = "$RECYCLE.BIN"; const VERSION: &'static str = "0.4.0"; diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index debb942..d6bb908 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -23,7 +23,7 @@ fn macos_run() { } #[cfg(target_os = "linux")] -fn linux_run(idx_store: Arc) { +fn linux_run() { let sub_root = utils::subs("/"); for sub in sub_root { let mut watcher = FsWatcher::new(sub); From a8cdab51a94d592058c3cac5e484db512ee6cc7e Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 20:14:56 +0800 Subject: [PATCH 22/28] Fix exclude path on win --- src-tauri/Cargo.toml | 4 ++-- src-tauri/src/fs_watcher.rs | 16 ++++++++-------- src-tauri/src/user_setting.rs | 11 ++++++++--- src-tauri/src/utils.rs | 16 ++++++++++++++++ src-tauri/src/walk_exec.rs | 2 +- src/App.js | 7 ++++--- src/Theme.js | 4 +--- src/index.js | 3 +-- 8 files changed, 41 insertions(+), 22 deletions(-) diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index 52fdade..7ab05f2 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -54,5 +54,5 @@ default = [ "custom-protocol" ] # DO NOT remove this custom-protocol = [ "tauri/custom-protocol" ] -[profile.test] -opt-level=3 +#[profile.test] +#opt-level=3 diff --git a/src-tauri/src/fs_watcher.rs b/src-tauri/src/fs_watcher.rs index 90356b0..968fe26 100644 --- a/src-tauri/src/fs_watcher.rs +++ b/src-tauri/src/fs_watcher.rs @@ -177,14 +177,14 @@ mod tests { } } } -} -#[test] -fn t4() { - let _conf_path = format!("{}{}", utils::data_dir(), "/orangecachedata/conf"); - let idx_path = format!("{}{}", utils::data_dir(), "/orangecachedata/idx"); + #[test] + fn t4() { + let _conf_path = format!("{}{}", utils::data_dir(), "/orangecachedata/conf"); + let idx_path = format!("{}{}", utils::data_dir(), "/orangecachedata/idx"); - let _idx_store = Arc::new(IdxStore::new(&idx_path)); - let mut watcher = FsWatcher::new("/".to_string()); - watcher.start(); + let _idx_store = Arc::new(IdxStore::new(&idx_path)); + let mut watcher = FsWatcher::new("/".to_string()); + watcher.start(); + } } diff --git a/src-tauri/src/user_setting.rs b/src-tauri/src/user_setting.rs index 5549252..7c8c20d 100644 --- a/src-tauri/src/user_setting.rs +++ b/src-tauri/src/user_setting.rs @@ -78,7 +78,12 @@ impl UserSetting { if std::fs::metadata(&path).is_err() { return Err(UserSettingError::new(path.to_string())); } - self.exclude_index_path.push(path); + if cfg!(target_os = "windows") { + let path = utils::win_norm4exclude_path(utils::norm(&path)); + self.exclude_index_path.push(path); + } else { + self.exclude_index_path.push(path); + } self.store(); Ok(()) } @@ -125,8 +130,8 @@ impl Default for UserSetting { fn default() -> Self { UserSetting::load().unwrap_or_else(|_| { let setting = UserSetting { - theme: 1, - lang: "en".to_string(), + theme: 0, + lang: "default".to_string(), exclude_index_path: vec![], ext: Default::default(), }; diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 02024cd..5b5d442 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -183,6 +183,13 @@ pub unsafe fn get_win32_ready_drive_nos() -> Vec { res.sort(); res } +#[cfg(windows)] +pub fn win_norm4exclude_path(x: String) -> String { + let (x1, x2) = x.split_at(1); + let mut up = x1.to_uppercase(); + up.push_str(x2); + up.replace("//", "/") +} #[cfg(windows)] pub unsafe fn build_volume_path(str: &str) -> String { @@ -238,4 +245,13 @@ mod tests { fn t7() { let _result = webbrowser::open("/~https://github.com/naaive/orange/releases"); } + + #[test] + fn t8() { + let x = "c://".to_string(); + + let string = win_norm4exclude_path(x); + + println!("{}", string); + } } diff --git a/src-tauri/src/walk_exec.rs b/src-tauri/src/walk_exec.rs index a18b89c..922a27c 100644 --- a/src-tauri/src/walk_exec.rs +++ b/src-tauri/src/walk_exec.rs @@ -190,7 +190,7 @@ fn walk(path: &String, skip_path_opt: Option) { if curr_path.eq(skip_path.as_str()) || curr_path.eq("/proc") - || exclude_path.iter().any(|x| x.starts_with(&curr_path)) + || exclude_path.iter().any(|x| curr_path.starts_with(x)) || curr_path.eq(&format!("/System/Volumes/Data/Users/{}", home_name)) { info!("skip path {}", curr_path); diff --git a/src/App.js b/src/App.js index ce368e1..e709cc7 100644 --- a/src/App.js +++ b/src/App.js @@ -34,12 +34,13 @@ const App = ({setTheme,theme}) => { if (!init) { get_lang().then(lang => { - if (lang) { - let _ = i18next.changeLanguage(lang, (err, t) => { + if (lang==="default") { + let localeLang= navigator.language || navigator.userLanguage; + let _ = i18next.changeLanguage(localeLang, (err, t) => { if (err) return console.log('something went wrong loading', err); t('key'); }); - setSelectedKey(lang) + setSelectedKey(localeLang) } else { let en = "en"; setSelectedKey(en); diff --git a/src/Theme.js b/src/Theme.js index 2f864c7..8604fff 100644 --- a/src/Theme.js +++ b/src/Theme.js @@ -83,9 +83,7 @@ const themes = [default_theme, light_purple,light_blue]; const Theme = () => { let [theme,setTheme] = useState(0); useEffect(async ()=>{ - let newVar = await get_theme(); - console.log(newVar) - setTheme(newVar) + setTheme(await get_theme()) },[]) return (
diff --git a/src/index.js b/src/index.js index d95ca26..8e3a34d 100644 --- a/src/index.js +++ b/src/index.js @@ -19,7 +19,6 @@ mergeStyles({ height: '100vh', }, }); -let lang= navigator.language || navigator.userLanguage; let _ = i18n .use(initReactI18next) .init({ @@ -84,7 +83,7 @@ let _ = i18n } } }, - lng: lang, + lng: "en", fallbackLng: "en", interpolation: { escapeValue: false From a0fd713724c151224e780870f34f4433857cf97f Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 20:37:27 +0800 Subject: [PATCH 23/28] STATUS_ACCESS_VIOLATION fix --- src/App.js | 14 +++++++++----- src/Tab.js | 8 ++++---- 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/src/App.js b/src/App.js index e709cc7..d184f9c 100644 --- a/src/App.js +++ b/src/App.js @@ -28,9 +28,11 @@ const App = ({setTheme,theme}) => { const [selectedKey, setSelectedKey] = useState(0); const [hideDialog, {toggle: toggleHideDialog}] = useBoolean(true); let [init, setInit] = useState(false); + let [lang, setLang] = useState(false); const { t } = useTranslation(); useEffect(() => { + if (!init) { get_lang().then(lang => { @@ -40,11 +42,13 @@ const App = ({setTheme,theme}) => { if (err) return console.log('something went wrong loading', err); t('key'); }); - setSelectedKey(localeLang) + setLang(localeLang) } else { - let en = "en"; - setSelectedKey(en); - change_lang(en) + let _ = i18next.changeLanguage(lang, (err, t) => { + if (err) return console.log('something went wrong loading', err); + t('key'); + }); + setLang(lang); } }) @@ -69,7 +73,7 @@ const App = ({setTheme,theme}) => { {/**/} - +
diff --git a/src/Tab.js b/src/Tab.js index 5d998e1..9cd31a8 100644 --- a/src/Tab.js +++ b/src/Tab.js @@ -40,7 +40,7 @@ const dragOptions = { }; -const Tab = ({setSelectedKey, selectedKey, kw, setItems,setTheme,theme}) => { +const Tab = ({setSelectedKey, selectedKey, kw, setItems,setTheme,theme,lang,setLang}) => { const [isOpen, {setTrue: openPanel, setFalse: dismissPanel}] = useBoolean(false); const {t} = useTranslation(); @@ -72,7 +72,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems,setTheme,theme}) => { setExcludePaths(await get_exclude_paths()); let version = await app.getVersion(); setVersion(version); - }, [excludePaths]) + }, []) const options = [ {key: 'en', text: 'EN'}, {key: 'zh-CN', text: '中文'}, @@ -119,7 +119,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems,setTheme,theme}) => { } function handle_lang_change(_, item) { let key = item.key; - setSelectedKey(key); + setLang(key); change_lang(key); i18next.changeLanguage(key, (err, t) => { if (err) return console.log('something went wrong loading', err); @@ -169,7 +169,7 @@ const Tab = ({setSelectedKey, selectedKey, kw, setItems,setTheme,theme}) => { From bc722e8777eaa9a30830a3a02141440897bc01c3 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 20:50:07 +0800 Subject: [PATCH 24/28] Fix win watcher --- src-tauri/src/indexing.rs | 11 ++++++++++- src-tauri/src/watch_exec.rs | 6 ++++-- 2 files changed, 14 insertions(+), 3 deletions(-) diff --git a/src-tauri/src/indexing.rs b/src-tauri/src/indexing.rs index 0e83d05..7b37e1c 100644 --- a/src-tauri/src/indexing.rs +++ b/src-tauri/src/indexing.rs @@ -45,9 +45,18 @@ fn do_run() { IDX_STORE.disable_full_indexing(); info!("start fs watch"); + #[cfg(windows)] - win_watch(); + if cfg!(target_os = "windows") { + if reindex { + info!("use watcher due to reindex"); + watch_exec::run(); + }else { + info!("try use usn"); + win_watch(); + } + } #[cfg(unix)] watch_exec::run(); } diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index d6bb908..bb38a05 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -37,7 +37,9 @@ fn linux_run() { fn win_run() { let drives = unsafe { get_win32_ready_drives() }; for driv in drives { - let mut watcher = FsWatcher::new(driv); - watcher.start(); + std::thread::spawn(move || { + let mut watcher = FsWatcher::new(driv); + watcher.start(); + }); } } From c26507ced245ce334b7fb98cfe8bf6f80933c1bf Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 20:55:21 +0800 Subject: [PATCH 25/28] Fix --- src-tauri/src/utils.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src-tauri/src/utils.rs b/src-tauri/src/utils.rs index 5b5d442..b3d1e19 100644 --- a/src-tauri/src/utils.rs +++ b/src-tauri/src/utils.rs @@ -183,7 +183,6 @@ pub unsafe fn get_win32_ready_drive_nos() -> Vec { res.sort(); res } -#[cfg(windows)] pub fn win_norm4exclude_path(x: String) -> String { let (x1, x2) = x.split_at(1); let mut up = x1.to_uppercase(); From 9203933e5943756e936a5647ac85c1d9778835d4 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 20:56:49 +0800 Subject: [PATCH 26/28] Fix --- src-tauri/src/watch_exec.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index bb38a05..2eeb0b4 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -1,4 +1,6 @@ use crate::fs_watcher::FsWatcher; +#[cfg(target_os = "linux")] +use crate::utils::subs; #[cfg(windows)] use crate::utils::get_win32_ready_drives; From f190d273cb8c09f6527ab43cd371b67c580af8ff Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 21:18:34 +0800 Subject: [PATCH 27/28] Fix exclude path css --- src-tauri/src/watch_exec.rs | 2 +- src/index.css | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src-tauri/src/watch_exec.rs b/src-tauri/src/watch_exec.rs index 2eeb0b4..424256c 100644 --- a/src-tauri/src/watch_exec.rs +++ b/src-tauri/src/watch_exec.rs @@ -1,6 +1,6 @@ use crate::fs_watcher::FsWatcher; #[cfg(target_os = "linux")] -use crate::utils::subs; +use crate::utils; #[cfg(windows)] use crate::utils::get_win32_ready_drives; diff --git a/src/index.css b/src/index.css index c8fd19e..7aad588 100644 --- a/src/index.css +++ b/src/index.css @@ -93,6 +93,8 @@ body { display: flex; justify-content:space-between; } + + .tabs>.menu{ display: flex; flex-direction: column-reverse; @@ -109,6 +111,9 @@ body { margin: 10px 0 0 0 !important; display: flex; } +.setting-item .added label{ + max-width: 260px; +} .setting-item .add button{ margin: 0 0 10px 0; } From 6a9758c6279debe02fb82a0c0f51d56bcfd60514 Mon Sep 17 00:00:00 2001 From: Jeff Date: Sat, 2 Apr 2022 21:24:15 +0800 Subject: [PATCH 28/28] Bump version --- src-tauri/tauri.conf.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src-tauri/tauri.conf.json b/src-tauri/tauri.conf.json index f582dcb..f32a774 100644 --- a/src-tauri/tauri.conf.json +++ b/src-tauri/tauri.conf.json @@ -1,7 +1,7 @@ { "package": { "productName": "Orange", - "version": "0.4.0" + "version": "0.5.0" }, "build": { "distDir": "../build",