fn check_for_similar_images(&mut self, stop_receiver: Option<&Receiver<()>>, progress_sender: Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>) -> bool {
        let start_time: SystemTime = SystemTime::now();
        let mut folders_to_check: Vec<PathBuf> = 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

        // Add root folders for finding
        for id in &self.directories.included_directories {
            folders_to_check.push(id.clone());
        }

        //// PROGRESS THREAD START
        const LOOP_DURATION: u32 = 200; //in ms
        let progress_thread_run = Arc::new(AtomicBool::new(true));

        let atomic_file_counter = Arc::new(AtomicUsize::new(0));

        let progress_thread_handle;
        if let Some(progress_sender) = progress_sender {
            let progress_send = progress_sender.clone();
            let progress_thread_run = progress_thread_run.clone();
            let atomic_file_counter = atomic_file_counter.clone();
            progress_thread_handle = thread::spawn(move || loop {
                progress_send
                    .unbounded_send(ProgressData {
                        current_stage: 0,
                        max_stage: 1,
                        images_checked: atomic_file_counter.load(Ordering::Relaxed) as usize,
                        images_to_check: 0,
                    })
                    .unwrap();
                if !progress_thread_run.load(Ordering::Relaxed) {
                    break;
                }
                sleep(Duration::from_millis(LOOP_DURATION as u64));
            });
        } else {
            progress_thread_handle = thread::spawn(|| {});
        }
        //// PROGRESS THREAD END

        while !folders_to_check.is_empty() {
            if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
                // End thread which send info to gui
                progress_thread_run.store(false, Ordering::Relaxed);
                progress_thread_handle.join().unwrap();
                return false;
            }
            let current_folder = folders_to_check.pop().unwrap();

            // Read current dir, if permission are denied just go to next
            let read_dir = match fs::read_dir(&current_folder) {
                Ok(t) => t,
                Err(e) => {
                    self.text_messages.warnings.push(format!("Cannot open dir {}, reason {}", current_folder.display(), e));
                    continue;
                } // Permissions denied
            };

            // Check every sub folder/file/link etc.
            'dir: for entry in read_dir {
                let entry_data = match entry {
                    Ok(t) => t,
                    Err(e) => {
                        self.text_messages.warnings.push(format!("Cannot read entry in dir {}, reason {}", current_folder.display(), e));
                        continue;
                    } //Permissions denied
                };
                let metadata: Metadata = match entry_data.metadata() {
                    Ok(t) => t,
                    Err(e) => {
                        self.text_messages.warnings.push(format!("Cannot read metadata in dir {}, reason {}", current_folder.display(), e));
                        continue;
                    } //Permissions denied
                };
                if metadata.is_dir() {
                    if !self.recursive_search {
                        continue;
                    }

                    let next_folder = current_folder.join(entry_data.file_name());
                    if self.directories.is_excluded(&next_folder) {
                        continue 'dir;
                    }

                    if self.excluded_items.is_excluded(&next_folder) {
                        continue 'dir;
                    }

                    folders_to_check.push(next_folder);
                } else if metadata.is_file() {
                    atomic_file_counter.fetch_add(1, Ordering::Relaxed);

                    let file_name_lowercase: String = match entry_data.file_name().into_string() {
                        Ok(t) => t,
                        Err(_inspected) => {
                            println!("File {:?} has not valid UTF-8 name", entry_data);
                            continue 'dir;
                        }
                    }
                    .to_lowercase();

                    // Checking allowed image extensions
                    let allowed_image_extensions = [".jpg", ".jpeg", ".png" /*, ".bmp"*/, ".tiff", ".tif", ".tga", ".ff" /*, ".gif"*/, ".jif", ".jfi" /*, ".webp"*/]; // webp cannot be seen in preview, gif needs to be enabled after releasing image crate 0.24.0, bmp needs to be fixed in image crate
                    if !allowed_image_extensions.iter().any(|e| file_name_lowercase.ends_with(e)) {
                        continue 'dir;
                    }

                    // Checking files
                    if (self.minimal_file_size..=self.maximal_file_size).contains(&metadata.len()) {
                        let current_file_name = current_folder.join(entry_data.file_name());
                        if self.excluded_items.is_excluded(&current_file_name) {
                            continue 'dir;
                        }

                        let fe: FileEntry = FileEntry {
                            path: current_file_name.clone(),
                            size: metadata.len(),
                            dimensions: "".to_string(),
                            modified_date: match metadata.modified() {
                                Ok(t) => match t.duration_since(UNIX_EPOCH) {
                                    Ok(d) => d.as_secs(),
                                    Err(_inspected) => {
                                        self.text_messages.warnings.push(format!("File {} seems to be modified before Unix Epoch.", current_file_name.display()));
                                        0
                                    }
                                },
                                Err(e) => {
                                    self.text_messages.warnings.push(format!("Unable to get modification date from file {}, reason {}", current_file_name.display(), e));
                                    0
                                } // Permissions Denied
                            },

                            hash: Vec::new(),
                            similarity: Similarity::None,
                        };

                        self.images_to_check.insert(current_file_name.to_string_lossy().to_string(), fe);
                    }
                }
            }
        }
        // End thread which send info to gui
        progress_thread_run.store(false, Ordering::Relaxed);
        progress_thread_handle.join().unwrap();
        Common::print_time(start_time, SystemTime::now(), "check_for_similar_images".to_string());
        true
    }
/// Function to check if folder are empty.
/// Parameter initial_checking for second check before deleting to be sure that checked folder is still empty
Function to check if folder are empty.
Parameter initial_checking for second check before deleting to be sure that checked folder is still empty
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<ProgressData>>) -> bool {
        let start_time: SystemTime = SystemTime::now();
        let mut folders_to_check: Vec<PathBuf> = 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
        // Add root folders for finding
        for id in &self.directories.included_directories {
            folders_to_check.push(id.clone());
        }
        //// PROGRESS THREAD START
        const LOOP_DURATION: u32 = 200; //in ms
        let progress_thread_run = Arc::new(AtomicBool::new(true));
        let atomic_file_counter = Arc::new(AtomicUsize::new(0));
        let progress_thread_handle;
        if let Some(progress_sender) = progress_sender {
            let progress_send = progress_sender.clone();
            let progress_thread_run = progress_thread_run.clone();
            let atomic_file_counter = atomic_file_counter.clone();
            progress_thread_handle = thread::spawn(move || loop {
                progress_send
                    .unbounded_send(ProgressData {
                        current_stage: 0,
                        max_stage: 1,
                        images_checked: atomic_file_counter.load(Ordering::Relaxed) as usize,
                        images_to_check: 0,
                    })
                    .unwrap();
                if !progress_thread_run.load(Ordering::Relaxed) {
                    break;
                }
                sleep(Duration::from_millis(LOOP_DURATION as u64));
            });
        } else {
            progress_thread_handle = thread::spawn(|| {});
        }
        //// PROGRESS THREAD END
        while !folders_to_check.is_empty() {
            if stop_receiver.is_some() && stop_receiver.unwrap().try_recv().is_ok() {
                // End thread which send info to gui
                progress_thread_run.store(false, Ordering::Relaxed);
                progress_thread_handle.join().unwrap();
                return false;
            }
            let current_folder = folders_to_check.pop().unwrap();
            // Read current dir, if permission are denied just go to next
            let read_dir = match fs::read_dir(&current_folder) {
                Ok(t) => t,
                Err(e) => {
                    self.text_messages.warnings.push(format!("Cannot open dir {}, reason {}", current_folder.display(), e));
                    continue;
                } // Permissions denied
            };
            // Check every sub folder/file/link etc.
            'dir: for entry in read_dir {
                let entry_data = match entry {
                    Ok(t) => t,
                    Err(e) => {
                        self.text_messages.warnings.push(format!("Cannot read entry in dir {}, reason {}", current_folder.display(), e));
                        continue;
                    } //Permissions denied
                };
                let metadata: Metadata = match entry_data.metadata() {
                    Ok(t) => t,
                    Err(e) => {
                        self.text_messages.warnings.push(format!("Cannot read metadata in dir {}, reason {}", current_folder.display(), e));
                        continue;
                    } //Permissions denied
                };
                if metadata.is_dir() {
                    if !self.recursive_search {
                        continue;
                    }
                    let next_folder = current_folder.join(entry_data.file_name());
                    if self.directories.is_excluded(&next_folder) {
                        continue 'dir;
                    }
                    if self.excluded_items.is_excluded(&next_folder) {
                        continue 'dir;
                    }
                    folders_to_check.push(next_folder);
                } else if metadata.is_file() {
                    atomic_file_counter.fetch_add(1, Ordering::Relaxed);
                    let file_name_lowercase: String = match entry_data.file_name().into_string() {
                        Ok(t) => t,
                        Err(_inspected) => {
                            println!("File {:?} has not valid UTF-8 name", entry_data);
                            continue 'dir;
                        }
                    }
                    .to_lowercase();
                    // Checking allowed image extensions
                    let allowed_image_extensions = [".jpg", ".jpeg", ".png" /*, ".bmp"*/, ".tiff", ".tif", ".tga", ".ff" /*, ".gif"*/, ".jif", ".jfi" /*, ".webp"*/]; // webp cannot be seen in preview, gif needs to be enabled after releasing image crate 0.24.0, bmp needs to be fixed in image crate
                    if !allowed_image_extensions.iter().any(|e| file_name_lowercase.ends_with(e)) {
                        continue 'dir;
                    }
                    // Checking files
                    if (self.minimal_file_size..=self.maximal_file_size).contains(&metadata.len()) {
                        let current_file_name = current_folder.join(entry_data.file_name());
                        if self.excluded_items.is_excluded(&current_file_name) {
                            continue 'dir;
                        }
                        let fe: FileEntry = FileEntry {
                            path: current_file_name.clone(),
                            size: metadata.len(),
                            dimensions: "".to_string(),
                            modified_date: match metadata.modified() {
                                Ok(t) => match t.duration_since(UNIX_EPOCH) {
                                    Ok(d) => d.as_secs(),
                                    Err(_inspected) => {
                                        self.text_messages.warnings.push(format!("File {} seems to be modified before Unix Epoch.", current_file_name.display()));
                                        0
                                    }
                                },
                                Err(e) => {
                                    self.text_messages.warnings.push(format!("Unable to get modification date from file {}, reason {}", current_file_name.display(), e));
                                    0
                                } // Permissions Denied
                            },
                            hash: Vec::new(),
                            similarity: Similarity::None,
                        };
                        self.images_to_check.insert(current_file_name.to_string_lossy().to_string(), fe);
                    }
                }
            }
        }
        // End thread which send info to gui
        progress_thread_run.store(false, Ordering::Relaxed);
        progress_thread_handle.join().unwrap();
        Common::print_time(start_time, SystemTime::now(), "check_for_similar_images".to_string());
        true
    }
fn check_for_similar_images ( & mut self , stop_receiver : Option < & Receiver < ( ) > > , progress_sender : Option < & futures :: channel :: mpsc :: UnboundedSender < ProgressData > > ) -> bool { let start_time : SystemTime = SystemTime :: now ( ) ; let mut folders_to_check : Vec < PathBuf > = 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 // Add root folders for finding for id in & self . directories . included_directories { folders_to_check . push ( id . clone ( ) ) ; } //// PROGRESS THREAD START const LOOP_DURATION : u32 = 200 ; //in ms let progress_thread_run = Arc :: new ( AtomicBool :: new ( true ) ) ; let atomic_file_counter = Arc :: new ( AtomicUsize :: new ( 0 ) ) ; let progress_thread_handle ; if let Some ( progress_sender ) = progress_sender { let progress_send = progress_sender . clone ( ) ; let progress_thread_run = progress_thread_run . clone ( ) ; let atomic_file_counter = atomic_file_counter . clone ( ) ; progress_thread_handle = thread :: spawn ( move | | loop { progress_send . unbounded_send ( ProgressData { current_stage : 0 , max_stage : 1 , images_checked : atomic_file_counter . load ( Ordering :: Relaxed ) as usize , images_to_check : 0 , } ) . unwrap ( ) ; if ! progress_thread_run . load ( Ordering :: Relaxed ) { break ; } sleep ( Duration :: from_millis ( LOOP_DURATION as u64 ) ) ; } ) ; } else { progress_thread_handle = thread :: spawn ( | | { } ) ; } //// PROGRESS THREAD END while ! folders_to_check . is_empty ( ) { if stop_receiver . is_some ( ) && stop_receiver . unwrap ( ) . try_recv ( ) . is_ok ( ) { // End thread which send info to gui progress_thread_run . store ( false , Ordering :: Relaxed ) ; progress_thread_handle . join ( ) . unwrap ( ) ; return false ; } let current_folder = folders_to_check . pop ( ) . unwrap ( ) ; // Read current dir, if permission are denied just go to next let read_dir = match fs :: read_dir ( & current_folder ) { Ok ( t ) => t , Err ( e ) => { self . text_messages . warnings . push ( format ! ( " " current_folder display ( ) e ) ) ; continue ; } // Permissions denied } ; // Check every sub folder/file/link etc. ' dir : for entry in read_dir { let entry_data = match entry { Ok ( t ) => t , Err ( e ) => { self . text_messages . warnings . push ( format ! ( " " current_folder display ( ) e ) ) ; continue ; } //Permissions denied } ; let metadata : Metadata = match entry_data . metadata ( ) { Ok ( t ) => t , Err ( e ) => { self . text_messages . warnings . push ( format ! ( " " current_folder display ( ) e ) ) ; continue ; } //Permissions denied } ; if metadata . is_dir ( ) { if ! self . recursive_search { continue ; } let next_folder = current_folder . join ( entry_data . file_name ( ) ) ; if self . directories . is_excluded ( & next_folder ) { continue ' dir ; } if self . excluded_items . is_excluded ( & next_folder ) { continue ' dir ; } folders_to_check . push ( next_folder ) ; } else if metadata . is_file ( ) { atomic_file_counter . fetch_add ( 1 , Ordering :: Relaxed ) ; let file_name_lowercase : String = match entry_data . file_name ( ) . into_string ( ) { Ok ( t ) => t , Err ( _inspected ) => { println ! ( " " entry_data ) ; continue ' dir ; } } . to_lowercase ( ) ; // Checking allowed image extensions let allowed_image_extensions = [ " " , " " , " " /*, ".bmp"*/ , " " , " " , " " , " " /*, ".gif"*/ , " " , " " /*, ".webp"*/ ] ; // webp cannot be seen in preview, gif needs to be enabled after releasing image crate 0.24.0, bmp needs to be fixed in image crate if ! allowed_image_extensions . iter ( ) . any ( | e | file_name_lowercase . ends_with ( e ) ) { continue ' dir ; } // Checking files if ( self . minimal_file_size ..= self . maximal_file_size ) . contains ( & metadata . len ( ) ) { let current_file_name = current_folder . join ( entry_data . file_name ( ) ) ; if self . excluded_items . is_excluded ( & current_file_name ) { continue ' dir ; } let fe : FileEntry = FileEntry { path : current_file_name . clone ( ) , size : metadata . len ( ) , dimensions : " " . to_string ( ) , modified_date : match metadata . modified ( ) { Ok ( t ) => match t . duration_since ( UNIX_EPOCH ) { Ok ( d ) => d . as_secs ( ) , Err ( _inspected ) => { self . text_messages . warnings . push ( format ! ( " " current_file_name display ( ) ) ) ; 0 } } , Err ( e ) => { self . text_messages . warnings . push ( format ! ( " " current_file_name display ( ) e ) ) ; 0 } // Permissions Denied } , hash : Vec :: new ( ) , similarity : Similarity :: None , } ; self . images_to_check . insert ( current_file_name . to_string_lossy ( ) . to_string ( ) , fe ) ; } } } } // End thread which send info to gui progress_thread_run . store ( false , Ordering :: Relaxed ) ; progress_thread_handle . join ( ) . unwrap ( ) ; Common :: print_time ( start_time , SystemTime :: now ( ) , " " . to_string ( ) ) ; true }
Function to check if folder are empty.
Function to check if folder are empty .
&mut self
stop_receiver
Option<&Receiver<()>>
progress_sender
Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>
&mut self
stop_receiver
Option<&Receiver<()>>
progress_sender
Option<&futures::channel::mpsc::UnboundedSender<ProgressData>>