diff --git a/krokiet/src/common.rs b/krokiet/src/common.rs index 2243774..e915277 100644 --- a/krokiet/src/common.rs +++ b/krokiet/src/common.rs @@ -9,7 +9,7 @@ pub fn get_str_path_idx(active_tab: CurrentTab) -> usize { CurrentTab::EmptyFolders => 1, CurrentTab::EmptyFiles => 1, CurrentTab::SimilarImages => 4, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } pub fn get_str_name_idx(active_tab: CurrentTab) -> usize { @@ -17,7 +17,7 @@ pub fn get_str_name_idx(active_tab: CurrentTab) -> usize { CurrentTab::EmptyFolders => 0, CurrentTab::EmptyFiles => 0, CurrentTab::SimilarImages => 3, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -26,14 +26,14 @@ pub fn get_int_modification_date_idx(active_tab: CurrentTab) -> usize { CurrentTab::EmptyFiles => 0, CurrentTab::SimilarImages => 0, CurrentTab::EmptyFolders => 0, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } pub fn get_int_size_idx(active_tab: CurrentTab) -> usize { match active_tab { CurrentTab::EmptyFiles => 2, CurrentTab::SimilarImages => 2, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), CurrentTab::EmptyFolders => panic!("Unable to get size from this tab"), } } @@ -41,14 +41,14 @@ pub fn get_int_size_idx(active_tab: CurrentTab) -> usize { pub fn get_int_width_idx(active_tab: CurrentTab) -> usize { match active_tab { CurrentTab::SimilarImages => 4, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), _ => panic!("Unable to get height from this tab"), } } pub fn get_int_height_idx(active_tab: CurrentTab) -> usize { match active_tab { CurrentTab::SimilarImages => 5, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), _ => panic!("Unable to get height from this tab"), } } @@ -57,7 +57,7 @@ pub fn get_is_header_mode(active_tab: CurrentTab) -> bool { match active_tab { CurrentTab::EmptyFolders | CurrentTab::EmptyFiles => false, CurrentTab::SimilarImages => true, - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -66,7 +66,7 @@ pub fn get_tool_model(app: &MainWindow, tab: CurrentTab) -> ModelRc app.get_empty_folder_model(), CurrentTab::SimilarImages => app.get_similar_images_model(), CurrentTab::EmptyFiles => app.get_empty_files_model(), - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -75,7 +75,7 @@ pub fn set_tool_model(app: &MainWindow, tab: CurrentTab, model: ModelRc app.set_empty_folder_model(model), CurrentTab::SimilarImages => app.set_similar_images_model(model), CurrentTab::EmptyFiles => app.set_empty_files_model(model), - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } diff --git a/krokiet/src/connect_delete.rs b/krokiet/src/connect_delete.rs index ea5ec6d..00a5327 100644 --- a/krokiet/src/connect_delete.rs +++ b/krokiet/src/connect_delete.rs @@ -6,7 +6,7 @@ use czkawka_core::common_messages::Messages; use crate::common::{get_is_header_mode, get_tool_model, set_tool_model}; use crate::model_operations::{collect_full_path_from_model, deselect_all_items, filter_out_checked_items}; -use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow}; +use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow, Settings}; pub fn connect_delete_button(app: &MainWindow) { let a = app.as_weak(); @@ -17,9 +17,9 @@ pub fn connect_delete_button(app: &MainWindow) { let model = get_tool_model(&app, active_tab); - let remove_to_trash = false; + let settings = app.global::(); - let (errors, new_model) = handle_delete_items(&model, active_tab, remove_to_trash); + let (errors, new_model) = handle_delete_items(&app, &model, active_tab, settings.get_move_to_trash()); if let Some(new_model) = new_model { set_tool_model(&app, active_tab, new_model); @@ -31,13 +31,14 @@ pub fn connect_delete_button(app: &MainWindow) { }); } -fn handle_delete_items(items: &ModelRc, active_tab: CurrentTab, remove_to_trash: bool) -> (Vec, Option>) { +fn handle_delete_items(app: &MainWindow, items: &ModelRc, active_tab: CurrentTab, remove_to_trash: bool) -> (Vec, Option>) { let (entries_to_delete, mut entries_left) = filter_out_checked_items(items, get_is_header_mode(active_tab)); if !entries_to_delete.is_empty() { let vec_items_to_remove = collect_full_path_from_model(&entries_to_delete, active_tab); let errors = remove_selected_items(vec_items_to_remove, active_tab, remove_to_trash); deselect_all_items(&mut entries_left); + app.set_text_summary_text(format!("Deleted {} items, failed to remove {} items", entries_to_delete.len() - errors.len(), errors.len()).into()); let r = ModelRc::new(VecModel::from(entries_left)); // TODO here maybe should also stay old model if entries cannot be removed return (errors, Some(r)); @@ -48,7 +49,6 @@ fn handle_delete_items(items: &ModelRc, active_tab: CurrentTab, r // TODO delete in parallel items, consider to add progress bar // For empty folders double check if folders are really empty - this function probably should be run in thread // and at the end should be send signal to main thread to update model -// TODO handle also situations where cannot delete file/folder fn remove_selected_items(items_to_remove: Vec, active_tab: CurrentTab, remove_to_trash: bool) -> Vec { // Iterate over empty folders and not delete them if they are not empty if active_tab == CurrentTab::EmptyFolders { diff --git a/krokiet/src/connect_open.rs b/krokiet/src/connect_open.rs index 9165b97..eb7aa22 100644 --- a/krokiet/src/connect_open.rs +++ b/krokiet/src/connect_open.rs @@ -37,4 +37,13 @@ pub fn connect_open_items(app: &MainWindow) { error!("Failed to open cache folder {:?}: {e}", cache_folder); } }); + + app.global::().on_open_link(move |link| { + match open::that(link.as_str()) { + Ok(()) => {} + Err(e) => { + eprintln!("Failed to open link: {e}"); + } + }; + }); } diff --git a/krokiet/src/connect_scan.rs b/krokiet/src/connect_scan.rs index 3c68a3d..bde53a4 100644 --- a/krokiet/src/connect_scan.rs +++ b/krokiet/src/connect_scan.rs @@ -46,7 +46,7 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender { scan_similar_images(a, progress_sender, stop_receiver, custom_settings); } - CurrentTab::Settings => panic!("Button should be disabled"), + CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } }); } @@ -58,12 +58,12 @@ fn scan_similar_images(a: Weak, progress_sender: Sender, Receiver) = unbounded(); let (stop_sender, stop_receiver): (Sender<()>, Receiver<()>) = unbounded(); - // to_remove_debug(&app); - - // Slint files may already contains data in models, so clear them before starting - todo, - // check if non zeroed models are useful zeroing_all_models(&app); set_initial_gui_infos(&app); @@ -98,56 +94,3 @@ pub fn zeroing_all_models(app: &MainWindow) { app.set_empty_files_model(Rc::new(VecModel::default()).into()); app.set_similar_images_model(Rc::new(VecModel::default()).into()); } - -// // TODO remove this after debugging - or leave commented -// pub fn to_remove_debug(app: &MainWindow) { -// app.set_empty_folder_model(to_remove_create_without_header("@@").into()); -// app.set_empty_files_model(to_remove_create_without_header("%%").into()); -// app.set_similar_images_model(to_remove_create_with_header().into()); -// } - -// fn to_remove_create_with_header() -> Rc> { -// let header_row_data: Rc> = Rc::new(VecModel::default()); -// for r in 0..10_000 { -// let items = VecModel::default(); -// -// for c in 0..3 { -// items.push(slint::format!("Item {r}.{c}")); -// } -// -// let is_header = r % 3 == 0; -// let is_checked = (r % 2 == 0) && !is_header; -// -// let item = MainListModel { -// checked: is_checked, -// header_row: is_header, -// selected_row: false, -// val: ModelRc::new(items), -// }; -// -// header_row_data.push(item); -// } -// header_row_data -// } -// fn to_remove_create_without_header(s: &str) -> Rc> { -// let non_header_row_data: Rc> = Rc::new(VecModel::default()); -// for r in 0..100_000 { -// let items = VecModel::default(); -// -// for c in 0..3 { -// items.push(slint::format!("Item {r}.{c}.{s}")); -// } -// -// let is_checked = r % 2 == 0; -// -// let item = MainListModel { -// checked: is_checked, -// header_row: false, -// selected_row: false, -// val: ModelRc::new(items), -// }; -// -// non_header_row_data.push(item); -// } -// non_header_row_data -// } diff --git a/krokiet/src/settings.rs b/krokiet/src/settings.rs index 7beb513..a8b427c 100644 --- a/krokiet/src/settings.rs +++ b/krokiet/src/settings.rs @@ -199,7 +199,7 @@ pub fn create_default_settings_files() { } } - for i in 1..=10 { + for i in 0..10 { let config_file = get_config_file(i); if let Some(config_file) = config_file { if !config_file.is_file() { diff --git a/krokiet/ui/action_buttons.slint b/krokiet/ui/action_buttons.slint index f00ed0c..50e8616 100644 --- a/krokiet/ui/action_buttons.slint +++ b/krokiet/ui/action_buttons.slint @@ -23,10 +23,10 @@ export component ActionButtons inherits HorizontalLayout { callback show_select_popup(length, length); callback show_remove_popup(); callback request_folder_to_move(); - in-out property bottom_panel_visibility: BottomPanelVisibility.Directories; + in-out property bottom_panel_visibility <=> GuiState.bottom_panel_visibility; in-out property stop_requested: false; in-out property scanning; - in-out property lists_enabled: GuiState.active_tab != CurrentTab.Settings; + in-out property lists_enabled: GuiState.is_tool_tab_active; out property name; height: 30px; spacing: 4px; diff --git a/krokiet/ui/callabler.slint b/krokiet/ui/callabler.slint index 33cd9a6..edff596 100644 --- a/krokiet/ui/callabler.slint +++ b/krokiet/ui/callabler.slint @@ -32,4 +32,6 @@ export global Callabler { callback open_config_folder(); callback open_cache_folder(); + + callback open_link(string); } diff --git a/krokiet/ui/common.slint b/krokiet/ui/common.slint index 97b41b4..d16f850 100644 --- a/krokiet/ui/common.slint +++ b/krokiet/ui/common.slint @@ -2,7 +2,8 @@ export enum CurrentTab { EmptyFolders, EmptyFiles, SimilarImages, - Settings + Settings, + About } export enum TypeOfOpenedItem { diff --git a/krokiet/ui/gui_state.slint b/krokiet/ui/gui_state.slint index 84d38eb..0ab6afc 100644 --- a/krokiet/ui/gui_state.slint +++ b/krokiet/ui/gui_state.slint @@ -1,5 +1,5 @@ import {CurrentTab} from "common.slint"; -import {SelectModel, SelectMode} from "common.slint"; +import {SelectModel, SelectMode, BottomPanelVisibility} from "common.slint"; // State Gui state that shows the current state of the GUI // It extends Settings global state with settings that are not saved to the settings file @@ -19,5 +19,8 @@ export global GuiState { in-out property available_subsettings: active_tab == CurrentTab.SimilarImages; in-out property active_tab: CurrentTab.EmptyFiles; + in-out property is_tool_tab_active: active_tab != CurrentTab.Settings && active_tab != CurrentTab.About; in-out property <[SelectModel]> select_results_list: [{data: SelectMode.SelectAll, name: "Select All"}, {data: SelectMode.UnselectAll, name: "Deselect All"}, {data: SelectMode.SelectTheSmallestResolution, name: "Select the smallest resolution"}]; + + in-out property bottom_panel_visibility: BottomPanelVisibility.Directories; } diff --git a/krokiet/ui/left_side_panel.slint b/krokiet/ui/left_side_panel.slint index 8d8e349..9a9326f 100644 --- a/krokiet/ui/left_side_panel.slint +++ b/krokiet/ui/left_side_panel.slint @@ -1,5 +1,5 @@ import { Button, VerticalBox , HorizontalBox, TabWidget, ListView, StandardListView, StandardTableView, CheckBox} from "std-widgets.slint"; -import {CurrentTab} from "common.slint"; +import {CurrentTab, BottomPanelVisibility} from "common.slint"; import {ColorPalette} from "color_palette.slint"; import {GuiState} from "gui_state.slint"; import {Callabler} from "callabler.slint"; @@ -70,11 +70,20 @@ export component LeftSidePanel { VerticalLayout { spacing: 20px; Rectangle { + visible: GuiState.active_tab != CurrentTab.About; height: 100px; Image { width: root.width; source: @image-url("../icons/logo.png"); } + touch_area := TouchArea { + clicked => { + GuiState.active_tab = CurrentTab.About; + Callabler.tab_changed(); + root.changed_current_tab(); + GuiState.bottom_panel_visibility = BottomPanelVisibility.NotVisible; + } + } } VerticalLayout { @@ -110,7 +119,7 @@ export component LeftSidePanel { HorizontalLayout { alignment: start; Button { - visible: GuiState.active_tab != CurrentTab.Settings && GuiState.available_subsettings; + visible: GuiState.available_subsettings; min-width: 20px; min-height: 20px; max-height: self.width; diff --git a/krokiet/ui/main_lists.slint b/krokiet/ui/main_lists.slint index 6ce0d48..5a19c63 100644 --- a/krokiet/ui/main_lists.slint +++ b/krokiet/ui/main_lists.slint @@ -5,6 +5,7 @@ import {CurrentTab, TypeOfOpenedItem} from "common.slint"; import {MainListModel} from "common.slint"; import {SettingsList} from "settings_list.slint"; import {GuiState} from "gui_state.slint"; +import {About} from "about.slint"; export component MainList { in-out property <[MainListModel]> empty_folder_model: [ @@ -55,6 +56,10 @@ export component MainList { visible: GuiState.active_tab == CurrentTab.Settings; } + about_app := About { + visible: GuiState.active_tab == CurrentTab.About; + } + focus_item := FocusScope { width: 0px; // Hack to not steal first click from other components - https://github.com/slint-ui/slint/issues/3503 // Hack not works https://github.com/slint-ui/slint/issues/3503#issuecomment-1817809834 because disables key-released event diff --git a/krokiet/ui/main_window.slint b/krokiet/ui/main_window.slint index e825c34..e9dbdd6 100644 --- a/krokiet/ui/main_window.slint +++ b/krokiet/ui/main_window.slint @@ -83,7 +83,7 @@ export component MainWindow inherits Window { similar_images_model <=> root.similar_images_model; } preview_or_tool_settings := Rectangle { - visible: (GuiState.preview_visible || tool_settings.visible) && GuiState.active_tab != CurrentTab.Settings; + visible: (GuiState.preview_visible || tool_settings.visible) && GuiState.is_tool_tab_active; height: parent.height; x: parent.width / 2; width: self.visible ? parent.width / 2 : 0; @@ -134,9 +134,17 @@ export component MainWindow inherits Window { } } - text_summary := LineEdit { - text: text_summary_text; - read-only: true; + HorizontalLayout { + spacing: 5px; + text_summary := LineEdit { + text: text_summary_text; + read-only: true; + } + Text { + text: "Krokiet\n7.0.0"; + vertical-alignment: center; + horizontal-alignment: center; + } } bottom_panel := BottomPanel { diff --git a/krokiet/ui/popup_move_folders.slint b/krokiet/ui/popup_move_folders.slint index 56861b2..e68ae83 100644 --- a/krokiet/ui/popup_move_folders.slint +++ b/krokiet/ui/popup_move_folders.slint @@ -84,10 +84,6 @@ export component PopupMoveFolders inherits Rectangle { } } - init => { - show_popup(); - } - show_popup() => { popup_window.show(); }