Subsettings
This commit is contained in:
parent
2cc8b97035
commit
062785c008
|
@ -32,11 +32,20 @@ const TEMP_EXTENSIONS: &[&str] = &[
|
|||
];
|
||||
|
||||
#[derive(Clone, Serialize, Debug)]
|
||||
pub struct FileEntry {
|
||||
pub struct TemporaryFileEntry {
|
||||
pub path: PathBuf,
|
||||
pub modified_date: u64,
|
||||
}
|
||||
|
||||
impl TemporaryFileEntry {
|
||||
pub fn get_path(&self) -> &PathBuf {
|
||||
&self.path
|
||||
}
|
||||
pub fn get_modified_date(&self) -> u64 {
|
||||
self.modified_date
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct Info {
|
||||
pub number_of_temporary_files: usize,
|
||||
|
@ -45,7 +54,7 @@ pub struct Info {
|
|||
pub struct Temporary {
|
||||
common_data: CommonToolData,
|
||||
information: Info,
|
||||
temporary_files: Vec<FileEntry>,
|
||||
temporary_files: Vec<TemporaryFileEntry>,
|
||||
}
|
||||
|
||||
impl Temporary {
|
||||
|
@ -138,7 +147,7 @@ impl Temporary {
|
|||
|
||||
true
|
||||
}
|
||||
pub fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>) -> Option<FileEntry> {
|
||||
pub fn get_file_entry(&self, atomic_counter: &Arc<AtomicUsize>, entry_data: &DirEntry, warnings: &mut Vec<String>) -> Option<TemporaryFileEntry> {
|
||||
atomic_counter.fetch_add(1, Ordering::Relaxed);
|
||||
|
||||
let current_file_name = entry_data.path();
|
||||
|
@ -158,7 +167,7 @@ impl Temporary {
|
|||
};
|
||||
|
||||
// Creating new file entry
|
||||
Some(FileEntry {
|
||||
Some(TemporaryFileEntry {
|
||||
modified_date: get_modified_time(&metadata, warnings, ¤t_file_name, false),
|
||||
path: current_file_name,
|
||||
})
|
||||
|
@ -234,7 +243,7 @@ impl CommonData for Temporary {
|
|||
}
|
||||
|
||||
impl Temporary {
|
||||
pub const fn get_temporary_files(&self) -> &Vec<FileEntry> {
|
||||
pub const fn get_temporary_files(&self) -> &Vec<TemporaryFileEntry> {
|
||||
&self.temporary_files
|
||||
}
|
||||
|
||||
|
|
|
@ -73,12 +73,9 @@ pub enum StrDataEmptyFiles {
|
|||
pub enum IntDataTemporaryFiles {
|
||||
ModificationDatePart1,
|
||||
ModificationDatePart2,
|
||||
SizePart1,
|
||||
SizePart2,
|
||||
}
|
||||
#[repr(u8)]
|
||||
pub enum StrDataTemporaryFiles {
|
||||
Size,
|
||||
Name,
|
||||
Path,
|
||||
ModificationDate,
|
||||
|
@ -253,13 +250,12 @@ pub fn get_int_size_idx(active_tab: CurrentTab) -> usize {
|
|||
CurrentTab::SimilarImages => IntDataSimilarImages::SizePart1 as usize,
|
||||
CurrentTab::DuplicateFiles => IntDataDuplicateFiles::SizePart1 as usize,
|
||||
CurrentTab::BigFiles => IntDataBigFiles::SizePart1 as usize,
|
||||
CurrentTab::TemporaryFiles => IntDataTemporaryFiles::SizePart1 as usize,
|
||||
CurrentTab::SimilarVideos => IntDataSimilarVideos::SizePart1 as usize,
|
||||
CurrentTab::SimilarMusic => IntDataSimilarMusic::SizePart1 as usize,
|
||||
CurrentTab::BrokenFiles => IntDataBrokenFiles::SizePart1 as usize,
|
||||
CurrentTab::BadExtensions => IntDataBadExtensions::SizePart1 as usize,
|
||||
CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"),
|
||||
CurrentTab::EmptyFolders | CurrentTab::InvalidSymlinks => panic!("Unable to get size from this tab"),
|
||||
CurrentTab::EmptyFolders | CurrentTab::InvalidSymlinks | CurrentTab::TemporaryFiles => panic!("Unable to get size from this tab"),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -22,6 +22,7 @@ use czkawka_core::same_music::{MusicEntry, SameMusic};
|
|||
use czkawka_core::similar_images;
|
||||
use czkawka_core::similar_images::{ImagesEntry, SimilarImages};
|
||||
use czkawka_core::similar_videos::{SimilarVideos, VideosEntry};
|
||||
use czkawka_core::temporary::{Temporary, TemporaryFileEntry};
|
||||
|
||||
use crate::common::split_u64_into_i32s;
|
||||
use crate::settings::{collect_settings, SettingsCustom, ALLOWED_HASH_TYPE_VALUES, ALLOWED_RESIZE_ALGORITHM_VALUES};
|
||||
|
@ -74,8 +75,10 @@ pub fn connect_scan_button(app: &MainWindow, progress_sender: Sender<ProgressDat
|
|||
CurrentTab::BrokenFiles => {
|
||||
scan_broken_files(a, progress_sender, stop_receiver, custom_settings);
|
||||
}
|
||||
CurrentTab::TemporaryFiles => {
|
||||
scan_temporary_files(a, progress_sender, stop_receiver, custom_settings);
|
||||
}
|
||||
CurrentTab::Settings | CurrentTab::About => panic!("Button should be disabled"),
|
||||
_ => unimplemented!(),
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -168,7 +171,7 @@ fn write_duplicate_results(app: &MainWindow, vector: Vec<(Option<DuplicateEntry>
|
|||
insert_data_to_model(&items, data_model_str, data_model_int, false);
|
||||
}
|
||||
}
|
||||
app.set_similar_images_model(items.into());
|
||||
app.set_duplicate_files_model(items.into());
|
||||
app.invoke_scan_ended(format!("Found {items_found} similar duplicates files").into());
|
||||
app.global::<GuiState>().set_info_text(messages.into());
|
||||
}
|
||||
|
@ -257,7 +260,7 @@ fn write_big_files_results(app: &MainWindow, vector: Vec<FileEntry>, messages: S
|
|||
let (data_model_str, data_model_int) = prepare_data_model_big_files(&fe);
|
||||
insert_data_to_model(&items, data_model_str, data_model_int, false);
|
||||
}
|
||||
app.set_empty_folder_model(items.into());
|
||||
app.set_big_files_model(items.into());
|
||||
app.invoke_scan_ended(format!("Found {items_found} files").into());
|
||||
app.global::<GuiState>().set_info_text(messages.into());
|
||||
}
|
||||
|
@ -592,6 +595,48 @@ fn prepare_data_model_invalid_symlinks(fe: &SymlinksFileEntry) -> (ModelRc<Share
|
|||
let modification_split = split_u64_into_i32s(fe.get_modified_date());
|
||||
let data_model_int = VecModel::from_slice(&[modification_split.0, modification_split.1]);
|
||||
(data_model_str, data_model_int)
|
||||
} ////////////////////////////////////////// Temporary Files
|
||||
fn scan_temporary_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) {
|
||||
thread::Builder::new()
|
||||
.stack_size(DEFAULT_THREAD_SIZE)
|
||||
.spawn(move || {
|
||||
let mut finder = Temporary::new();
|
||||
set_common_settings(&mut finder, &custom_settings);
|
||||
finder.find_temporary_files(Some(&stop_receiver), Some(&progress_sender));
|
||||
|
||||
let mut vector = finder.get_temporary_files().clone();
|
||||
let messages = finder.get_text_messages().create_messages_text();
|
||||
|
||||
vector.par_sort_unstable_by(|a, b| split_path_compare(a.path.as_path(), b.path.as_path()));
|
||||
|
||||
a.upgrade_in_event_loop(move |app| {
|
||||
crate::connect_scan::write_temporary_files_results(&app, vector, messages);
|
||||
})
|
||||
})
|
||||
.unwrap();
|
||||
}
|
||||
fn write_temporary_files_results(app: &MainWindow, vector: Vec<TemporaryFileEntry>, messages: String) {
|
||||
let items_found = vector.len();
|
||||
let items = Rc::new(VecModel::default());
|
||||
for fe in vector {
|
||||
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_temporary_files(&fe);
|
||||
insert_data_to_model(&items, data_model_str, data_model_int, false);
|
||||
}
|
||||
app.set_temporary_files_model(items.into());
|
||||
app.invoke_scan_ended(format!("Found {items_found} files").into());
|
||||
app.global::<GuiState>().set_info_text(messages.into());
|
||||
}
|
||||
|
||||
fn prepare_data_model_temporary_files(fe: &TemporaryFileEntry) -> (ModelRc<SharedString>, ModelRc<i32>) {
|
||||
let (directory, file) = split_path(&fe.path);
|
||||
let data_model_str = VecModel::from_slice(&[
|
||||
file.into(),
|
||||
directory.into(),
|
||||
NaiveDateTime::from_timestamp_opt(fe.modified_date as i64, 0).unwrap().to_string().into(),
|
||||
]);
|
||||
let modification_split = split_u64_into_i32s(fe.get_modified_date());
|
||||
let data_model_int = VecModel::from_slice(&[modification_split.0, modification_split.1]);
|
||||
(data_model_str, data_model_int)
|
||||
}
|
||||
////////////////////////////////////////// Broken Files
|
||||
fn scan_broken_files(a: Weak<MainWindow>, progress_sender: Sender<ProgressData>, stop_receiver: Receiver<()>, custom_settings: SettingsCustom) {
|
||||
|
@ -620,7 +665,7 @@ fn write_broken_files_results(app: &MainWindow, vector: Vec<BrokenEntry>, messag
|
|||
let (data_model_str, data_model_int) = crate::connect_scan::prepare_data_model_broken_files(&fe);
|
||||
insert_data_to_model(&items, data_model_str, data_model_int, false);
|
||||
}
|
||||
app.set_empty_folder_model(items.into());
|
||||
app.set_broken_files_model(items.into());
|
||||
app.invoke_scan_ended(format!("Found {items_found} files").into());
|
||||
app.global::<GuiState>().set_info_text(messages.into());
|
||||
}
|
||||
|
@ -666,7 +711,7 @@ fn write_bad_extensions_results(app: &MainWindow, vector: Vec<BadFileEntry>, mes
|
|||
let (data_model_str, data_model_int) = prepare_data_model_bad_extensions(&fe);
|
||||
insert_data_to_model(&items, data_model_str, data_model_int, false);
|
||||
}
|
||||
app.set_empty_folder_model(items.into());
|
||||
app.set_bad_extensions_model(items.into());
|
||||
app.invoke_scan_ended(format!("Found {items_found} files with bad extensions").into());
|
||||
app.global::<GuiState>().set_info_text(messages.into());
|
||||
}
|
||||
|
|
|
@ -93,4 +93,12 @@ pub fn zeroing_all_models(app: &MainWindow) {
|
|||
app.set_empty_folder_model(Rc::new(VecModel::default()).into());
|
||||
app.set_empty_files_model(Rc::new(VecModel::default()).into());
|
||||
app.set_similar_images_model(Rc::new(VecModel::default()).into());
|
||||
app.set_duplicate_files_model(Rc::new(VecModel::default()).into());
|
||||
app.set_similar_music_model(Rc::new(VecModel::default()).into());
|
||||
app.set_big_files_model(Rc::new(VecModel::default()).into());
|
||||
app.set_bad_extensions_model(Rc::new(VecModel::default()).into());
|
||||
app.set_broken_files_model(Rc::new(VecModel::default()).into());
|
||||
app.set_similar_videos_model(Rc::new(VecModel::default()).into());
|
||||
app.set_invalid_symlinks_model(Rc::new(VecModel::default()).into());
|
||||
app.set_temporary_files_model(Rc::new(VecModel::default()).into());
|
||||
}
|
||||
|
|
|
@ -17,7 +17,7 @@ export global GuiState {
|
|||
in-out property <bool> choosing_include_directories;
|
||||
in-out property <bool> visible_tool_settings;
|
||||
|
||||
in-out property <bool> available_subsettings: active_tab == CurrentTab.SimilarImages;
|
||||
in-out property <bool> available_subsettings: active_tab == CurrentTab.SimilarImages || active_tab == CurrentTab.DuplicateFiles || active_tab == CurrentTab.SimilarVideos || active_tab == CurrentTab.SimilarMusic || active_tab == CurrentTab.BigFiles || active_tab == CurrentTab.BrokenFiles;
|
||||
in-out property <CurrentTab> active_tab: CurrentTab.DuplicateFiles;
|
||||
in-out property <bool> is_tool_tab_active: active_tab != CurrentTab.Settings && active_tab != CurrentTab.About;
|
||||
in-out property <[SelectModel]> select_results_list: [{data: SelectMode.SelectAll, name: "Select All"}, {data: SelectMode.UnselectAll, name: "Deselect All"}, {data: SelectMode.SelectTheSmallestResolution, name: "Select the smallest resolution"}];
|
||||
|
|
|
@ -68,7 +68,7 @@ export component LeftSidePanel {
|
|||
callback changed_current_tab();
|
||||
width: 120px;
|
||||
VerticalLayout {
|
||||
spacing: 10px;
|
||||
spacing: 2px;
|
||||
Rectangle {
|
||||
visible: GuiState.active_tab != CurrentTab.About;
|
||||
height: 80px;
|
||||
|
@ -110,7 +110,6 @@ export component LeftSidePanel {
|
|||
curr_tab: r.tab;
|
||||
changed_current_tab() => {root.changed_current_tab();}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Rectangle {
|
||||
|
|
|
@ -88,8 +88,8 @@ export component MainList {
|
|||
visible: GuiState.active_tab == CurrentTab.TemporaryFiles;
|
||||
min-width: 200px;
|
||||
height: parent.height;
|
||||
columns: ["Selection", "Size", "File Name", "Path", "Modification Date"];
|
||||
column-sizes: [35px, size_px, name_px, path_px, mod_px];
|
||||
columns: ["Selection", "File Name", "Path", "Modification Date"];
|
||||
column-sizes: [35px, name_px, path_px, mod_px];
|
||||
values <=> temporary_files_model;
|
||||
parentPathIdx: 3;
|
||||
fileNameIdx: 2;
|
||||
|
@ -143,8 +143,8 @@ export component MainList {
|
|||
visible: GuiState.active_tab == CurrentTab.BrokenFiles;
|
||||
min-width: 200px;
|
||||
height: parent.height;
|
||||
columns: ["Selection", "Size", "File Name", "Type of Error", "Path", "Modification Date"];
|
||||
column-sizes: [35px, size_px, name_px, 200px, path_px, mod_px];
|
||||
columns: ["Selection", "File Name", "Path", "Type of Error", "Size", "Modification Date"];
|
||||
column-sizes: [35px, name_px, path_px, 200px, size_px, mod_px];
|
||||
values <=> broken_files_model;
|
||||
parentPathIdx: 4;
|
||||
fileNameIdx: 2;
|
||||
|
|
|
@ -72,14 +72,7 @@ export component PopupNewDirectories inherits Rectangle {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Button {
|
||||
// text:"KKK";
|
||||
// clicked => {
|
||||
// show-popup();
|
||||
// }
|
||||
// }
|
||||
|
||||
|
||||
show_popup() => {
|
||||
popup_window.show();
|
||||
}
|
||||
|
|
|
@ -40,7 +40,7 @@ export global Settings {
|
|||
|
||||
|
||||
// Allowed subsettings
|
||||
// Duplicate
|
||||
// Similar Images
|
||||
in-out property <[string]> similar_images_sub_available_hash_size: ["8", "16", "32", "64"];
|
||||
in-out property <int> similar_images_sub_hash_size_index: 0;
|
||||
in-out property <[string]> similar_images_sub_available_resize_algorithm: ["Lanczos3", "Nearest", "Triangle", "Gaussian", "CatmullRom"];
|
||||
|
@ -50,4 +50,37 @@ export global Settings {
|
|||
in-out property <float> similar_images_sub_max_similarity: 40;
|
||||
in-out property <float> similar_images_sub_current_similarity: 20;
|
||||
in-out property <bool> similar_images_sub_ignore_same_size;
|
||||
|
||||
// Duplicates
|
||||
in-out property <[string]> duplicates_sub_check_method: ["Hash", "Size", "Name", "Size and Name"];
|
||||
in-out property <int> duplicates_sub_check_method_index: 0;
|
||||
in-out property <[string]> duplicates_sub_available_hash_type: ["Blake3", "CRC32", "XXH3"];
|
||||
in-out property <int> duplicates_sub_available_hash_type_index: 0;
|
||||
|
||||
// Big files
|
||||
in-out property <[string]> biggest_files_sub_method: ["The Biggest", "The Smallest"];
|
||||
in-out property <int> biggest_files_sub_method_index: 0;
|
||||
in-out property <string> biggest_files_sub_number_of_files: 50;
|
||||
|
||||
// Similar Videos
|
||||
in-out property <bool> similar_videos_sub_ignore_same_size;
|
||||
in-out property <float> similar_videos_sub_max_similarity: 20;
|
||||
in-out property <float> similar_videos_sub_current_similarity: 15;
|
||||
|
||||
// Same Music
|
||||
in-out property <[string]> similar_music_sub_audio_check_type: ["Tags", "Fingerprint"];
|
||||
in-out property <int> similar_music_sub_audio_check_type_index: 0;
|
||||
in-out property <bool> similar_music_sub_approximate_comparison;
|
||||
in-out property <bool> similar_music_sub_title: true;
|
||||
in-out property <bool> similar_music_sub_artist: true;
|
||||
in-out property <bool> similar_music_sub_year: false;
|
||||
in-out property <bool> similar_music_sub_bitrate: false;
|
||||
in-out property <bool> similar_music_sub_genre: false;
|
||||
in-out property <bool> similar_music_sub_length: false;
|
||||
|
||||
// Broken Files
|
||||
in-out property <bool> broken_files_sub_audio: true;
|
||||
in-out property <bool> broken_files_sub_pdf: false;
|
||||
in-out property <bool> broken_files_sub_archive: false;
|
||||
in-out property <bool> broken_files_sub_image: false;
|
||||
}
|
||||
|
|
|
@ -9,7 +9,7 @@ global SettingsSize {
|
|||
out property <length> item_height: 30px;
|
||||
}
|
||||
|
||||
component TextComponent inherits HorizontalLayout {
|
||||
export component TextComponent inherits HorizontalLayout {
|
||||
in-out property <string> model;
|
||||
in property <string> name;
|
||||
spacing: 5px;
|
||||
|
|
|
@ -13,6 +13,7 @@ import {ColorPalette} from "color_palette.slint";
|
|||
import {GuiState} from "gui_state.slint";
|
||||
import { Preview } from "preview.slint";
|
||||
import {PopupNewDirectories} from "popup_new_directories.slint";
|
||||
import {TextComponent} from "settings_list.slint";
|
||||
|
||||
component ComboBoxWrapper inherits HorizontalLayout {
|
||||
in-out property <string> text;
|
||||
|
@ -62,7 +63,8 @@ component SliderWrapper inherits HorizontalLayout {
|
|||
|
||||
export component ToolSettings {
|
||||
ScrollView {
|
||||
if GuiState.active_tab == CurrentTab.SimilarImages: VerticalLayout {
|
||||
VerticalLayout {
|
||||
visible: GuiState.active_tab == CurrentTab.SimilarImages;
|
||||
spacing: 5px;
|
||||
padding: 10px;
|
||||
SubsettingsHeader { }
|
||||
|
@ -94,5 +96,128 @@ export component ToolSettings {
|
|||
}
|
||||
Rectangle {}
|
||||
}
|
||||
VerticalLayout {
|
||||
visible: GuiState.active_tab == CurrentTab.DuplicateFiles;
|
||||
spacing: 5px;
|
||||
padding: 10px;
|
||||
SubsettingsHeader { }
|
||||
ComboBoxWrapper {
|
||||
text: "Check method";
|
||||
model: Settings.duplicates_sub_check_method;
|
||||
current_index <=> Settings.duplicates_sub_check_method_index;
|
||||
}
|
||||
ComboBoxWrapper {
|
||||
text: "Hash type";
|
||||
model: Settings.duplicates_sub_available_hash_type;
|
||||
current_index <=> Settings.duplicates_sub_available_hash_type_index;
|
||||
}
|
||||
Rectangle {}
|
||||
}
|
||||
VerticalLayout {
|
||||
visible: GuiState.active_tab == CurrentTab.BigFiles;
|
||||
spacing: 5px;
|
||||
padding: 10px;
|
||||
SubsettingsHeader { }
|
||||
ComboBoxWrapper {
|
||||
text: "Checked files";
|
||||
model: Settings.biggest_files_sub_method;
|
||||
current_index <=> Settings.biggest_files_sub_method_index;
|
||||
}
|
||||
TextComponent {
|
||||
name: "Number of files";
|
||||
model <=> Settings.biggest_files_sub_number_of_files;
|
||||
}
|
||||
Rectangle {}
|
||||
}
|
||||
VerticalLayout {
|
||||
visible: GuiState.active_tab == CurrentTab.SimilarVideos;
|
||||
spacing: 5px;
|
||||
padding: 10px;
|
||||
SubsettingsHeader { }
|
||||
SliderWrapper {
|
||||
text: "Max difference";
|
||||
end_text: "(" + round(Settings.similar_videos_sub_current_similarity) + "/" + round(Settings.similar_videos_sub_max_similarity) + ")";
|
||||
end_text_size: 40px;
|
||||
maximum <=> Settings.similar_videos_sub_max_similarity;
|
||||
value <=> Settings.similar_videos_sub_current_similarity;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Ignore same size";
|
||||
checked <=> Settings.similar_images_sub_ignore_same_size;
|
||||
}
|
||||
Rectangle {}
|
||||
}
|
||||
VerticalLayout {
|
||||
visible: GuiState.active_tab == CurrentTab.SimilarMusic;
|
||||
spacing: 5px;
|
||||
padding: 10px;
|
||||
SubsettingsHeader { }
|
||||
ComboBoxWrapper {
|
||||
text: "Audio check type";
|
||||
model: Settings.similar_music_sub_audio_check_type;
|
||||
current_index <=> Settings.similar_music_sub_audio_check_type_index;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Approximate Tag Comparison";
|
||||
checked <=> Settings.similar_music_sub_approximate_comparison;
|
||||
}
|
||||
Text {
|
||||
text: "Compared tags";
|
||||
font-size: 12px;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Title";
|
||||
checked <=> Settings.similar_music_sub_title;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Artist";
|
||||
checked <=> Settings.similar_music_sub_artist;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Bitrate";
|
||||
checked <=> Settings.similar_music_sub_bitrate;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Genre";
|
||||
checked <=> Settings.similar_music_sub_genre;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Year";
|
||||
checked <=> Settings.similar_music_sub_year;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Length";
|
||||
checked <=> Settings.similar_music_sub_length;
|
||||
}
|
||||
Rectangle {}
|
||||
}
|
||||
VerticalLayout {
|
||||
visible: GuiState.active_tab == CurrentTab.BrokenFiles;
|
||||
spacing: 5px;
|
||||
padding: 10px;
|
||||
SubsettingsHeader { }
|
||||
Text {
|
||||
text: "Type of files to check";
|
||||
font-size: 12px;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Audio";
|
||||
checked <=> Settings.broken_files_sub_audio;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Pdf";
|
||||
checked <=> Settings.broken_files_sub_pdf;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Archive";
|
||||
checked <=> Settings.broken_files_sub_archive;
|
||||
}
|
||||
CheckBoxWrapper {
|
||||
text: "Image";
|
||||
checked <=> Settings.broken_files_sub_image;
|
||||
}
|
||||
|
||||
Rectangle {}
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in a new issue