1
0
Fork 0
mirror of synced 2024-05-03 12:03:22 +12:00

Subsettings

This commit is contained in:
Rafał Mikrut 2024-02-15 19:15:13 +01:00
parent 2cc8b97035
commit 062785c008
11 changed files with 241 additions and 33 deletions

View file

@ -32,11 +32,20 @@ const TEMP_EXTENSIONS: &[&str] = &[
];
#[derive(Clone, Serialize, Debug)]
pub struct FileEntry {
pub struct TemporaryFileEntry {
pub path: PathBuf,
pub modified_date: u64,
}
impl TemporaryFileEntry {
pub fn get_path(&self) -> &PathBuf {
&self.path
}
pub fn get_modified_date(&self) -> u64 {
self.modified_date
}
}
#[derive(Default)]
pub struct Info {
pub number_of_temporary_files: usize,
@ -45,7 +54,7 @@ pub struct Info {
pub struct Temporary {
common_data: CommonToolData,
information: Info,
temporary_files: Vec<FileEntry>,
temporary_files: Vec<TemporaryFileEntry>,
}
impl Temporary {
@ -138,7 +147,7 @@ impl Temporary {
true
}
pub fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>) -> Option<FileEntry> {
pub fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>) -> Option<TemporaryFileEntry> {
atomic_counter.fetch_add(1, Ordering::Relaxed);
let current_file_name = entry_data.path();
@ -158,7 +167,7 @@ impl Temporary {
};
// Creating new file entry
Some(FileEntry {
Some(TemporaryFileEntry {
modified_date: get_modified_time(&metadata, warnings, &current_file_name, false),
path: current_file_name,
})
@ -234,7 +243,7 @@ impl CommonData for Temporary {
}
impl Temporary {
pub const fn get_temporary_files(&self) -> &Vec<FileEntry> {
pub const fn get_temporary_files(&self) -> &Vec<TemporaryFileEntry> {
&self.temporary_files
}

View file

@ -73,12 +73,9 @@ pub enum StrDataEmptyFiles {
pub enum IntDataTemporaryFiles {
ModificationDatePart1,
ModificationDatePart2,
SizePart1,
SizePart2,
}
#[repr(u8)]
pub enum StrDataTemporaryFiles {
Size,
Name,
Path,
ModificationDate,
@ -253,13 +250,12 @@ pub fn get_int_size_idx(active_tab: CurrentTab) -> 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 | CurrentTab::InvalidSymlinks => panic!("Unable to get size from this tab"),
CurrentTab::EmptyFolders | CurrentTab::InvalidSymlinks | CurrentTab::TemporaryFiles => panic!("Unable to get size from this tab"),
}
}

View file

@ -22,6 +22,7 @@ use czkawka_core::same_music::{MusicEntry, SameMusic};
use czkawka_core::similar_images;
use czkawka_core::similar_images::{ImagesEntry, SimilarImages};
use czkawka_core::similar_videos::{SimilarVideos, VideosEntry};
use czkawka_core::temporary::{Temporary, TemporaryFileEntry};
use crate::common::split_u64_into_i32s;
use crate::settings::{collect_settings, SettingsCustom, ALLOWED_HASH_TYPE_VALUES, ALLOWED_RESIZE_ALGORITHM_VALUES};
@ -74,8 +75,10 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender<ProgressDat
CurrentTab::BrokenFiles => {
scan_broken_files(a, progress_sender, stop_receiver, custom_settings);
}
CurrentTab::TemporaryFiles => {
scan_temporary_files(a, progress_sender, stop_receiver, custom_settings);
}
CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"),
_ => unimplemented!(),
}
});
}
@ -168,7 +171,7 @@ fn write_duplicate_results(app: &MainWindow, vector: Vec<(Option<DuplicateEntry>
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
}
app.set_similar_images_model(items.into());
app.set_duplicate_files_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} similar duplicates files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
@ -257,7 +260,7 @@ fn write_big_files_results(app: &MainWindow, vector: Vec<FileEntry>, messages: S
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.set_big_files_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
@ -592,6 +595,48 @@ fn prepare_data_model_invalid_symlinks(fe: &SymlinksFileEntry) -> (ModelRc<Share
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)
} ////////////////////////////////////////// Temporary Files
fn scan_temporary_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 = Temporary::new();
set_common_settings(&mut finder, &custom_settings);
finder.find_temporary_files(Some(&stop_receiver), Some(&progress_sender));
let mut vector = finder.get_temporary_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_temporary_files_results(&app, vector, messages);
})
})
.unwrap();
}
fn write_temporary_files_results(app: &MainWindow, vector: Vec<TemporaryFileEntry>, 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_temporary_files(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
app.set_temporary_files_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_temporary_files(fe: &TemporaryFileEntry) -> (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)
}
////////////////////////////////////////// Broken Files
fn scan_broken_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) {
@ -620,7 +665,7 @@ fn write_broken_files_results(app: &MainWindow, vector: Vec<BrokenEntry>, messag
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_broken_files(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
app.set_empty_folder_model(items.into());
app.set_broken_files_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
@ -666,7 +711,7 @@ fn write_bad_extensions_results(app: &MainWindow, vector: Vec<BadFileEntry>, mes
let (data_model_str, data_model_int) = prepare_data_model_bad_extensions(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
app.set_empty_folder_model(items.into());
app.set_bad_extensions_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} files with bad extensions").into());
app.global::<GuiState>().set_info_text(messages.into());
}

View file

@ -93,4 +93,12 @@ pub fn zeroing_all_models(app: &MainWindow) {
app.set_empty_folder_model(Rc::new(VecModel::default()).into());
app.set_empty_files_model(Rc::new(VecModel::default()).into());
app.set_similar_images_model(Rc::new(VecModel::default()).into());
app.set_duplicate_files_model(Rc::new(VecModel::default()).into());
app.set_similar_music_model(Rc::new(VecModel::default()).into());
app.set_big_files_model(Rc::new(VecModel::default()).into());
app.set_bad_extensions_model(Rc::new(VecModel::default()).into());
app.set_broken_files_model(Rc::new(VecModel::default()).into());
app.set_similar_videos_model(Rc::new(VecModel::default()).into());
app.set_invalid_symlinks_model(Rc::new(VecModel::default()).into());
app.set_temporary_files_model(Rc::new(VecModel::default()).into());
}

View file

@ -17,7 +17,7 @@ export global GuiState {
in-out property <bool> choosing_include_directories;
in-out property <bool> visible_tool_settings;
in-out property <bool> available_subsettings: active_tab == CurrentTab.SimilarImages;
in-out property <bool> available_subsettings: active_tab == CurrentTab.SimilarImages || active_tab == CurrentTab.DuplicateFiles || active_tab == CurrentTab.SimilarVideos || active_tab == CurrentTab.SimilarMusic || active_tab == CurrentTab.BigFiles || active_tab == CurrentTab.BrokenFiles;
in-out property <CurrentTab> active_tab: CurrentTab.DuplicateFiles;
in-out property <bool> is_tool_tab_active: active_tab != CurrentTab.Settings && active_tab != CurrentTab.About;
in-out property <[SelectModel]> select_results_list: [{data: SelectMode.SelectAll, name: "Select All"}, {data: SelectMode.UnselectAll, name: "Deselect All"}, {data: SelectMode.SelectTheSmallestResolution, name: "Select the smallest resolution"}];

View file

@ -68,7 +68,7 @@ export component LeftSidePanel {
callback changed_current_tab();
width: 120px;
VerticalLayout {
spacing: 10px;
spacing: 2px;
Rectangle {
visible: GuiState.active_tab != CurrentTab.About;
height: 80px;
@ -110,7 +110,6 @@ export component LeftSidePanel {
curr_tab: r.tab;
changed_current_tab() => {root.changed_current_tab();}
}
}
Rectangle {

View file

@ -88,8 +88,8 @@ export component MainList {
visible: GuiState.active_tab == CurrentTab.TemporaryFiles;
min-width: 200px;
height: parent.height;
columns: ["Selection", "Size", "File Name", "Path", "Modification Date"];
column-sizes: [35px, size_px, name_px, path_px, mod_px];
columns: ["Selection", "File Name", "Path", "Modification Date"];
column-sizes: [35px, name_px, path_px, mod_px];
values <=> temporary_files_model;
parentPathIdx: 3;
fileNameIdx: 2;
@ -143,8 +143,8 @@ export component MainList {
visible: GuiState.active_tab == CurrentTab.BrokenFiles;
min-width: 200px;
height: parent.height;
columns: ["Selection", "Size", "File Name", "Type of Error", "Path", "Modification Date"];
column-sizes: [35px, size_px, name_px, 200px, path_px, mod_px];
columns: ["Selection", "File Name", "Path", "Type of Error", "Size", "Modification Date"];
column-sizes: [35px, name_px, path_px, 200px, size_px, mod_px];
values <=> broken_files_model;
parentPathIdx: 4;
fileNameIdx: 2;

View file

@ -72,14 +72,7 @@ export component PopupNewDirectories inherits Rectangle {
}
}
}
// Button {
// text:"KKK";
// clicked => {
// show-popup();
// }
// }
show_popup() => {
popup_window.show();
}

View file

@ -40,7 +40,7 @@ export global Settings {
// Allowed subsettings
// Duplicate
// Similar Images
in-out property <[string]> similar_images_sub_available_hash_size: ["8", "16", "32", "64"];
in-out property <int> similar_images_sub_hash_size_index: 0;
in-out property <[string]> similar_images_sub_available_resize_algorithm: ["Lanczos3", "Nearest", "Triangle", "Gaussian", "CatmullRom"];
@ -50,4 +50,37 @@ export global Settings {
in-out property <float> similar_images_sub_max_similarity: 40;
in-out property <float> similar_images_sub_current_similarity: 20;
in-out property <bool> similar_images_sub_ignore_same_size;
// Duplicates
in-out property <[string]> duplicates_sub_check_method: ["Hash", "Size", "Name", "Size and Name"];
in-out property <int> duplicates_sub_check_method_index: 0;
in-out property <[string]> duplicates_sub_available_hash_type: ["Blake3", "CRC32", "XXH3"];
in-out property <int> duplicates_sub_available_hash_type_index: 0;
// Big files
in-out property <[string]> biggest_files_sub_method: ["The Biggest", "The Smallest"];
in-out property <int> biggest_files_sub_method_index: 0;
in-out property <string> biggest_files_sub_number_of_files: 50;
// Similar Videos
in-out property <bool> similar_videos_sub_ignore_same_size;
in-out property <float> similar_videos_sub_max_similarity: 20;
in-out property <float> similar_videos_sub_current_similarity: 15;
// Same Music
in-out property <[string]> similar_music_sub_audio_check_type: ["Tags", "Fingerprint"];
in-out property <int> similar_music_sub_audio_check_type_index: 0;
in-out property <bool> similar_music_sub_approximate_comparison;
in-out property <bool> similar_music_sub_title: true;
in-out property <bool> similar_music_sub_artist: true;
in-out property <bool> similar_music_sub_year: false;
in-out property <bool> similar_music_sub_bitrate: false;
in-out property <bool> similar_music_sub_genre: false;
in-out property <bool> similar_music_sub_length: false;
// Broken Files
in-out property <bool> broken_files_sub_audio: true;
in-out property <bool> broken_files_sub_pdf: false;
in-out property <bool> broken_files_sub_archive: false;
in-out property <bool> broken_files_sub_image: false;
}

View file

@ -9,7 +9,7 @@ global SettingsSize {
out property <length> item_height: 30px;
}
component TextComponent inherits HorizontalLayout {
export component TextComponent inherits HorizontalLayout {
in-out property <string> model;
in property <string> name;
spacing: 5px;

View file

@ -13,6 +13,7 @@ import {ColorPalette} from "color_palette.slint";
import {GuiState} from "gui_state.slint";
import { Preview } from "preview.slint";
import {PopupNewDirectories} from "popup_new_directories.slint";
import {TextComponent} from "settings_list.slint";
component ComboBoxWrapper inherits HorizontalLayout {
in-out property <string> text;
@ -62,7 +63,8 @@ component SliderWrapper inherits HorizontalLayout {
export component ToolSettings {
ScrollView {
if GuiState.active_tab == CurrentTab.SimilarImages: VerticalLayout {
VerticalLayout {
visible: GuiState.active_tab == CurrentTab.SimilarImages;
spacing: 5px;
padding: 10px;
SubsettingsHeader { }
@ -94,5 +96,128 @@ export component ToolSettings {
}
Rectangle {}
}
VerticalLayout {
visible: GuiState.active_tab == CurrentTab.DuplicateFiles;
spacing: 5px;
padding: 10px;
SubsettingsHeader { }
ComboBoxWrapper {
text: "Check method";
model: Settings.duplicates_sub_check_method;
current_index <=> Settings.duplicates_sub_check_method_index;
}
ComboBoxWrapper {
text: "Hash type";
model: Settings.duplicates_sub_available_hash_type;
current_index <=> Settings.duplicates_sub_available_hash_type_index;
}
Rectangle {}
}
VerticalLayout {
visible: GuiState.active_tab == CurrentTab.BigFiles;
spacing: 5px;
padding: 10px;
SubsettingsHeader { }
ComboBoxWrapper {
text: "Checked files";
model: Settings.biggest_files_sub_method;
current_index <=> Settings.biggest_files_sub_method_index;
}
TextComponent {
name: "Number of files";
model <=> Settings.biggest_files_sub_number_of_files;
}
Rectangle {}
}
VerticalLayout {
visible: GuiState.active_tab == CurrentTab.SimilarVideos;
spacing: 5px;
padding: 10px;
SubsettingsHeader { }
SliderWrapper {
text: "Max difference";
end_text: "(" + round(Settings.similar_videos_sub_current_similarity) + "/" + round(Settings.similar_videos_sub_max_similarity) + ")";
end_text_size: 40px;
maximum <=> Settings.similar_videos_sub_max_similarity;
value <=> Settings.similar_videos_sub_current_similarity;
}
CheckBoxWrapper {
text: "Ignore same size";
checked <=> Settings.similar_images_sub_ignore_same_size;
}
Rectangle {}
}
VerticalLayout {
visible: GuiState.active_tab == CurrentTab.SimilarMusic;
spacing: 5px;
padding: 10px;
SubsettingsHeader { }
ComboBoxWrapper {
text: "Audio check type";
model: Settings.similar_music_sub_audio_check_type;
current_index <=> Settings.similar_music_sub_audio_check_type_index;
}
CheckBoxWrapper {
text: "Approximate Tag Comparison";
checked <=> Settings.similar_music_sub_approximate_comparison;
}
Text {
text: "Compared tags";
font-size: 12px;
}
CheckBoxWrapper {
text: "Title";
checked <=> Settings.similar_music_sub_title;
}
CheckBoxWrapper {
text: "Artist";
checked <=> Settings.similar_music_sub_artist;
}
CheckBoxWrapper {
text: "Bitrate";
checked <=> Settings.similar_music_sub_bitrate;
}
CheckBoxWrapper {
text: "Genre";
checked <=> Settings.similar_music_sub_genre;
}
CheckBoxWrapper {
text: "Year";
checked <=> Settings.similar_music_sub_year;
}
CheckBoxWrapper {
text: "Length";
checked <=> Settings.similar_music_sub_length;
}
Rectangle {}
}
VerticalLayout {
visible: GuiState.active_tab == CurrentTab.BrokenFiles;
spacing: 5px;
padding: 10px;
SubsettingsHeader { }
Text {
text: "Type of files to check";
font-size: 12px;
}
CheckBoxWrapper {
text: "Audio";
checked <=> Settings.broken_files_sub_audio;
}
CheckBoxWrapper {
text: "Pdf";
checked <=> Settings.broken_files_sub_pdf;
}
CheckBoxWrapper {
text: "Archive";
checked <=> Settings.broken_files_sub_archive;
}
CheckBoxWrapper {
text: "Image";
checked <=> Settings.broken_files_sub_image;
}
Rectangle {}
}
}
}