diff --git a/krokiet/src/common.rs b/krokiet/src/common.rs index b1a9886..f594f9f 100644 --- a/krokiet/src/common.rs +++ b/krokiet/src/common.rs @@ -6,9 +6,81 @@ use slint::{ModelRc, SharedString, VecModel}; // Int model is used to store data in unchanged(* except that we need to split u64 into two i32) form and is used to sort/select data // Str model is used to display data in gui +#[repr(u8)] +pub enum IntDataDuplicateFiles { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} +#[repr(u8)] +pub enum StrDataDuplicateFiles { + Size, + Name, + Path, + ModificationDate, +} + +#[repr(u8)] +pub enum IntDataEmptyFolders { + ModificationDatePart1, + ModificationDatePart2, +} + +#[repr(u8)] +pub enum StrDataEmptyFolders { + Name, + Path, + ModificationDate, +} +#[repr(u8)] +pub enum IntDataBigFiles { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} + +#[repr(u8)] +pub enum StrDataBigFiles { + Size, + Name, + Path, + ModificationDate, +} + +#[repr(u8)] +pub enum IntDataEmptyFiles { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} + +#[repr(u8)] +pub enum StrDataEmptyFiles { + Name, + Path, + ModificationDate, +} +#[repr(u8)] +pub enum IntDataTemporaryFiles { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} +#[repr(u8)] +pub enum StrDataTemporaryFiles { + Size, + Name, + Path, + ModificationDate, +} + #[repr(u8)] pub enum IntDataSimilarImages { - ModificationDatePart1 = 0, + ModificationDatePart1, ModificationDatePart2, SizePart1, SizePart2, @@ -18,7 +90,7 @@ pub enum IntDataSimilarImages { #[repr(u8)] pub enum StrDataSimilarImages { - Similarity = 0, + Similarity, Size, Resolution, Name, @@ -27,32 +99,87 @@ pub enum StrDataSimilarImages { } #[repr(u8)] -pub enum IntDataEmptyFiles { - ModificationDatePart1 = 0, +pub enum IntDataSimilarVideos { + ModificationDatePart1, ModificationDatePart2, SizePart1, SizePart2, } #[repr(u8)] -pub enum StrDataEmptyFiles { - Name = 0, +pub enum StrDataSimilarVideos { + Size, + Name, Path, ModificationDate, } #[repr(u8)] -pub enum IntDataEmptyFolders { - ModificationDatePart1 = 0, +pub enum IntDataSimilarMusic { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} + +#[repr(u8)] +pub enum StrDataSimilarMusic { + Size, + Name, + Title, + Artist, + Year, + Bitrate, + Length, + Genre, + Path, + ModificationDate, +} +#[repr(u8)] +pub enum IntDataInvalidSymlinks { + ModificationDatePart1, ModificationDatePart2, } #[repr(u8)] -pub enum StrDataEmptyFolders { - Name = 0, - Path, +pub enum StrDataInvalidSymlinks { + SymlinkName, + SymlinkFolder, + DestinationPath, + TypeOfError, ModificationDate, } +#[repr(u8)] +pub enum IntDataBrokenFiles { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} + +#[repr(u8)] +pub enum StrDataBrokenFiles { + Name, + Path, + TypeOfError, + Size, + ModificationDate, +} +#[repr(u8)] +pub enum IntDataBadExtensions { + ModificationDatePart1, + ModificationDatePart2, + SizePart1, + SizePart2, +} + +#[repr(u8)] +pub enum StrDataBadExtensions { + Name, + Path, + CurrentExtension, + ProperExtension, +} // Remember to match updated this according to ui/main_lists.slint and connect_scan.rs files pub fn get_str_path_idx(active_tab: CurrentTab) -> usize { @@ -60,6 +187,14 @@ pub fn get_str_path_idx(active_tab: CurrentTab) -> usize { CurrentTab::EmptyFolders => StrDataEmptyFolders::Path as usize, CurrentTab::EmptyFiles => StrDataEmptyFiles::Path as usize, CurrentTab::SimilarImages => StrDataSimilarImages::Path as usize, + CurrentTab::DuplicateFiles => StrDataDuplicateFiles::Path as usize, + CurrentTab::BigFiles => StrDataBigFiles::Path as usize, + CurrentTab::TemporaryFiles => StrDataTemporaryFiles::Path as usize, + CurrentTab::SimilarVideos => StrDataSimilarVideos::Path as usize, + CurrentTab::SimilarMusic => StrDataSimilarMusic::Path as usize, + CurrentTab::InvalidSymlinks => StrDataInvalidSymlinks::SymlinkFolder as usize, + CurrentTab::BrokenFiles => StrDataBrokenFiles::Path as usize, + CurrentTab::BadExtensions => StrDataBadExtensions::Path as usize, CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -69,6 +204,14 @@ pub fn get_str_name_idx(active_tab: CurrentTab) -> usize { CurrentTab::EmptyFolders => StrDataEmptyFolders::Name as usize, CurrentTab::EmptyFiles => StrDataEmptyFiles::Name as usize, CurrentTab::SimilarImages => StrDataSimilarImages::Name as usize, + CurrentTab::DuplicateFiles => StrDataDuplicateFiles::Name as usize, + CurrentTab::BigFiles => StrDataBigFiles::Name as usize, + CurrentTab::TemporaryFiles => StrDataTemporaryFiles::Name as usize, + CurrentTab::SimilarVideos => StrDataSimilarVideos::Name as usize, + CurrentTab::SimilarMusic => StrDataSimilarMusic::Name as usize, + CurrentTab::InvalidSymlinks => StrDataInvalidSymlinks::SymlinkName as usize, + CurrentTab::BrokenFiles => StrDataBrokenFiles::Name as usize, + CurrentTab::BadExtensions => StrDataBadExtensions::Name as usize, CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -78,6 +221,14 @@ pub fn get_int_modification_date_idx(active_tab: CurrentTab) -> usize { CurrentTab::EmptyFiles => IntDataEmptyFiles::ModificationDatePart1 as usize, CurrentTab::EmptyFolders => IntDataEmptyFolders::ModificationDatePart1 as usize, CurrentTab::SimilarImages => IntDataSimilarImages::ModificationDatePart1 as usize, + CurrentTab::DuplicateFiles => IntDataDuplicateFiles::ModificationDatePart1 as usize, + CurrentTab::BigFiles => IntDataBigFiles::ModificationDatePart1 as usize, + CurrentTab::TemporaryFiles => IntDataTemporaryFiles::ModificationDatePart1 as usize, + CurrentTab::SimilarVideos => IntDataSimilarVideos::ModificationDatePart1 as usize, + CurrentTab::SimilarMusic => IntDataSimilarMusic::ModificationDatePart1 as usize, + CurrentTab::InvalidSymlinks => IntDataInvalidSymlinks::ModificationDatePart1 as usize, + CurrentTab::BrokenFiles => IntDataBrokenFiles::ModificationDatePart1 as usize, + CurrentTab::BadExtensions => IntDataBadExtensions::ModificationDatePart1 as usize, CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -86,8 +237,15 @@ pub fn get_int_size_idx(active_tab: CurrentTab) -> usize { match active_tab { CurrentTab::EmptyFiles => IntDataEmptyFiles::SizePart1 as usize, CurrentTab::SimilarImages => IntDataSimilarImages::SizePart1 as usize, + CurrentTab::DuplicateFiles => IntDataDuplicateFiles::SizePart1 as usize, + CurrentTab::BigFiles => IntDataBigFiles::SizePart1 as usize, + CurrentTab::TemporaryFiles => IntDataTemporaryFiles::SizePart1 as usize, + CurrentTab::SimilarVideos => IntDataSimilarVideos::SizePart1 as usize, + CurrentTab::SimilarMusic => IntDataSimilarMusic::SizePart1 as usize, + CurrentTab::BrokenFiles => IntDataBrokenFiles::SizePart1 as usize, + CurrentTab::BadExtensions => IntDataBadExtensions::SizePart1 as usize, CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), - CurrentTab::EmptyFolders => panic!("Unable to get size from this tab"), + CurrentTab::EmptyFolders | CurrentTab::InvalidSymlinks => panic!("Unable to get size from this tab"), } } @@ -109,8 +267,14 @@ pub fn get_int_height_idx(active_tab: CurrentTab) -> usize { pub fn get_is_header_mode(active_tab: CurrentTab) -> bool { match active_tab { - CurrentTab::EmptyFolders | CurrentTab::EmptyFiles => false, - CurrentTab::SimilarImages => true, + CurrentTab::EmptyFolders + | CurrentTab::EmptyFiles + | CurrentTab::BrokenFiles + | CurrentTab::BigFiles + | CurrentTab::TemporaryFiles + | CurrentTab::InvalidSymlinks + | CurrentTab::BadExtensions => false, + CurrentTab::SimilarImages | CurrentTab::DuplicateFiles | CurrentTab::SimilarVideos | CurrentTab::SimilarMusic => true, CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -120,6 +284,14 @@ 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::DuplicateFiles => app.get_duplicate_files_model(), + CurrentTab::BigFiles => app.get_big_files_model(), + CurrentTab::TemporaryFiles => app.get_temporary_files_model(), + CurrentTab::SimilarVideos => app.get_similar_videos_model(), + CurrentTab::SimilarMusic => app.get_similar_music_model(), + CurrentTab::InvalidSymlinks => app.get_invalid_symlinks_model(), + CurrentTab::BrokenFiles => app.get_broken_files_model(), + CurrentTab::BadExtensions => app.get_bad_extensions_model(), CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } @@ -129,6 +301,14 @@ 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::DuplicateFiles => app.set_duplicate_files_model(model), + CurrentTab::BigFiles => app.set_big_files_model(model), + CurrentTab::TemporaryFiles => app.set_temporary_files_model(model), + CurrentTab::SimilarVideos => app.set_similar_videos_model(model), + CurrentTab::SimilarMusic => app.set_similar_music_model(model), + CurrentTab::InvalidSymlinks => app.set_invalid_symlinks_model(model), + CurrentTab::BrokenFiles => app.set_broken_files_model(model), + CurrentTab::BadExtensions => app.set_bad_extensions_model(model), CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"), } } diff --git a/krokiet/src/connect_scan.rs b/krokiet/src/connect_scan.rs index bde53a4..c56ef8c 100644 --- a/krokiet/src/connect_scan.rs +++ b/krokiet/src/connect_scan.rs @@ -3,6 +3,7 @@ use std::thread; use chrono::NaiveDateTime; use crossbeam_channel::{Receiver, Sender}; +use czkawka_core::big_file::BigFile; use humansize::{format_size, BINARY}; use rayon::prelude::*; use slint::{ComponentHandle, ModelRc, SharedString, VecModel, Weak}; @@ -11,6 +12,7 @@ use czkawka_core::common::{split_path, split_path_compare, DEFAULT_THREAD_SIZE}; use czkawka_core::common_dir_traversal::{FileEntry, ProgressData}; use czkawka_core::common_tool::CommonData; use czkawka_core::common_traits::ResultEntry; +use czkawka_core::duplicate::DuplicateFinder; use czkawka_core::empty_files::EmptyFiles; use czkawka_core::empty_folder::{EmptyFolder, FolderEntry}; use czkawka_core::similar_images; @@ -18,6 +20,7 @@ use czkawka_core::similar_images::{ImagesEntry, SimilarImages}; use crate::common::split_u64_into_i32s; use crate::settings::{collect_settings, SettingsCustom, ALLOWED_HASH_TYPE_VALUES, ALLOWED_RESIZE_ALGORITHM_VALUES}; +use crate::CurrentTab::DuplicateFiles; use crate::{CurrentTab, GuiState, MainListModel, MainWindow, ProgressToSend}; pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender, stop_receiver: Receiver<()>) { @@ -47,10 +50,183 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender panic!("Button should be disabled"), + _ => unimplemented!(), } }); } +// Scan Duplicates + +// fn scan_duplicates(a: Weak, progress_sender: Sender, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) { +// thread::Builder::new() +// .stack_size(DEFAULT_THREAD_SIZE) +// .spawn(move || { +// let mut finder = DuplicateFinder::new(); +// set_common_settings(&mut finder, &custom_settings); +// // TODO Fill rest of settings +// finder.find_duplicates(Some(&stop_receiver), Some(&progress_sender)); +// +// if finder.get_use_reference() { +// let mut vector = finder.get_ref().clone(); +// let messages = finder.get_text_messages().create_messages_text(); +// +// for (_first_entry, vec_fe) in &mut vector { +// vec_fe.par_sort_unstable_by_key(|e| e.similarity); +// } +// +// a.upgrade_in_event_loop(move |app| { +// write_duplicates_results_referenced(&app, vector, messages); +// }) +// } else { +// let mut vector = finder.get_similar_images().clone(); +// let messages = finder.get_text_messages().create_messages_text(); +// +// for vec_fe in &mut vector { +// vec_fe.par_sort_unstable_by_key(|e| e.similarity); +// } +// +// a.upgrade_in_event_loop(move |app| { +// write_duplicates_results(&app, vector, messages); +// }) +// } +// }) +// .unwrap(); +// } +// fn write_duplicates_results_referenced(app: &MainWindow, vector: Vec<(ImagesEntry, Vec)>, messages: String) { +// let items_found = vector.len(); +// let items = Rc::new(VecModel::default()); +// for (ref_fe, vec_fe) in vector { +// let (data_model_str, data_model_int) = prepare_data_model_duplicates(&ref_fe); +// insert_data_to_model(&items, data_model_str, data_model_int, true); +// +// for fe in vec_fe { +// let (data_model_str, data_model_int) = prepare_data_model_duplicates(&fe); +// insert_data_to_model(&items, data_model_str, data_model_int, false); +// } +// } +// app.set_duplicate_files_model(items.into()); +// app.invoke_scan_ended(format!("Found {items_found} duplicate files").into()); +// app.global::().set_info_text(messages.into()); +// } +// fn write_duplicates_results(app: &MainWindow, vector: Vec>, messages: String) { +// let items_found = vector.len(); +// let items = Rc::new(VecModel::default()); +// for vec_fe in vector { +// insert_data_to_model(&items, ModelRc::new(VecModel::default()), ModelRc::new(VecModel::default()), true); +// for fe in vec_fe { +// let (data_model_str, data_model_int) = prepare_data_model_duplicates(&fe); +// insert_data_to_model(&items, data_model_str, data_model_int, false); +// } +// } +// app.set_duplicate_files_model(items.into()); +// app.invoke_scan_ended(format!("Found {items_found} duplicate files").into()); +// app.global::().set_info_text(messages.into()); +// } +// fn prepare_data_model_duplicates(fe: &ImagesEntry) -> (ModelRc, ModelRc) { +// let (directory, file) = split_path(fe.get_path()); +// let data_model_str = VecModel::from_slice(&[ +// format_size(fe.size, BINARY).into(), +// file.into(), +// directory.into(), +// NaiveDateTime::from_timestamp_opt(fe.get_modified_date() as i64, 0).unwrap().to_string().into(), +// ]); +// let modification_split = split_u64_into_i32s(fe.get_modified_date()); +// let size_split = split_u64_into_i32s(fe.size); +// let data_model_int = VecModel::from_slice(&[modification_split.0, modification_split.1, size_split.0, size_split.1]); +// (data_model_str, data_model_int) +// } + +////////////////////////////////////////// Empty Folders +fn scan_empty_folders(a: Weak, progress_sender: Sender, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) { + thread::Builder::new() + .stack_size(DEFAULT_THREAD_SIZE) + .spawn(move || { + let mut finder = EmptyFolder::new(); + set_common_settings(&mut finder, &custom_settings); + finder.find_empty_folders(Some(&stop_receiver), Some(&progress_sender)); + + let mut vector = finder.get_empty_folder_list().values().cloned().collect::>(); + let messages = finder.get_text_messages().create_messages_text(); + + vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path())); + + a.upgrade_in_event_loop(move |app| { + write_empty_folders_results(&app, vector, messages); + }) + }) + .unwrap(); +} +fn write_empty_folders_results(app: &MainWindow, vector: Vec, messages: String) { + let items_found = vector.len(); + let items = Rc::new(VecModel::default()); + for fe in vector { + let (data_model_str, data_model_int) = prepare_data_model_empty_folders(&fe); + insert_data_to_model(&items, data_model_str, data_model_int, false); + } + app.set_empty_folder_model(items.into()); + app.invoke_scan_ended(format!("Found {items_found} empty folders").into()); + app.global::().set_info_text(messages.into()); +} + +fn prepare_data_model_empty_folders(fe: &FolderEntry) -> (ModelRc, ModelRc) { + let (directory, file) = split_path(&fe.path); + let data_model_str = VecModel::from_slice(&[ + file.into(), + directory.into(), + NaiveDateTime::from_timestamp_opt(fe.modified_date as i64, 0).unwrap().to_string().into(), + ]); + let modification_split = split_u64_into_i32s(fe.get_modified_date()); + let data_model_int = VecModel::from_slice(&[modification_split.0, modification_split.1]); + (data_model_str, data_model_int) +} + +////////////////////////////////////////// Big files +fn scan_big_files(a: Weak, progress_sender: Sender, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) { + thread::Builder::new() + .stack_size(DEFAULT_THREAD_SIZE) + .spawn(move || { + let mut finder = BigFile::new(); + set_common_settings(&mut finder, &custom_settings); + finder.find_big_files(Some(&stop_receiver), Some(&progress_sender)); + + let mut vector = finder.get_big_files().clone(); + let messages = finder.get_text_messages().create_messages_text(); + + vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path())); + + a.upgrade_in_event_loop(move |app| { + crate::connect_scan::write_big_files_results(&app, vector, messages); + }) + }) + .unwrap(); +} +fn write_big_files_results(app: &MainWindow, vector: Vec, messages: String) { + let items_found = vector.len(); + let items = Rc::new(VecModel::default()); + for fe in vector { + let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_big_files(&fe); + insert_data_to_model(&items, data_model_str, data_model_int, false); + } + app.set_empty_folder_model(items.into()); + app.invoke_scan_ended(format!("Found {items_found} empty folders").into()); + app.global::().set_info_text(messages.into()); +} + +fn prepare_data_model_big_files(fe: &FileEntry) -> (ModelRc, ModelRc) { + let (directory, file) = split_path(&fe.path); + let data_model_str = VecModel::from_slice(&[ + format_size(fe.size, BINARY).into(), + file.into(), + directory.into(), + NaiveDateTime::from_timestamp_opt(fe.modified_date as i64, 0).unwrap().to_string().into(), + ]); + let modification_split = split_u64_into_i32s(fe.get_modified_date()); + let size_split = split_u64_into_i32s(fe.size); + let data_model_int = VecModel::from_slice(&[modification_split.0, modification_split.1, size_split.0, size_split.1]); + (data_model_str, data_model_int) +} +// Scan Similar Images + fn scan_similar_images(a: Weak, progress_sender: Sender, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) { thread::Builder::new() .stack_size(DEFAULT_THREAD_SIZE) @@ -70,62 +246,46 @@ fn scan_similar_images(a: Weak, progress_sender: Sender>(); } else { - let mut vector = finder.get_similar_images().clone(); - let messages = finder.get_text_messages().create_messages_text(); - - let hash_size = custom_settings.similar_images_sub_hash_size; - - for vec_fe in &mut vector { - vec_fe.par_sort_unstable_by_key(|e| e.similarity); - } - - a.upgrade_in_event_loop(move |app| { - write_similar_images_results(&app, vector, messages, hash_size); - }) + vector = finder.get_similar_images().iter().cloned().map(|items| (None, items)).collect::>(); } + for (_first_entry, vec_fe) in &mut vector { + vec_fe.par_sort_unstable_by_key(|e| e.similarity); + } + + a.upgrade_in_event_loop(move |app| { + write_similar_images_results(&app, vector, messages, hash_size); + }) }) .unwrap(); } -fn write_similar_images_results_referenced(app: &MainWindow, vector: Vec<(ImagesEntry, Vec)>, messages: String, hash_size: u8) { +fn write_similar_images_results(app: &MainWindow, vector: Vec<(Option, Vec)>, messages: String, hash_size: u8) { let items_found = vector.len(); let items = Rc::new(VecModel::default()); for (ref_fe, vec_fe) in vector { - let (data_model_str, data_model_int) = prepare_data_model_similar_images(&ref_fe, hash_size); - insert_data_to_model(&items, data_model_str, data_model_int, true); - - for fe in vec_fe { - let (data_model_str, data_model_int) = prepare_data_model_similar_images(&fe, hash_size); - insert_data_to_model(&items, data_model_str, data_model_int, false); + if let Some(ref_fe) = ref_fe { + let (data_model_str, data_model_int) = prepare_data_model_similar_images(&ref_fe, hash_size); + insert_data_to_model(&items, data_model_str, data_model_int, true); + } else { + insert_data_to_model(&items, ModelRc::new(VecModel::default()), ModelRc::new(VecModel::default()), true); } - } - app.set_similar_images_model(items.into()); - app.invoke_scan_ended(format!("Found {items_found} similar images files").into()); - app.global::().set_info_text(messages.into()); -} -fn write_similar_images_results(app: &MainWindow, vector: Vec>, messages: String, hash_size: u8) { - let items_found = vector.len(); - let items = Rc::new(VecModel::default()); - for vec_fe in vector { - insert_data_to_model(&items, ModelRc::new(VecModel::default()), ModelRc::new(VecModel::default()), true); + for fe in vec_fe { let (data_model_str, data_model_int) = prepare_data_model_similar_images(&fe, hash_size); insert_data_to_model(&items, data_model_str, data_model_int, false); @@ -196,50 +356,6 @@ fn prepare_data_model_empty_files(fe: &FileEntry) -> (ModelRc, Mod (data_model_str, data_model_int) } -////////////////////////////////////////// Empty Folders -fn scan_empty_folders(a: Weak, progress_sender: Sender, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) { - thread::Builder::new() - .stack_size(DEFAULT_THREAD_SIZE) - .spawn(move || { - let mut finder = EmptyFolder::new(); - set_common_settings(&mut finder, &custom_settings); - finder.find_empty_folders(Some(&stop_receiver), Some(&progress_sender)); - - let mut vector = finder.get_empty_folder_list().values().cloned().collect::>(); - let messages = finder.get_text_messages().create_messages_text(); - - vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path())); - - a.upgrade_in_event_loop(move |app| { - write_empty_folders_results(&app, vector, messages); - }) - }) - .unwrap(); -} -fn write_empty_folders_results(app: &MainWindow, vector: Vec, messages: String) { - let items_found = vector.len(); - let items = Rc::new(VecModel::default()); - for fe in vector { - let (data_model_str, data_model_int) = prepare_data_model_empty_folders(&fe); - insert_data_to_model(&items, data_model_str, data_model_int, false); - } - app.set_empty_folder_model(items.into()); - app.invoke_scan_ended(format!("Found {items_found} empty folders").into()); - app.global::().set_info_text(messages.into()); -} - -fn prepare_data_model_empty_folders(fe: &FolderEntry) -> (ModelRc, ModelRc) { - let (directory, file) = split_path(&fe.path); - let data_model_str = VecModel::from_slice(&[ - file.into(), - directory.into(), - NaiveDateTime::from_timestamp_opt(fe.modified_date as i64, 0).unwrap().to_string().into(), - ]); - let modification_split = split_u64_into_i32s(fe.get_modified_date()); - let data_model_int = VecModel::from_slice(&[modification_split.0, modification_split.1]); - (data_model_str, data_model_int) -} - ////////////////////////////////////////// Common fn insert_data_to_model(items: &Rc>, data_model_str: ModelRc, data_model_int: ModelRc, header_row: bool) { let main = MainListModel { diff --git a/krokiet/ui/common.slint b/krokiet/ui/common.slint index 61df0ed..6a9f2ed 100644 --- a/krokiet/ui/common.slint +++ b/krokiet/ui/common.slint @@ -6,7 +6,7 @@ export enum CurrentTab { TemporaryFiles, SimilarImages, SimilarVideos, - MusicDuplicates, + SimilarMusic, InvalidSymlinks, BrokenFiles, BadExtensions, diff --git a/krokiet/ui/left_side_panel.slint b/krokiet/ui/left_side_panel.slint index b4aaf3a..6ab414e 100644 --- a/krokiet/ui/left_side_panel.slint +++ b/krokiet/ui/left_side_panel.slint @@ -97,7 +97,7 @@ export component LeftSidePanel { {name: "Temporary Files", tab: CurrentTab.TemporaryFiles}, {name: "Similar Images", tab: CurrentTab.SimilarImages}, {name: "Similar Videos", tab: CurrentTab.SimilarVideos}, - {name: "Music Duplicates", tab: CurrentTab.MusicDuplicates}, + {name: "Music Duplicates", tab: CurrentTab.SimilarMusic}, {name: "Invalid Symlinks", tab: CurrentTab.InvalidSymlinks}, {name: "Broken Files", tab: CurrentTab.BrokenFiles}, {name: "Bad Extensions", tab: CurrentTab.BadExtensions}