1
0
Fork 0
mirror of synced 2024-05-03 03:52:58 +12:00
This commit is contained in:
Rafał Mikrut 2024-02-10 23:57:52 +01:00
parent 8f202dd2ef
commit 9a1e1939ac
9 changed files with 109 additions and 99 deletions

View file

@ -40,7 +40,8 @@ pub const SIMILAR_VALUES: [[u32; 6]; 4] = [
pub struct ImagesEntry {
pub path: PathBuf,
pub size: u64,
pub dimensions: String,
pub width: u32,
pub height: u32,
pub modified_date: u64,
pub hash: ImHash,
pub similarity: u32,
@ -65,7 +66,8 @@ impl FileEntry {
path: self.path,
modified_date: self.modified_date,
dimensions: String::new(),
width: 0,
height: 0,
hash: Vec::new(),
similarity: 0,
image_type: ImageType::Unknown,
@ -393,7 +395,8 @@ impl SimilarImages {
let dimensions = img.dimensions();
file_entry.dimensions = format!("{}x{}", dimensions.0, dimensions.1);
file_entry.width = dimensions.0;
file_entry.height = dimensions.1;
let hasher_config = HasherConfig::new()
.hash_size(self.hash_size as u32, self.hash_size as u32)
@ -782,9 +785,10 @@ impl PrintResults for SimilarImages {
for file_entry in struct_similar {
writeln!(
writer,
"{:?} - {} - {} - {}",
"{:?} - {}x{} - {} - {}",
file_entry.path,
file_entry.dimensions,
file_entry.width,
file_entry.height,
format_size(file_entry.size, BINARY),
get_string_from_similarity(&file_entry.similarity, self.hash_size)
)?;
@ -799,18 +803,20 @@ impl PrintResults for SimilarImages {
writeln!(writer)?;
writeln!(
writer,
"{:?} - {} - {} - {}",
"{:?} - {}x{} - {} - {}",
file_entry.path,
file_entry.dimensions,
file_entry.width,
file_entry.height,
format_size(file_entry.size, BINARY),
get_string_from_similarity(&file_entry.similarity, self.hash_size)
)?;
for file_entry in vec_file_entry {
writeln!(
writer,
"{:?} - {} - {} - {}",
"{:?} - {}x{} - {} - {}",
file_entry.path,
file_entry.dimensions,
file_entry.width,
file_entry.height,
format_size(file_entry.size, BINARY),
get_string_from_similarity(&file_entry.similarity, self.hash_size)
)?;
@ -1505,7 +1511,8 @@ mod tests {
ImagesEntry {
path: PathBuf::from(name.to_string()),
size: 0,
dimensions: String::new(),
width: 100,
height: 100,
modified_date: 0,
hash,
similarity: 0,

View file

@ -755,7 +755,7 @@ fn compute_similar_images(
&directory,
base_file_entry.size,
base_file_entry.modified_date,
&base_file_entry.dimensions,
&format!("{}x{}", base_file_entry.width, base_file_entry.height),
0,
hash_size,
true,
@ -769,7 +769,7 @@ fn compute_similar_images(
&directory,
file_entry.size,
file_entry.modified_date,
&file_entry.dimensions,
&format!("{}x{}", file_entry.width, file_entry.height),
file_entry.similarity,
hash_size,
false,
@ -799,7 +799,7 @@ fn compute_similar_images(
&directory,
file_entry.size,
file_entry.modified_date,
&file_entry.dimensions,
&format!("{}x{}", file_entry.width, file_entry.height),
file_entry.similarity,
hash_size,
false,

View file

@ -49,8 +49,8 @@ fn remove_selected_items(items: Vec<MainListModel>, active_tab: CurrentTab) {
let items_to_remove = items
.iter()
.map(|item| {
let path = item.val.iter().nth(path_idx).unwrap();
let name = item.val.iter().nth(name_idx).unwrap();
let path = item.val_str.iter().nth(path_idx).unwrap();
let name = item.val_str.iter().nth(name_idx).unwrap();
format!("{}{}{}", path, MAIN_SEPARATOR, name)
})
.collect::<Vec<_>>();
@ -196,8 +196,8 @@ mod tests {
(false, false, false, vec!["5"]),
]);
let (to_delete, left) = filter_out_checked_items(&items, false);
let to_delete_data = get_single_data_from_model(&to_delete);
let left_data = get_single_data_from_model(&left);
let to_delete_data = get_single_data_str_from_model(&to_delete);
let left_data = get_single_data_str_from_model(&left);
assert_eq!(to_delete_data, vec!["3", "4"]);
assert_eq!(left_data, vec!["1", "2", "5"]);
@ -216,8 +216,8 @@ mod tests {
(false, false, false, vec!["8"]),
]);
let (to_delete, left) = filter_out_checked_items(&items, true);
let to_delete_data = get_single_data_from_model(&to_delete);
let left_data = get_single_data_from_model(&left);
let to_delete_data = get_single_data_str_from_model(&to_delete);
let left_data = get_single_data_str_from_model(&left);
assert_eq!(to_delete_data, vec!["3"]);
assert_eq!(left_data, vec!["6", "7", "8"]);
@ -236,15 +236,15 @@ mod tests {
(false, false, false, vec!["8"]),
]);
let (to_delete, left) = filter_out_checked_items(&items, true);
let to_delete_data = get_single_data_from_model(&to_delete);
let left_data = get_single_data_from_model(&left);
let to_delete_data = get_single_data_str_from_model(&to_delete);
let left_data = get_single_data_str_from_model(&left);
assert_eq!(to_delete_data, vec!["3"]);
assert_eq!(left_data, vec!["1", "2", "4", "5", "6"]);
}
fn get_single_data_from_model(model: &[MainListModel]) -> Vec<String> {
let mut d = model.iter().map(|item| item.val.iter().next().unwrap().to_string()).collect::<Vec<_>>();
fn get_single_data_str_from_model(model: &[MainListModel]) -> Vec<String> {
let mut d = model.iter().map(|item| item.val_str.iter().next().unwrap().to_string()).collect::<Vec<_>>();
d.sort();
d
}
@ -258,7 +258,8 @@ mod tests {
checked: item.0,
header_row: item.1,
selected_row: item.2,
val: ModelRc::new(all_items),
val_str: ModelRc::new(all_items),
val_int: ModelRc::new(VecModel::default()),
});
}
ModelRc::new(model)

View file

@ -108,29 +108,12 @@ fn write_similar_images_results_referenced(app: &MainWindow, vector: Vec<(Images
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for (ref_fe, vec_fe) in vector {
let (ref_directory, ref_file) = split_path(ref_fe.get_path());
let ref_data_model = VecModel::from_slice(&[
similar_images::get_string_from_similarity(&ref_fe.similarity, hash_size).into(),
format_size(ref_fe.size, BINARY).into(),
ref_fe.dimensions.clone().into(),
ref_file.into(),
ref_directory.into(),
NaiveDateTime::from_timestamp_opt(ref_fe.get_modified_date() as i64, 0).unwrap().to_string().into(),
]);
insert_data_to_model(&items, ref_data_model, true);
let (data_model_str, data_model_int) = prepare_data_model_similar_images(&ref_fe, hash_size);
insert_data_to_model(&items, data_model_str, data_model_int, true);
for fe in vec_fe {
let (directory, file) = split_path(fe.get_path());
let data_model = VecModel::from_slice(&[
similar_images::get_string_from_similarity(&fe.similarity, hash_size).into(),
format_size(fe.size, BINARY).into(),
fe.dimensions.clone().into(),
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.get_modified_date() as i64, 0).unwrap().to_string().into(),
]);
insert_data_to_model(&items, data_model, false);
let (data_model_str, data_model_int) = prepare_data_model_similar_images(&fe, hash_size);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
}
app.set_similar_images_model(items.into());
@ -141,26 +124,31 @@ fn write_similar_images_results(app: &MainWindow, vector: Vec<Vec<ImagesEntry>>,
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for vec_fe in vector {
insert_data_to_model(&items, ModelRc::new(VecModel::default()), true);
insert_data_to_model(&items, ModelRc::new(VecModel::default()), ModelRc::new(VecModel::default()), true);
for fe in vec_fe {
let (directory, file) = split_path(fe.get_path());
let data_model = VecModel::from_slice(&[
similar_images::get_string_from_similarity(&fe.similarity, hash_size).into(),
format_size(fe.size, BINARY).into(),
fe.dimensions.clone().into(),
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.get_modified_date() as i64, 0).unwrap().to_string().into(),
]);
insert_data_to_model(&items, data_model, false);
let (data_model_str, data_model_int) = prepare_data_model_similar_images(&fe, hash_size);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
}
app.set_similar_images_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} similar images files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_similar_images(fe: &ImagesEntry, hash_size: u8) -> (ModelRc<SharedString>, ModelRc<i32>) {
let (directory, file) = split_path(fe.get_path());
let data_model_str = VecModel::from_slice(&[
similar_images::get_string_from_similarity(&fe.similarity, hash_size).into(),
format_size(fe.size, BINARY).into(),
format!("{}x{}", fe.width, fe.height).into(),
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.get_modified_date() as i64, 0).unwrap().to_string().into(),
]);
let data_model_int = VecModel::from_slice(&[fe.width as i32, fe.height as i32]);
(data_model_str, data_model_int)
}
///////////////////////////////// Empty Files
fn scan_empty_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) {
thread::Builder::new()
.stack_size(DEFAULT_THREAD_SIZE)
@ -184,20 +172,26 @@ fn write_empty_files_results(app: &MainWindow, vector: Vec<FileEntry>, messages:
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for fe in vector {
let (directory, file) = split_path(fe.get_path());
let data_model = VecModel::from_slice(&[
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.get_modified_date() as i64, 0).unwrap().to_string().into(),
]);
insert_data_to_model(&items, data_model, false);
let (data_model_str, data_model_int) = prepare_data_model_empty_files(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
app.set_empty_files_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} empty files").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn prepare_data_model_empty_files(fe: &FileEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
let (directory, file) = split_path(fe.get_path());
let data_model_str = VecModel::from_slice(&[
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.get_modified_date() as i64, 0).unwrap().to_string().into(),
]);
let data_model_int = VecModel::from_slice(&[]);
(data_model_str, data_model_int)
}
////////////////////////////////////////// Empty Folders
fn scan_empty_folders(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) {
thread::Builder::new()
.stack_size(DEFAULT_THREAD_SIZE)
@ -221,26 +215,33 @@ fn write_empty_folders_results(app: &MainWindow, vector: Vec<FolderEntry>, messa
let items_found = vector.len();
let items = Rc::new(VecModel::default());
for fe in vector {
let (directory, file) = split_path(&fe.path);
let data_model = VecModel::from_slice(&[
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.modified_date as i64, 0).unwrap().to_string().into(),
]);
insert_data_to_model(&items, data_model, false);
let (data_model_str, data_model_int) = prepare_data_model_empty_folders(&fe);
insert_data_to_model(&items, data_model_str, data_model_int, false);
}
app.set_empty_folder_model(items.into());
app.invoke_scan_ended(format!("Found {items_found} empty folders").into());
app.global::<GuiState>().set_info_text(messages.into());
}
fn insert_data_to_model(items: &Rc<VecModel<MainListModel>>, data_model: ModelRc<SharedString>, header_row: bool) {
fn prepare_data_model_empty_folders(fe: &FolderEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
let (directory, file) = split_path(&fe.path);
let data_model_str = VecModel::from_slice(&[
file.into(),
directory.into(),
NaiveDateTime::from_timestamp_opt(fe.modified_date as i64, 0).unwrap().to_string().into(),
]);
let data_model_int = VecModel::from_slice(&[]);
(data_model_str, data_model_int)
}
////////////////////////////////////////// Common
fn insert_data_to_model(items: &Rc<VecModel<MainListModel>>, data_model_str: ModelRc<SharedString>, data_model_int: ModelRc<i32>, header_row: bool) {
let main = MainListModel {
checked: false,
header_row,
selected_row: false,
val: ModelRc::new(data_model),
val_str: ModelRc::new(data_model_str),
val_int: ModelRc::new(data_model_int), // TODO fill
};
items.push(main);
}

View file

@ -1,6 +1,6 @@
use crate::common::{get_tool_model, set_tool_model};
use crate::SelectModel;
use crate::{Callabler, GuiState, MainListModel, MainWindow, SelectMode};
use crate::{CurrentTab, SelectModel};
use slint::{ComponentHandle, Model, ModelRc, VecModel};
// TODO optimize this, not sure if it is possible to not copy entire model to just select item
@ -22,7 +22,7 @@ pub fn connect_select(app: &MainWindow) {
}
pub fn connect_showing_proper_select_buttons(app: &MainWindow) {
set_select_buttons(&app);
set_select_buttons(app);
let a = app.as_weak();
app.global::<Callabler>().on_tab_changed(move || {
let app = a.upgrade().unwrap();

View file

@ -20,7 +20,8 @@ export struct MainListModel {
checked: bool,
header_row: bool,
selected_row: bool,
val: [string]
val_str: [string],
val_int: [int]
}
export enum BottomPanelVisibility {

View file

@ -8,10 +8,10 @@ import {GuiState} from "gui_state.slint";
export component MainList {
in-out property <[MainListModel]> empty_folder_model: [
{checked: false, selected_row: false, header_row: true, val: ["kropkarz", "/Xd1", "24.10.2023"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: true, selected_row: false, header_row: false, val: ["lokkaler", "/Xd1/Vide2", "01.23.1911"]}
{checked: false, selected_row: false, header_row: true, val_str: ["kropkarz", "/Xd1", "24.10.2023"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: true, selected_row: false, header_row: false, val_str: ["lokkaler", "/Xd1/Vide2", "01.23.1911"], val_int: []}
];
in-out property <[MainListModel]> empty_files_model;
in-out property <[MainListModel]> similar_images_model;

View file

@ -38,16 +38,16 @@ export component MainWindow inherits Window {
step_name: "Cache",
};
in-out property <[MainListModel]> empty_folder_model: [
{checked: false, selected_row: false, header_row: true, val: ["kropkarz", "/Xd1", "24.10.2023"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: true, selected_row: false, header_row: false, val: ["lokkaler", "/Xd1/Vide2", "01.23.1911"]}
{checked: false, selected_row: false, header_row: true, val_str: ["kropkarz", "/Xd1", "24.10.2023"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: true, selected_row: false, header_row: false, val_str: ["lokkaler", "/Xd1/Vide2", "01.23.1911"], val_int: []}
];
in-out property <[MainListModel]> empty_files_model: [
{checked: false, selected_row: false, header_row: true, val: ["kropkarz", "/Xd1", "24.10.2023"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: true, selected_row: false, header_row: false, val: ["lokkaler", "/Xd1/Vide2", "01.23.1911"]}
{checked: false, selected_row: false, header_row: true, val_str: ["kropkarz", "/Xd1", "24.10.2023"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: true, selected_row: false, header_row: false, val_str: ["lokkaler", "/Xd1/Vide2", "01.23.1911"], val_int: []}
];
in-out property <[MainListModel]> similar_images_model: [];

View file

@ -9,10 +9,10 @@ export component SelectableTableView inherits Rectangle {
callback item_opened(string);
in property <[string]> columns;
in-out property <[MainListModel]> values: [
{checked: false, selected_row: false, header_row: true, val: ["kropkarz", "/Xd1", "24.10.2023"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: false, selected_row: false, header_row: false, val: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"]} ,
{checked: true, selected_row: false, header_row: false, val: ["lokkaler", "/Xd1/Vide2", "01.23.1911"]}
{checked: false, selected_row: false, header_row: true, val_str: ["kropkarz", "/Xd1", "24.10.2023"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: false, selected_row: false, header_row: false, val_str: ["witasphere", "/Xd1/Imagerren2", "25.11.1991"], val_int: []} ,
{checked: true, selected_row: false, header_row: false, val_str: ["lokkaler", "/Xd1/Vide2", "01.23.1911"], val_int: []}
];
in-out property <[length]> column_sizes: [30px, 80px, 150px, 160px];
private property <int> column_number: column-sizes.length + 1;
@ -89,24 +89,24 @@ export component SelectableTableView inherits Rectangle {
}
if (root.selected_item != -1) {
Callabler.load_image_preview(r.val[root.parentPathIdx - 1] + "/" + r.val[root.fileNameIdx - 1]);
Callabler.load_image_preview(r.val_str[root.parentPathIdx - 1] + "/" + r.val_str[root.fileNameIdx - 1]);
} else {
GuiState.preview_visible = false;
}
}
}
double-clicked => {
Callabler.item_opened(r.val[root.parentPathIdx - 1] + "/" + r.val[root.fileNameIdx - 1])
Callabler.item_opened(r.val_str[root.parentPathIdx - 1] + "/" + r.val_str[root.fileNameIdx - 1])
}
pointer-event(event) => {
// 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])
Callabler.item_opened(r.val_str[root.parentPathIdx - 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])
// Callabler.item_opened(r.val_str[root.parentPathIdx - 1] + "/" + r.val_str[root.fileNameIdx - 1])
//}
}
}
@ -123,7 +123,7 @@ export component SelectableTableView inherits Rectangle {
HorizontalLayout {
spacing: 5px;
for f [idx] in r.val: Text {
for f [idx] in r.val_str: Text {
width: root.column-sizes[idx + 1];
text: f;
font-size: 12px;