diff --git a/czkawka_core/src/bad_extensions.rs b/czkawka_core/src/bad_extensions.rs index 6864279..5d32adc 100644 --- a/czkawka_core/src/bad_extensions.rs +++ b/czkawka_core/src/bad_extensions.rs @@ -10,6 +10,7 @@ use std::mem; use std::time::SystemTime; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use mime_guess::get_mime_extensions; use rayon::prelude::*; @@ -208,7 +209,7 @@ impl BadExtensions { } } - pub fn find_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); if !self.check_files(stop_receiver, progress_sender) { self.stopped_search = true; @@ -283,7 +284,7 @@ impl BadExtensions { self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages); } - fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let result = DirTraversalBuilder::new() .root_dirs(self.directories.included_directories.clone()) .group_by(|_fe| ()) @@ -317,14 +318,13 @@ impl BadExtensions { } } - fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn look_for_bad_extensions_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let system_time = SystemTime::now(); let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = prepare_thread_handler_common( progress_sender, &progress_thread_run, diff --git a/czkawka_core/src/big_file.rs b/czkawka_core/src/big_file.rs index 426dd3f..cd2e663 100644 --- a/czkawka_core/src/big_file.rs +++ b/czkawka_core/src/big_file.rs @@ -2,33 +2,28 @@ use std::collections::BTreeMap; use std::fs::{DirEntry, File, Metadata}; use std::io::{BufWriter, Write}; use std::path::{Path, PathBuf}; -use std::sync::atomic::Ordering; -use std::sync::atomic::{AtomicBool, AtomicU64}; +use std::sync::atomic::AtomicBool; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::Arc; -use std::thread::{sleep, JoinHandle}; -use std::time::Duration; + +use std::fs; use std::time::SystemTime; -use std::{fs, thread}; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use humansize::format_size; use humansize::BINARY; use rayon::prelude::*; -use crate::common::{check_folder_children, send_info_and_wait_for_ending_all_threads, split_path}; -use crate::common::{Common, LOOP_DURATION}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time}; +use crate::common::Common; +use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, split_path}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; use crate::common_messages::Messages; use crate::common_traits::{DebugPrint, PrintResults, SaveResults}; -#[derive(Debug)] -pub struct ProgressData { - pub files_checked: usize, -} - #[derive(Clone)] pub struct FileEntry { pub path: PathBuf, @@ -94,7 +89,7 @@ impl BigFile { } } - pub fn find_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.optimize_directories(); if !self.look_for_big_files(stop_receiver, progress_sender) { self.stopped_search = true; @@ -147,33 +142,7 @@ impl BigFile { self.allowed_extensions.set_allowed_extensions(allowed_extensions, &mut self.text_messages); } - pub fn prepare_thread_handler( - &self, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, - progress_thread_run: &Arc, - atomic_counter: &Arc, - ) -> JoinHandle<()> { - if let Some(progress_sender) = progress_sender { - let progress_send = progress_sender.clone(); - let progress_thread_run = progress_thread_run.clone(); - let atomic_counter = atomic_counter.clone(); - thread::spawn(move || loop { - progress_send - .unbounded_send(ProgressData { - files_checked: atomic_counter.load(Ordering::Relaxed) as usize, - }) - .unwrap(); - if !progress_thread_run.load(Ordering::Relaxed) { - break; - } - sleep(Duration::from_millis(LOOP_DURATION as u64)); - }) - } else { - thread::spawn(|| {}) - } - } - - fn look_for_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn look_for_big_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let start_time: SystemTime = SystemTime::now(); let mut folders_to_check: Vec = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector let mut old_map: BTreeMap> = Default::default(); @@ -184,8 +153,8 @@ impl BigFile { } let progress_thread_run = Arc::new(AtomicBool::new(true)); - let atomic_counter = Arc::new(AtomicU64::new(0)); - let progress_thread_handle = self.prepare_thread_handler(progress_sender, &progress_thread_run, &atomic_counter); + let atomic_counter = Arc::new(AtomicUsize::new(0)); + let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 0, 0, CheckingMethod::None); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -251,7 +220,7 @@ impl BigFile { pub fn collect_file_entry( &self, - atomic_counter: &Arc, + atomic_counter: &Arc, metadata: &Metadata, entry_data: &DirEntry, fe_result: &mut Vec<(u64, FileEntry)>, diff --git a/czkawka_core/src/broken_files.rs b/czkawka_core/src/broken_files.rs index faf2474..d57774b 100644 --- a/czkawka_core/src/broken_files.rs +++ b/czkawka_core/src/broken_files.rs @@ -5,11 +5,12 @@ use std::io::{BufReader, BufWriter}; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; -use std::thread::{sleep, JoinHandle}; -use std::time::{Duration, SystemTime}; -use std::{fs, mem, panic, thread}; + +use std::time::SystemTime; +use std::{fs, mem, panic}; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use pdf::file::FileOptions; use pdf::object::ParseOptions; use pdf::PdfError; @@ -17,23 +18,17 @@ use pdf::PdfError::Try; use rayon::prelude::*; use serde::{Deserialize, Serialize}; -use crate::common::{check_folder_children, create_crash_message, open_cache_folder, send_info_and_wait_for_ending_all_threads, Common, LOOP_DURATION, PDF_FILES_EXTENSIONS}; +use crate::common::{ + check_folder_children, create_crash_message, open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, Common, PDF_FILES_EXTENSIONS, +}; use crate::common::{AUDIO_FILES_EXTENSIONS, IMAGE_RS_BROKEN_FILES_EXTENSIONS, ZIP_FILES_EXTENSIONS}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; use crate::common_messages::Messages; use crate::common_traits::*; -#[derive(Debug)] -pub struct ProgressData { - pub current_stage: u8, - pub max_stage: u8, - pub files_checked: usize, - pub files_to_check: usize, -} - #[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, @@ -121,7 +116,7 @@ impl BrokenFiles { } } - pub fn find_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); if !self.check_files(stop_receiver, progress_sender) { self.stopped_search = true; @@ -197,39 +192,7 @@ impl BrokenFiles { self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages); } - pub fn prepare_thread_handler_broken_files( - &self, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, - progress_thread_run: &Arc, - atomic_counter: &Arc, - current_stage: u8, - max_stage: u8, - max_value: usize, - ) -> JoinHandle<()> { - if let Some(progress_sender) = progress_sender { - let progress_send = progress_sender.clone(); - let progress_thread_run = progress_thread_run.clone(); - let atomic_counter = atomic_counter.clone(); - thread::spawn(move || loop { - progress_send - .unbounded_send(ProgressData { - current_stage, - max_stage, - files_checked: atomic_counter.load(Ordering::Relaxed), - files_to_check: max_value, - }) - .unwrap(); - if !progress_thread_run.load(Ordering::Relaxed) { - break; - } - sleep(Duration::from_millis(LOOP_DURATION as u64)); - }) - } else { - thread::spawn(|| {}) - } - } - - fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let start_time: SystemTime = SystemTime::now(); let mut folders_to_check: Vec = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector @@ -240,7 +203,7 @@ impl BrokenFiles { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_broken_files(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0); + let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0, CheckingMethod::None); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -441,7 +404,7 @@ impl BrokenFiles { } } - fn look_for_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn look_for_broken_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let system_time = SystemTime::now(); let loaded_hash_map; @@ -481,7 +444,15 @@ impl BrokenFiles { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_broken_files(progress_sender, &progress_thread_run, &atomic_counter, 1, 1, non_cached_files_to_check.len()); + let progress_thread_handle = prepare_thread_handler_common( + progress_sender, + &progress_thread_run, + &atomic_counter, + 1, + 1, + non_cached_files_to_check.len(), + CheckingMethod::None, + ); let mut vec_file_entry: Vec = non_cached_files_to_check .into_par_iter() diff --git a/czkawka_core/src/common.rs b/czkawka_core/src/common.rs index e6ed3f1..783da89 100644 --- a/czkawka_core/src/common.rs +++ b/czkawka_core/src/common.rs @@ -11,6 +11,7 @@ use std::{fs, thread}; #[cfg(feature = "heif")] use anyhow::Result; use directories_next::ProjectDirs; +use futures::channel::mpsc::UnboundedSender; use image::{DynamicImage, ImageBuffer, Rgb}; use imagepipe::{ImageSource, Pipeline}; // #[cfg(feature = "heif")] @@ -360,7 +361,7 @@ pub fn check_folder_children( } pub fn prepare_thread_handler_common( - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, + progress_sender: Option<&UnboundedSender>, progress_thread_run: &Arc, atomic_counter: &Arc, current_stage: u8, diff --git a/czkawka_core/src/common_dir_traversal.rs b/czkawka_core/src/common_dir_traversal.rs index 8eb3eef..4140e5d 100644 --- a/czkawka_core/src/common_dir_traversal.rs +++ b/czkawka_core/src/common_dir_traversal.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use std::time::{SystemTime, UNIX_EPOCH}; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use rayon::prelude::*; use crate::common::{prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads}; @@ -99,7 +100,7 @@ pub struct DirTraversalBuilder<'a, 'b, F> { group_by: Option, root_dirs: Vec, stop_receiver: Option<&'a Receiver<()>>, - progress_sender: Option<&'b futures::channel::mpsc::UnboundedSender>, + progress_sender: Option<&'b UnboundedSender>, minimal_file_size: Option, maximal_file_size: Option, checking_method: CheckingMethod, @@ -115,7 +116,7 @@ pub struct DirTraversal<'a, 'b, F> { group_by: F, root_dirs: Vec, stop_receiver: Option<&'a Receiver<()>>, - progress_sender: Option<&'b futures::channel::mpsc::UnboundedSender>, + progress_sender: Option<&'b UnboundedSender>, recursive_search: bool, directories: Directories, excluded_items: ExcludedItems, @@ -168,7 +169,7 @@ impl<'a, 'b, F> DirTraversalBuilder<'a, 'b, F> { } #[must_use] - pub fn progress_sender(mut self, progress_sender: Option<&'b futures::channel::mpsc::UnboundedSender>) -> Self { + pub fn progress_sender(mut self, progress_sender: Option<&'b UnboundedSender>) -> Self { self.progress_sender = progress_sender; self } @@ -333,16 +334,8 @@ where folders_to_check.extend(self.root_dirs); let progress_thread_run = Arc::new(AtomicBool::new(true)); - let atomic_entry_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = prepare_thread_handler_common( - self.progress_sender, - &progress_thread_run, - &atomic_entry_counter, - 0, - self.max_stage, - 0, - self.checking_method, - ); + let atomic_counter = Arc::new(AtomicUsize::new(0)); + let progress_thread_handle = prepare_thread_handler_common(self.progress_sender, &progress_thread_run, &atomic_counter, 0, self.max_stage, 0, self.checking_method); let DirTraversal { collect, @@ -386,7 +379,7 @@ where process_dir_in_file_symlink_mode(recursive_search, current_folder, entry_data, &directories, &mut dir_result, &mut warnings, &excluded_items); } (EntryType::Dir, Collect::EmptyFolders) => { - atomic_entry_counter.fetch_add(1, Ordering::Relaxed); + atomic_counter.fetch_add(1, Ordering::Relaxed); process_dir_in_dir_mode( &metadata, current_folder, @@ -400,7 +393,7 @@ where ); } (EntryType::File, Collect::Files) => { - atomic_entry_counter.fetch_add(1, Ordering::Relaxed); + atomic_counter.fetch_add(1, Ordering::Relaxed); process_file_in_file_mode( &metadata, entry_data, @@ -427,10 +420,10 @@ where set_as_not_empty_folder_list.push(current_folder.clone()); } (EntryType::File, Collect::InvalidSymlinks) => { - atomic_entry_counter.fetch_add(1, Ordering::Relaxed); + atomic_counter.fetch_add(1, Ordering::Relaxed); } (EntryType::Symlink, Collect::InvalidSymlinks) => { - atomic_entry_counter.fetch_add(1, Ordering::Relaxed); + atomic_counter.fetch_add(1, Ordering::Relaxed); process_symlink_in_symlink_mode( &metadata, entry_data, diff --git a/czkawka_core/src/duplicate.rs b/czkawka_core/src/duplicate.rs index 6f8ffca..8bbd224 100644 --- a/czkawka_core/src/duplicate.rs +++ b/czkawka_core/src/duplicate.rs @@ -15,9 +15,11 @@ use std::time::SystemTime; use std::{fs, mem}; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use humansize::format_size; use humansize::BINARY; use rayon::prelude::*; +use xxhash_rust::xxh3::Xxh3; use crate::common::{open_cache_folder, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, Common}; use crate::common_dir_traversal::{CheckingMethod, DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData}; @@ -43,7 +45,7 @@ impl HashType { match self { HashType::Blake3 => Box::new(blake3::Hasher::new()), HashType::Crc32 => Box::new(crc32fast::Hasher::new()), - HashType::Xxh3 => Box::new(xxhash_rust::xxh3::Xxh3::new()), + HashType::Xxh3 => Box::new(Xxh3::new()), } } } @@ -147,7 +149,7 @@ impl DuplicateFinder { } } - pub fn find_duplicates(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_duplicates(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); self.use_reference_folders = !self.directories.reference_directories.is_empty(); @@ -340,7 +342,7 @@ impl DuplicateFinder { &self.files_with_identical_size_names_referenced } - fn check_files_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let group_by_func = if self.case_sensitive_name_comparison { |fe: &FileEntry| fe.path.file_name().unwrap().to_string_lossy().to_string() } else { @@ -435,7 +437,7 @@ impl DuplicateFinder { } } - fn check_files_size_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files_size_name(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let group_by_func = if self.case_sensitive_name_comparison { |fe: &FileEntry| (fe.size, fe.path.file_name().unwrap().to_string_lossy().to_string()) } else { @@ -535,7 +537,7 @@ impl DuplicateFinder { /// Read file length and puts it to different boxes(each for different lengths) /// If in box is only 1 result, then it is removed - fn check_files_size(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files_size(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let max_stage = match self.check_method { CheckingMethod::Size => 0, CheckingMethod::Hash => 2, @@ -718,7 +720,7 @@ impl DuplicateFinder { fn prehashing( &mut self, stop_receiver: Option<&Receiver<()>>, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, + progress_sender: Option<&UnboundedSender>, pre_checked_map: &mut BTreeMap>, ) -> Option<()> { let start_time: SystemTime = SystemTime::now(); @@ -886,7 +888,7 @@ impl DuplicateFinder { fn full_hashing( &mut self, stop_receiver: Option<&Receiver<()>>, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, + progress_sender: Option<&UnboundedSender>, pre_checked_map: BTreeMap>, ) -> Option<()> { let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread @@ -1018,7 +1020,7 @@ impl DuplicateFinder { } /// The slowest checking type, which must be applied after checking for size - fn check_files_hash(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files_hash(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { assert_eq!(self.check_method, CheckingMethod::Hash); let mut pre_checked_map: BTreeMap> = Default::default(); @@ -1617,7 +1619,7 @@ impl MyHasher for crc32fast::Hasher { } } -impl MyHasher for xxhash_rust::xxh3::Xxh3 { +impl MyHasher for Xxh3 { fn update(&mut self, bytes: &[u8]) { self.write(bytes); } diff --git a/czkawka_core/src/empty_files.rs b/czkawka_core/src/empty_files.rs index b3bcba2..f1f76c3 100644 --- a/czkawka_core/src/empty_files.rs +++ b/czkawka_core/src/empty_files.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use std::time::SystemTime; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use crate::common::Common; use crate::common_dir_traversal::{DirTraversalBuilder, DirTraversalResult, FileEntry, ProgressData}; @@ -64,7 +65,7 @@ impl EmptyFiles { } /// Finding empty files, save results to internal struct variables - pub fn find_empty_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_empty_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); if !self.check_files(stop_receiver, progress_sender) { self.stopped_search = true; @@ -125,7 +126,7 @@ impl EmptyFiles { } /// Check files for any with size == 0 - fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let result = DirTraversalBuilder::new() .root_dirs(self.directories.included_directories.clone()) .group_by(|_fe| ()) diff --git a/czkawka_core/src/empty_folder.rs b/czkawka_core/src/empty_folder.rs index 0ab2c38..f4129df 100644 --- a/czkawka_core/src/empty_folder.rs +++ b/czkawka_core/src/empty_folder.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use std::time::SystemTime; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use crate::common::Common; use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, FolderEmptiness, FolderEntry, ProgressData}; @@ -88,7 +89,7 @@ impl EmptyFolder { self.directories.set_excluded_directory(excluded_directory, &mut self.text_messages); } /// Public function used by CLI to search for empty folders - pub fn find_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(true, &mut self.text_messages); if !self.check_for_empty_folders(stop_receiver, progress_sender) { self.stopped_search = true; @@ -128,7 +129,7 @@ impl EmptyFolder { /// Function to check if folder are empty. /// Parameter `initial_checking` for second check before deleting to be sure that checked folder is still empty - fn check_for_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_for_empty_folders(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let result = DirTraversalBuilder::new() .root_dirs(self.directories.included_directories.clone()) .group_by(|_fe| ()) diff --git a/czkawka_core/src/invalid_symlinks.rs b/czkawka_core/src/invalid_symlinks.rs index ba1a8c8..1bc064b 100644 --- a/czkawka_core/src/invalid_symlinks.rs +++ b/czkawka_core/src/invalid_symlinks.rs @@ -6,6 +6,7 @@ use std::path::PathBuf; use std::time::SystemTime; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use crate::common::Common; use crate::common_dir_traversal::{Collect, DirTraversalBuilder, DirTraversalResult, ErrorType, FileEntry, ProgressData}; @@ -63,7 +64,7 @@ impl InvalidSymlinks { } } - pub fn find_invalid_links(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_invalid_links(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); if !self.check_files(stop_receiver, progress_sender) { self.stopped_search = true; @@ -124,7 +125,7 @@ impl InvalidSymlinks { } /// Check files for any with size == 0 - fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let result = DirTraversalBuilder::new() .root_dirs(self.directories.included_directories.clone()) .group_by(|_fe| ()) diff --git a/czkawka_core/src/same_music.rs b/czkawka_core/src/same_music.rs index 8fcf75d..44214ab 100644 --- a/czkawka_core/src/same_music.rs +++ b/czkawka_core/src/same_music.rs @@ -9,6 +9,7 @@ use std::time::SystemTime; use std::{mem, panic}; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use lofty::TaggedFileExt; use lofty::{read_from, AudioFile, ItemKey}; use rayon::prelude::*; @@ -148,7 +149,7 @@ impl SameMusic { } } - pub fn find_same_music(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_same_music(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); self.use_reference_folders = !self.directories.reference_directories.is_empty(); if !self.check_files(stop_receiver, progress_sender) { @@ -276,7 +277,7 @@ impl SameMusic { self.use_reference_folders } - fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { if !self.allowed_extensions.using_custom_extensions() { self.allowed_extensions.extend_allowed_extensions(AUDIO_FILES_EXTENSIONS); } else { @@ -367,7 +368,7 @@ impl SameMusic { save_cache_to_file(&all_results, &mut self.text_messages, self.save_also_as_json); } - fn read_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn read_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let start_time: SystemTime = SystemTime::now(); let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.read_tags_load_cache(); @@ -515,7 +516,7 @@ impl SameMusic { Some(music_entry) } - fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_for_duplicate_tags(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { assert_ne!(MusicSimilarity::NONE, self.music_similarity, "This can't be none"); let start_time: SystemTime = SystemTime::now(); diff --git a/czkawka_core/src/similar_images.rs b/czkawka_core/src/similar_images.rs index 0d0b34f..fc1efd1 100644 --- a/czkawka_core/src/similar_images.rs +++ b/czkawka_core/src/similar_images.rs @@ -6,12 +6,13 @@ use std::panic; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; -use std::thread::{sleep, JoinHandle}; -use std::time::{Duration, SystemTime}; -use std::{mem, thread}; + +use std::mem; +use std::time::SystemTime; use bk_tree::BKTree; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use humansize::format_size; use humansize::BINARY; use image::GenericImageView; @@ -22,10 +23,10 @@ use serde::{Deserialize, Serialize}; #[cfg(feature = "heif")] use crate::common::get_dynamic_image_from_heic; use crate::common::{ - check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, send_info_and_wait_for_ending_all_threads, Common, - HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, LOOP_DURATION, RAW_IMAGE_EXTENSIONS, + check_folder_children, create_crash_message, get_dynamic_image_from_raw_image, get_number_of_threads, open_cache_folder, prepare_thread_handler_common, + send_info_and_wait_for_ending_all_threads, Common, HEIC_EXTENSIONS, IMAGE_RS_SIMILAR_IMAGES_EXTENSIONS, RAW_IMAGE_EXTENSIONS, }; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -42,14 +43,6 @@ pub const SIMILAR_VALUES: [[u32; 6]; 4] = [ [6, 20, 40, 40, 40, 40], // 64 ]; -#[derive(Debug)] -pub struct ProgressData { - pub current_stage: u8, - pub max_stage: u8, - pub images_checked: usize, - pub images_to_check: usize, -} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FileEntry { pub path: PathBuf, @@ -254,7 +247,7 @@ impl SimilarImages { } /// Public function used by CLI to search for empty folders - pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(true, &mut self.text_messages); self.use_reference_folders = !self.directories.reference_directories.is_empty(); if !self.check_for_similar_images(stop_receiver, progress_sender) { @@ -279,41 +272,9 @@ impl SimilarImages { // self.delete_folders = delete_folder; // } - pub fn prepare_thread_handler_similar_images( - &self, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, - progress_thread_run: &Arc, - atomic_counter: &Arc, - current_stage: u8, - max_stage: u8, - max_value: usize, - ) -> JoinHandle<()> { - if let Some(progress_sender) = progress_sender { - let progress_send = progress_sender.clone(); - let progress_thread_run = progress_thread_run.clone(); - let atomic_counter = atomic_counter.clone(); - thread::spawn(move || loop { - progress_send - .unbounded_send(ProgressData { - current_stage, - max_stage, - images_checked: atomic_counter.load(Ordering::Relaxed), - images_to_check: max_value, - }) - .unwrap(); - if !progress_thread_run.load(Ordering::Relaxed) { - break; - } - sleep(Duration::from_millis(LOOP_DURATION as u64)); - }) - } else { - thread::spawn(|| {}) - } - } - /// Function to check if folder are empty. /// Parameter `initial_checking` for second check before deleting to be sure that checked folder is still empty - fn check_for_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_for_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let start_time: SystemTime = SystemTime::now(); let mut folders_to_check: Vec = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector @@ -337,7 +298,7 @@ impl SimilarImages { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_similar_images(progress_sender, &progress_thread_run, &atomic_counter, 0, 3, 0); + let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 2, 0, CheckingMethod::None); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -466,7 +427,7 @@ impl SimilarImages { // - Join already read hashes with hashes which were read from file // - Join all hashes and save it to file - fn hash_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn hash_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let hash_map_modification = SystemTime::now(); let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.hash_images_load_cache(); @@ -477,7 +438,15 @@ impl SimilarImages { let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_similar_images(progress_sender, &progress_thread_run, &atomic_counter, 1, 3, non_cached_files_to_check.len()); + let progress_thread_handle = prepare_thread_handler_common( + progress_sender, + &progress_thread_run, + &atomic_counter, + 1, + 2, + non_cached_files_to_check.len(), + CheckingMethod::None, + ); let mut vec_file_entry: Vec<(FileEntry, ImHash)> = non_cached_files_to_check .into_par_iter() @@ -610,7 +579,7 @@ impl SimilarImages { fn compare_hashes( &self, hashes_to_check: &[ImHash], - atomic_mode_counter: &Arc, + atomic_counter: &Arc, stop_receiver: Option<&Receiver<()>>, check_was_stopped: &AtomicBool, tolerance: u32, @@ -632,7 +601,7 @@ impl SimilarImages { // Also don't add too often data to atomic variable const CYCLES_COUNTER: usize = 0b11_1111; if ((index & CYCLES_COUNTER) == CYCLES_COUNTER) && index != 0 { - atomic_mode_counter.fetch_add(CYCLES_COUNTER, Ordering::Relaxed); + atomic_counter.fetch_add(CYCLES_COUNTER, Ordering::Relaxed); if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { check_was_stopped.store(true, Ordering::Relaxed); return None; @@ -839,7 +808,7 @@ impl SimilarImages { self.collect_hash_compare_result(hashes_parents, hashes_with_multiple_images, all_hashed_images, collected_similar_images, hashes_similarity); } - fn find_similar_hashes(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn find_similar_hashes(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { if self.image_hashes.is_empty() { return true; } @@ -865,8 +834,8 @@ impl SimilarImages { } else { let check_was_stopped = AtomicBool::new(false); // Used for breaking from GUI and ending check thread let progress_thread_run = Arc::new(AtomicBool::new(true)); - let atomic_mode_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_similar_images(progress_sender, &progress_thread_run, &atomic_mode_counter, 2, 2, all_hashes.len()); + let atomic_counter = Arc::new(AtomicUsize::new(0)); + let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 2, 2, all_hashes.len(), CheckingMethod::None); // Don't use hashes with multiple images in bktree, because they will always be master of group and cannot be find by other hashes @@ -877,7 +846,7 @@ impl SimilarImages { .map(|hashes_to_check| { self.compare_hashes( &hashes_to_check, - &atomic_mode_counter, + &atomic_counter, stop_receiver, &check_was_stopped, tolerance, diff --git a/czkawka_core/src/similar_videos.rs b/czkawka_core/src/similar_videos.rs index f754774..8c326d4 100644 --- a/czkawka_core/src/similar_videos.rs +++ b/czkawka_core/src/similar_videos.rs @@ -5,12 +5,13 @@ use std::io::*; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; -use std::thread::{sleep, JoinHandle}; -use std::time::{Duration, SystemTime}; -use std::{mem, thread}; + +use std::mem; +use std::time::SystemTime; use crossbeam_channel::Receiver; use ffmpeg_cmdline_utils::FfmpegErrorKind::FfmpegNotFound; +use futures::channel::mpsc::UnboundedSender; use humansize::format_size; use humansize::BINARY; use rayon::prelude::*; @@ -18,9 +19,9 @@ use serde::{Deserialize, Serialize}; use vid_dup_finder_lib::HashCreationErrorKind::DetermineVideo; use vid_dup_finder_lib::{NormalizedTolerance, VideoHash}; -use crate::common::{check_folder_children, send_info_and_wait_for_ending_all_threads, VIDEO_FILES_EXTENSIONS}; -use crate::common::{open_cache_folder, Common, LOOP_DURATION}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time}; +use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, VIDEO_FILES_EXTENSIONS}; +use crate::common::{open_cache_folder, Common}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; use crate::common_directory::Directories; use crate::common_extensions::Extensions; use crate::common_items::ExcludedItems; @@ -31,14 +32,6 @@ use crate::localizer_core::generate_translation_hashmap; pub const MAX_TOLERANCE: i32 = 20; -#[derive(Debug)] -pub struct ProgressData { - pub current_stage: u8, - pub max_stage: u8, - pub videos_checked: usize, - pub videos_to_check: usize, -} - #[derive(Clone, Debug, Serialize, Deserialize)] pub struct FileEntry { pub path: PathBuf, @@ -215,7 +208,7 @@ impl SimilarVideos { } /// Public function used by CLI to search for empty folders - pub fn find_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { if !check_if_ffmpeg_is_installed() { self.text_messages.errors.push(flc!("core_ffmpeg_not_found")); #[cfg(target_os = "windows")] @@ -247,41 +240,9 @@ impl SimilarVideos { // self.delete_folders = delete_folder; // } - pub fn prepare_thread_handler_similar_video( - &self, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, - progress_thread_run: &Arc, - atomic_counter: &Arc, - current_stage: u8, - max_stage: u8, - max_value: usize, - ) -> JoinHandle<()> { - if let Some(progress_sender) = progress_sender { - let progress_send = progress_sender.clone(); - let progress_thread_run = progress_thread_run.clone(); - let atomic_counter = atomic_counter.clone(); - thread::spawn(move || loop { - progress_send - .unbounded_send(ProgressData { - current_stage, - max_stage, - videos_checked: atomic_counter.load(Ordering::Relaxed), - videos_to_check: max_value, - }) - .unwrap(); - if !progress_thread_run.load(Ordering::Relaxed) { - break; - } - sleep(Duration::from_millis(LOOP_DURATION as u64)); - }) - } else { - thread::spawn(|| {}) - } - } - /// Function to check if folder are empty. /// Parameter `initial_checking` for second check before deleting to be sure that checked folder is still empty - fn check_for_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_for_similar_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let start_time: SystemTime = SystemTime::now(); let mut folders_to_check: Vec = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector @@ -301,7 +262,7 @@ impl SimilarVideos { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_similar_video(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0); + let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 1, 0, CheckingMethod::None); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { @@ -424,7 +385,7 @@ impl SimilarVideos { (loaded_hash_map, records_already_cached, non_cached_files_to_check) } - fn sort_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn sort_videos(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let hash_map_modification = SystemTime::now(); let (loaded_hash_map, records_already_cached, non_cached_files_to_check) = self.load_cache_at_start(); @@ -436,7 +397,15 @@ impl SimilarVideos { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_similar_video(progress_sender, &progress_thread_run, &atomic_counter, 1, 1, non_cached_files_to_check.len()); + let progress_thread_handle = prepare_thread_handler_common( + progress_sender, + &progress_thread_run, + &atomic_counter, + 1, + 1, + non_cached_files_to_check.len(), + CheckingMethod::None, + ); let mut vec_file_entry: Vec = non_cached_files_to_check .par_iter() diff --git a/czkawka_core/src/temporary.rs b/czkawka_core/src/temporary.rs index 39bab18..cdf5659 100644 --- a/czkawka_core/src/temporary.rs +++ b/czkawka_core/src/temporary.rs @@ -4,15 +4,16 @@ use std::io::BufWriter; use std::path::{Path, PathBuf}; use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; use std::sync::Arc; -use std::thread::{sleep, JoinHandle}; -use std::time::{Duration, SystemTime}; -use std::{fs, thread}; + +use std::fs; +use std::time::SystemTime; use crossbeam_channel::Receiver; +use futures::channel::mpsc::UnboundedSender; use rayon::prelude::*; -use crate::common::{check_folder_children, send_info_and_wait_for_ending_all_threads, Common, LOOP_DURATION}; -use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time}; +use crate::common::{check_folder_children, prepare_thread_handler_common, send_info_and_wait_for_ending_all_threads, Common}; +use crate::common_dir_traversal::{common_get_entry_data_metadata, common_read_dir, get_lowercase_name, get_modified_time, CheckingMethod, ProgressData}; use crate::common_directory::Directories; use crate::common_items::ExcludedItems; use crate::common_messages::Messages; @@ -34,13 +35,6 @@ const TEMP_EXTENSIONS: &[&str] = &[ ".partial", ]; -#[derive(Debug)] -pub struct ProgressData { - pub current_stage: u8, - pub max_stage: u8, - pub files_checked: usize, -} - #[derive(Eq, PartialEq, Clone, Debug, Copy)] pub enum DeleteMethod { None, @@ -94,7 +88,7 @@ impl Temporary { } /// Finding temporary files, save results to internal struct variables - pub fn find_temporary_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) { + pub fn find_temporary_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) { self.directories.optimize_directories(self.recursive_search, &mut self.text_messages); if !self.check_files(stop_receiver, progress_sender) { self.stopped_search = true; @@ -149,35 +143,7 @@ impl Temporary { self.excluded_items.set_excluded_items(excluded_items, &mut self.text_messages); } - fn prepare_thread_handler_temporary( - &self, - progress_sender: Option<&futures::channel::mpsc::UnboundedSender>, - progress_thread_run: &Arc, - atomic_counter: &Arc, - ) -> JoinHandle<()> { - if let Some(progress_sender) = progress_sender { - let progress_send = progress_sender.clone(); - let progress_thread_run = progress_thread_run.clone(); - let atomic_counter = atomic_counter.clone(); - thread::spawn(move || loop { - progress_send - .unbounded_send(ProgressData { - current_stage: 0, - max_stage: 0, - files_checked: atomic_counter.load(Ordering::Relaxed), - }) - .unwrap(); - if !progress_thread_run.load(Ordering::Relaxed) { - break; - } - sleep(Duration::from_millis(LOOP_DURATION as u64)); - }) - } else { - thread::spawn(|| {}) - } - } - - fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender>) -> bool { + fn check_files(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&UnboundedSender>) -> bool { let start_time: SystemTime = SystemTime::now(); let mut folders_to_check: Vec = Vec::with_capacity(1024 * 2); // This should be small enough too not see to big difference and big enough to store most of paths without needing to resize vector @@ -188,7 +154,7 @@ impl Temporary { let progress_thread_run = Arc::new(AtomicBool::new(true)); let atomic_counter = Arc::new(AtomicUsize::new(0)); - let progress_thread_handle = self.prepare_thread_handler_temporary(progress_sender, &progress_thread_run, &atomic_counter); + let progress_thread_handle = prepare_thread_handler_common(progress_sender, &progress_thread_run, &atomic_counter, 0, 0, 0, CheckingMethod::None); while !folders_to_check.is_empty() { if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() { diff --git a/czkawka_gui/src/connect_things/connect_button_move.rs b/czkawka_gui/src/connect_things/connect_button_move.rs index 734f8b5..2f9b64e 100644 --- a/czkawka_gui/src/connect_things/connect_button_move.rs +++ b/czkawka_gui/src/connect_things/connect_button_move.rs @@ -1,3 +1,4 @@ +use fs_extra::dir::CopyOptions; use std::path::{Path, PathBuf}; use gtk4::prelude::*; @@ -199,7 +200,7 @@ fn move_files_common( let thing = get_full_name_from_path_name(&path, &file_name); let destination_file = destination_folder.join(file_name); if Path::new(&thing).is_dir() { - if let Err(e) = fs_extra::dir::move_dir(&thing, &destination_file, &fs_extra::dir::CopyOptions::new()) { + if let Err(e) = fs_extra::dir::move_dir(&thing, &destination_file, &CopyOptions::new()) { messages += flg!("move_folder_failed", generate_translation_hashmap(vec![("name", thing), ("reason", e.to_string())])).as_str(); messages += "\n"; continue 'next_result; diff --git a/czkawka_gui/src/connect_things/connect_button_search.rs b/czkawka_gui/src/connect_things/connect_button_search.rs index 948753a..4ae5311 100644 --- a/czkawka_gui/src/connect_things/connect_button_search.rs +++ b/czkawka_gui/src/connect_things/connect_button_search.rs @@ -1,3 +1,4 @@ +use futures::channel::mpsc::UnboundedSender; use std::sync::atomic::{AtomicBool, Ordering}; use std::sync::Arc; use std::thread; @@ -8,7 +9,8 @@ use gtk4::prelude::*; use czkawka_core::bad_extensions::BadExtensions; use czkawka_core::big_file::BigFile; use czkawka_core::broken_files::{BrokenFiles, CheckedTypes}; -use czkawka_core::common_dir_traversal; + +use czkawka_core::common_dir_traversal::ProgressData; use czkawka_core::duplicate::DuplicateFinder; use czkawka_core::empty_files::EmptyFiles; use czkawka_core::empty_folder::EmptyFolder; @@ -17,7 +19,6 @@ use czkawka_core::same_music::{MusicSimilarity, SameMusic}; use czkawka_core::similar_images::SimilarImages; use czkawka_core::similar_videos::SimilarVideos; use czkawka_core::temporary::Temporary; -use czkawka_core::*; use crate::gui_structs::gui_data::GuiData; use crate::help_combo_box::{ @@ -33,17 +34,17 @@ use crate::{flg, DEFAULT_MAXIMAL_FILE_SIZE, DEFAULT_MINIMAL_CACHE_SIZE, DEFAULT_ pub fn connect_button_search( gui_data: &GuiData, glib_stop_sender: Sender, - futures_sender_duplicate_files: futures::channel::mpsc::UnboundedSender, - futures_sender_empty_files: futures::channel::mpsc::UnboundedSender, - futures_sender_empty_folder: futures::channel::mpsc::UnboundedSender, - futures_sender_big_file: futures::channel::mpsc::UnboundedSender, - futures_sender_same_music: futures::channel::mpsc::UnboundedSender, - futures_sender_similar_images: futures::channel::mpsc::UnboundedSender, - futures_sender_similar_videos: futures::channel::mpsc::UnboundedSender, - futures_sender_temporary: futures::channel::mpsc::UnboundedSender, - futures_sender_invalid_symlinks: futures::channel::mpsc::UnboundedSender, - futures_sender_broken_files: futures::channel::mpsc::UnboundedSender, - futures_sender_bad_extensions: futures::channel::mpsc::UnboundedSender, + futures_sender_duplicate_files: UnboundedSender, + futures_sender_empty_files: UnboundedSender, + futures_sender_empty_folder: UnboundedSender, + futures_sender_big_file: UnboundedSender, + futures_sender_same_music: UnboundedSender, + futures_sender_similar_images: UnboundedSender, + futures_sender_similar_videos: UnboundedSender, + futures_sender_temporary: UnboundedSender, + futures_sender_invalid_symlinks: UnboundedSender, + futures_sender_broken_files: UnboundedSender, + futures_sender_bad_extensions: UnboundedSender, ) { let check_button_settings_one_filesystem = gui_data.settings.check_button_settings_one_filesystem.clone(); let combo_box_image_hash_size = gui_data.main_notebook.combo_box_image_hash_size.clone(); diff --git a/czkawka_gui/src/connect_things/connect_popovers_sort.rs b/czkawka_gui/src/connect_things/connect_popovers_sort.rs index 62156cc..ca8c5ee 100644 --- a/czkawka_gui/src/connect_things/connect_popovers_sort.rs +++ b/czkawka_gui/src/connect_things/connect_popovers_sort.rs @@ -119,6 +119,7 @@ pub fn connect_popover_sort(gui_data: &GuiData) { #[cfg(test)] mod test { + use glib::types::Type; use gtk4::prelude::*; use gtk4::{Popover, TreeView}; @@ -126,7 +127,7 @@ mod test { #[gtk4::test] fn test_sort_iters() { - let columns_types: &[glib::types::Type] = &[glib::types::Type::U32, glib::types::Type::STRING]; + let columns_types: &[Type] = &[Type::U32, Type::STRING]; let list_store = gtk4::ListStore::new(columns_types); let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &2), (1, &"AAA")], &[(0, &3), (1, &"CCC")], &[(0, &1), (1, &"BBB")]]; @@ -156,7 +157,7 @@ mod test { #[gtk4::test] pub fn test_popover_sort_general_simple() { - let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL, glib::types::Type::STRING]; + let columns_types: &[Type] = &[Type::BOOL, Type::STRING]; let list_store = gtk4::ListStore::new(columns_types); let tree_view = TreeView::builder().model(&list_store).build(); let popover = Popover::new(); @@ -179,7 +180,7 @@ mod test { #[gtk4::test] pub fn test_popover_sort_general() { - let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL, glib::types::Type::STRING]; + let columns_types: &[Type] = &[Type::BOOL, Type::STRING]; let list_store = gtk4::ListStore::new(columns_types); let tree_view = TreeView::builder().model(&list_store).build(); let popover = Popover::new(); diff --git a/czkawka_gui/src/connect_things/connect_progress_window.rs b/czkawka_gui/src/connect_things/connect_progress_window.rs index 825281c..1a80f03 100644 --- a/czkawka_gui/src/connect_things/connect_progress_window.rs +++ b/czkawka_gui/src/connect_things/connect_progress_window.rs @@ -2,8 +2,8 @@ use futures::channel::mpsc::UnboundedReceiver; use futures::StreamExt; use gtk4::prelude::*; +use czkawka_core::common_dir_traversal; use czkawka_core::common_dir_traversal::ProgressData; -use czkawka_core::{big_file, broken_files, common_dir_traversal, similar_images, similar_videos, temporary}; use crate::flg; use crate::gui_structs::gui_data::GuiData; @@ -16,13 +16,13 @@ pub fn connect_progress_window( mut futures_receiver_duplicate_files: UnboundedReceiver, mut futures_receiver_empty_files: UnboundedReceiver, mut futures_receiver_empty_folder: UnboundedReceiver, - mut futures_receiver_big_files: UnboundedReceiver, + mut futures_receiver_big_files: UnboundedReceiver, mut futures_receiver_same_music: UnboundedReceiver, - mut futures_receiver_similar_images: UnboundedReceiver, - mut futures_receiver_similar_videos: UnboundedReceiver, - mut futures_receiver_temporary: UnboundedReceiver, + mut futures_receiver_similar_images: UnboundedReceiver, + mut futures_receiver_similar_videos: UnboundedReceiver, + mut futures_receiver_temporary: UnboundedReceiver, mut futures_receiver_invalid_symlinks: UnboundedReceiver, - mut futures_receiver_broken_files: UnboundedReceiver, + mut futures_receiver_broken_files: UnboundedReceiver, mut futures_receiver_bad_extensions: UnboundedReceiver, ) { let main_context = glib::MainContext::default(); @@ -175,7 +175,7 @@ pub fn connect_progress_window( while let Some(item) = futures_receiver_big_files.next().await { label_stage.set_text(&flg!( "progress_scanning_general_file", - generate_translation_hashmap(vec![("file_number", item.files_checked.to_string())]) + generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())]) )); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } @@ -257,18 +257,18 @@ pub fn connect_progress_window( progress_bar_current_stage.hide(); label_stage.set_text(&flg!( "progress_scanning_general_file", - generate_translation_hashmap(vec![("file_number", item.images_checked.to_string())]) + generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())]) )); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } 1 => { progress_bar_current_stage.show(); - if item.images_to_check != 0 { - progress_bar_all_stages.set_fraction((1f64 + (item.images_checked) as f64 / item.images_to_check as f64) / (item.max_stage + 1) as f64); - progress_bar_current_stage.set_fraction((item.images_checked) as f64 / item.images_to_check as f64); + if item.entries_to_check != 0 { + progress_bar_all_stages.set_fraction((1f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64); + progress_bar_current_stage.set_fraction((item.entries_checked) as f64 / item.entries_to_check as f64); taskbar_state.borrow().set_progress_value( - (item.images_to_check + item.images_checked) as u64, - item.images_to_check as u64 * (item.max_stage + 1) as u64, + (item.entries_to_check + item.entries_checked) as u64, + item.entries_to_check as u64 * (item.max_stage + 1) as u64, ); } else { progress_bar_all_stages.set_fraction((item.current_stage as f64) / (item.max_stage + 1) as f64); @@ -277,17 +277,17 @@ pub fn connect_progress_window( } label_stage.set_text(&flg!( "progress_scanning_image", - generate_translation_hashmap(vec![("file_checked", item.images_checked.to_string()), ("all_files", item.images_to_check.to_string())]) + generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())]) )); } 2 => { progress_bar_current_stage.show(); - if item.images_to_check != 0 { - progress_bar_all_stages.set_fraction((2f64 + (item.images_checked) as f64 / item.images_to_check as f64) / (item.max_stage + 1) as f64); - progress_bar_current_stage.set_fraction((item.images_checked) as f64 / item.images_to_check as f64); + if item.entries_to_check != 0 { + progress_bar_all_stages.set_fraction((2f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64); + progress_bar_current_stage.set_fraction((item.entries_checked) as f64 / item.entries_to_check as f64); taskbar_state.borrow().set_progress_value( - (item.images_to_check + item.images_checked) as u64, - item.images_to_check as u64 * (item.max_stage + 1) as u64, + (item.entries_to_check + item.entries_checked) as u64, + item.entries_to_check as u64 * (item.max_stage + 1) as u64, ); } else { progress_bar_all_stages.set_fraction((item.current_stage as f64) / (item.max_stage + 1) as f64); @@ -296,7 +296,7 @@ pub fn connect_progress_window( } label_stage.set_text(&flg!( "progress_comparing_image_hashes", - generate_translation_hashmap(vec![("file_checked", item.images_checked.to_string()), ("all_files", item.images_to_check.to_string())]) + generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())]) )); } _ => { @@ -320,18 +320,18 @@ pub fn connect_progress_window( progress_bar_current_stage.hide(); label_stage.set_text(&flg!( "progress_scanning_general_file", - generate_translation_hashmap(vec![("file_number", item.videos_checked.to_string())]) + generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())]) )); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } 1 => { progress_bar_current_stage.show(); - if item.videos_to_check != 0 { - progress_bar_all_stages.set_fraction((1f64 + (item.videos_checked) as f64 / item.videos_to_check as f64) / (item.max_stage + 1) as f64); - progress_bar_current_stage.set_fraction((item.videos_checked) as f64 / item.videos_to_check as f64); + if item.entries_to_check != 0 { + progress_bar_all_stages.set_fraction((1f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64); + progress_bar_current_stage.set_fraction((item.entries_checked) as f64 / item.entries_to_check as f64); taskbar_state.borrow().set_progress_value( - (item.videos_to_check + item.videos_checked) as u64, - item.videos_to_check as u64 * (item.max_stage + 1) as u64, + (item.entries_to_check + item.entries_checked) as u64, + item.entries_to_check as u64 * (item.max_stage + 1) as u64, ); } else { progress_bar_all_stages.set_fraction((1f64) / (item.max_stage + 1) as f64); @@ -340,7 +340,7 @@ pub fn connect_progress_window( } label_stage.set_text(&flg!( "progress_scanning_video", - generate_translation_hashmap(vec![("file_checked", item.videos_checked.to_string()), ("all_files", item.videos_to_check.to_string())]) + generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())]) )); } _ => { @@ -359,7 +359,7 @@ pub fn connect_progress_window( while let Some(item) = futures_receiver_temporary.next().await { label_stage.set_text(&flg!( "progress_scanning_general_file", - generate_translation_hashmap(vec![("file_number", item.files_checked.to_string())]) + generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())]) )); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } @@ -394,18 +394,19 @@ pub fn connect_progress_window( progress_bar_current_stage.hide(); label_stage.set_text(&flg!( "progress_scanning_general_file", - generate_translation_hashmap(vec![("file_number", item.files_checked.to_string())]) + generate_translation_hashmap(vec![("file_number", item.entries_checked.to_string())]) )); taskbar_state.borrow().set_progress_state(TBPF_INDETERMINATE); } 1 => { progress_bar_current_stage.show(); - if item.files_to_check != 0 { - progress_bar_all_stages.set_fraction((1f64 + (item.files_checked) as f64 / item.files_to_check as f64) / (item.max_stage + 1) as f64); - progress_bar_current_stage.set_fraction((item.files_checked) as f64 / item.files_to_check as f64); - taskbar_state - .borrow() - .set_progress_value((item.files_to_check + item.files_checked) as u64, item.files_to_check as u64 * (item.max_stage + 1) as u64); + if item.entries_to_check != 0 { + progress_bar_all_stages.set_fraction((1f64 + (item.entries_checked) as f64 / item.entries_to_check as f64) / (item.max_stage + 1) as f64); + progress_bar_current_stage.set_fraction((item.entries_checked) as f64 / item.entries_to_check as f64); + taskbar_state.borrow().set_progress_value( + (item.entries_to_check + item.entries_checked) as u64, + item.entries_to_check as u64 * (item.max_stage + 1) as u64, + ); } else { progress_bar_all_stages.set_fraction((1f64) / (item.max_stage + 1) as f64); progress_bar_current_stage.set_fraction(0f64); @@ -413,7 +414,7 @@ pub fn connect_progress_window( } label_stage.set_text(&flg!( "progress_scanning_broken_files", - generate_translation_hashmap(vec![("file_checked", item.files_checked.to_string()), ("all_files", item.files_to_check.to_string())]) + generate_translation_hashmap(vec![("file_checked", item.entries_checked.to_string()), ("all_files", item.entries_to_check.to_string())]) )); } _ => { diff --git a/czkawka_gui/src/gui_structs/gui_data.rs b/czkawka_gui/src/gui_structs/gui_data.rs index ef96646..f00e2d3 100644 --- a/czkawka_gui/src/gui_structs/gui_data.rs +++ b/czkawka_gui/src/gui_structs/gui_data.rs @@ -1,5 +1,6 @@ use std::cell::RefCell; use std::collections::HashMap; +use std::io::BufReader; use std::rc::Rc; use crossbeam_channel::bounded; @@ -122,7 +123,7 @@ impl GuiData { window_main.set_title(Some(&flg!("window_main_title"))); window_main.show(); - let pixbuf = Pixbuf::from_read(std::io::BufReader::new(ICON_ABOUT)).unwrap(); + let pixbuf = Pixbuf::from_read(BufReader::new(ICON_ABOUT)).unwrap(); window_main.set_application(Some(application)); diff --git a/czkawka_gui/src/help_functions.rs b/czkawka_gui/src/help_functions.rs index f530101..e3af425 100644 --- a/czkawka_gui/src/help_functions.rs +++ b/czkawka_gui/src/help_functions.rs @@ -1,5 +1,6 @@ use std::cmp::Ordering; use std::collections::HashMap; +use std::io::BufReader; use std::path::PathBuf; use gdk4::gdk_pixbuf::{InterpType, Pixbuf}; @@ -714,7 +715,7 @@ const TYPE_OF_INTERPOLATION: InterpType = InterpType::Tiles; pub fn set_icon_of_button>(button: &P, data: &'static [u8]) { let image = get_custom_image_from_widget(&button.clone()); - let pixbuf = Pixbuf::from_read(std::io::BufReader::new(data)).unwrap(); + let pixbuf = Pixbuf::from_read(BufReader::new(data)).unwrap(); let pixbuf = pixbuf.scale_simple(SIZE_OF_ICON, SIZE_OF_ICON, TYPE_OF_INTERPOLATION).unwrap(); image.set_from_pixbuf(Some(&pixbuf)); } @@ -778,6 +779,7 @@ pub fn scale_step_function(scale: >k4::Scale, _scroll_type: ScrollType, value: #[cfg(test)] mod test { + use glib::types::Type; use gtk4::prelude::*; use gtk4::Orientation; use image::DynamicImage; @@ -789,7 +791,7 @@ mod test { #[gtk4::test] fn test_check_if_list_store_column_have_all_same_values() { - let columns_types: &[glib::types::Type] = &[glib::types::Type::BOOL]; + let columns_types: &[Type] = &[Type::BOOL]; let list_store = gtk4::ListStore::new(columns_types); list_store.clear(); @@ -823,7 +825,7 @@ mod test { #[gtk4::test] fn test_check_if_value_is_in_list_store() { - let columns_types: &[glib::types::Type] = &[glib::types::Type::STRING]; + let columns_types: &[Type] = &[Type::STRING]; let list_store = gtk4::ListStore::new(columns_types); let values_to_add: &[(u32, &dyn ToValue)] = &[(0, &"Koczkodan"), (0, &"Kachir")]; for i in values_to_add { @@ -833,7 +835,7 @@ mod test { assert!(check_if_value_is_in_list_store(&list_store, 0, "Kachir")); assert!(!check_if_value_is_in_list_store(&list_store, 0, "Koczkodan2")); - let columns_types: &[glib::types::Type] = &[glib::types::Type::STRING, glib::types::Type::STRING]; + let columns_types: &[Type] = &[Type::STRING, Type::STRING]; let list_store = gtk4::ListStore::new(columns_types); let values_to_add: &[&[(u32, &dyn ToValue)]] = &[&[(0, &"Koczkodan"), (1, &"Krakus")], &[(0, &"Kachir"), (1, &"Wodnica")]]; for i in values_to_add { diff --git a/czkawka_gui/src/initialize_gui.rs b/czkawka_gui/src/initialize_gui.rs index 2c4690b..527d180 100644 --- a/czkawka_gui/src/initialize_gui.rs +++ b/czkawka_gui/src/initialize_gui.rs @@ -3,6 +3,7 @@ use std::path::Path; use std::rc::Rc; use gdk4::gdk_pixbuf::Pixbuf; +use glib::types::Type; use gtk4::gdk_pixbuf::InterpType; use gtk4::prelude::*; use gtk4::{CheckButton, Image, SelectionMode, TextView, TreeView}; @@ -304,9 +305,9 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let evk = gui_data.upper_notebook.evk_tree_view_included_directories.clone(); let gc = gui_data.upper_notebook.gc_tree_view_included_directories.clone(); - let col_types: [glib::types::Type; 2] = [ - glib::types::Type::STRING, // Path - glib::types::Type::BOOL, // ReferenceButton + let col_types: [Type; 2] = [ + Type::STRING, // Path + Type::BOOL, // ReferenceButton ]; let list_store: gtk4::ListStore = gtk4::ListStore::new(&col_types); @@ -341,7 +342,7 @@ pub fn initialize_gui(gui_data: &mut GuiData) { let evk = gui_data.upper_notebook.evk_tree_view_excluded_directories.clone(); let gc = gui_data.upper_notebook.gc_tree_view_excluded_directories.clone(); - let col_types: [glib::types::Type; 1] = [glib::types::Type::STRING]; + let col_types: [Type; 1] = [Type::STRING]; let list_store: gtk4::ListStore = gtk4::ListStore::new(&col_types); tree_view.set_model(Some(&list_store)); diff --git a/czkawka_gui/src/main.rs b/czkawka_gui/src/main.rs index 604c914..d0ec0a8 100644 --- a/czkawka_gui/src/main.rs +++ b/czkawka_gui/src/main.rs @@ -5,6 +5,8 @@ #![allow(clippy::type_complexity)] #![allow(clippy::needless_late_init)] +use futures::channel::mpsc; +use futures::channel::mpsc::{UnboundedReceiver, UnboundedSender}; use std::env; use std::ffi::OsString; @@ -32,6 +34,7 @@ use connect_things::connect_settings::*; use connect_things::connect_show_hide_ui::*; use connect_things::connect_similar_image_size_change::*; use czkawka_core::common::{get_number_of_threads, set_number_of_threads}; +use czkawka_core::common_dir_traversal::ProgressData; use czkawka_core::*; use gui_structs::gui_data::*; @@ -80,50 +83,17 @@ fn build_ui(application: &Application, arguments: &[OsString]) { let (glib_stop_sender, glib_stop_receiver) = glib::MainContext::channel(glib::PRIORITY_DEFAULT); // Futures progress report - let (futures_sender_duplicate_files, futures_receiver_duplicate_files): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_empty_files, futures_receiver_empty_files): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_empty_folder, futures_receiver_empty_folder): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_big_file, futures_receiver_big_files): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_same_music, futures_receiver_same_music): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_similar_images, futures_receiver_similar_images): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_similar_videos, futures_receiver_similar_videos): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_temporary, futures_receiver_temporary): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_broken_files, futures_receiver_broken_files): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); - let (futures_sender_bad_extensions, futures_receiver_bad_extensions): ( - futures::channel::mpsc::UnboundedSender, - futures::channel::mpsc::UnboundedReceiver, - ) = futures::channel::mpsc::unbounded(); + let (futures_sender_duplicate_files, futures_receiver_duplicate_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_empty_files, futures_receiver_empty_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_empty_folder, futures_receiver_empty_folder): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_big_file, futures_receiver_big_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_same_music, futures_receiver_same_music): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_similar_images, futures_receiver_similar_images): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_similar_videos, futures_receiver_similar_videos): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_temporary, futures_receiver_temporary): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_invalid_symlinks, futures_receiver_invalid_symlinks): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_broken_files, futures_receiver_broken_files): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); + let (futures_sender_bad_extensions, futures_receiver_bad_extensions): (UnboundedSender, UnboundedReceiver) = mpsc::unbounded(); initialize_gui(&mut gui_data); validate_notebook_data(&gui_data); // Must be run after initialization of gui, to check if everything was properly setup diff --git a/czkawka_gui/src/notebook_info.rs b/czkawka_gui/src/notebook_info.rs index 1438be0..95aba44 100644 --- a/czkawka_gui/src/notebook_info.rs +++ b/czkawka_gui/src/notebook_info.rs @@ -3,6 +3,7 @@ use crate::help_functions::{ ColumnsSameMusic, ColumnsSimilarImages, ColumnsSimilarVideos, ColumnsTemporaryFiles, PopoverTypes, }; use crate::notebook_enums::{NotebookMainEnum, NUMBER_OF_NOTEBOOK_MAIN_TABS}; +use glib::types::Type; pub struct NotebookObject { pub notebook_type: NotebookMainEnum, @@ -16,7 +17,7 @@ pub struct NotebookObject { pub column_size: Option, pub column_size_as_bytes: Option, pub column_modification_as_secs: Option, - pub columns_types: &'static [glib::types::Type], + pub columns_types: &'static [Type], pub bottom_buttons: &'static [BottomButtonsEnum], } @@ -41,17 +42,17 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: Some(ColumnsDuplicates::SizeAsBytes as i32), column_modification_as_secs: Some(ColumnsDuplicates::ModificationAsSecs as i32), columns_types: &[ - glib::types::Type::BOOL, // ActivatableSelectButton - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Size - glib::types::Type::U64, // SizeAsBytes - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs - glib::types::Type::STRING, // Color - glib::types::Type::BOOL, // IsHeader - glib::types::Type::STRING, // TextColor + Type::BOOL, // ActivatableSelectButton + Type::BOOL, // SelectionButton + Type::STRING, // Size + Type::U64, // SizeAsBytes + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // ModificationAsSecs + Type::STRING, // Color + Type::BOOL, // IsHeader + Type::STRING, // TextColor ], bottom_buttons: &[ BottomButtonsEnum::Save, @@ -76,11 +77,11 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], }, @@ -97,13 +98,13 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Size - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // SizeAsBytes - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Size + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // SizeAsBytes + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], }, @@ -120,11 +121,11 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], }, @@ -141,11 +142,11 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], }, @@ -162,19 +163,19 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: Some(ColumnsSimilarImages::SizeAsBytes as i32), column_modification_as_secs: Some(ColumnsSimilarImages::ModificationAsSecs as i32), columns_types: &[ - glib::types::Type::BOOL, // ActivatableSelectButton - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Similarity - glib::types::Type::STRING, // Size - glib::types::Type::U64, // SizeAsBytes - glib::types::Type::STRING, // Dimensions - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs - glib::types::Type::STRING, // Color - glib::types::Type::BOOL, // IsHeader - glib::types::Type::STRING, // TextColor + Type::BOOL, // ActivatableSelectButton + Type::BOOL, // SelectionButton + Type::STRING, // Similarity + Type::STRING, // Size + Type::U64, // SizeAsBytes + Type::STRING, // Dimensions + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // ModificationAsSecs + Type::STRING, // Color + Type::BOOL, // IsHeader + Type::STRING, // TextColor ], bottom_buttons: &[ BottomButtonsEnum::Save, @@ -200,17 +201,17 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: Some(ColumnsSimilarVideos::SizeAsBytes as i32), column_modification_as_secs: Some(ColumnsSimilarVideos::ModificationAsSecs as i32), columns_types: &[ - glib::types::Type::BOOL, // ActivatableSelectButton - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Size - glib::types::Type::U64, // SizeAsBytes - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs - glib::types::Type::STRING, // Color - glib::types::Type::BOOL, // IsHeader - glib::types::Type::STRING, // TextColor + Type::BOOL, // ActivatableSelectButton + Type::BOOL, // SelectionButton + Type::STRING, // Size + Type::U64, // SizeAsBytes + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Modification + Type::U64, // ModificationAsSecs + Type::STRING, // Color + Type::BOOL, // IsHeader + Type::STRING, // TextColor ], bottom_buttons: &[ BottomButtonsEnum::Save, @@ -235,24 +236,24 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: Some(ColumnsSameMusic::SizeAsBytes as i32), column_modification_as_secs: Some(ColumnsSameMusic::ModificationAsSecs as i32), columns_types: &[ - glib::types::Type::BOOL, // ActivatableSelectButton - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Size - glib::types::Type::U64, // SizeAsBytes - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // Title - glib::types::Type::STRING, // Artist - glib::types::Type::STRING, // Year - glib::types::Type::STRING, // Bitrate - glib::types::Type::U64, // BitrateAsNumber - glib::types::Type::STRING, // Length - glib::types::Type::STRING, // Genre - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs - glib::types::Type::STRING, // Color - glib::types::Type::BOOL, // IsHeader - glib::types::Type::STRING, // TextColor + Type::BOOL, // ActivatableSelectButton + Type::BOOL, // SelectionButton + Type::STRING, // Size + Type::U64, // SizeAsBytes + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // Title + Type::STRING, // Artist + Type::STRING, // Year + Type::STRING, // Bitrate + Type::U64, // BitrateAsNumber + Type::STRING, // Length + Type::STRING, // Genre + Type::STRING, // Modification + Type::U64, // ModificationAsSecs + Type::STRING, // Color + Type::BOOL, // IsHeader + Type::STRING, // TextColor ], bottom_buttons: &[ BottomButtonsEnum::Save, @@ -277,13 +278,13 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // DestinationPath - glib::types::Type::STRING, // TypeOfError - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // DestinationPath + Type::STRING, // TypeOfError + Type::STRING, // Modification + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], }, @@ -300,12 +301,12 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // ErrorType - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // ErrorType + Type::STRING, // Modification + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], }, @@ -322,13 +323,13 @@ pub static NOTEBOOKS_INFO: [NotebookObject; NUMBER_OF_NOTEBOOK_MAIN_TABS] = [ column_size_as_bytes: None, column_modification_as_secs: None, columns_types: &[ - glib::types::Type::BOOL, // SelectionButton - glib::types::Type::STRING, // Name - glib::types::Type::STRING, // Path - glib::types::Type::STRING, // CurrentExtension - glib::types::Type::STRING, // ProperExtensions - glib::types::Type::STRING, // Modification - glib::types::Type::U64, // ModificationAsSecs + Type::BOOL, // SelectionButton + Type::STRING, // Name + Type::STRING, // Path + Type::STRING, // CurrentExtension + Type::STRING, // ProperExtensions + Type::STRING, // Modification + Type::U64, // ModificationAsSecs ], bottom_buttons: &[BottomButtonsEnum::Save, BottomButtonsEnum::Delete, BottomButtonsEnum::Select, BottomButtonsEnum::Move], },