From 298dc8bfb6a9d82b0e63861ce6ba604fa6c22e8d Mon Sep 17 00:00:00 2001 From: mtkennerly Date: Thu, 19 Dec 2024 18:31:40 -0500 Subject: [PATCH] Group config events together --- src/gui/app.rs | 977 ++++++++++++++++++----------------------- src/gui/button.rs | 51 +-- src/gui/common.rs | 160 ++----- src/gui/editor.rs | 187 +++++--- src/gui/file_tree.rs | 46 +- src/gui/game_list.rs | 14 +- src/gui/screen.rs | 98 ++--- src/gui/shortcuts.rs | 76 ++-- src/gui/widget.rs | 2 +- src/prelude.rs | 39 ++ src/resource/config.rs | 75 +++- 11 files changed, 853 insertions(+), 872 deletions(-) diff --git a/src/gui/app.rs b/src/gui/app.rs index 8eb0249..71a4ce2 100644 --- a/src/gui/app.rs +++ b/src/gui/app.rs @@ -10,8 +10,8 @@ use crate::{ gui::{ button, common::{ - BackupPhase, BrowseFileSubject, BrowseSubject, EditAction, Flags, GameAction, GameSelection, Message, - Operation, RedirectEditActionField, RestorePhase, Screen, ScrollSubject, UndoSubject, ValidatePhase, + BackupPhase, BrowseFileSubject, BrowseSubject, Flags, GameAction, GameSelection, Message, Operation, + RestorePhase, Screen, ScrollSubject, UndoSubject, ValidatePhase, }, modal::{CloudModalState, Modal, ModalField, ModalInputKind}, notification::Notification, @@ -21,7 +21,10 @@ use crate::{ widget::{id, Column, Container, Element, IcedParentExt, Progress, Row, Stack}, }, lang::TRANSLATOR, - prelude::{app_dir, get_threads_from_env, initialize_rayon, Error, Finality, StrictPath, SyncDirection}, + prelude::{ + app_dir, get_threads_from_env, initialize_rayon, EditAction, Error, Finality, RedirectEditActionField, + StrictPath, SyncDirection, + }, resource::{ cache::{self, Cache}, config::{self, Config, CustomGame, CustomGameKind, Root}, @@ -1424,10 +1427,436 @@ impl App { } Task::none() } - Message::AppReleaseToggle(enabled) => { - self.config.release.check = enabled; + Message::Config { event } => { + let mut task = None; + + match event { + config::Event::Theme(theme) => { + self.config.theme = theme; + } + config::Event::Language(language) => { + TRANSLATOR.set_language(language); + self.config.language = language; + } + config::Event::CheckRelease(enabled) => { + self.config.release.check = enabled; + } + config::Event::BackupTarget(text) => { + self.text_histories.backup_target.push(&text); + self.config.backup.path.reset(text); + } + config::Event::RestoreSource(text) => { + self.text_histories.restore_source.push(&text); + self.config.restore.path.reset(text); + } + config::Event::Root(action) => match action { + EditAction::Add => { + self.text_histories.roots.push(Default::default()); + self.config.roots.push(Root::default()); + } + EditAction::Change(index, value) => { + self.text_histories.roots[index].path.push(&value); + self.config.roots[index].path_mut().reset(value); + } + EditAction::Remove(index) => { + self.text_histories.roots.remove(index); + self.config.roots.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.roots.swap(index, offset); + self.config.roots.swap(index, offset); + } + }, + config::Event::RootLutrisDatabase(index, value) => { + self.text_histories.roots[index].lutris_database.push(&value); + if let Root::Lutris(root) = &mut self.config.roots[index] { + root.database = if value.is_empty() { None } else { Some(value.into()) }; + } + } + config::Event::SecondaryManifest(action) => match action { + EditAction::Add => { + self.text_histories.secondary_manifests.push(Default::default()); + self.config.manifest.secondary.push(Default::default()); + } + EditAction::Change(index, value) => { + self.text_histories.secondary_manifests[index].push(&value); + self.config.manifest.secondary[index].set(value); + } + EditAction::Remove(index) => { + self.text_histories.secondary_manifests.remove(index); + self.config.manifest.secondary.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.secondary_manifests.swap(index, offset); + self.config.manifest.secondary.swap(index, offset); + } + }, + config::Event::RootStore(index, store) => { + self.text_histories.roots[index].clear_secondary(); + self.config.roots[index].set_store(store); + } + config::Event::RedirectKind(index, kind) => { + self.config.redirects[index].kind = kind; + } + config::Event::SecondaryManifestKind(index, kind) => { + self.config.manifest.secondary[index].convert(kind); + } + config::Event::CustomGameKind(index, kind) => { + self.config.custom_games[index].convert(kind); + match kind { + CustomGameKind::Game => { + self.text_histories.custom_games[index].alias.clear(); + } + CustomGameKind::Alias => {} + } + } + config::Event::CustomGameIntegration(index, integration) => { + self.config.custom_games[index].integration = integration; + } + config::Event::Redirect(action, field) => { + // TODO: Automatically refresh redirected paths in the game list. + match action { + EditAction::Add => { + self.text_histories.redirects.push(Default::default()); + self.config.add_redirect(&StrictPath::default(), &StrictPath::default()); + } + EditAction::Change(index, value) => match field { + Some(RedirectEditActionField::Source) => { + self.text_histories.redirects[index].source.push(&value); + self.config.redirects[index].source.reset(value); + } + Some(RedirectEditActionField::Target) => { + self.text_histories.redirects[index].target.push(&value); + self.config.redirects[index].target.reset(value); + } + _ => {} + }, + EditAction::Remove(index) => { + self.text_histories.redirects.remove(index); + self.config.redirects.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.redirects.swap(index, offset); + self.config.redirects.swap(index, offset); + } + } + } + config::Event::ReverseRedirectsOnRestore(enabled) => { + self.config.restore.reverse_redirects = enabled; + } + config::Event::CustomGame(action) => { + let mut snap = false; + match action { + EditAction::Add => { + self.text_histories.custom_games.push(Default::default()); + self.config.add_custom_game(); + snap = true; + } + EditAction::Change(index, value) => { + self.text_histories.custom_games[index].name.push(&value); + self.config.custom_games[index].name = value; + } + EditAction::Remove(index) => { + self.text_histories.custom_games.remove(index); + self.config.custom_games.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.custom_games.swap(index, offset); + self.config.custom_games.swap(index, offset); + } + } + if snap { + self.scroll_offsets.insert( + ScrollSubject::CustomGames, + scrollable::AbsoluteOffset { x: 0.0, y: f32::MAX }, + ); + task = Some(self.refresh_scroll_position()); + } + } + config::Event::CustomGameAlias(index, value) => { + self.text_histories.custom_games[index].alias.push(&value); + self.config.custom_games[index].alias = Some(value); + } + config::Event::CustomGaleAliasDisplay(index, value) => { + self.config.custom_games[index].prefer_alias = value; + } + config::Event::CustomGameFile(game_index, action) => match action { + EditAction::Add => { + self.text_histories.custom_games[game_index] + .files + .push(Default::default()); + self.config.custom_games[game_index].files.push("".to_string()); + } + EditAction::Change(index, value) => { + self.text_histories.custom_games[game_index].files[index].push(&value); + self.config.custom_games[game_index].files[index] = value; + } + EditAction::Remove(index) => { + self.text_histories.custom_games[game_index].files.remove(index); + self.config.custom_games[game_index].files.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.custom_games[game_index].files.swap(index, offset); + self.config.custom_games[game_index].files.swap(index, offset); + } + }, + config::Event::CustomGameRegistry(game_index, action) => match action { + EditAction::Add => { + self.text_histories.custom_games[game_index] + .registry + .push(Default::default()); + self.config.custom_games[game_index].registry.push("".to_string()); + } + EditAction::Change(index, value) => { + self.text_histories.custom_games[game_index].registry[index].push(&value); + self.config.custom_games[game_index].registry[index] = value; + } + EditAction::Remove(index) => { + self.text_histories.custom_games[game_index].registry.remove(index); + self.config.custom_games[game_index].registry.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.custom_games[game_index] + .registry + .swap(index, offset); + self.config.custom_games[game_index].registry.swap(index, offset); + } + }, + config::Event::ExcludeStoreScreenshots(enabled) => { + self.config.backup.filter.exclude_store_screenshots = enabled; + } + config::Event::CloudFilter(filter) => { + self.config.backup.filter.cloud = filter; + } + config::Event::BackupFilterIgnoredPath(action) => { + match action { + EditAction::Add => { + self.text_histories.backup_filter_ignored_paths.push(Default::default()); + self.config + .backup + .filter + .ignored_paths + .push(StrictPath::new("".to_string())); + } + EditAction::Change(index, value) => { + self.text_histories.backup_filter_ignored_paths[index].push(&value); + self.config.backup.filter.ignored_paths[index] = StrictPath::new(value); + } + EditAction::Remove(index) => { + self.text_histories.backup_filter_ignored_paths.remove(index); + self.config.backup.filter.ignored_paths.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.backup_filter_ignored_paths.swap(index, offset); + self.config.backup.filter.ignored_paths.swap(index, offset); + } + } + self.config.backup.filter.build_globs(); + } + config::Event::BackupFilterIgnoredRegistry(action) => match action { + EditAction::Add => { + self.text_histories + .backup_filter_ignored_registry + .push(Default::default()); + self.config + .backup + .filter + .ignored_registry + .push(RegistryItem::new("".to_string())); + } + EditAction::Change(index, value) => { + self.text_histories.backup_filter_ignored_registry[index].push(&value); + self.config.backup.filter.ignored_registry[index] = RegistryItem::new(value); + } + EditAction::Remove(index) => { + self.text_histories.backup_filter_ignored_registry.remove(index); + self.config.backup.filter.ignored_registry.remove(index); + } + EditAction::Move(index, direction) => { + let offset = direction.shift(index); + self.text_histories.backup_filter_ignored_registry.swap(index, offset); + self.config.backup.filter.ignored_registry.swap(index, offset); + } + }, + config::Event::GameListEntryEnabled { + name, + enabled, + scan_kind, + } => { + match (scan_kind, enabled) { + (ScanKind::Backup, false) => self.config.disable_game_for_backup(&name), + (ScanKind::Backup, true) => self.config.enable_game_for_backup(&name), + (ScanKind::Restore, false) => self.config.disable_game_for_restore(&name), + (ScanKind::Restore, true) => self.config.enable_game_for_restore(&name), + }; + + match scan_kind { + ScanKind::Backup => { + self.backup_screen.log.refresh_game_tree( + &name, + &self.config, + &mut self.backup_screen.duplicate_detector, + scan_kind, + ); + } + ScanKind::Restore => { + self.restore_screen.log.refresh_game_tree( + &name, + &self.config, + &mut self.restore_screen.duplicate_detector, + scan_kind, + ); + } + } + } + config::Event::CustomGameEnabled { index, enabled } => { + if enabled { + self.config.enable_custom_game(index); + } else { + self.config.disable_custom_game(index); + } + } + config::Event::PrimaryManifestEnabled { enabled } => { + self.config.manifest.enable = enabled; + } + config::Event::SecondaryManifestEnabled { index, enabled } => { + self.config.manifest.secondary[index].enable(enabled); + } + config::Event::ToggleSpecificGamePathIgnored { name, path, scan_kind } => match scan_kind { + ScanKind::Backup => { + self.config.backup.toggled_paths.toggle(&name, &path); + self.backup_screen.log.refresh_game_tree( + &name, + &self.config, + &mut self.backup_screen.duplicate_detector, + scan_kind, + ); + } + ScanKind::Restore => { + self.config.restore.toggled_paths.toggle(&name, &path); + self.restore_screen.log.refresh_game_tree( + &name, + &self.config, + &mut self.restore_screen.duplicate_detector, + scan_kind, + ); + } + }, + config::Event::ToggleSpecificGameRegistryIgnored { + name, + path, + value, + scan_kind, + } => match scan_kind { + ScanKind::Backup => { + self.config.backup.toggled_registry.toggle_owned(&name, &path, value); + self.backup_screen.log.refresh_game_tree( + &name, + &self.config, + &mut self.backup_screen.duplicate_detector, + scan_kind, + ); + } + ScanKind::Restore => { + self.config.restore.toggled_registry.toggle_owned(&name, &path, value); + self.restore_screen.log.refresh_game_tree( + &name, + &self.config, + &mut self.restore_screen.duplicate_detector, + scan_kind, + ); + } + }, + config::Event::SortKey(value) => match self.screen { + Screen::Backup => { + self.config.backup.sort.key = value; + self.backup_screen.log.sort(&self.config.backup.sort, &self.config); + } + Screen::Restore => { + self.config.restore.sort.key = value; + self.restore_screen.log.sort(&self.config.restore.sort, &self.config); + } + _ => {} + }, + config::Event::SortReversed(value) => match self.screen { + Screen::Backup => { + self.config.backup.sort.reversed = value; + self.backup_screen.log.sort(&self.config.backup.sort, &self.config); + } + Screen::Restore => { + self.config.restore.sort.reversed = value; + self.restore_screen.log.sort(&self.config.restore.sort, &self.config); + } + _ => {} + }, + config::Event::FullRetention(value) => { + self.config.backup.retention.full = value; + } + config::Event::DiffRetention(value) => { + self.config.backup.retention.differential = value; + } + config::Event::BackupFormat(format) => { + self.config.backup.format.chosen = format; + } + config::Event::BackupCompression(compression) => { + self.config.backup.format.zip.compression = compression; + } + config::Event::CompressionLevel(value) => { + self.config.backup.format.set_level(value); + } + config::Event::ToggleCloudSynchronize => { + self.config.cloud.synchronize = !self.config.cloud.synchronize; + } + config::Event::ShowDeselectedGames(value) => { + self.config.scan.show_deselected_games = value; + } + config::Event::ShowUnchangedGames(value) => { + self.config.scan.show_unchanged_games = value; + } + config::Event::ShowUnscannedGames(value) => { + self.config.scan.show_unscanned_games = value; + } + config::Event::OverrideMaxThreads(overridden) => { + self.config.override_threads(overridden); + } + config::Event::MaxThreads(threads) => { + self.config.set_threads(threads); + } + config::Event::RcloneExecutable(text) => { + self.text_histories.rclone_executable.push(&text); + self.config.apps.rclone.path.reset(text); + } + config::Event::RcloneArguments(text) => { + self.text_histories.rclone_arguments.push(&text); + self.config.apps.rclone.arguments = text; + } + config::Event::CloudRemoteId(text) => { + self.text_histories.cloud_remote_id.push(&text); + if let Some(Remote::Custom { id }) = &mut self.config.cloud.remote { + *id = text; + } + } + config::Event::CloudPath(text) => { + self.text_histories.cloud_path.push(&text); + self.config.cloud.path = text; + } + config::Event::SortCustomGames => { + self.config.custom_games.sort_by(|x, y| x.name.cmp(&y.name)); + self.text_histories + .custom_games + .sort_by(|x, y| x.name.current().cmp(&y.name.current())); + } + } + self.save_config(); - Task::none() + task.unwrap_or_else(Task::none) } Message::CheckAppRelease => { if !self.cache.should_check_app_update() { @@ -1514,18 +1943,6 @@ impl App { Message::ValidateBackups(phase) => self.handle_validation(phase), Message::CancelOperation => self.cancel_operation(), Message::ShowGameNotes { game, notes } => self.show_modal(Modal::GameNotes { game, notes }), - Message::EditedBackupTarget(text) => { - self.text_histories.backup_target.push(&text); - self.config.backup.path.reset(text); - self.save_config(); - Task::none() - } - Message::EditedRestoreSource(text) => { - self.text_histories.restore_source.push(&text); - self.config.restore.path.reset(text); - self.save_config(); - Task::none() - } Message::FindRoots => { let missing = self.config.find_missing_roots(); if missing.is_empty() { @@ -1558,294 +1975,6 @@ impl App { self.go_idle(); Task::none() } - Message::EditedRoot(action) => { - match action { - EditAction::Add => { - self.text_histories.roots.push(Default::default()); - self.config.roots.push(Root::default()); - } - EditAction::Change(index, value) => { - self.text_histories.roots[index].path.push(&value); - self.config.roots[index].path_mut().reset(value); - } - EditAction::Remove(index) => { - self.text_histories.roots.remove(index); - self.config.roots.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.roots.swap(index, offset); - self.config.roots.swap(index, offset); - } - } - self.save_config(); - Task::none() - } - Message::EditedRootLutrisDatabase(index, value) => { - self.text_histories.roots[index].lutris_database.push(&value); - if let Root::Lutris(root) = &mut self.config.roots[index] { - root.database = if value.is_empty() { None } else { Some(value.into()) }; - } - - self.save_config(); - Task::none() - } - Message::EditedSecondaryManifest(action) => { - match action { - EditAction::Add => { - self.text_histories.secondary_manifests.push(Default::default()); - self.config.manifest.secondary.push(Default::default()); - } - EditAction::Change(index, value) => { - self.text_histories.secondary_manifests[index].push(&value); - self.config.manifest.secondary[index].set(value); - } - EditAction::Remove(index) => { - self.text_histories.secondary_manifests.remove(index); - self.config.manifest.secondary.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.secondary_manifests.swap(index, offset); - self.config.manifest.secondary.swap(index, offset); - } - } - self.save_config(); - Task::none() - } - Message::SelectedRootStore(index, store) => { - self.text_histories.roots[index].clear_secondary(); - self.config.roots[index].set_store(store); - self.save_config(); - Task::none() - } - Message::SelectedRedirectKind(index, kind) => { - self.config.redirects[index].kind = kind; - self.save_config(); - Task::none() - } - Message::SelectedSecondaryManifestKind(index, kind) => { - self.config.manifest.secondary[index].convert(kind); - self.save_config(); - Task::none() - } - Message::SelectedCustomGameKind(index, kind) => { - self.config.custom_games[index].convert(kind); - match kind { - CustomGameKind::Game => { - self.text_histories.custom_games[index].alias.clear(); - } - CustomGameKind::Alias => {} - } - self.save_config(); - Task::none() - } - Message::SelectedCustomGameIntegration(index, integration) => { - self.config.custom_games[index].integration = integration; - self.save_config(); - Task::none() - } - Message::EditedRedirect(action, field) => { - // TODO: Automatically refresh redirected paths in the game list. - match action { - EditAction::Add => { - self.text_histories.redirects.push(Default::default()); - self.config.add_redirect(&StrictPath::default(), &StrictPath::default()); - } - EditAction::Change(index, value) => match field { - Some(RedirectEditActionField::Source) => { - self.text_histories.redirects[index].source.push(&value); - self.config.redirects[index].source.reset(value); - } - Some(RedirectEditActionField::Target) => { - self.text_histories.redirects[index].target.push(&value); - self.config.redirects[index].target.reset(value); - } - _ => {} - }, - EditAction::Remove(index) => { - self.text_histories.redirects.remove(index); - self.config.redirects.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.redirects.swap(index, offset); - self.config.redirects.swap(index, offset); - } - } - self.save_config(); - Task::none() - } - Message::EditedReverseRedirectsOnRestore(enabled) => { - self.config.restore.reverse_redirects = enabled; - self.config.save(); - Task::none() - } - Message::EditedCustomGame(action) => { - let mut snap = false; - match action { - EditAction::Add => { - self.text_histories.custom_games.push(Default::default()); - self.config.add_custom_game(); - snap = true; - } - EditAction::Change(index, value) => { - self.text_histories.custom_games[index].name.push(&value); - self.config.custom_games[index].name = value; - } - EditAction::Remove(index) => { - self.text_histories.custom_games.remove(index); - self.config.custom_games.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.custom_games.swap(index, offset); - self.config.custom_games.swap(index, offset); - } - } - self.save_config(); - if snap { - self.scroll_offsets.insert( - ScrollSubject::CustomGames, - scrollable::AbsoluteOffset { x: 0.0, y: f32::MAX }, - ); - self.refresh_scroll_position() - } else { - Task::none() - } - } - Message::EditedCustomGameAlias(index, value) => { - self.text_histories.custom_games[index].alias.push(&value); - self.config.custom_games[index].alias = Some(value); - - self.save_config(); - Task::none() - } - Message::EditedCustomGaleAliasDisplay(index, value) => { - self.config.custom_games[index].prefer_alias = value; - - self.save_config(); - Task::none() - } - Message::EditedCustomGameFile(game_index, action) => { - match action { - EditAction::Add => { - self.text_histories.custom_games[game_index] - .files - .push(Default::default()); - self.config.custom_games[game_index].files.push("".to_string()); - } - EditAction::Change(index, value) => { - self.text_histories.custom_games[game_index].files[index].push(&value); - self.config.custom_games[game_index].files[index] = value; - } - EditAction::Remove(index) => { - self.text_histories.custom_games[game_index].files.remove(index); - self.config.custom_games[game_index].files.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.custom_games[game_index].files.swap(index, offset); - self.config.custom_games[game_index].files.swap(index, offset); - } - } - self.save_config(); - Task::none() - } - Message::EditedCustomGameRegistry(game_index, action) => { - match action { - EditAction::Add => { - self.text_histories.custom_games[game_index] - .registry - .push(Default::default()); - self.config.custom_games[game_index].registry.push("".to_string()); - } - EditAction::Change(index, value) => { - self.text_histories.custom_games[game_index].registry[index].push(&value); - self.config.custom_games[game_index].registry[index] = value; - } - EditAction::Remove(index) => { - self.text_histories.custom_games[game_index].registry.remove(index); - self.config.custom_games[game_index].registry.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.custom_games[game_index] - .registry - .swap(index, offset); - self.config.custom_games[game_index].registry.swap(index, offset); - } - } - self.save_config(); - Task::none() - } - Message::EditedExcludeStoreScreenshots(enabled) => { - self.config.backup.filter.exclude_store_screenshots = enabled; - self.save_config(); - Task::none() - } - Message::EditedCloudFilter(filter) => { - self.config.backup.filter.cloud = filter; - self.save_config(); - Task::none() - } - Message::EditedBackupFilterIgnoredPath(action) => { - match action { - EditAction::Add => { - self.text_histories.backup_filter_ignored_paths.push(Default::default()); - self.config - .backup - .filter - .ignored_paths - .push(StrictPath::new("".to_string())); - } - EditAction::Change(index, value) => { - self.text_histories.backup_filter_ignored_paths[index].push(&value); - self.config.backup.filter.ignored_paths[index] = StrictPath::new(value); - } - EditAction::Remove(index) => { - self.text_histories.backup_filter_ignored_paths.remove(index); - self.config.backup.filter.ignored_paths.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.backup_filter_ignored_paths.swap(index, offset); - self.config.backup.filter.ignored_paths.swap(index, offset); - } - } - self.config.backup.filter.build_globs(); - self.save_config(); - Task::none() - } - Message::EditedBackupFilterIgnoredRegistry(action) => { - match action { - EditAction::Add => { - self.text_histories - .backup_filter_ignored_registry - .push(Default::default()); - self.config - .backup - .filter - .ignored_registry - .push(RegistryItem::new("".to_string())); - } - EditAction::Change(index, value) => { - self.text_histories.backup_filter_ignored_registry[index].push(&value); - self.config.backup.filter.ignored_registry[index] = RegistryItem::new(value); - } - EditAction::Remove(index) => { - self.text_histories.backup_filter_ignored_registry.remove(index); - self.config.backup.filter.ignored_registry.remove(index); - } - EditAction::Move(index, direction) => { - let offset = direction.shift(index); - self.text_histories.backup_filter_ignored_registry.swap(index, offset); - self.config.backup.filter.ignored_registry.swap(index, offset); - } - } - self.save_config(); - Task::none() - } Message::SwitchScreen(screen) => self.switch_screen(screen), Message::ToggleGameListEntryExpanded { name } => { match self.screen { @@ -1893,117 +2022,11 @@ impl App { } Task::none() } - Message::ToggleGameListEntryEnabled { - name, - enabled, - scan_kind, - } => { - match (scan_kind, enabled) { - (ScanKind::Backup, false) => self.config.disable_game_for_backup(&name), - (ScanKind::Backup, true) => self.config.enable_game_for_backup(&name), - (ScanKind::Restore, false) => self.config.disable_game_for_restore(&name), - (ScanKind::Restore, true) => self.config.enable_game_for_restore(&name), - }; - self.save_config(); - - match scan_kind { - ScanKind::Backup => { - self.backup_screen.log.refresh_game_tree( - &name, - &self.config, - &mut self.backup_screen.duplicate_detector, - scan_kind, - ); - } - ScanKind::Restore => { - self.restore_screen.log.refresh_game_tree( - &name, - &self.config, - &mut self.restore_screen.duplicate_detector, - scan_kind, - ); - } - } - - Task::none() - } - Message::ToggleCustomGameEnabled { index, enabled } => { - if enabled { - self.config.enable_custom_game(index); - } else { - self.config.disable_custom_game(index); - } - self.save_config(); - Task::none() - } Message::ToggleCustomGameExpanded { index, expanded } => { self.config.custom_games[index].expanded = expanded; self.save_config(); Task::none() } - Message::TogglePrimaryManifestEnabled { enabled } => { - self.config.manifest.enable = enabled; - self.save_config(); - Task::none() - } - Message::ToggleSecondaryManifestEnabled { index, enabled } => { - self.config.manifest.secondary[index].enable(enabled); - self.save_config(); - Task::none() - } - Message::ToggleSpecificGamePathIgnored { name, path, scan_kind } => { - match scan_kind { - ScanKind::Backup => { - self.config.backup.toggled_paths.toggle(&name, &path); - self.backup_screen.log.refresh_game_tree( - &name, - &self.config, - &mut self.backup_screen.duplicate_detector, - scan_kind, - ); - } - ScanKind::Restore => { - self.config.restore.toggled_paths.toggle(&name, &path); - self.restore_screen.log.refresh_game_tree( - &name, - &self.config, - &mut self.restore_screen.duplicate_detector, - scan_kind, - ); - } - } - self.save_config(); - Task::none() - } - Message::ToggleSpecificGameRegistryIgnored { - name, - path, - value, - scan_kind, - } => { - match scan_kind { - ScanKind::Backup => { - self.config.backup.toggled_registry.toggle_owned(&name, &path, value); - self.backup_screen.log.refresh_game_tree( - &name, - &self.config, - &mut self.backup_screen.duplicate_detector, - scan_kind, - ); - } - ScanKind::Restore => { - self.config.restore.toggled_registry.toggle_owned(&name, &path, value); - self.restore_screen.log.refresh_game_tree( - &name, - &self.config, - &mut self.restore_screen.duplicate_detector, - scan_kind, - ); - } - } - self.save_config(); - Task::none() - } Message::Filter { event } => { let mut task = None; @@ -2117,36 +2140,6 @@ impl App { task.unwrap_or_else(Task::none) } - Message::EditedSortKey { screen, value } => { - match screen { - Screen::Backup => { - self.config.backup.sort.key = value; - self.backup_screen.log.sort(&self.config.backup.sort, &self.config); - } - Screen::Restore => { - self.config.restore.sort.key = value; - self.restore_screen.log.sort(&self.config.restore.sort, &self.config); - } - _ => {} - } - self.save_config(); - Task::none() - } - Message::EditedSortReversed { screen, value } => { - match screen { - Screen::Backup => { - self.config.backup.sort.reversed = value; - self.backup_screen.log.sort(&self.config.backup.sort, &self.config); - } - Screen::Restore => { - self.config.restore.sort.reversed = value; - self.restore_screen.log.sort(&self.config.restore.sort, &self.config); - } - _ => {} - } - self.save_config(); - Task::none() - } Message::BrowseDir(subject) => Task::future(async move { let choice = async move { rfd::AsyncFileDialog::new().pick_folder().await }.await; @@ -2425,16 +2418,6 @@ impl App { self.save_config(); Task::none() } - Message::EditedFullRetention(value) => { - self.config.backup.retention.full = value; - self.save_config(); - Task::none() - } - Message::EditedDiffRetention(value) => { - self.config.backup.retention.differential = value; - self.save_config(); - Task::none() - } Message::SelectedBackupToRestore { game, backup } => { self.backups_to_restore.insert(game.clone(), backup.id()); self.handle_restore(RestorePhase::Start { @@ -2442,37 +2425,6 @@ impl App { games: Some(GameSelection::single(game)), }) } - Message::SelectedLanguage(language) => { - TRANSLATOR.set_language(language); - self.config.language = language; - self.save_config(); - Task::none() - } - Message::SelectedTheme(theme) => { - self.config.theme = theme; - self.save_config(); - Task::none() - } - Message::SelectedBackupFormat(format) => { - self.config.backup.format.chosen = format; - self.save_config(); - Task::none() - } - Message::SelectedBackupCompression(compression) => { - self.config.backup.format.zip.compression = compression; - self.save_config(); - Task::none() - } - Message::EditedCompressionLevel(value) => { - self.config.backup.format.set_level(value); - self.save_config(); - Task::none() - } - Message::ToggleCloudSynchronize => { - self.config.cloud.synchronize = !self.config.cloud.synchronize; - self.save_config(); - Task::none() - } Message::GameAction { action, game } => match action { GameAction::PreviewBackup => self.handle_backup(BackupPhase::Start { preview: true, @@ -2542,21 +2494,6 @@ impl App { Task::none() } - Message::SetShowDeselectedGames(value) => { - self.config.scan.show_deselected_games = value; - self.save_config(); - Task::none() - } - Message::SetShowUnchangedGames(value) => { - self.config.scan.show_unchanged_games = value; - self.save_config(); - Task::none() - } - Message::SetShowUnscannedGames(value) => { - self.config.scan.show_unscanned_games = value; - self.save_config(); - Task::none() - } Message::FilterDuplicates { scan_kind, game } => { let log = match scan_kind { ScanKind::Backup => &mut self.backup_screen.log, @@ -2565,42 +2502,6 @@ impl App { log.filter_duplicates_of = game; Task::none() } - Message::OverrideMaxThreads(overridden) => { - self.config.override_threads(overridden); - self.save_config(); - Task::none() - } - Message::EditedMaxThreads(threads) => { - self.config.set_threads(threads); - self.save_config(); - Task::none() - } - Message::EditedRcloneExecutable(text) => { - self.text_histories.rclone_executable.push(&text); - self.config.apps.rclone.path.reset(text); - self.save_config(); - Task::none() - } - Message::EditedRcloneArguments(text) => { - self.text_histories.rclone_arguments.push(&text); - self.config.apps.rclone.arguments = text; - self.save_config(); - Task::none() - } - Message::EditedCloudRemoteId(text) => { - self.text_histories.cloud_remote_id.push(&text); - if let Some(Remote::Custom { id }) = &mut self.config.cloud.remote { - *id = text; - } - self.save_config(); - Task::none() - } - Message::EditedCloudPath(text) => { - self.text_histories.cloud_path.push(&text); - self.config.cloud.path = text; - self.save_config(); - Task::none() - } Message::OpenUrl(url) => Self::open_url(url), Message::OpenUrlAndCloseModal(url) => Task::batch([Self::open_url(url), self.close_modal()]), Message::EditedCloudRemote(choice) => { @@ -2803,14 +2704,6 @@ impl App { None => Message::Ignore, }) } - Message::SortCustomGames => { - self.config.custom_games.sort_by(|x, y| x.name.cmp(&y.name)); - self.text_histories - .custom_games - .sort_by(|x, y| x.name.current().cmp(&y.name.current())); - self.config.save(); - Task::none() - } } } diff --git a/src/gui/button.rs b/src/gui/button.rs index cf67b33..12b6635 100644 --- a/src/gui/button.rs +++ b/src/gui/button.rs @@ -3,16 +3,15 @@ use iced::{alignment, keyboard, Length}; use crate::{ gui::{ common::{ - BackupPhase, BrowseFileSubject, BrowseSubject, EditAction, Message, Operation, RestorePhase, Screen, - ValidatePhase, + BackupPhase, BrowseFileSubject, BrowseSubject, Message, Operation, RestorePhase, Screen, ValidatePhase, }, icon::Icon, style, widget::{text, Button, Container, Element, Row, Text, Tooltip}, }, lang::TRANSLATOR, - prelude::{Finality, SyncDirection}, - resource::manifest, + prelude::{EditAction, Finality, SyncDirection}, + resource::{config, manifest}, scan::game_filter, }; @@ -94,15 +93,15 @@ pub fn negative<'a>(content: String, action: Option) -> Element<'a> { .into() } -pub fn add<'a>(action: fn(EditAction) -> Message) -> Element<'a> { +pub fn add<'a>(action: impl Fn(EditAction) -> Message) -> Element<'a> { template(Icon::AddCircle.text(), Some(action(EditAction::Add)), None) } -pub fn add_nested<'a>(action: fn(usize, EditAction) -> Message, parent: usize) -> Element<'a> { +pub fn add_nested<'a>(action: impl Fn(usize, EditAction) -> Message, parent: usize) -> Element<'a> { template(Icon::AddCircle.text(), Some(action(parent, EditAction::Add)), None) } -pub fn remove<'a>(action: fn(EditAction) -> Message, index: usize) -> Element<'a> { +pub fn remove<'a>(action: impl Fn(EditAction) -> Message, index: usize) -> Element<'a> { template( Icon::RemoveCircle.text(), Some(action(EditAction::Remove(index))), @@ -110,7 +109,7 @@ pub fn remove<'a>(action: fn(EditAction) -> Message, index: usize) -> Element<'a ) } -pub fn remove_nested<'a>(action: fn(usize, EditAction) -> Message, parent: usize, index: usize) -> Element<'a> { +pub fn remove_nested<'a>(action: impl Fn(usize, EditAction) -> Message, parent: usize, index: usize) -> Element<'a> { template( Icon::RemoveCircle.text(), Some(action(parent, EditAction::Remove(index))), @@ -118,7 +117,7 @@ pub fn remove_nested<'a>(action: fn(usize, EditAction) -> Message, parent: usize ) } -pub fn delete<'a>(action: fn(EditAction) -> Message, index: usize) -> Element<'a> { +pub fn delete<'a>(action: impl Fn(EditAction) -> Message, index: usize) -> Element<'a> { template( Icon::Delete.text(), Some(action(EditAction::Remove(index))), @@ -166,21 +165,18 @@ pub fn reset_filter<'a>(dirty: bool) -> Element<'a> { ) } -pub fn sort<'a>(message: Message) -> Element<'a> { - template(text(TRANSLATOR.sort_button()).width(WIDTH), Some(message), None) +pub fn sort<'a>(message: impl Into) -> Element<'a> { + template(text(TRANSLATOR.sort_button()).width(WIDTH), Some(message.into()), None) } -pub fn sort_order<'a>(screen: Screen, reversed: bool) -> Element<'a> { +pub fn sort_order<'a>(reversed: bool) -> Element<'a> { template( if reversed { Icon::ArrowDownward.text() } else { Icon::ArrowUpward.text() }, - Some(Message::EditedSortReversed { - screen, - value: !reversed, - }), + Some(config::Event::SortReversed(!reversed).into()), None, ) } @@ -197,7 +193,7 @@ pub fn search<'a>(action: Message) -> Element<'a> { template(Icon::Search.text(), Some(action), None) } -pub fn move_up<'a>(action: fn(EditAction) -> Message, index: usize) -> Element<'a> { +pub fn move_up<'a>(action: impl Fn(EditAction) -> Message, index: usize) -> Element<'a> { template( Icon::ArrowUpward.text_small(), (index > 0).then(|| action(EditAction::move_up(index))), @@ -205,7 +201,7 @@ pub fn move_up<'a>(action: fn(EditAction) -> Message, index: usize) -> Element<' ) } -pub fn move_up_maybe<'a>(action: fn(EditAction) -> Message, index: usize, enabled: bool) -> Element<'a> { +pub fn move_up_maybe<'a>(action: impl Fn(EditAction) -> Message, index: usize, enabled: bool) -> Element<'a> { template( Icon::ArrowUpward.text_small(), (enabled && index > 0).then(|| action(EditAction::move_up(index))), @@ -213,7 +209,7 @@ pub fn move_up_maybe<'a>(action: fn(EditAction) -> Message, index: usize, enable ) } -pub fn move_up_nested<'a>(action: fn(usize, EditAction) -> Message, parent: usize, index: usize) -> Element<'a> { +pub fn move_up_nested<'a>(action: impl Fn(usize, EditAction) -> Message, parent: usize, index: usize) -> Element<'a> { template( Icon::ArrowUpward.text_small(), (index > 0).then(|| action(parent, EditAction::move_up(index))), @@ -221,7 +217,7 @@ pub fn move_up_nested<'a>(action: fn(usize, EditAction) -> Message, parent: usiz ) } -pub fn move_down<'a>(action: fn(EditAction) -> Message, index: usize, max: usize) -> Element<'a> { +pub fn move_down<'a>(action: impl Fn(EditAction) -> Message, index: usize, max: usize) -> Element<'a> { template( Icon::ArrowDownward.text_small(), (index < max - 1).then(|| action(EditAction::move_down(index))), @@ -229,7 +225,12 @@ pub fn move_down<'a>(action: fn(EditAction) -> Message, index: usize, max: usize ) } -pub fn move_down_maybe<'a>(action: fn(EditAction) -> Message, index: usize, max: usize, enabled: bool) -> Element<'a> { +pub fn move_down_maybe<'a>( + action: impl Fn(EditAction) -> Message, + index: usize, + max: usize, + enabled: bool, +) -> Element<'a> { template( Icon::ArrowDownward.text_small(), (enabled && index < max - 1).then(|| action(EditAction::move_down(index))), @@ -238,7 +239,7 @@ pub fn move_down_maybe<'a>(action: fn(EditAction) -> Message, index: usize, max: } pub fn move_down_nested<'a>( - action: fn(usize, EditAction) -> Message, + action: impl Fn(usize, EditAction) -> Message, parent: usize, index: usize, max: usize, @@ -250,7 +251,7 @@ pub fn move_down_nested<'a>( ) } -pub fn next_page<'a>(action: fn(usize) -> Message, page: usize, pages: usize) -> Element<'a> { +pub fn next_page<'a>(action: impl Fn(usize) -> Message, page: usize, pages: usize) -> Element<'a> { template( Icon::ArrowForward.text(), (page < pages).then(|| action(page + 1)), @@ -258,7 +259,7 @@ pub fn next_page<'a>(action: fn(usize) -> Message, page: usize, pages: usize) -> ) } -pub fn previous_page<'a>(action: fn(usize) -> Message, page: usize) -> Element<'a> { +pub fn previous_page<'a>(action: impl Fn(usize) -> Message, page: usize) -> Element<'a> { template(Icon::ArrowBack.text(), (page > 0).then(|| action(page - 1)), None) } @@ -297,7 +298,7 @@ pub fn toggle_all_custom_games<'a>(all_enabled: bool) -> Element<'a> { pub fn add_game<'a>() -> Element<'a> { template( text(TRANSLATOR.add_game_button()).width(WIDTH), - Some(Message::EditedCustomGame(EditAction::Add)), + Some(config::Event::CustomGame(EditAction::Add).into()), None, ) } diff --git a/src/gui/common.rs b/src/gui/common.rs index f718c69..98a722d 100644 --- a/src/gui/common.rs +++ b/src/gui/common.rs @@ -8,19 +8,15 @@ use crate::{ icon::Icon, modal::{ModalField, ModalInputKind}, }, - lang::{Language, TRANSLATOR}, - prelude::{CommandError, Error, Finality, Privacy, StrictPath, SyncDirection}, + lang::TRANSLATOR, + prelude::{CommandError, EditAction, Error, Finality, Privacy, RedirectEditActionField, StrictPath, SyncDirection}, resource::{ - config::{ - BackupFormat, CloudFilter, CustomGameKind, Integration, RedirectKind, Root, SecondaryManifestConfigKind, - SortKey, Theme, ZipCompression, - }, - manifest::{self, Manifest, ManifestUpdate, Store}, + config::{self, Root}, + manifest::{self, Manifest, ManifestUpdate}, }, scan::{ game_filter, layout::{Backup, BackupLayout, GameLayout}, - registry::RegistryItem, BackupInfo, Launchers, ScanInfo, ScanKind, SteamShortcuts, }, }; @@ -116,7 +112,9 @@ pub enum Message { CloseModal, UpdateTime, PruneNotifications, - AppReleaseToggle(bool), + Config { + event: config::Event, + }, CheckAppRelease, AppReleaseChecked(Result), UpdateManifest { @@ -127,29 +125,8 @@ pub enum Message { Restore(RestorePhase), ValidateBackups(ValidatePhase), CancelOperation, - EditedBackupTarget(String), - EditedRestoreSource(String), FindRoots, ConfirmAddMissingRoots(Vec), - EditedRoot(EditAction), - EditedRootLutrisDatabase(usize, String), - EditedSecondaryManifest(EditAction), - SelectedRootStore(usize, Store), - SelectedRedirectKind(usize, RedirectKind), - SelectedSecondaryManifestKind(usize, SecondaryManifestConfigKind), - SelectedCustomGameKind(usize, CustomGameKind), - SelectedCustomGameIntegration(usize, Integration), - EditedRedirect(EditAction, Option), - EditedReverseRedirectsOnRestore(bool), - EditedCustomGame(EditAction), - EditedCustomGameAlias(usize, String), - EditedCustomGaleAliasDisplay(usize, bool), - EditedCustomGameFile(usize, EditAction), - EditedCustomGameRegistry(usize, EditAction), - EditedExcludeStoreScreenshots(bool), - EditedCloudFilter(CloudFilter), - EditedBackupFilterIgnoredPath(EditAction), - EditedBackupFilterIgnoredRegistry(EditAction), SwitchScreen(Screen), ToggleGameListEntryExpanded { name: String, @@ -158,48 +135,13 @@ pub enum Message { name: String, keys: Vec, }, - ToggleGameListEntryEnabled { - name: String, - enabled: bool, - scan_kind: ScanKind, - }, - ToggleSpecificGamePathIgnored { - name: String, - path: StrictPath, - scan_kind: ScanKind, - }, - ToggleSpecificGameRegistryIgnored { - name: String, - path: RegistryItem, - value: Option, - scan_kind: ScanKind, - }, - ToggleCustomGameEnabled { - index: usize, - enabled: bool, - }, ToggleCustomGameExpanded { index: usize, expanded: bool, }, - TogglePrimaryManifestEnabled { - enabled: bool, - }, - ToggleSecondaryManifestEnabled { - index: usize, - enabled: bool, - }, Filter { event: game_filter::Event, }, - EditedSortKey { - screen: Screen, - value: SortKey, - }, - EditedSortReversed { - screen: Screen, - value: bool, - }, BrowseDir(BrowseSubject), BrowseFile(BrowseFileSubject), SelectedFile(BrowseFileSubject, StrictPath), @@ -217,18 +159,10 @@ pub enum Message { url: String, }, KeyboardEvent(iced::keyboard::Event), - EditedFullRetention(u8), - EditedDiffRetention(u8), SelectedBackupToRestore { game: String, backup: Backup, }, - SelectedLanguage(Language), - SelectedTheme(Theme), - SelectedBackupFormat(BackupFormat), - SelectedBackupCompression(ZipCompression), - EditedCompressionLevel(i32), - ToggleCloudSynchronize, GameAction { action: GameAction, game: String, @@ -250,19 +184,10 @@ pub enum Message { game: String, comment: String, }, - SetShowDeselectedGames(bool), - SetShowUnchangedGames(bool), - SetShowUnscannedGames(bool), FilterDuplicates { scan_kind: ScanKind, game: Option, }, - OverrideMaxThreads(bool), - EditedMaxThreads(usize), - EditedRcloneExecutable(String), - EditedRcloneArguments(String), - EditedCloudRemoteId(String), - EditedCloudPath(String), OpenUrl(String), OpenUrlAndCloseModal(String), EditedCloudRemote(RemoteChoice), @@ -282,35 +207,35 @@ pub enum Message { ShowCustomGame { name: String, }, - SortCustomGames, } impl Message { pub fn browsed_dir(subject: BrowseSubject, choice: Option) -> Self { match choice { Some(path) => match subject { - BrowseSubject::BackupTarget => Message::EditedBackupTarget(crate::path::render_pathbuf(&path)), - BrowseSubject::RestoreSource => Message::EditedRestoreSource(crate::path::render_pathbuf(&path)), - BrowseSubject::Root(i) => Message::EditedRoot(EditAction::Change( + BrowseSubject::BackupTarget => config::Event::BackupTarget(crate::path::render_pathbuf(&path)), + BrowseSubject::RestoreSource => config::Event::RestoreSource(crate::path::render_pathbuf(&path)), + BrowseSubject::Root(i) => config::Event::Root(EditAction::Change( i, globetter::Pattern::escape(&crate::path::render_pathbuf(&path)), )), - BrowseSubject::RedirectSource(i) => Message::EditedRedirect( + BrowseSubject::RedirectSource(i) => config::Event::Redirect( EditAction::Change(i, crate::path::render_pathbuf(&path)), Some(RedirectEditActionField::Source), ), - BrowseSubject::RedirectTarget(i) => Message::EditedRedirect( + BrowseSubject::RedirectTarget(i) => config::Event::Redirect( EditAction::Change(i, crate::path::render_pathbuf(&path)), Some(RedirectEditActionField::Target), ), - BrowseSubject::CustomGameFile(i, j) => Message::EditedCustomGameFile( + BrowseSubject::CustomGameFile(i, j) => config::Event::CustomGameFile( i, EditAction::Change(j, globetter::Pattern::escape(&crate::path::render_pathbuf(&path))), ), BrowseSubject::BackupFilterIgnoredPath(i) => { - Message::EditedBackupFilterIgnoredPath(EditAction::Change(i, crate::path::render_pathbuf(&path))) + config::Event::BackupFilterIgnoredPath(EditAction::Change(i, crate::path::render_pathbuf(&path))) } - }, + } + .into(), None => Message::Ignore, } } @@ -321,6 +246,20 @@ impl Message { None => Message::Ignore, } } + + pub fn config(convert: impl Fn(T) -> config::Event) -> impl Fn(T) -> Self { + move |value: T| Self::Config { event: convert(value) } + } + + pub fn config2(convert: impl Fn(T, T2) -> config::Event) -> impl Fn(T, T2) -> Self { + move |v1: T, v2: T2| Self::Config { event: convert(v1, v2) } + } +} + +impl From for Message { + fn from(event: config::Event) -> Self { + Self::Config { event } + } } #[derive(Debug, Clone, PartialEq, Eq)] @@ -669,45 +608,6 @@ pub enum Screen { Other, } -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum EditDirection { - Up, - Down, -} - -impl EditDirection { - pub fn shift(&self, index: usize) -> usize { - match self { - Self::Up => index - 1, - Self::Down => index + 1, - } - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum EditAction { - Add, - Change(usize, String), - Remove(usize), - Move(usize, EditDirection), -} - -impl EditAction { - pub fn move_up(index: usize) -> Self { - Self::Move(index, EditDirection::Up) - } - - pub fn move_down(index: usize) -> Self { - Self::Move(index, EditDirection::Down) - } -} - -#[derive(Debug, Clone, PartialEq, Eq)] -pub enum RedirectEditActionField { - Source, - Target, -} - #[derive(Debug, Clone, PartialEq, Eq)] pub enum BrowseSubject { BackupTarget, diff --git a/src/gui/editor.rs b/src/gui/editor.rs index 3a4f8a2..cd8466d 100644 --- a/src/gui/editor.rs +++ b/src/gui/editor.rs @@ -18,7 +18,7 @@ use crate::{ lang::TRANSLATOR, resource::{ cache::Cache, - config::{Config, CustomGameKind, Integration, RedirectKind, SecondaryManifestConfigKind}, + config::{self, Config, CustomGameKind, Integration, RedirectKind, SecondaryManifestConfigKind}, manifest::{Manifest, Store}, }, }; @@ -37,17 +37,23 @@ pub fn root<'a>(config: &Config, histories: &TextHistories, modifiers: &keyboard .push( Row::new() .spacing(20) - .push(button::move_up(Message::EditedRoot, i)) - .push(button::move_down(Message::EditedRoot, i, config.roots.len())) + .push(button::move_up(Message::config(config::Event::Root), i)) + .push(button::move_down( + Message::config(config::Event::Root), + i, + config.roots.len(), + )) .push(histories.input(UndoSubject::RootPath(i))) .push( - pick_list(Store::ALL, Some(root.store()), move |v| { - Message::SelectedRootStore(i, v) - }) + pick_list( + Store::ALL, + Some(root.store()), + Message::config(move |v| config::Event::RootStore(i, v)), + ) .class(style::PickList::Primary), ) .push(button::choose_folder(BrowseSubject::Root(i), modifiers)) - .push(button::remove(Message::EditedRoot, i)), + .push(button::remove(Message::config(config::Event::Root), i)), ) .push( Row::new() @@ -61,17 +67,23 @@ pub fn root<'a>(config: &Config, histories: &TextHistories, modifiers: &keyboard _ => parent.push( Row::new() .spacing(20) - .push(button::move_up(Message::EditedRoot, i)) - .push(button::move_down(Message::EditedRoot, i, config.roots.len())) + .push(button::move_up(Message::config(config::Event::Root), i)) + .push(button::move_down( + Message::config(config::Event::Root), + i, + config.roots.len(), + )) .push(histories.input(UndoSubject::RootPath(i))) .push( - pick_list(Store::ALL, Some(root.store()), move |v| { - Message::SelectedRootStore(i, v) - }) + pick_list( + Store::ALL, + Some(root.store()), + Message::config(move |v| config::Event::RootStore(i, v)), + ) .class(style::PickList::Primary), ) .push(button::choose_folder(BrowseSubject::Root(i), modifiers)) - .push(button::remove(Message::EditedRoot, i)), + .push(button::remove(Message::config(config::Event::Root), i)), ), }); }; @@ -79,7 +91,7 @@ pub fn root<'a>(config: &Config, histories: &TextHistories, modifiers: &keyboard content = content.push( Row::new() .spacing(20) - .push(button::add(Message::EditedRoot)) + .push(button::add(Message::config(config::Event::Root))) .push(button::search(Message::FindRoots)), ); @@ -138,9 +150,11 @@ pub fn manifest<'a>( .spacing(20) .align_y(Alignment::Center) .push( - checkbox("", config.manifest.enable, move |enabled| { - Message::TogglePrimaryManifestEnabled { enabled } - }) + checkbox( + "", + config.manifest.enable, + Message::config(move |enabled| config::Event::PrimaryManifestEnabled { enabled }), + ) .spacing(0) .class(style::Checkbox), ) @@ -163,15 +177,20 @@ pub fn manifest<'a>( .spacing(20) .align_y(Alignment::Center) .push( - checkbox("", config.manifest.secondary[i].enabled(), move |enabled| { - Message::ToggleSecondaryManifestEnabled { index: i, enabled } - }) + checkbox( + "", + config.manifest.secondary[i].enabled(), + Message::config(move |enabled| config::Event::SecondaryManifestEnabled { + index: i, + enabled, + }), + ) .spacing(0) .class(style::Checkbox), ) - .push(button::move_up(Message::EditedSecondaryManifest, i)) + .push(button::move_up(Message::config(config::Event::SecondaryManifest), i)) .push(button::move_down( - Message::EditedSecondaryManifest, + Message::config(config::Event::SecondaryManifest), i, config.manifest.secondary.len(), )) @@ -179,7 +198,7 @@ pub fn manifest<'a>( pick_list( SecondaryManifestConfigKind::ALL, Some(config.manifest.secondary[i].kind()), - move |v| Message::SelectedSecondaryManifestKind(i, v), + Message::config(move |v| config::Event::SecondaryManifestKind(i, v)), ) .class(style::PickList::Primary) .width(75), @@ -193,11 +212,11 @@ pub fn manifest<'a>( } SecondaryManifestConfigKind::Remote => None, }) - .push(button::remove(Message::EditedSecondaryManifest, i)), + .push(button::remove(Message::config(config::Event::SecondaryManifest), i)), ) }); - content = content.push(button::add(Message::EditedSecondaryManifest)); + content = content.push(button::add(Message::config(config::Event::SecondaryManifest))); Container::new(content).class(style::Container::GameListEntry) } @@ -209,34 +228,42 @@ pub fn redirect<'a>(config: &Config, histories: &TextHistories, modifiers: &keyb let mut content = Column::new().padding(5).spacing(4).push(checkbox( TRANSLATOR.reverse_redirects_when_restoring(), config.restore.reverse_redirects, - Message::EditedReverseRedirectsOnRestore, + Message::config(config::Event::ReverseRedirectsOnRestore), )); content = config.redirects.iter().enumerate().fold(content, |parent, (i, _)| { parent.push( Row::new() .spacing(20) - .push(button::move_up(|x| Message::EditedRedirect(x, None), i)) + .push(button::move_up( + Message::config(move |x| config::Event::Redirect(x, None)), + i, + )) .push(button::move_down( - |x| Message::EditedRedirect(x, None), + Message::config(move |x| config::Event::Redirect(x, None)), i, config.redirects.len(), )) .push( - pick_list(RedirectKind::ALL, Some(redirects[i].kind), move |v| { - Message::SelectedRedirectKind(i, v) - }) + pick_list( + RedirectKind::ALL, + Some(redirects[i].kind), + Message::config(move |v| config::Event::RedirectKind(i, v)), + ) .class(style::PickList::Primary), ) .push(histories.input(UndoSubject::RedirectSource(i))) .push(button::choose_folder(BrowseSubject::RedirectSource(i), modifiers)) .push(histories.input(UndoSubject::RedirectTarget(i))) .push(button::choose_folder(BrowseSubject::RedirectTarget(i), modifiers)) - .push(button::remove(|x| Message::EditedRedirect(x, None), i)), + .push(button::remove( + Message::config(move |x| config::Event::Redirect(x, None)), + i, + )), ) }); - content.push(button::add(|x| Message::EditedRedirect(x, None))) + content.push(button::add(Message::config(move |x| config::Event::Redirect(x, None)))) }) .class(style::Container::GameListEntry); @@ -282,15 +309,24 @@ pub fn custom_games<'a>( .spacing(20) .align_y(Alignment::Center) .push( - checkbox("", config.is_custom_game_enabled(i), move |enabled| { - Message::ToggleCustomGameEnabled { index: i, enabled } - }) + checkbox( + "", + config.is_custom_game_enabled(i), + Message::config(move |enabled| config::Event::CustomGameEnabled { + index: i, + enabled, + }), + ) .spacing(0) .class(style::Checkbox), ) - .push(button::move_up_maybe(Message::EditedCustomGame, i, !filter.enabled)) + .push(button::move_up_maybe( + Message::config(config::Event::CustomGame), + i, + !filter.enabled, + )) .push(button::move_down_maybe( - Message::EditedCustomGame, + Message::config(config::Event::CustomGame), i, config.custom_games.len(), !filter.enabled, @@ -310,9 +346,11 @@ pub fn custom_games<'a>( None }) .push( - pick_list(CustomGameKind::ALL, Some(config.custom_games[i].kind()), move |v| { - Message::SelectedCustomGameKind(i, v) - }) + pick_list( + CustomGameKind::ALL, + Some(config.custom_games[i].kind()), + Message::config(move |v| config::Event::CustomGameKind(i, v)), + ) .class(style::PickList::Primary) .width(100), ) @@ -334,7 +372,7 @@ pub fn custom_games<'a>( .gap(5) .class(style::Container::Tooltip), ) - .push(button::delete(Message::EditedCustomGame, i)), + .push(button::delete(Message::config(config::Event::CustomGame), i)), ); if x.expanded { @@ -363,7 +401,7 @@ pub fn custom_games<'a>( .push(checkbox( TRANSLATOR.prefer_alias_display(), config.custom_games[i].prefer_alias, - move |x| Message::EditedCustomGaleAliasDisplay(i, x), + Message::config(move |x| config::Event::CustomGaleAliasDisplay(i, x)), )) }) .push_if(config.custom_games[i].kind() == CustomGameKind::Game, || { @@ -376,9 +414,11 @@ pub fn custom_games<'a>( .push(text(TRANSLATOR.field(&TRANSLATOR.integration_label()))), ) .push( - pick_list(Integration::ALL, Some(config.custom_games[i].integration), move |v| { - Message::SelectedCustomGameIntegration(i, v) - }) + pick_list( + Integration::ALL, + Some(config.custom_games[i].integration), + Message::config(move |v| config::Event::CustomGameIntegration(i, v)), + ) .class(style::PickList::Primary), ) }) @@ -400,9 +440,13 @@ pub fn custom_games<'a>( Row::new() .align_y(Alignment::Center) .spacing(20) - .push(button::move_up_nested(Message::EditedCustomGameFile, i, ii)) + .push(button::move_up_nested( + Message::config2(config::Event::CustomGameFile), + i, + ii, + )) .push(button::move_down_nested( - Message::EditedCustomGameFile, + Message::config2(config::Event::CustomGameFile), i, ii, x.files.len(), @@ -412,10 +456,14 @@ pub fn custom_games<'a>( BrowseSubject::CustomGameFile(i, ii), modifiers, )) - .push(button::remove_nested(Message::EditedCustomGameFile, i, ii)), + .push(button::remove_nested( + Message::config2(config::Event::CustomGameFile), + i, + ii, + )), ) }) - .push(button::add_nested(Message::EditedCustomGameFile, i)), + .push(button::add_nested(Message::config2(config::Event::CustomGameFile), i)), ) }) .push_if(config.custom_games[i].kind() == CustomGameKind::Game, || { @@ -437,25 +485,28 @@ pub fn custom_games<'a>( .spacing(20) .align_y(Alignment::Center) .push(button::move_up_nested( - Message::EditedCustomGameRegistry, + Message::config2(config::Event::CustomGameRegistry), i, ii, )) .push(button::move_down_nested( - Message::EditedCustomGameRegistry, + Message::config2(config::Event::CustomGameRegistry), i, ii, x.registry.len(), )) .push(histories.input(UndoSubject::CustomGameRegistry(i, ii))) .push(button::remove_nested( - Message::EditedCustomGameRegistry, + Message::config2(config::Event::CustomGameRegistry), i, ii, )), ) }) - .push(button::add_nested(Message::EditedCustomGameRegistry, i)), + .push(button::add_nested( + Message::config2(config::Event::CustomGameRegistry), + i, + )), ) }); } @@ -491,9 +542,12 @@ pub fn ignored_items<'a>(config: &Config, histories: &TextHistories, modifiers: column.push( Row::new() .spacing(20) - .push(button::move_up(Message::EditedBackupFilterIgnoredPath, ii)) + .push(button::move_up( + Message::config(config::Event::BackupFilterIgnoredPath), + ii, + )) .push(button::move_down( - Message::EditedBackupFilterIgnoredPath, + Message::config(config::Event::BackupFilterIgnoredPath), ii, config.backup.filter.ignored_paths.len(), )) @@ -502,10 +556,13 @@ pub fn ignored_items<'a>(config: &Config, histories: &TextHistories, modifiers: BrowseSubject::BackupFilterIgnoredPath(ii), modifiers, )) - .push(button::remove(Message::EditedBackupFilterIgnoredPath, ii)), + .push(button::remove( + Message::config(config::Event::BackupFilterIgnoredPath), + ii, + )), ) }) - .push(button::add(Message::EditedBackupFilterIgnoredPath)), + .push(button::add(Message::config(config::Event::BackupFilterIgnoredPath))), ), ) .push( @@ -522,17 +579,23 @@ pub fn ignored_items<'a>(config: &Config, histories: &TextHistories, modifiers: column.push( Row::new() .spacing(20) - .push(button::move_up(Message::EditedBackupFilterIgnoredRegistry, ii)) + .push(button::move_up( + Message::config(config::Event::BackupFilterIgnoredRegistry), + ii, + )) .push(button::move_down( - Message::EditedBackupFilterIgnoredRegistry, + Message::config(config::Event::BackupFilterIgnoredRegistry), ii, config.backup.filter.ignored_registry.len(), )) .push(histories.input(UndoSubject::BackupFilterIgnoredRegistry(ii))) - .push(button::remove(Message::EditedBackupFilterIgnoredRegistry, ii)), + .push(button::remove( + Message::config(config::Event::BackupFilterIgnoredRegistry), + ii, + )), ) }) - .push(button::add(Message::EditedBackupFilterIgnoredRegistry)), + .push(button::add(Message::config(config::Event::BackupFilterIgnoredRegistry))), ), ), ) diff --git a/src/gui/file_tree.rs b/src/gui/file_tree.rs index 093495a..f92b92b 100644 --- a/src/gui/file_tree.rs +++ b/src/gui/file_tree.rs @@ -14,7 +14,7 @@ use crate::{ }, lang::TRANSLATOR, path::StrictPath, - resource::config::Config, + resource::config::{self, Config}, scan::{ registry::RegistryItem, BackupError, BackupInfo, DuplicateDetector, Duplication, ScanChange, ScanInfo, ScanKind, ScannedFile, ScannedRegistryValues, @@ -113,25 +113,31 @@ impl FileTreeNode { let path = self.path.clone(); Some( Container::new( - checkbox("", !self.ignored, move |_| match &path { - FileTreeNodePath::File(path) => Message::ToggleSpecificGamePathIgnored { - name: game_name.clone(), - path: path.clone(), - scan_kind, - }, - FileTreeNodePath::RegistryKey(path) => Message::ToggleSpecificGameRegistryIgnored { - name: game_name.clone(), - path: path.clone(), - value: None, - scan_kind, - }, - FileTreeNodePath::RegistryValue(path, name) => Message::ToggleSpecificGameRegistryIgnored { - name: game_name.clone(), - path: path.clone(), - value: Some(name.clone()), - scan_kind, - }, - }) + checkbox( + "", + !self.ignored, + Message::config(move |_| match &path { + FileTreeNodePath::File(path) => config::Event::ToggleSpecificGamePathIgnored { + name: game_name.clone(), + path: path.clone(), + scan_kind, + }, + FileTreeNodePath::RegistryKey(path) => config::Event::ToggleSpecificGameRegistryIgnored { + name: game_name.clone(), + path: path.clone(), + value: None, + scan_kind, + }, + FileTreeNodePath::RegistryValue(path, name) => { + config::Event::ToggleSpecificGameRegistryIgnored { + name: game_name.clone(), + path: path.clone(), + value: Some(name.clone()), + scan_kind, + } + } + }), + ) .spacing(5) .class(style::Checkbox), ) diff --git a/src/gui/game_list.rs b/src/gui/game_list.rs index a2b6f18..4a33a3c 100644 --- a/src/gui/game_list.rs +++ b/src/gui/game_list.rs @@ -26,7 +26,7 @@ use crate::{ lang::TRANSLATOR, resource::{ cache::Cache, - config::{Config, Sort}, + config::{self, Config, Sort}, manifest::{self, Manifest, Os}, }, scan::{ @@ -85,11 +85,15 @@ impl GameListEntry { .align_y(Alignment::Center) .push({ let name = name.clone(); - checkbox("", enabled, move |enabled| Message::ToggleGameListEntryEnabled { - name: name.clone(), + checkbox( + "", enabled, - scan_kind, - }) + Message::config(move |enabled| config::Event::GameListEntryEnabled { + name: name.clone(), + enabled, + scan_kind, + }), + ) .spacing(0) .class(style::Checkbox) }) diff --git a/src/gui/screen.rs b/src/gui/screen.rs index c137e8e..1e0f963 100644 --- a/src/gui/screen.rs +++ b/src/gui/screen.rs @@ -7,7 +7,7 @@ use crate::{ gui::{ badge::Badge, button, - common::{BrowseFileSubject, BrowseSubject, Message, Operation, Screen, ScrollSubject, UndoSubject}, + common::{BrowseFileSubject, BrowseSubject, Message, Operation, ScrollSubject, UndoSubject}, editor, game_list::GameList, icon::Icon, @@ -20,7 +20,7 @@ use crate::{ prelude::{AVAILABLE_PARALELLISM, STEAM_DECK}, resource::{ cache::Cache, - config::{BackupFormat, CloudFilter, Config, SortKey, Theme, ZipCompression}, + config::{self, BackupFormat, CloudFilter, Config, SortKey, Theme, ZipCompression}, manifest::{Manifest, Store}, }, scan::{DuplicateDetector, Duplication, OperationStatus, ScanKind}, @@ -83,7 +83,6 @@ impl Backup { histories: &TextHistories, modifiers: &keyboard::Modifiers, ) -> Element { - let screen = Screen::Backup; let sort = &config.backup.sort; let content = Column::new() @@ -114,13 +113,10 @@ impl Backup { .push("|") .push(text(TRANSLATOR.sort_label())) .push( - pick_list(SortKey::ALL, Some(sort.key), move |value| Message::EditedSortKey { - screen, - value, - }) - .class(style::PickList::Primary), + pick_list(SortKey::ALL, Some(sort.key), Message::config(config::Event::SortKey)) + .class(style::PickList::Primary), ) - .push(button::sort_order(screen, sort.reversed)), + .push(button::sort_order(sort.reversed)), ) .push(self.log.view( Self::SCAN_KIND, @@ -160,7 +156,6 @@ impl Restore { histories: &TextHistories, modifiers: &keyboard::Modifiers, ) -> Element { - let screen = Screen::Restore; let sort = &config.restore.sort; let content = Column::new() @@ -192,13 +187,10 @@ impl Restore { .push("|") .push(text(TRANSLATOR.sort_label())) .push( - pick_list(SortKey::ALL, Some(sort.key), move |value| Message::EditedSortKey { - screen, - value, - }) - .class(style::PickList::Primary), + pick_list(SortKey::ALL, Some(sort.key), Message::config(config::Event::SortKey)) + .class(style::PickList::Primary), ) - .push(button::sort_order(screen, sort.reversed)), + .push(button::sort_order(sort.reversed)), ) .push(self.log.view( Self::SCAN_KIND, @@ -236,7 +228,7 @@ impl CustomGames { .align_y(Alignment::Center) .push(button::add_game()) .push(button::toggle_all_custom_games(config.are_all_custom_games_enabled())) - .push(button::sort(Message::SortCustomGames)) + .push(button::sort(config::Event::SortCustomGames)) .push(button::filter(self.filter.enabled)), ) .push_maybe(self.filter.view(histories)) @@ -290,8 +282,12 @@ pub fn other<'a>( .spacing(20) .push(text(TRANSLATOR.field_language())) .push( - pick_list(Language::ALL, Some(config.language), Message::SelectedLanguage) - .class(style::PickList::Primary), + pick_list( + Language::ALL, + Some(config.language), + Message::config(config::Event::Language), + ) + .class(style::PickList::Primary), ), ) .push( @@ -300,7 +296,7 @@ pub fn other<'a>( .spacing(20) .push(text(TRANSLATOR.field_theme())) .push( - pick_list(Theme::ALL, Some(config.theme), Message::SelectedTheme) + pick_list(Theme::ALL, Some(config.theme), Message::config(config::Event::Theme)) .class(style::PickList::Primary), ), ) @@ -311,7 +307,7 @@ pub fn other<'a>( .push(checkbox( TRANSLATOR.new_version_check(), config.release.check, - Message::AppReleaseToggle, + Message::config(config::Event::CheckRelease), )) .push(button::open_url_icon(RELEASE_URL.to_string())), ) @@ -328,7 +324,7 @@ pub fn other<'a>( .push(checkbox( TRANSLATOR.override_max_threads(), config.runtime.threads.is_some(), - Message::OverrideMaxThreads, + Message::config(config::Event::OverrideMaxThreads), )) .push_maybe({ config.runtime.threads.map(|threads| { @@ -336,7 +332,7 @@ pub fn other<'a>( threads.get() as i32, TRANSLATOR.threads_label(), 1..=(max_threads.get() as i32), - |x| Message::EditedMaxThreads(x as usize), + Message::config(|x| config::Event::MaxThreads(x as usize)), )) .padding(padding::left(35)) }) @@ -347,34 +343,34 @@ pub fn other<'a>( checkbox( TRANSLATOR.explanation_for_exclude_store_screenshots(), config.backup.filter.exclude_store_screenshots, - Message::EditedExcludeStoreScreenshots, + Message::config(config::Event::ExcludeStoreScreenshots), ) .class(style::Checkbox), ) .push(checkbox( TRANSLATOR.show_disabled_games(), config.scan.show_deselected_games, - Message::SetShowDeselectedGames, + Message::config(config::Event::ShowDeselectedGames), )) .push(checkbox( TRANSLATOR.show_unchanged_games(), config.scan.show_unchanged_games, - Message::SetShowUnchangedGames, + Message::config(config::Event::ShowUnchangedGames), )) .push(checkbox( TRANSLATOR.show_unscanned_games(), config.scan.show_unscanned_games, - Message::SetShowUnscannedGames, + Message::config(config::Event::ShowUnscannedGames), )) .push(checkbox( TRANSLATOR.field(&TRANSLATOR.explanation_for_exclude_cloud_games()), config.backup.filter.cloud.exclude, - |exclude| { - Message::EditedCloudFilter(CloudFilter { + Message::config(move |exclude| { + config::Event::CloudFilter(CloudFilter { exclude, ..config.backup.filter.cloud }) - }, + }), )) .push( Row::new() @@ -384,12 +380,12 @@ pub fn other<'a>( checkbox( TRANSLATOR.store(&Store::Epic), config.backup.filter.cloud.epic, - |epic| { - Message::EditedCloudFilter(CloudFilter { + Message::config(move |epic| { + config::Event::CloudFilter(CloudFilter { epic, ..config.backup.filter.cloud }) - }, + }), ) .class(style::Checkbox), ) @@ -397,12 +393,12 @@ pub fn other<'a>( checkbox( TRANSLATOR.store(&Store::Gog), config.backup.filter.cloud.gog, - |gog| { - Message::EditedCloudFilter(CloudFilter { + Message::config(move |gog| { + config::Event::CloudFilter(CloudFilter { gog, ..config.backup.filter.cloud }) - }, + }), ) .class(style::Checkbox), ) @@ -414,12 +410,12 @@ pub fn other<'a>( TRANSLATOR.store(&Store::Ea) ), config.backup.filter.cloud.origin, - |origin| { - Message::EditedCloudFilter(CloudFilter { + Message::config(move |origin| { + config::Event::CloudFilter(CloudFilter { origin, ..config.backup.filter.cloud }) - }, + }), ) .class(style::Checkbox), ) @@ -427,12 +423,12 @@ pub fn other<'a>( checkbox( TRANSLATOR.store(&Store::Steam), config.backup.filter.cloud.steam, - |steam| { - Message::EditedCloudFilter(CloudFilter { + Message::config(move |steam| { + config::Event::CloudFilter(CloudFilter { steam, ..config.backup.filter.cloud }) - }, + }), ) .class(style::Checkbox), ) @@ -440,12 +436,12 @@ pub fn other<'a>( checkbox( TRANSLATOR.store(&Store::Uplay), config.backup.filter.cloud.uplay, - |uplay| { - Message::EditedCloudFilter(CloudFilter { + Message::config(move |uplay| { + config::Event::CloudFilter(CloudFilter { uplay, ..config.backup.filter.cloud }) - }, + }), ) .class(style::Checkbox), ), @@ -470,7 +466,7 @@ pub fn other<'a>( config.backup.retention.full as i32, TRANSLATOR.full_retention(), 1..=255, - |x| Message::EditedFullRetention(x as u8), + Message::config(|x| config::Event::FullRetention(x as u8)), ) }) .push({ @@ -478,7 +474,7 @@ pub fn other<'a>( config.backup.retention.differential as i32, TRANSLATOR.differential_retention(), 0..=255, - |x| Message::EditedDiffRetention(x as u8), + Message::config(|x| config::Event::DiffRetention(x as u8)), ) }), ) @@ -495,7 +491,7 @@ pub fn other<'a>( pick_list( BackupFormat::ALL, Some(config.backup.format.chosen), - Message::SelectedBackupFormat, + Message::config(config::Event::BackupFormat), ) .class(style::PickList::Primary), ), @@ -509,7 +505,7 @@ pub fn other<'a>( pick_list( ZipCompression::ALL, Some(config.backup.format.zip.compression), - Message::SelectedBackupCompression, + Message::config(config::Event::BackupCompression), ) .class(style::PickList::Primary), ) @@ -520,7 +516,7 @@ pub fn other<'a>( level, TRANSLATOR.backup_compression_level_field(), range, - Message::EditedCompressionLevel, + Message::config(config::Event::CompressionLevel), )), _ => None, }, @@ -621,7 +617,7 @@ pub fn other<'a>( .push(checkbox( TRANSLATOR.synchronize_automatically(), config.cloud.synchronize, - |_| Message::ToggleCloudSynchronize, + Message::config(|_| config::Event::ToggleCloudSynchronize), )) }) .push_if(!is_cloud_configured, || text(TRANSLATOR.cloud_not_configured())) diff --git a/src/gui/shortcuts.rs b/src/gui/shortcuts.rs index dbbb78f..879b540 100644 --- a/src/gui/shortcuts.rs +++ b/src/gui/shortcuts.rs @@ -8,14 +8,14 @@ use iced::Length; use crate::{ cloud::Remote, gui::{ - common::{EditAction, Message, RedirectEditActionField, UndoSubject, ERROR_ICON}, + common::{Message, UndoSubject, ERROR_ICON}, modal::{ModalField, ModalInputKind}, style, widget::{id, Element, TextInput, Undoable}, }, lang::TRANSLATOR, - prelude::StrictPath, - resource::config::{Config, CustomGame}, + prelude::{EditAction, RedirectEditActionField, StrictPath}, + resource::config::{self, Config, CustomGame}, scan::{game_filter, registry::RegistryItem}, }; @@ -366,8 +366,8 @@ impl TextHistories { }; let event: Box Message> = match subject.clone() { - UndoSubject::BackupTarget => Box::new(Message::EditedBackupTarget), - UndoSubject::RestoreSource => Box::new(Message::EditedRestoreSource), + UndoSubject::BackupTarget => Box::new(Message::config(config::Event::BackupTarget)), + UndoSubject::RestoreSource => Box::new(Message::config(config::Event::RestoreSource)), UndoSubject::BackupSearchGameName => Box::new(|value| Message::Filter { event: game_filter::Event::EditedGameName(value), }), @@ -377,37 +377,43 @@ impl TextHistories { UndoSubject::CustomGamesSearchGameName => Box::new(|value| Message::Filter { event: game_filter::Event::EditedGameName(value), }), - UndoSubject::RootPath(i) => Box::new(move |value| Message::EditedRoot(EditAction::Change(i, value))), - UndoSubject::RootLutrisDatabase(i) => Box::new(move |value| Message::EditedRootLutrisDatabase(i, value)), - UndoSubject::SecondaryManifest(i) => { - Box::new(move |value| Message::EditedSecondaryManifest(EditAction::Change(i, value))) + UndoSubject::RootPath(i) => Box::new(Message::config(move |value| { + config::Event::Root(EditAction::Change(i, value)) + })), + UndoSubject::RootLutrisDatabase(i) => Box::new(Message::config(move |value| { + config::Event::RootLutrisDatabase(i, value) + })), + UndoSubject::SecondaryManifest(i) => Box::new(Message::config(move |value| { + config::Event::SecondaryManifest(EditAction::Change(i, value)) + })), + UndoSubject::RedirectSource(i) => Box::new(Message::config(move |value| { + config::Event::Redirect(EditAction::Change(i, value), Some(RedirectEditActionField::Source)) + })), + UndoSubject::RedirectTarget(i) => Box::new(Message::config(move |value| { + config::Event::Redirect(EditAction::Change(i, value), Some(RedirectEditActionField::Target)) + })), + UndoSubject::CustomGameName(i) => Box::new(Message::config(move |value| { + config::Event::CustomGame(EditAction::Change(i, value)) + })), + UndoSubject::CustomGameAlias(i) => { + Box::new(Message::config(move |value| config::Event::CustomGameAlias(i, value))) } - UndoSubject::RedirectSource(i) => Box::new(move |value| { - Message::EditedRedirect(EditAction::Change(i, value), Some(RedirectEditActionField::Source)) - }), - UndoSubject::RedirectTarget(i) => Box::new(move |value| { - Message::EditedRedirect(EditAction::Change(i, value), Some(RedirectEditActionField::Target)) - }), - UndoSubject::CustomGameName(i) => { - Box::new(move |value| Message::EditedCustomGame(EditAction::Change(i, value))) - } - UndoSubject::CustomGameAlias(i) => Box::new(move |value| Message::EditedCustomGameAlias(i, value)), - UndoSubject::CustomGameFile(i, j) => { - Box::new(move |value| Message::EditedCustomGameFile(i, EditAction::Change(j, value))) - } - UndoSubject::CustomGameRegistry(i, j) => { - Box::new(move |value| Message::EditedCustomGameRegistry(i, EditAction::Change(j, value))) - } - UndoSubject::BackupFilterIgnoredPath(i) => { - Box::new(move |value| Message::EditedBackupFilterIgnoredPath(EditAction::Change(i, value))) - } - UndoSubject::BackupFilterIgnoredRegistry(i) => { - Box::new(move |value| Message::EditedBackupFilterIgnoredRegistry(EditAction::Change(i, value))) - } - UndoSubject::RcloneExecutable => Box::new(Message::EditedRcloneExecutable), - UndoSubject::RcloneArguments => Box::new(Message::EditedRcloneArguments), - UndoSubject::CloudRemoteId => Box::new(Message::EditedCloudRemoteId), - UndoSubject::CloudPath => Box::new(Message::EditedCloudPath), + UndoSubject::CustomGameFile(i, j) => Box::new(Message::config(move |value| { + config::Event::CustomGameFile(i, EditAction::Change(j, value)) + })), + UndoSubject::CustomGameRegistry(i, j) => Box::new(Message::config(move |value| { + config::Event::CustomGameRegistry(i, EditAction::Change(j, value)) + })), + UndoSubject::BackupFilterIgnoredPath(i) => Box::new(Message::config(move |value| { + config::Event::BackupFilterIgnoredPath(EditAction::Change(i, value)) + })), + UndoSubject::BackupFilterIgnoredRegistry(i) => Box::new(Message::config(move |value| { + config::Event::BackupFilterIgnoredRegistry(EditAction::Change(i, value)) + })), + UndoSubject::RcloneExecutable => Box::new(Message::config(config::Event::RcloneExecutable)), + UndoSubject::RcloneArguments => Box::new(Message::config(config::Event::RcloneArguments)), + UndoSubject::CloudRemoteId => Box::new(Message::config(config::Event::CloudRemoteId)), + UndoSubject::CloudPath => Box::new(Message::config(config::Event::CloudPath)), UndoSubject::ModalField(field) => Box::new(move |value| { Message::EditedModalField(match field { ModalInputKind::Url => ModalField::Url(value), diff --git a/src/gui/widget.rs b/src/gui/widget.rs index 37c4c4d..8df0e08 100644 --- a/src/gui/widget.rs +++ b/src/gui/widget.rs @@ -117,7 +117,7 @@ pub fn number_input<'a>( value: i32, label: String, range: RangeInclusive, - change: fn(i32) -> Message, + change: impl Fn(i32) -> Message, ) -> Element<'a> { Container::new( Row::new() diff --git a/src/prelude.rs b/src/prelude.rs index 79245ea..4162fba 100644 --- a/src/prelude.rs +++ b/src/prelude.rs @@ -327,3 +327,42 @@ pub fn unregister_sigint() { } } } + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum EditDirection { + Up, + Down, +} + +impl EditDirection { + pub fn shift(&self, index: usize) -> usize { + match self { + Self::Up => index - 1, + Self::Down => index + 1, + } + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum EditAction { + Add, + Change(usize, String), + Remove(usize), + Move(usize, EditDirection), +} + +impl EditAction { + pub fn move_up(index: usize) -> Self { + Self::Move(index, EditDirection::Up) + } + + pub fn move_down(index: usize) -> Self { + Self::Move(index, EditDirection::Down) + } +} + +#[derive(Debug, Clone, PartialEq, Eq)] +pub enum RedirectEditActionField { + Source, + Target, +} diff --git a/src/resource/config.rs b/src/resource/config.rs index 98cd49c..abbd1bf 100644 --- a/src/resource/config.rs +++ b/src/resource/config.rs @@ -10,7 +10,7 @@ use crate::{ cloud::Remote, lang::{Language, TRANSLATOR}, path::CommonPath, - prelude::{app_dir, Error, StrictPath, AVAILABLE_PARALELLISM}, + prelude::{app_dir, EditAction, Error, RedirectEditActionField, StrictPath, AVAILABLE_PARALELLISM}, resource::{ manifest::{self, CloudMetadata, Manifest, Store}, ResourceFile, SaveableResourceFile, @@ -25,6 +25,79 @@ fn default_backup_dir() -> StrictPath { StrictPath::new(format!("{}/ludusavi-backup", CommonPath::Home.get().unwrap())) } +#[derive(Debug, Clone)] +pub enum Event { + Theme(Theme), + Language(Language), + CheckRelease(bool), + BackupTarget(String), + RestoreSource(String), + Root(EditAction), + RootLutrisDatabase(usize, String), + SecondaryManifest(EditAction), + RootStore(usize, Store), + RedirectKind(usize, RedirectKind), + SecondaryManifestKind(usize, SecondaryManifestConfigKind), + CustomGameKind(usize, CustomGameKind), + CustomGameIntegration(usize, Integration), + Redirect(EditAction, Option), + ReverseRedirectsOnRestore(bool), + CustomGame(EditAction), + CustomGameAlias(usize, String), + CustomGaleAliasDisplay(usize, bool), + CustomGameFile(usize, EditAction), + CustomGameRegistry(usize, EditAction), + ExcludeStoreScreenshots(bool), + CloudFilter(CloudFilter), + BackupFilterIgnoredPath(EditAction), + BackupFilterIgnoredRegistry(EditAction), + GameListEntryEnabled { + name: String, + enabled: bool, + scan_kind: ScanKind, + }, + ToggleSpecificGamePathIgnored { + name: String, + path: StrictPath, + scan_kind: ScanKind, + }, + ToggleSpecificGameRegistryIgnored { + name: String, + path: RegistryItem, + value: Option, + scan_kind: ScanKind, + }, + CustomGameEnabled { + index: usize, + enabled: bool, + }, + PrimaryManifestEnabled { + enabled: bool, + }, + SecondaryManifestEnabled { + index: usize, + enabled: bool, + }, + SortKey(SortKey), + SortReversed(bool), + FullRetention(u8), + DiffRetention(u8), + BackupFormat(BackupFormat), + BackupCompression(ZipCompression), + CompressionLevel(i32), + ToggleCloudSynchronize, + ShowDeselectedGames(bool), + ShowUnchangedGames(bool), + ShowUnscannedGames(bool), + OverrideMaxThreads(bool), + MaxThreads(usize), + RcloneExecutable(String), + RcloneArguments(String), + CloudRemoteId(String), + CloudPath(String), + SortCustomGames, +} + /// Settings for `config.yaml` #[derive(Clone, Debug, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize, schemars::JsonSchema)] #[serde(default, rename_all = "camelCase")]