1
0
Fork 0
mirror of synced 2024-05-03 03:52:58 +12:00
This commit is contained in:
Rafał Mikrut 2024-02-15 11:45:59 +01:00
parent da6779735c
commit 2609064860
4 changed files with 398 additions and 102 deletions

View file

@ -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<MainListMode
CurrentTab::EmptyFolders => 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<MainList
CurrentTab::EmptyFolders => 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"),
}
}

View file

@ -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<ProgressData>, stop_receiver: Receiver<()>) {
@ -47,10 +50,183 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender<ProgressDat
scan_similar_images(a, progress_sender, stop_receiver, custom_settings);
}
CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"),
_ => unimplemented!(),
}
});
}
// Scan Duplicates
// fn scan_duplicates(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, 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<ImagesEntry>)>, 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::<GuiState>().set_info_text(messages.into());
// }
// fn write_duplicates_results(app: &MainWindow, vector: Vec<Vec<ImagesEntry>>, 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::<GuiState>().set_info_text(messages.into());
// }
// fn prepare_data_model_duplicates(fe: &ImagesEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
// 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<MainWindow>, progress_sender: Sender<ProgressData>, 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::<Vec<_>>();
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<FolderEntry>, 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::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_empty_folders(fe: &FolderEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
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<MainWindow>, progress_sender: Sender<ProgressData>, 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<FileEntry>, 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::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_big_files(fe: &FileEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
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<MainWindow>, progress_sender: Sender<ProgressData>, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) {
thread::Builder::new()
.stack_size(DEFAULT_THREAD_SIZE)
@ -70,62 +246,46 @@ fn scan_similar_images(a: Weak<MainWindow>, progress_sender: Sender<ProgressData
.expect("Hash type not found")
.2;
finder.set_hash_alg(hash_type);
dbg!(&custom_settings.similar_images_sub_ignore_same_size);
finder.set_exclude_images_with_same_size(custom_settings.similar_images_sub_ignore_same_size);
finder.set_similarity(custom_settings.similar_images_sub_similarity as u32);
finder.find_similar_images(Some(&stop_receiver), Some(&progress_sender));
let messages = finder.get_text_messages().create_messages_text();
let hash_size = custom_settings.similar_images_sub_hash_size;
let mut vector;
if finder.get_use_reference() {
let mut vector = finder.get_similar_images_referenced().clone();
let messages = finder.get_text_messages().create_messages_text();
let hash_size = custom_settings.similar_images_sub_hash_size;
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_referenced(&app, vector, messages, hash_size);
})
vector = finder
.get_similar_images_referenced()
.iter()
.cloned()
.map(|(original, others)| (Some(original), others))
.collect::<Vec<_>>();
} 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::<Vec<_>>();
}
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<ImagesEntry>)>, messages: String, hash_size: u8) {
fn write_similar_images_results(app: &MainWindow, vector: Vec<(Option<ImagesEntry>, Vec<ImagesEntry>)>, 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::<GuiState>().set_info_text(messages.into());
}
fn write_similar_images_results(app: &MainWindow, vector: Vec<Vec<ImagesEntry>>, 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<SharedString>, Mod
(data_model_str, data_model_int)
}
////////////////////////////////////////// Empty Folders
fn scan_empty_folders(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, 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::<Vec<_>>();
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<FolderEntry>, 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::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_empty_folders(fe: &FolderEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
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<VecModel<MainListModel>>, data_model_str: ModelRc<SharedString>, data_model_int: ModelRc<i32>, header_row: bool) {
let main = MainListModel {

View file

@ -6,7 +6,7 @@ export enum CurrentTab {
TemporaryFiles,
SimilarImages,
SimilarVideos,
MusicDuplicates,
SimilarMusic,
InvalidSymlinks,
BrokenFiles,
BadExtensions,

View file

@ -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}