1
0
Fork 0
mirror of synced 2024-05-02 19:44:09 +12:00
This commit is contained in:
Rafał Mikrut 2024-02-15 13:49:23 +01:00
parent 2609064860
commit 2310b7a6e9
6 changed files with 153 additions and 102 deletions

View file

@ -1 +1,5 @@
<svg height="48" viewBox="0 0 48 48" width="48" xmlns="http://www.w3.org/2000/svg"><path d="m39.6 27.2c.1-.7.2-1.4.2-2.2s-.1-1.5-.2-2.2l4.5-3.2c.4-.3.6-.9.3-1.4l-4.4-7.4c-.3-.5-.8-.7-1.3-.4l-5 2.3c-1.2-.9-2.4-1.6-3.8-2.2l-.5-5.5c-.1-.5-.5-.9-1-.9h-8.6c-.5 0-1 .4-1 .9l-.5 5.5c-1.4.6-2.7 1.3-3.8 2.2l-5-2.3c-.5-.2-1.1 0-1.3.4l-4.3 7.4c-.3.5-.1 1.1.3 1.4l4.5 3.2c-.1.7-.2 1.4-.2 2.2s.1 1.5.2 2.2l-4.7 3.2c-.4.3-.6.9-.3 1.4l4.3 7.4c.3.5.8.7 1.3.4l5-2.3c1.2.9 2.4 1.6 3.8 2.2l.5 5.5c.1.5.5.9 1 .9h8.6c.5 0 1-.4 1-.9l.5-5.5c1.4-.6 2.7-1.3 3.8-2.2l5 2.3c.5.2 1.1 0 1.3-.4l4.3-7.4c.3-.5.1-1.1-.3-1.4zm-15.6 7.8c-5.5 0-10-4.5-10-10s4.5-10 10-10 10 4.5 10 10-4.5 10-10 10z" fill="#607d8b"/><path d="m24 13c-6.6 0-12 5.4-12 12s5.4 12 12 12 12-5.4 12-12-5.4-12-12-12zm0 17c-2.8 0-5-2.2-5-5s2.2-5 5-5 5 2.2 5 5-2.2 5-5 5z" fill="#455a64"/></svg>
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path d="m296 186.72a80 80 0 1 0 29.282 109.28 80.24 80.24 0 0 0-29.282-109.28zm109.58 155.64a165.53 165.53 0 0 1-12.59 18.527l23.107 57.358a11.59 11.59 0 0 1-5.1124 14.115l-79.649 45.836a11.64 11.64 0 0 1-14.711-2.8005l-38.08-48.544a176.56 176.56 0 0 1-44.954 0.2228l-37.803 48.357a11.93 11.93 0 0 1-14.898 2.784l-79.778-46.06a12 12 0 0 1-5.203-14.008l22.977-56.917a169.3 169.3 0 0 1-22.274-39.06l-61.08-8.7064a11.64 11.64 0 0 1-9.7856-11.331l-0.13413-91.888a11.59 11.59 0 0 1 9.6676-11.485l61.227-8.6679a174.58 174.58 0 0 1 9.9147-20.453 165.53 165.53 0 0 1 12.59-18.527l-23.107-57.358a11.59 11.59 0 0 1 5.1124-14.115l79.649-45.836a11.64 11.64 0 0 1 14.711 2.8005l38.08 48.544a176.56 176.56 0 0 1 44.954-0.2228l37.803-48.357a11.93 11.93 0 0 1 14.898-2.784l79.778 46.06a12 12 0 0 1 5.203 14.008l-22.977 56.917a169.3 169.3 0 0 1 22.317 39.085l61.037 8.6814a11.64 11.64 0 0 1 9.7856 11.331l0.12913 91.896a11.59 11.59 0 0 1-9.6676 11.485l-61.227 8.6679a174.58 174.58 0 0 1-9.9097 20.444z"/>
</svg>

Before

Width:  |  Height:  |  Size: 833 B

After

Width:  |  Height:  |  Size: 1.1 KiB

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="UTF-8"?>
<svg version="1.1" viewBox="0 0 512 512" xmlns="http://www.w3.org/2000/svg">
<path d="m259.96 178.63c-116.38 0.46054-109.81 154.42-4.8963 157.07 110.82 2.7975 108.63-157.48 4.8963-157.07zm-4.5114 238.17-59.661 58.623c-3.663 4.3684-9.9047 5.5348-14.898 2.784l-79.778-46.06c-4.7847-2.888-6.9422-8.6968-5.203-14.008l22.977-56.917c-9.1283-11.972-16.619-25.108-22.274-39.06l-61.08-8.7064c-5.5804-0.89998-9.7077-5.679-9.7856-11.331l-0.13413-91.888c-0.02721-5.6801 4.0661-10.543 9.6676-11.485l61.227-8.6679c2.8571-7.0258 6.169-13.858 9.9147-20.453 3.7735-6.4529 7.9798-12.643 12.59-18.527l-23.107-57.358c-1.985-5.3221 0.17966-11.298 5.1124-14.115l79.649-45.836c4.933-2.7634 11.138-1.5821 14.711 2.8005l66.966 73.793c-6.8372 161.75-1.2386 214.48-6.8946 306.41z"/>
<rect x="275" y="50" width="200" height="20" stroke-width=".8921"/>
<rect x="275" y="85" width="200" height="20" stroke-width=".8921"/>
<rect x="275" y="120" width="200" height="20" stroke-width=".8921"/>
<rect x="275" y="155" width="200" height="20" stroke-width=".8921"/>
<rect x="335" y="190" width="140" height="20" stroke-width=".74638"/>
<rect x="345" y="225" width="130" height="20" stroke-width=".71923"/>
<rect transform="scale(1,-1)" x="273.16" y="-466.69" width="199.81" height="20" stroke-width=".89168"/>
<rect transform="scale(1,-1)" x="273.16" y="-431.69" width="199.81" height="20" stroke-width=".89168"/>
<rect transform="scale(1,-1)" x="273.16" y="-396.69" width="199.81" height="20" stroke-width=".89168"/>
<rect transform="scale(1,-1)" x="273.16" y="-361.69" width="199.81" height="20" stroke-width=".89168"/>
<rect transform="scale(1,-1)" x="333.1" y="-326.69" width="139.87" height="20" stroke-width=".74603"/>
<rect transform="scale(1,-1)" x="343.09" y="-291.69" width="129.88" height="20" stroke-width=".71889"/>
</svg>

After

Width:  |  Height:  |  Size: 1.8 KiB

View file

@ -1,3 +1,4 @@
#![allow(dead_code)] // TODO later remove
use std::path::PathBuf;
use crate::{CurrentTab, ExcludedDirectoriesModel, IncludedDirectoriesModel, MainListModel, MainWindow};

View file

@ -9,10 +9,10 @@ use rayon::prelude::*;
use slint::{ComponentHandle, ModelRc, SharedString, VecModel, Weak};
use czkawka_core::common::{split_path, split_path_compare, DEFAULT_THREAD_SIZE};
use czkawka_core::common_dir_traversal::{FileEntry, ProgressData};
use czkawka_core::common_dir_traversal::{CheckingMethod, FileEntry, ProgressData};
use czkawka_core::common_tool::CommonData;
use czkawka_core::common_traits::ResultEntry;
use czkawka_core::duplicate::DuplicateFinder;
use czkawka_core::duplicate::{DuplicateEntry, DuplicateFinder};
use czkawka_core::empty_files::EmptyFiles;
use czkawka_core::empty_folder::{EmptyFolder, FolderEntry};
use czkawka_core::similar_images;
@ -20,7 +20,6 @@ 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<()>) {
@ -49,6 +48,12 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender<ProgressDat
CurrentTab::SimilarImages => {
scan_similar_images(a, progress_sender, stop_receiver, custom_settings);
}
CurrentTab::BigFiles => {
scan_big_files(a, progress_sender, stop_receiver, custom_settings);
}
CurrentTab::DuplicateFiles => {
scan_duplicates(a, progress_sender, stop_receiver, custom_settings);
}
CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"),
_ => unimplemented!(),
}
@ -57,84 +62,109 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender<ProgressDat
// 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)
// }
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.set_check_method(CheckingMethod::Hash);
// finder.set_minimal_cache_file_size(loaded_commons.minimal_cache_file_size);
// finder.set_minimal_prehash_cache_file_size(minimal_prehash_cache_file_size);
// finder.set_check_method(check_method);
// finder.set_hash_type(hash_type);
// finder.set_ignore_hard_links(loaded_commons.hide_hard_links);
// finder.set_use_prehash_cache(use_prehash_cache);
// finder.set_delete_outdated_cache(delete_outdated_cache);
// finder.set_case_sensitive_name_comparison(case_sensitive_name_comparison);
finder.find_duplicates(Some(&stop_receiver), Some(&progress_sender));
let messages = finder.get_text_messages().create_messages_text();
let mut vector;
if finder.get_use_reference() {
match finder.get_check_method() {
CheckingMethod::Hash => {
vector = finder
.get_files_with_identical_hashes_referenced()
.values()
.cloned()
.flatten()
.map(|(original, other)| (Some(original), other))
.collect::<Vec<_>>();
}
CheckingMethod::Name | CheckingMethod::Size | CheckingMethod::SizeName => {
let values: Vec<_> = match finder.get_check_method() {
CheckingMethod::Name => finder.get_files_with_identical_name_referenced().values().cloned().collect(),
CheckingMethod::Size => finder.get_files_with_identical_size_referenced().values().cloned().collect(),
CheckingMethod::SizeName => finder.get_files_with_identical_size_names_referenced().values().cloned().collect(),
_ => unreachable!("Invalid check method."),
};
vector = values.into_iter().map(|(original, other)| (Some(original), other)).collect::<Vec<_>>();
}
_ => unreachable!("Invalid check method."),
}
} else {
match finder.get_check_method() {
CheckingMethod::Hash => {
vector = finder.get_files_sorted_by_hash().values().cloned().flatten().map(|items| (None, items)).collect::<Vec<_>>();
}
CheckingMethod::Name | CheckingMethod::Size | CheckingMethod::SizeName => {
let values: Vec<_> = match finder.get_check_method() {
CheckingMethod::Name => finder.get_files_sorted_by_names().values().cloned().collect(),
CheckingMethod::Size => finder.get_files_sorted_by_size().values().cloned().collect(),
CheckingMethod::SizeName => finder.get_files_sorted_by_size_name().values().cloned().collect(),
_ => unreachable!("Invalid check method."),
};
vector = values.into_iter().map(|items| (None, items)).collect::<Vec<_>>();
}
_ => unreachable!("Invalid check method."),
}
}
for (_first, vec) in &mut vector {
vec.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_duplicate_results(&app, vector, messages);
})
})
.unwrap();
}
fn write_duplicate_results(app: &MainWindow, vector: Vec<(Option<DuplicateEntry>, Vec<DuplicateEntry>)>, messages: String) {
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for (ref_fe, vec_fe) in vector {
if let Some(ref_fe) = ref_fe {
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);
} else {
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_similar_images_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} similar duplicates files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_duplicates(fe: &DuplicateEntry) -> (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) {
@ -195,7 +225,7 @@ fn scan_big_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, st
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);
write_big_files_results(&app, vector, messages);
})
})
.unwrap();
@ -204,11 +234,11 @@ fn write_big_files_results(app: &MainWindow, vector: Vec<FileEntry>, messages: S
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);
let (data_model_str, data_model_int) = 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.invoke_scan_ended(format!("Found {items_found} files").into());
app.global::<GuiState>().set_info_text(messages.into());
}

View file

@ -2,12 +2,11 @@ use std::panic;
use std::path::Path;
use std::time::{Duration, Instant};
use czkawka_core::broken_files::BrokenEntry;
use image::DynamicImage;
use log::{debug, error};
use slint::ComponentHandle;
use czkawka_core::common::{create_crash_message, get_dynamic_image_from_raw_image, IMAGE_RS_EXTENSIONS, RAW_IMAGE_EXTENSIONS};
use czkawka_core::common::{get_dynamic_image_from_raw_image, IMAGE_RS_EXTENSIONS, RAW_IMAGE_EXTENSIONS};
use crate::{Callabler, CurrentTab, GuiState, MainWindow, Settings};
@ -72,7 +71,7 @@ fn convert_into_slint_image(img: DynamicImage) -> slint::Image {
slint::Image::from_rgba8(buffer)
}
fn load_image(image_path: &Path) -> Option<(Duration, image::DynamicImage)> {
fn load_image(image_path: &Path) -> Option<(Duration, DynamicImage)> {
if !image_path.is_file() {
return None;
}

View file

@ -116,20 +116,6 @@ export component LeftSidePanel {
Rectangle {
HorizontalLayout {
alignment: start;
Button {
visible: GuiState.available_subsettings;
min-width: 20px;
min-height: 20px;
max-height: self.width;
preferred-height: self.width;
icon: @image-url("../icons/settings.svg");
clicked => {
GuiState.visible_tool_settings = !GuiState.visible-tool-settings;
}
}
}
HorizontalLayout {
alignment: end;
Button {
visible: GuiState.active_tab != CurrentTab.Settings;
min-width: 20px;
@ -144,6 +130,20 @@ export component LeftSidePanel {
}
}
}
HorizontalLayout {
alignment: end;
Button {
visible: GuiState.available_subsettings;
min-width: 20px;
min-height: 20px;
max-height: self.width;
preferred-height: self.width;
icon: @image-url("../icons/subsettings.svg");
clicked => {
GuiState.visible_tool_settings = !GuiState.visible-tool-settings;
}
}
}
}
}
}