1
0
Fork 0
mirror of synced 2024-04-28 09:33:30 +12:00

Fixes random things (#1160)

* AB

* More simple

* Optimize even more code

* Delete info

* Common

* Randoms

* Included

* ProfData

* Upgrade
This commit is contained in:
Rafał Mikrut 2024-01-13 13:57:51 +01:00 committed by GitHub
parent bf78fc8b57
commit 0defcbd253
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
18 changed files with 577 additions and 530 deletions

3
.gitignore vendored
View file

@ -17,4 +17,5 @@ ci_tester/target
ci_tester/Cargo.lock
krokiet/Cargo.lock
krokiet/target
*.json
*.json
*.mm_profdata

847
Cargo.lock generated

File diff suppressed because it is too large Load diff

View file

@ -1,4 +1,8 @@
## Version 7.0.0 - ?
### BREAKING CHANGES
- Reducing size of cache files, made old cache files incompatible with new version
- `-C` in CLI now saves as compact json
### GTK GUI
- Added drag&drop support for included/excluded folders - [#1106](https://github.com/qarmin/czkawka/pull/1106)
- Added information where are saved scan results - [#1102](https://github.com/qarmin/czkawka/pull/1102)
@ -23,6 +27,7 @@
- Fixed recognizing not accessible folders as non-empty - [#1152](https://github.com/qarmin/czkawka/pull/1152)
- Unifying code for collecting files to scan - [#1159](https://github.com/qarmin/czkawka/pull/1159)
- Decrease memory usage when collecting files by removing unused fields in custom file entries structs - [#1159](https://github.com/qarmin/czkawka/pull/1159)
- Decrease a little size of cache by few percents and improve loading/saving speed - [#1159](https://github.com/qarmin/czkawka/pull/1159)
## Version 6.1.0 - 15.10.2023r
- BREAKING CHANGE - Changed cache saving method, deduplicated, optimized and simplified procedure(all files needs to be hashed again) - [#1072](https://github.com/qarmin/czkawka/pull/1072), [#1086](https://github.com/qarmin/czkawka/pull/1086)
@ -171,7 +176,7 @@
## Version 3.2.0 - 07.08.2021r
- Use checkbox instead selection to select files [#392](https://github.com/qarmin/czkawka/pull/392)
- Re-enable hardlink on windows - [#410](https://github.com/qarmin/czkawka/pull/410)
- Fix symlink and harlink creating - [#409](https://github.com/qarmin/czkawka/pull/409)
- Fix symlink and hardlink creating - [#409](https://github.com/qarmin/czkawka/pull/409)
- Add image preview to duplicate finder [#408](https://github.com/qarmin/czkawka/pull/408)
- Add setting maximum file size [#407](https://github.com/qarmin/czkawka/pull/407)
- Add new grouping algorithm to similar images [#405](https://github.com/qarmin/czkawka/pull/405)

View file

@ -26,7 +26,7 @@ hamming = "0.1"
# Needed by same music
bitflags = "2.4"
lofty = "0.17"
lofty = "0.18"
# Needed by broken files
zip = { version = "0.6", features = ["aes-crypto", "bzip2", "deflate", "time"], default-features = false }
@ -42,7 +42,7 @@ blake3 = "1.5"
crc32fast = "1.3"
xxhash-rust = { version = "0.8", features = ["xxh3"] }
tempfile = "3.8"
tempfile = "3.9"
# Video Duplicates
vid_dup_finder_lib = "0.1"
@ -56,7 +56,7 @@ serde_json = "1.0"
# Language
i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.7"
rust-embed = { version = "8.1", features = ["debug-embed"] }
rust-embed = { version = "8.2", features = ["debug-embed"] }
once_cell = "1.19"
# Raw image files

View file

@ -331,40 +331,21 @@ pub fn split_path(path: &Path) -> (String, String) {
}
pub fn split_path_compare(path_a: &Path, path_b: &Path) -> Ordering {
let parent_dir_a = path_a.parent();
let parent_dir_b = path_b.parent();
if parent_dir_a.is_none() || parent_dir_b.is_none() {
let file_name_a = path_a.file_name();
let file_name_b = path_b.file_name();
if file_name_a.is_none() || file_name_b.is_none() {
return Ordering::Equal;
}
return if file_name_a > file_name_b { Ordering::Greater } else { Ordering::Less };
}
if parent_dir_a > parent_dir_b {
Ordering::Greater
} else {
Ordering::Less
match path_a.parent().cmp(&path_b.parent()) {
Ordering::Equal => path_a.file_name().cmp(&path_b.file_name()),
other => other,
}
}
pub fn create_crash_message(library_name: &str, file_path: &str, home_library_url: &str) -> String {
format!("{library_name} library crashed when opening \"{file_path}\", please check if this is fixed with the latest version of {library_name} (e.g. with https://github.com/qarmin/crates_tester) and if it is not fixed, please report bug here - {home_library_url}")
format!("{library_name} library crashed when opening \"{file_path}\", please check if this is fixed with the latest version of {library_name} and if it is not fixed, please report bug here - {home_library_url}")
}
pub fn regex_check(expression_item: &SingleExcludedItem, directory: impl AsRef<Path>) -> bool {
if expression_item.expression == "*" {
pub fn regex_check(expression_item: &SingleExcludedItem, directory_name: &str) -> bool {
if expression_item.expression_splits.is_empty() {
return true;
}
if expression_item.expression_splits.is_empty() {
return false;
}
// Get rid of non unicode characters
let directory_name = directory.as_ref().to_string_lossy();
// Early checking if directory contains all parts needed by expression
for split in &expression_item.unique_extensions_splits {
if !directory_name.contains(split) {
@ -481,7 +462,7 @@ where
infos.push(format!(
"dry_run - would create hardlink from {:?} to {:?}",
original_file.get_path(),
original_file.get_path()
file_entry.get_path()
));
} else {
if dry_run {
@ -519,7 +500,7 @@ where
if dry_run {
infos.push(format!("dry_run - would delete file: {:?}", i.get_path()));
} else {
if let Err(e) = std::fs::remove_file(i.get_path()) {
if let Err(e) = fs::remove_file(i.get_path()) {
errors.push(format!("Cannot delete file: {:?} - {e}", i.get_path()));
failed_to_remove_files += 1;
} else {
@ -661,6 +642,7 @@ mod test {
#[test]
fn test_regex() {
assert!(regex_check(&new_excluded_item("*"), "/home/rafal"));
assert!(regex_check(&new_excluded_item("*home*"), "/home/rafal"));
assert!(regex_check(&new_excluded_item("*home"), "/home"));
assert!(regex_check(&new_excluded_item("*home/"), "/home/"));

View file

@ -12,33 +12,34 @@ use serde::{Deserialize, Serialize};
use std::collections::BTreeMap;
use std::io::{BufReader, BufWriter};
const CACHE_VERSION: &str = "70";
pub fn get_broken_files_cache_file() -> String {
"cache_broken_files_61.bin".to_string()
format!("cache_broken_files_{CACHE_VERSION}.bin")
}
pub fn get_similar_images_cache_file(hash_size: &u8, hash_alg: &HashAlg, image_filter: &FilterType) -> String {
format!(
"cache_similar_images_{}_{}_{}_61.bin",
hash_size,
"cache_similar_images_{hash_size}_{}_{}_{CACHE_VERSION}.bin",
convert_algorithm_to_string(hash_alg),
convert_filters_to_string(image_filter),
)
}
pub fn get_similar_videos_cache_file() -> String {
"cache_similar_videos_61.bin".to_string()
format!("cache_similar_videos_{CACHE_VERSION}.bin")
}
pub fn get_similar_music_cache_file(checking_tags: bool) -> &'static str {
pub fn get_similar_music_cache_file(checking_tags: bool) -> String {
if checking_tags {
"cache_same_music_tags_61.bin"
format!("cache_same_music_tags_{CACHE_VERSION}.bin")
} else {
"cache_same_music_fingerprints_61.bin"
format!("cache_same_music_fingerprints_{CACHE_VERSION}.bin")
}
}
pub fn get_duplicate_cache_file(type_of_hash: &HashType, is_prehash: bool) -> String {
let prehash_str = if is_prehash { "_prehash" } else { "" };
format!("cache_duplicates_{type_of_hash:?}{prehash_str}_61.bin")
format!("cache_duplicates_{type_of_hash:?}{prehash_str}_{CACHE_VERSION}.bin")
}
#[fun_time(message = "save_cache_to_file_generalized", level = "debug")]

View file

@ -305,8 +305,7 @@ impl Directories {
self.reference_directories.iter().any(|e| path.starts_with(e))
}
pub fn is_excluded(&self, path: impl AsRef<Path>) -> bool {
let path = path.as_ref();
pub fn is_excluded(&self, path: &Path) -> bool {
#[cfg(target_family = "windows")]
let path = normalize_windows_path(path);
// We're assuming that `excluded_directories` are already normalized

View file

@ -85,15 +85,17 @@ impl ExcludedItems {
pub fn get_excluded_items(&self) -> &Vec<String> {
&self.expressions
}
pub fn is_excluded(&self, path: impl AsRef<Path>) -> bool {
pub fn is_excluded(&self, path: &Path) -> bool {
if self.connected_expressions.is_empty() {
return false;
}
#[cfg(target_family = "windows")]
let path = normalize_windows_path(path);
let path_str = path.to_string_lossy();
for expression in &self.connected_expressions {
if regex_check(expression, &path) {
if regex_check(expression, &path_str) {
return true;
}
}
@ -107,6 +109,7 @@ pub fn new_excluded_item(expression: &str) -> SingleExcludedItem {
let mut unique_extensions_splits = expression_splits.clone();
unique_extensions_splits.sort();
unique_extensions_splits.dedup();
unique_extensions_splits.sort_by_key(|b| std::cmp::Reverse(b.len()));
SingleExcludedItem {
expression,
expression_splits,

View file

@ -222,7 +222,7 @@ impl SameMusic {
if self.common_data.use_cache {
let (messages, loaded_items) =
load_cache_from_file_generalized_by_path::<MusicEntry>(get_similar_music_cache_file(checking_tags), self.get_delete_outdated_cache(), &self.music_to_check);
load_cache_from_file_generalized_by_path::<MusicEntry>(&get_similar_music_cache_file(checking_tags), self.get_delete_outdated_cache(), &self.music_to_check);
self.get_text_messages_mut().extend_with_another_messages(messages);
loaded_hash_map = loaded_items.unwrap_or_default();
@ -260,7 +260,7 @@ impl SameMusic {
all_results.insert(file_entry.path.to_string_lossy().to_string(), file_entry);
}
let messages = save_cache_to_file_generalized(get_similar_music_cache_file(checking_tags), &all_results, self.common_data.save_also_as_json, 0);
let messages = save_cache_to_file_generalized(&get_similar_music_cache_file(checking_tags), &all_results, self.common_data.save_also_as_json, 0);
self.get_text_messages_mut().extend_with_another_messages(messages);
}

View file

@ -36,7 +36,7 @@ regex = "1.10"
image_hasher = "1.2"
# Move files to trash
trash = "3.1"
trash = "3.2"
# For moving files(why std::fs doesn't have such features?)
fs_extra = "1.3"
@ -44,7 +44,7 @@ fs_extra = "1.3"
# Language
i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.7"
rust-embed = { version = "8.1", features = ["debug-embed"] }
rust-embed = { version = "8.2", features = ["debug-embed"] }
once_cell = "1.19"
log = "0.4.20"

View file

@ -450,7 +450,7 @@ fn popover_custom_select_unselect(
need_to_change_thing = true;
}
} else {
if regex_check(&name_wildcard_lowercase_excluded, name.to_lowercase()) {
if regex_check(&name_wildcard_lowercase_excluded, &name.to_lowercase()) {
need_to_change_thing = true;
}
}
@ -461,7 +461,7 @@ fn popover_custom_select_unselect(
need_to_change_thing = true;
}
} else {
if regex_check(&path_wildcard_lowercase_excluded, path.to_lowercase()) {
if regex_check(&path_wildcard_lowercase_excluded, &path.to_lowercase()) {
need_to_change_thing = true;
}
}

View file

@ -11,15 +11,6 @@ repository = "https://github.com/qarmin/czkawka"
build = "build.rs"
[dependencies]
# Try to use only needed features from https://github.com/slint-ui/slint/blob/master/api/rs/slint/Cargo.toml#L23-L31
#slint = { path = "/home/rafal/test/slint/api/rs/slint/", default-features = false, features = ["std",
#slint = { git = "https://github.com/slint-ui/slint.git", default-features = false, features = [
slint = { version = "1.3", default-features = false, features = [
"std",
"backend-winit",
"compat-1-2"
] }
rand = "0.8"
czkawka_core = { version = "6.1.0", path = "../czkawka_core" }
chrono = "0.4.31"
@ -40,13 +31,21 @@ rayon = "1.8.0"
# Translations
i18n-embed = { version = "0.14", features = ["fluent-system", "desktop-requester"] }
i18n-embed-fl = "0.7"
rust-embed = { version = "8.1", features = ["debug-embed"] }
rust-embed = { version = "8.2", features = ["debug-embed"] }
once_cell = "1.19"
# Try to use only needed features from https://github.com/slint-ui/slint/blob/master/api/rs/slint/Cargo.toml#L23-L31
#slint = { path = "/home/rafal/test/slint/api/rs/slint/", default-features = false, features = ["std",
slint = { git = "https://github.com/slint-ui/slint.git", default-features = false, features = [
# slint = { version = "1.3", default-features = false, features = [
"std",
"backend-winit",
"compat-1-2"
] }
[build-dependencies]
slint-build = "1.3"
#slint-build = { git = "https://github.com/slint-ui/slint.git" }
#slint-build = { path = "/home/rafal/test/slint/api/rs/build/"}
slint-build = { git = "https://github.com/slint-ui/slint.git" }
# slint-build = "1.3"
[features]
default = ["winit_femtovg", "winit_software"]

View file

@ -3,7 +3,6 @@ use slint::{ComponentHandle, Model, ModelRc, VecModel};
use crate::common::{get_is_header_mode, get_name_idx, get_path_idx};
use crate::{Callabler, CurrentTab, GuiState, MainListModel, MainWindow};
use czkawka_core::common::{remove_folder_if_contains_only_empty_folders, CHARACTER};
use log::info;
use rayon::prelude::*;
pub fn connect_delete_button(app: &MainWindow) {
@ -64,7 +63,6 @@ fn remove_selected_items(items: Vec<MainListModel>, active_tab: CurrentTab) {
})
.collect::<Vec<_>>();
info!("Removing items: {:?} {:?}", items_to_remove, active_tab);
// Iterate over empty folders and not delete them if they are not empty
if active_tab == CurrentTab::EmptyFolders {
items_to_remove.into_par_iter().for_each(|item| {

View file

@ -259,7 +259,7 @@ pub fn save_base_settings_to_file(app: &MainWindow) {
pub fn save_custom_settings_to_file(app: &MainWindow) {
let current_item = app.global::<Settings>().get_settings_preset_idx();
let result = save_data_to_file(get_config_file(current_item), &collect_settings(app));
let result = save_data_to_file(get_config_file(current_item + 1), &collect_settings(app));
if let Err(e) = result {
error!("{e}");
@ -279,14 +279,18 @@ where
}
let result = match std::fs::read_to_string(&config_file) {
Ok(serialized) => match serde_json::from_str(&serialized) {
Ok(custom_settings) => Ok(custom_settings),
Err(e) => Err(format!("Cannot deserialize settings: {e}")),
},
Ok(serialized) => {
debug!("Loading data from file {:?} took {:?}", config_file, current_time.elapsed());
match serde_json::from_str(&serialized) {
Ok(custom_settings) => Ok(custom_settings),
Err(e) => Err(format!("Cannot deserialize settings: {e}")),
}
}
Err(e) => Err(format!("Cannot read config file: {e}")),
};
debug!("Loading data from file {:?} took {:?}", config_file, current_time.elapsed());
debug!("Loading and converting data from file {:?} took {:?}", config_file, current_time.elapsed());
result
}

View file

@ -0,0 +1,101 @@
import {Button, StandardListView, VerticalBox, ListView, ScrollView, TextEdit, CheckBox} from "std-widgets.slint";
import {Callabler} from "callabler.slint";
export struct IncludedDirectoriesModel {
path: string,
referended_folder: bool,
}
export component InlcudedDirectories {
in-out property <[IncludedDirectoriesModel]> model: [{path: "/home/path", referended_folder: false}];
in-out property <int> current_index: -1;
in-out property <length> size_referenced_folder: 40px;
min-width: 50px;
VerticalLayout {
HorizontalLayout {
spacing: 5px;
Text {
text: "Referenced folder";
width: size_referenced_folder;
}
Text{
horizontal-stretch: 1.0;
text: "Path";
}
}
ListView {
for data in model : Rectangle {
height: 30px;
border_radius: 5px;
width: parent.width;
HorizontalLayout {
spacing: 5px;
width: parent.width;
CheckBox {
checked: data.referended_folder;
width: size_referenced_folder;
}
Text {
horizontal-stretch: 1.0;
text: data.path;
vertical-alignment: center;
}
}
}
}
}
}
export component ExcludeDirectories {
in-out property <[string]> model: ["/home/path"];
in-out property <int> current_index: -1;
private property <PointerEvent> event;
min-width: 50px;
VerticalLayout {
HorizontalLayout {
spacing: 5px;
Text {
text: "Path";
}
}
ListView {
for data[idx] in model : Rectangle {
height: 30px;
border_radius: 5px;
width: parent.width;
touch_area := TouchArea {
clicked => {
if (current_index == -1) {
}
}
double-clicked => {
if (event.button == PointerEventButton.middle && event.kind == PointerEventKind.up) {
Callabler.item_opened(data)
}
}
pointer-event(event) => {
root.event = event;
}
}
HorizontalLayout {
spacing: 5px;
width: parent.width;
Text {
horizontal-stretch: 1.0;
text: data;
vertical-alignment: center;
}
}
}
}
}
}

View file

@ -108,7 +108,7 @@ export component LeftSidePanel {
HorizontalLayout {
alignment: start;
Button {
enabled: GuiState.active_tab != CurrentTab.Settings && GuiState.available_subsettings;
visible: GuiState.active_tab != CurrentTab.Settings && GuiState.available_subsettings;
min-width: 20px;
min-height: 20px;
max-height: self.width;
@ -122,7 +122,7 @@ export component LeftSidePanel {
HorizontalLayout {
alignment: end;
Button {
enabled: GuiState.active_tab != CurrentTab.Settings;
visible: GuiState.active_tab != CurrentTab.Settings;
min-width: 20px;
min-height: 20px;
max-height: self.width;

View file

@ -75,17 +75,16 @@ export component SelectableTableView inherits Rectangle {
height: 20px;
background: r.header-row ? ColorPalette.list_view_normal_header_color : (touch-area.has-hover ? (r.selected_row ? ColorPalette.list-view-normal-selected-header : ColorPalette.list_view_normal_color) : (r.selected_row ? ColorPalette.list-view-normal-selected-header : ColorPalette.list_view_normal_color));
touch_area := TouchArea {
clicked => {
function clicked_manual() {
if (!r.header_row) {
r.selected_row = !r.selected_row;
if (root.selected-item == -1) {
r.selected_row = !r.selected_row;
root.selected-item = idx;
} else {
if (r.selected_row == true) {
if (!r.selected_row && root.selected-item != idx) {
r.selected_row = !r.selected_row;
root.values[root.selected-item].selected_row = false;
root.selected-item = idx;
} else {
root.selected-item = -1;
}
}
@ -96,13 +95,19 @@ export component SelectableTableView inherits Rectangle {
}
}
}
double-clicked => {
Callabler.item_opened(r.val[root.parentPathIdx - 1] + "/" + r.val[root.fileNameIdx - 1])
}
pointer-event(event) => {
// TODO this should be clicked by double-click
// TODO this should be clicked by double-click - https://github.com/slint-ui/slint/issues/4235
if (event.button == PointerEventButton.right && event.kind == PointerEventKind.up) {
Callabler.item_opened(r.val[root.parentPathIdx - 1])
} else if (event.button == PointerEventButton.middle && event.kind == PointerEventKind.up) {
Callabler.item_opened(r.val[root.parentPathIdx - 1] + "/" + r.val[root.fileNameIdx - 1])
} else if (event.button == PointerEventButton.left && event.kind == PointerEventKind.up) {
clicked_manual();
}
//else if (event.button == PointerEventButton.middle && event.kind == PointerEventKind.up) {
// Callabler.item_opened(r.val[root.parentPathIdx - 1] + "/" + r.val[root.fileNameIdx - 1])
//}
}
}

View file

@ -15,7 +15,7 @@ import { Preview } from "preview.slint";
import {PopupNewDirectories} from "popup_new_directories.slint";
import { PopupSelect } from "popup_select.slint";
component ComboBoxWrapper inherits HorizontalLayout {
component ComboBoxWrapper inherits HorizontalLayout {
in-out property <string> text;
in-out property <[string]> model;
in-out property <int> current_index;