diff --git a/Cargo.lock b/Cargo.lock index 96f1014..dc88854 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -959,8 +959,7 @@ dependencies = [ [[package]] name = "const-field-offset" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6304465f16f463cddc572b737c3df93576edd3a6b53f057bd8beeb29f4ef8dfd" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "const-field-offset-macro", "field-offset", @@ -969,8 +968,7 @@ dependencies = [ [[package]] name = "const-field-offset-macro" version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "57aaaad9185d3bcb3afe63549d8ba60b2fb0ea8dc2da83f62dd56805edf56fd1" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "proc-macro2", "quote", @@ -1329,6 +1327,8 @@ dependencies = [ name = "czkawka_slint" version = "6.1.0" dependencies = [ + "chrono", + "czkawka_core", "rand", "slint", "slint-build", @@ -1569,12 +1569,6 @@ dependencies = [ "libc", ] -[[package]] -name = "dunce" -version = "1.0.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56ce8c6da7551ec6c462cbaf3bfbc75131ebbfa1c944aeaa9dab51ca1c5f0c3b" - [[package]] name = "dwrote" version = "0.11.0" @@ -2656,9 +2650,8 @@ dependencies = [ [[package]] name = "i-slint-backend-linuxkms" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e321d0f8d12509ec2ed5b5aba4996922606686ac3d86d70ba126cba1b4e4563" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "calloop 0.11.0", "drm", @@ -2676,9 +2669,8 @@ dependencies = [ [[package]] name = "i-slint-backend-qt" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0f1ce3687c329341842f79c31c95d7bcf49b6fda7fd19b09e0b5d7fb33b9d6b2" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "const-field-offset", "cpp", @@ -2696,22 +2688,21 @@ dependencies = [ [[package]] name = "i-slint-backend-selector" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7382cc01e9c9ef607debe1e4af7e1c6af78720a258fd18d8e32761b8593c5db" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "cfg-if", "i-slint-backend-linuxkms", "i-slint-backend-qt", "i-slint-backend-winit", + "i-slint-common", "i-slint-core", ] [[package]] name = "i-slint-backend-winit" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f8c0f3f01e2c678d24b81914a38e53d3b660a0ef13831acb59c71bd7c95ed0cb" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "accesskit", "accesskit_winit", @@ -2748,9 +2739,8 @@ dependencies = [ [[package]] name = "i-slint-common" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e7daf484e68bf27e06b7501767c6e66063c0f85948e57a6de679b53d2d9d2044" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "cfg-if", "derive_more", @@ -2760,16 +2750,14 @@ dependencies = [ [[package]] name = "i-slint-compiler" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b99172cc43ca17a78e96e3f8f13699d9fc1c00474d2d87bc57c0f7e816c4a48" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "by_address", "codemap", "codemap-diagnostic", "css-color-parser2", "derive_more", - "dunce", "fontdue", "i-slint-common", "image", @@ -2791,9 +2779,8 @@ dependencies = [ [[package]] name = "i-slint-core" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b62e590bb3d6009447a52760e9343c25a3bf7a8a7b0ad7ab5a77c5324fcaa957" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "auto_enums", "bytemuck", @@ -2835,9 +2822,8 @@ dependencies = [ [[package]] name = "i-slint-core-macros" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "62a416f1e9fc42c2bf1f171e5be38a8155850fcd390fce300869bcc9d6c9c117" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "quote", "syn 2.0.38", @@ -2845,9 +2831,8 @@ dependencies = [ [[package]] name = "i-slint-renderer-femtovg" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9e99a941fca00b96a7756d56e4bc5e2876283f34c693eabc73585c0b91ab84f0" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "cfg-if", "const-field-offset", @@ -2879,9 +2864,8 @@ dependencies = [ [[package]] name = "i-slint-renderer-skia" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f617268cfee53e1fa3fcab8f6ab2775deacfce74057386c4ad39ef2647f8db6" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "cfg-if", "cfg_aliases", @@ -3389,11 +3373,9 @@ version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "54a0adf8d8607a73a5b74cbe4132f57cb349e4bf860103cd089461bbcbc9907e" dependencies = [ - "cc", "errno", "libseat-sys", "log", - "pkg-config", ] [[package]] @@ -5062,9 +5044,8 @@ dependencies = [ [[package]] name = "slint" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c9a6f76430dde7dc57d374c37aa3103532813cc275a94b515b5907e91dd19334" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "const-field-offset", "i-slint-backend-selector", @@ -5079,21 +5060,19 @@ dependencies = [ [[package]] name = "slint-build" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c6edc7309a89f14c685086544ea3dbd7668ccdeb03d774f06879f38237e55815" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "i-slint-compiler", "spin_on", "thiserror", - "toml_edit 0.19.15", + "toml_edit 0.20.2", ] [[package]] name = "slint-macros" -version = "1.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "33f96e5ea0574ac69b773b159d43124f7a329107cf60c11516e63d38c2d8c89c" +version = "1.3.0" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "i-slint-compiler", "proc-macro2", @@ -6226,8 +6205,7 @@ dependencies = [ [[package]] name = "vtable" version = "0.1.11" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9f4c7506238561777a1861d3dc3c0001877c475187e7bc4392ea87ebf631fd9c" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "const-field-offset", "portable-atomic", @@ -6238,8 +6216,7 @@ dependencies = [ [[package]] name = "vtable-macro" version = "0.1.10" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6b2b8eecdb8e4284adf5546fc518f048f6dc33e7203dbe36fa93a4add39b31f6" +source = "git+https://github.com/slint-ui/slint.git?branch=olivier/fix-3700#c03366792958460a84e4c340a34928643338a963" dependencies = [ "proc-macro2", "quote", diff --git a/czkawka_slint_gui/Cargo.toml b/czkawka_slint_gui/Cargo.toml index fe3ee64..c47e946 100644 --- a/czkawka_slint_gui/Cargo.toml +++ b/czkawka_slint_gui/Cargo.toml @@ -14,7 +14,8 @@ build = "build.rs" #slint = "1.2.2" slint = { git = "https://github.com/slint-ui/slint.git", branch = "olivier/fix-3700"} rand = "0.8.5" -#czkawka_core = { version = "6.1.0", path = "../czkawka_core" } +czkawka_core = { version = "6.1.0", path = "../czkawka_core" } +chrono = "0.4.31" [build-dependencies] slint-build = { git = "https://github.com/slint-ui/slint.git", branch = "olivier/fix-3700"} \ No newline at end of file diff --git a/czkawka_slint_gui/src/connect_delete.rs b/czkawka_slint_gui/src/connect_delete.rs new file mode 100644 index 0000000..cb3af34 --- /dev/null +++ b/czkawka_slint_gui/src/connect_delete.rs @@ -0,0 +1,30 @@ +use crate::MainWindow; +use slint::{ComponentHandle, Model, ModelRc, VecModel}; +use std::borrow::BorrowMut; + +pub fn connect_delete_button(app: &MainWindow) { + let a = app.as_weak(); + app.on_deleted(move || { + let app = a.upgrade().unwrap(); + + let mut r = app.get_empty_folder_model(); + let m = r.borrow_mut(); + let length_before = m.iter().count(); + let (entries_to_delete, entries_left): (Vec<_>, Vec<_>) = m.iter().partition(|(checked, _selected_row, _header_row, _data)| *checked); + let mut s: Vec<_> = m.iter().filter(|(checked, _selected_row, _header_row, _data)| !*checked).collect(); + + entries_to_delete.into_iter().for_each(|(_checked, _selected_row, _header_row, _data)| { + // TODO delete in parallel items, consider to add progress bar + }); + + let length_after = s.len(); + if length_before != length_after { + dbg!(format!("Items to remove {}", length_before - length_after)); + s.iter_mut().for_each(|(_checked, selected_row, _header_row, _data)| { + *selected_row = false; + }); + let r = ModelRc::new(VecModel::from(s)); + app.set_empty_folder_model(r.into()); + } + }); +} diff --git a/czkawka_slint_gui/src/connect_scan.rs b/czkawka_slint_gui/src/connect_scan.rs new file mode 100644 index 0000000..35c8335 --- /dev/null +++ b/czkawka_slint_gui/src/connect_scan.rs @@ -0,0 +1,54 @@ +use crate::{split_path, CurrentTab, MainWindow}; +use chrono::NaiveDateTime; +use czkawka_core::common_tool::CommonData; +use czkawka_core::empty_folder::EmptyFolder; +use slint::{ComponentHandle, ModelRc, SharedString, VecModel}; +use std::path::PathBuf; +use std::rc::Rc; +use std::thread; + +pub fn connect_scan_button(app: &MainWindow) { + let a = app.as_weak(); + app.on_scanned(move |active_tab| { + let app = a.upgrade().unwrap(); + app.set_scanning(true); + + let a = app.as_weak(); + match active_tab { + CurrentTab::EmptyFolders => { + thread::spawn(move || { + let mut ef = EmptyFolder::new(); + ef.set_included_directory(vec![PathBuf::from("/home/rafal/Desktop")]); + ef.find_empty_folders(None, None); + + ef.get_empty_folder_list(); + + let mut vector = ef.get_empty_folder_list().keys().cloned().collect::>(); + + vector.sort_unstable_by_key(|e| { + let t = split_path(e.as_path()); + (t.0, t.1) + }); + + a.upgrade_in_event_loop(move |app| { + let mut folder_map = ef.get_empty_folder_list(); + let items = Rc::new(VecModel::default()); + for path in vector { + let (directory, file) = split_path(&path); + let data_model = VecModel::from_slice(&[ + SharedString::from(file), + SharedString::from(directory), + SharedString::from(NaiveDateTime::from_timestamp_opt(folder_map[&path].modified_date as i64, 0).unwrap().to_string()), + ]); + + items.push((false, false, false, ModelRc::new(data_model))); + } + app.set_empty_folder_model(items.into()); + app.set_scanning(false); + }) + }); + } + _ => panic!(), + } + }); +} diff --git a/czkawka_slint_gui/src/main.rs b/czkawka_slint_gui/src/main.rs index 6a95264..1981802 100644 --- a/czkawka_slint_gui/src/main.rs +++ b/czkawka_slint_gui/src/main.rs @@ -1,11 +1,21 @@ -use std::rc::Rc; -use slint::{Model, ModelRc, SharedString, VecModel}; -slint::include_modules!(); -use std::borrow::BorrowMut; +mod connect_delete; +mod connect_scan; +use std::borrow::BorrowMut; +use std::path::Path; +use std::rc::Rc; + +use crate::connect_delete::connect_delete_button; +use crate::connect_scan::connect_scan_button; + +use czkawka_core::common_tool::CommonData; +use czkawka_core::empty_folder::EmptyFolder; +use slint::{Model, ModelRc, SharedString, VecModel}; + +slint::include_modules!(); fn main() { - let app = MainWindow::new().unwrap();//.run().unwrap(); - let row_data: Rc)>> = Rc::new(VecModel::default()); + let app = MainWindow::new().unwrap(); //.run().unwrap(); + let row_data: Rc)>> = Rc::new(VecModel::default()); for r in 0..1000 { let items = VecModel::default(); @@ -14,33 +24,20 @@ fn main() { items.push(slint::format!("Item {r}.{c}").into()); } - row_data.push((r % 2 == 0, r% 3 == 0, ModelRc::new(items))); + row_data.push((r % 4 == 0, r % 3 == 0, r % 2 == 0, ModelRc::new(items))); } - app.set_empty_folder_model(row_data.into()); + // app.set_empty_folder_model(row_data.into()); - let a = app.as_weak(); - app.on_deleted(move || { - let app = a.upgrade().unwrap(); - - - let mut r = app.get_empty_folder_model(); - let m = r.borrow_mut(); - let length_before = m.iter().count(); - let mut s: Vec<_> = m.iter().filter(|(a,_b,_c)|{ - !*a - }).collect(); - - - let length_after = s.len(); - if length_before != length_after { - dbg!(format!("Items to remove {}", length_before - length_after)); - s.iter_mut().for_each(|(_a, selected_row, _)|{ - *selected_row = false; - }); - let r = ModelRc::new(VecModel::from(s)); - app.set_empty_folder_model(r.into()); - } - }); + connect_delete_button(&app); + connect_scan_button(&app); app.run().unwrap(); -} \ No newline at end of file +} + +pub fn split_path(path: &Path) -> (String, String) { + match (path.parent(), path.file_name()) { + (Some(dir), Some(file)) => (dir.display().to_string(), file.to_string_lossy().into_owned()), + (Some(dir), None) => (dir.display().to_string(), String::new()), + (None, _) => (String::new(), String::new()), + } +} diff --git a/czkawka_slint_gui/ui/main_window.slint b/czkawka_slint_gui/ui/main_window.slint index 7640d4d..daf35f2 100644 --- a/czkawka_slint_gui/ui/main_window.slint +++ b/czkawka_slint_gui/ui/main_window.slint @@ -1,19 +1,24 @@ import { Button, VerticalBox , HorizontalBox, TabWidget, ListView, StandardListView, StandardTableView, CheckBox} from "std-widgets.slint"; import {SelectableTableView} from "selectable_tree_view.slint"; +import {LeftSidePanel} from "left_side_panel.slint"; +import {CurrentTab} from "common.slint"; -enum CurrentTab { - EmptyFolders, - SimilarImages, -} - -export component MainWindow { +export component MainWindow inherits Window { callback deleted; - in-out property active-tab; - in-out property <[{checked: bool, selected_row: bool, val:[string]}]> empty-folder-model: [ - {checked: false, selected_row: false, val: ["kropkarz", "/Xd1", "24.10.2023"]} , - {checked: false, selected_row: true, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} , - {checked: true, selected_row: false, val: ["lokkaler", "/Xd1/Vide2", "01.23.1911"]} , -]; + callback scanned(CurrentTab); + + in-out property scanning: false; + + in-out property active-tab: CurrentTab.EmptyFolders; + in-out property <[{checked: bool, selected_row: bool, header_row: bool, val:[string]}]> empty_folder_model: [ + {checked: false, selected_row: false, header_row: true, val: ["kropkarz", "/Xd1", "24.10.2023"]} , + {checked: false, selected_row: true, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} , + {checked: true, selected_row: false, header_row: false, val: ["lokkaler", "/Xd1/Vide2", "01.23.1911"]} + ]; + in-out property <[{checked: bool, selected_row: bool, header_row: bool, val:[string]}]> empty_files_model: []; + in-out property <[{checked: bool, selected_row: bool, header_row: bool, val:[string]}]> similar_images_model: []; + + title: root.active-tab == CurrentTab.EmptyFiles ? "EmptyFiles" : (root.active-tab == CurrentTab.EmptyFolders ? "EmptyFolders" : "Similar Images"); min-width: 200px; VerticalBox { @@ -21,32 +26,42 @@ export component MainWindow { // min-width: 600px; preferred-height: 300px; - tab_bar := VerticalLayout { - width: 120px; - spacing: 3px; - Button { - text: "Empty Folders"; - clicked => { root.active-tab = CurrentTab.EmptyFolders; } - } - Button { - text: "Similar Images"; - clicked => { root.active-tab = CurrentTab.SimilarImages; } - } + LeftSidePanel { + scanning: root.scanning; + active-tab <=> root.active-tab; } - // TODO - using root.active-tab in visible property will not + // TODO - using root.active-tab in visible property will not clear model if root.active-tab == CurrentTab.EmptyFolders: SelectableTableView { min-width: 200px; columns: ["Selection", "Folder Name", "Path", "Modification Date"]; values: empty-folder-model; } + if root.active-tab == CurrentTab.EmptyFiles: SelectableTableView { + min-width: 200px; + + columns: ["Selection", "Folder Name", "Path", "Modification Date"]; + values: empty-files-model; + } + if root.active-tab == CurrentTab.SimilarImages: SelectableTableView { + min-width: 200px; + + columns: ["Selection", "Folder Name", "Path", "Modification Date"]; + values: similar-images-model; + } } HorizontalBox { + height: 50px; scan_button:= Button { + enabled: !scanning; text: "Scan"; + clicked => { + root.scanned(active-tab); + } } delete_button:= Button { + enabled: !scanning; text: "Delete"; clicked => { root.deleted(); @@ -55,4 +70,3 @@ export component MainWindow { } } } - diff --git a/czkawka_slint_gui/ui/selectable_tree_view.slint b/czkawka_slint_gui/ui/selectable_tree_view.slint index 9e1c006..777b1c9 100644 --- a/czkawka_slint_gui/ui/selectable_tree_view.slint +++ b/czkawka_slint_gui/ui/selectable_tree_view.slint @@ -2,7 +2,7 @@ import { Button, VerticalBox , HorizontalBox, TabWidget, ListView, StandardListV export component SelectableTableView inherits Rectangle { in property <[string]> columns; - in property <[{checked: bool, selected_row: bool, val:[string]}]> values; + in property <[{checked: bool, selected_row: bool, header_row: bool, val:[string]}]> values; private property <[length]> column_sizes: [30px, 100px, 100px, 100px]; private property column_number: 4; @@ -44,13 +44,16 @@ export component SelectableTableView inherits Rectangle { } } list_view:= ListView { + min-width: 100px; for r[idx] in root.values : Rectangle { - background: touch-area.has-hover ? (r.selected_row ? #cccccc : #dddddd) : (r.selected_row ? #cccccc: #dddddd); + background: r.header-row ? #888888 : (touch-area.has-hover ? (r.selected_row ? #cccccc : #dddddd) : (r.selected_row ? #cccccc: #dddddd)); // background: touch-area.has-hover ? (selected ? #333333 : #222222) : (selected ? #333333: #222222); touch_area:= TouchArea { clicked => { - r.selected_row = !r.selected_row + if (!r.header_row) { + r.selected_row = !r.selected_row + } } } @@ -61,7 +64,8 @@ export component SelectableTableView inherits Rectangle { CheckBox { //min-width: 200px; - checked: r.checked; + visible: !r.header-row; + checked: r.checked && !r.header-row; width: root.column-sizes[0]; toggled => { r.checked = self.checked;