More
This commit is contained in:
parent
da6779735c
commit
2609064860
|
@ -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"),
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -6,7 +6,7 @@ export enum CurrentTab {
|
|||
TemporaryFiles,
|
||||
SimilarImages,
|
||||
SimilarVideos,
|
||||
MusicDuplicates,
|
||||
SimilarMusic,
|
||||
InvalidSymlinks,
|
||||
BrokenFiles,
|
||||
BadExtensions,
|
||||
|
|
|
@ -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}
|
||||
|
|
Loading…
Reference in a new issue