From 283ca8be098ddf29106bf4f3e63ea2498c156f2d Mon Sep 17 00:00:00 2001 From: Jagandeep Brar Date: Tue, 1 Sep 2020 22:01:21 -0500 Subject: [PATCH] [TestFlight] v4.0.0+400005 (#248) NEW - [Settings] Entirely revamped the settings page to allow for easier navigation for new users - [Search] Ability to set custom headers for individual indexers TWEAKS - [Settings] Split apart customization and configuration of modules, and add AppBar actions to allow quickly switching between customization and configuration FIXES - None --- lib/core.dart | 1 - lib/core/constants.dart | 2 +- lib/core/database/adapters/profile.dart | 24 +-- lib/core/module_flags.dart | 18 -- lib/core/providers.dart | 11 +- lib/core/routes.dart | 46 +---- lib/core/ui/navigation/appbar_dropdown.dart | 6 + lib/core/ui/navigation/drawer.dart | 16 +- lib/modules/home/core/api/api.dart | 6 - lib/modules/home/routes/quick_access.dart | 2 +- lib/modules/search/core/api/api.dart | 36 ++-- lib/modules/settings.dart | 3 +- lib/modules/settings/core.dart | 3 +- lib/modules/settings/core/api.dart | 3 - lib/modules/settings/core/constants.dart | 62 ++++++ lib/modules/settings/core/state.dart | 25 +++ lib/modules/settings/core/state_global.dart | 11 - lib/modules/settings/modules.dart | 40 ++++ .../settings/modules/backup_restore.dart | 2 + .../modules/backup_restore/route.dart | 30 +++ .../modules/backup_restore/widgets.dart | 2 + .../backup_restore/widgets/backup_tile.dart} | 2 +- .../backup_restore/widgets/restore_tile.dart} | 2 +- .../settings/modules/customization.dart | 2 + .../settings/modules/customization/route.dart | 125 ++++++++++++ .../modules/customization/widgets.dart | 1 + .../customization/widgets/browser_tile.dart} | 4 +- .../modules/customization_appearance.dart | 2 + .../customization_appearance/route.dart | 30 +++ .../customization_appearance/widgets.dart | 3 + .../widgets/amoled_border_tile.dart} | 2 +- .../widgets/amoled_tile.dart} | 2 +- .../widgets}/use_24h_time.dart | 2 +- .../modules/customization_calendar.dart | 2 + .../modules/customization_calendar/route.dart | 34 +++ .../customization_calendar/widgets.dart | 6 + .../widgets/enable_lidarr_tile.dart} | 6 +- .../widgets/enable_radarr_tile.dart} | 6 +- .../widgets/enable_sonarr_tile.dart} | 6 +- .../widgets}/start_date_tile.dart | 2 +- .../widgets}/start_size_tile.dart | 2 +- .../widgets}/start_type_tile.dart | 2 +- .../modules/customization_drawer.dart | 2 + .../modules/customization_drawer/route.dart | 30 +++ .../modules/customization_drawer/widgets.dart | 3 + .../widgets/expand_automation_tile.dart} | 2 +- .../widgets/expand_clients_tile.dart} | 2 +- .../widgets/expand_monitoring_tile.dart} | 2 +- .../settings/modules/customization_home.dart | 2 + .../modules/customization_home/route.dart | 29 +++ .../modules/customization_home/widgets.dart | 2 + .../widgets/brand_colours_tile.dart} | 2 +- .../widgets/default_page_tile.dart} | 10 +- .../modules/customization_lidarr.dart | 2 + .../modules/customization_lidarr/route.dart | 36 ++++ .../modules/customization_lidarr/widgets.dart | 1 + .../widgets/default_page_tile.dart | 21 ++ .../modules/customization_nzbget.dart | 2 + .../modules/customization_nzbget/route.dart | 36 ++++ .../modules/customization_nzbget/widgets.dart | 1 + .../widgets/default_page_tile.dart | 21 ++ .../modules/customization_quickactions.dart | 2 + .../customization_quickactions/route.dart | 63 ++++++ .../customization_quickactions/widgets.dart | 1 + .../widgets/action_tile.dart | 28 +++ .../modules/customization_radarr.dart | 2 + .../modules/customization_radarr/route.dart | 36 ++++ .../modules/customization_radarr/widgets.dart | 1 + .../widgets/default_page_tile.dart | 21 ++ .../modules/customization_sabnzbd.dart | 2 + .../modules/customization_sabnzbd/route.dart | 36 ++++ .../customization_sabnzbd/widgets.dart | 1 + .../widgets/default_page_tile.dart | 21 ++ .../modules/customization_search.dart | 2 + .../modules/customization_search/route.dart | 36 ++++ .../modules/customization_search/widgets.dart | 1 + .../widgets/hide_adult_categories_tile.dart | 18 ++ .../modules/customization_sonarr.dart | 2 + .../modules/customization_sonarr/route.dart | 36 ++++ .../modules/customization_sonarr/widgets.dart | 1 + .../widgets/default_page_tile.dart | 21 ++ .../modules/customization_tautulli.dart | 2 + .../modules/customization_tautulli/route.dart | 36 ++++ .../customization_tautulli/widgets.dart | 1 + .../widgets/default_page_tile.dart | 21 ++ lib/modules/settings/modules/donations.dart | 2 + .../settings/modules/donations/route.dart | 70 +++++++ .../settings/modules/donations/widgets.dart | 1 + .../modules/donations/widgets/iap_tile.dart | 25 +++ .../settings/modules/donations_thankyou.dart | 1 + .../modules/donations_thankyou/route.dart | 57 ++++++ lib/modules/settings/modules/logs.dart | 2 + lib/modules/settings/modules/logs/route.dart | 68 ++++++ .../settings/modules/logs/widgets.dart | 2 + .../logs/widgets}/clear_tile.dart | 4 +- .../logs/widgets}/export_tile.dart | 4 +- .../settings/modules/logs_details.dart | 2 + .../settings/modules/logs_details/route.dart | 92 +++++++++ .../modules/logs_details/widgets.dart | 1 + .../logs_details/widgets/log_tile.dart | 123 +++++++++++ lib/modules/settings/modules/modules.dart | 2 + .../settings/modules/modules/route.dart | 77 +++++++ .../settings/modules/modules/widgets.dart | 1 + .../modules/widgets/enabled_profile.dart | 30 +++ .../settings/modules/modules_lidarr.dart | 2 + .../modules/modules_lidarr/route.dart | 62 ++++++ .../modules/modules_lidarr/widgets.dart | 6 + .../modules_lidarr/widgets/apikey_tile.dart | 28 +++ .../widgets/custom_headers_tile.dart | 13 ++ .../modules_lidarr/widgets/enabled_tile.dart | 16 ++ .../modules_lidarr/widgets/host_tile.dart | 29 +++ .../widgets/strict_tls_tile.dart | 28 +++ .../widgets/test_connection_tile.dart | 15 ++ .../modules/modules_lidarr_headers.dart | 2 + .../modules/modules_lidarr_headers/route.dart | 50 +++++ .../modules_lidarr_headers/widgets.dart | 2 + .../widgets/add_header_tile.dart | 52 +++++ .../widgets/header_tile.dart | 40 ++++ .../settings/modules/modules_nzbget.dart | 2 + .../modules/modules_nzbget/route.dart | 64 ++++++ .../modules/modules_nzbget/widgets.dart | 7 + .../widgets/custom_headers_tile.dart | 13 ++ .../modules_nzbget/widgets/enabled_tile.dart | 16 ++ .../modules_nzbget/widgets/host_tile.dart | 29 +++ .../modules_nzbget/widgets/password_tile.dart | 28 +++ .../widgets/strict_tls_tile.dart | 28 +++ .../widgets/test_connection_tile.dart | 15 ++ .../modules_nzbget/widgets/username_tile.dart | 28 +++ .../modules/modules_nzbget_headers.dart | 2 + .../modules/modules_nzbget_headers/route.dart | 50 +++++ .../modules_nzbget_headers/widgets.dart | 2 + .../widgets/add_header_tile.dart | 52 +++++ .../widgets/header_tile.dart | 40 ++++ .../settings/modules/modules_radarr.dart | 2 + .../modules/modules_radarr/route.dart | 62 ++++++ .../modules/modules_radarr/widgets.dart | 6 + .../modules_radarr/widgets/apikey_tile.dart | 28 +++ .../widgets/custom_headers_tile.dart | 13 ++ .../modules_radarr/widgets/enabled_tile.dart | 16 ++ .../modules_radarr/widgets/host_tile.dart | 29 +++ .../widgets/strict_tls_tile.dart | 28 +++ .../widgets/test_connection_tile.dart | 15 ++ .../modules/modules_radarr_headers.dart | 2 + .../modules/modules_radarr_headers/route.dart | 50 +++++ .../modules_radarr_headers/widgets.dart | 2 + .../widgets/add_header_tile.dart | 52 +++++ .../widgets/header_tile.dart | 40 ++++ .../settings/modules/modules_sabnzbd.dart | 2 + .../modules/modules_sabnzbd/route.dart | 62 ++++++ .../modules/modules_sabnzbd/widgets.dart | 6 + .../modules_sabnzbd/widgets/apikey_tile.dart | 28 +++ .../widgets/custom_headers_tile.dart | 13 ++ .../modules_sabnzbd/widgets/enabled_tile.dart | 16 ++ .../modules_sabnzbd/widgets/host_tile.dart | 29 +++ .../widgets/strict_tls_tile.dart | 28 +++ .../widgets/test_connection_tile.dart | 15 ++ .../modules/modules_sabnzbd_headers.dart | 2 + .../modules_sabnzbd_headers/route.dart | 50 +++++ .../modules_sabnzbd_headers/widgets.dart | 2 + .../widgets/add_header_tile.dart | 52 +++++ .../widgets/header_tile.dart | 40 ++++ .../settings/modules/modules_search.dart | 2 + .../modules/modules_search/route.dart | 61 ++++++ .../modules/modules_search/widgets.dart | 1 + .../modules_search/widgets/indexer_tile.dart | 25 +++ .../settings/modules/modules_search_add.dart | 1 + .../modules/modules_search_add/route.dart | 124 +++++++++++ .../settings/modules/modules_search_edit.dart | 1 + .../modules/modules_search_edit/route.dart | 144 +++++++++++++ .../modules/modules_search_headers.dart | 1 + .../modules/modules_search_headers/route.dart | 151 ++++++++++++++ .../settings/modules/modules_sonarr.dart | 2 + .../modules/modules_sonarr/route.dart | 62 ++++++ .../modules/modules_sonarr/widgets.dart | 6 + .../modules_sonarr/widgets/apikey_tile.dart | 28 +++ .../widgets/custom_headers_tile.dart | 13 ++ .../modules_sonarr/widgets/enabled_tile.dart | 16 ++ .../modules_sonarr/widgets/host_tile.dart | 29 +++ .../widgets/strict_tls_tile.dart | 28 +++ .../widgets/test_connection_tile.dart | 15 ++ .../modules/modules_sonarr_headers.dart | 2 + .../modules/modules_sonarr_headers/route.dart | 50 +++++ .../modules_sonarr_headers/widgets.dart | 2 + .../widgets/add_header_tile.dart | 52 +++++ .../widgets/header_tile.dart | 40 ++++ .../settings/modules/modules_tautulli.dart | 2 + .../modules/modules_tautulli/route.dart | 62 ++++++ .../modules/modules_tautulli/widgets.dart | 6 + .../modules_tautulli/widgets/apikey_tile.dart | 28 +++ .../widgets/custom_headers_tile.dart | 13 ++ .../widgets/enabled_tile.dart | 16 ++ .../modules_tautulli/widgets/host_tile.dart | 29 +++ .../widgets/strict_tls_tile.dart | 28 +++ .../widgets/test_connection_tile.dart | 34 +++ .../modules/modules_tautulli_headers.dart | 2 + .../modules_tautulli_headers/route.dart | 50 +++++ .../modules_tautulli_headers/widgets.dart | 2 + .../widgets/add_header_tile.dart | 52 +++++ .../widgets/header_tile.dart | 40 ++++ .../settings/modules/modules_wakeonlan.dart | 2 + .../modules/modules_wakeonlan/route.dart | 42 ++++ .../modules/modules_wakeonlan/widgets.dart | 3 + .../widgets/broadcast_address_tile.dart | 25 +++ .../widgets/enabled_tile.dart | 16 ++ .../widgets/mac_address_tile.dart | 25 +++ lib/modules/settings/modules/profiles.dart | 2 + .../settings/modules/profiles/route.dart | 40 ++++ .../settings/modules/profiles/widgets.dart | 4 + .../profiles/widgets}/add_tile.dart | 2 +- .../profiles/widgets}/delete_tile.dart | 2 +- .../profiles/widgets}/enabled_tile.dart | 10 +- .../profiles/widgets}/rename_tile.dart | 2 +- lib/modules/settings/modules/resources.dart | 1 + .../settings/modules/resources/route.dart | 74 +++++++ lib/modules/settings/modules/settings.dart | 1 + .../settings/modules/settings/route.dart | 89 ++++++++ lib/modules/settings/modules/system.dart | 2 + .../settings/modules/system/route.dart | 44 ++++ .../settings/modules/system/widgets.dart | 5 + .../widgets}/clear_configuration_tile.dart | 0 .../widgets}/clear_image_cache_tile.dart | 0 .../modules/system/widgets/licenses_tile.dart | 12 ++ .../system/widgets/sentry_tile.dart} | 2 +- .../modules/system/widgets/version_tile.dart | 20 ++ lib/modules/settings/routes.dart | 24 --- lib/modules/settings/routes/general.dart | 63 ------ .../settings/routes/logs/logs_details.dart | 76 ------- .../settings/routes/logs/logs_types.dart | 58 ------ .../settings/routes/logs/logs_view.dart | 100 --------- lib/modules/settings/routes/modules.dart | 82 -------- .../routes/modules/automation_lidarr.dart | 2 - .../automation_lidarr/automation_lidarr.dart | 156 -------------- .../automation_lidarr_headers.dart | 110 ---------- .../routes/modules/automation_radarr.dart | 2 - .../automation_radarr/automation_radarr.dart | 156 -------------- .../automation_radarr_headers.dart | 110 ---------- .../routes/modules/automation_sonarr.dart | 2 - .../automation_sonarr/automation_sonarr.dart | 167 --------------- .../automation_sonarr_headers.dart | 110 ---------- .../routes/modules/clients_nzbget.dart | 2 - .../clients_nzbget/clients_nzbget.dart | 193 ------------------ .../clients_nzbget_headers.dart | 110 ---------- .../routes/modules/clients_sabnzbd.dart | 2 - .../clients_sabnzbd/clients_sabnzbd.dart | 156 -------------- .../clients_sabnzbd_headers.dart | 110 ---------- .../settings/routes/modules/general_home.dart | 60 ------ .../routes/modules/general_lunasea.dart | 2 - .../general_lunasea/general_lunasea.dart | 61 ------ .../general_lunasea_quick_actions.dart | 58 ------ .../routes/modules/general_search.dart | 95 --------- .../routes/modules/general_search_add.dart | 84 -------- .../routes/modules/general_search_edit.dart | 100 --------- .../routes/modules/general_wake_on_lan.dart | 89 -------- .../routes/modules/monitoring_tautulli.dart | 2 - .../monitoring_tautulli.dart | 175 ---------------- .../monitoring_tautulli_headers.dart | 110 ---------- lib/modules/settings/routes/settings.dart | 49 ----- lib/modules/settings/routes/system.dart | 138 ------------- .../routes/system/resources_donations.dart | 85 -------- .../system/resources_donations_thankyou.dart | 49 ----- lib/modules/settings/widgets.dart | 4 - lib/modules/settings/widgets/general.dart | 3 - .../widgets/general/configuration.dart | 2 - .../settings/widgets/general/logs.dart | 3 - .../widgets/general/logs/view_tile.dart | 15 -- .../settings/widgets/general/profile.dart | 4 - lib/modules/settings/widgets/modules.dart | 2 - .../settings/widgets/modules/home.dart | 8 - .../settings/widgets/modules/lunasea.dart | 8 - .../modules/lunasea/quick_actions_tile.dart | 15 -- .../settings/widgets/navigation_bar.dart | 49 ----- lib/modules/settings/widgets/system.dart | 2 - pubspec.lock | 21 +- pubspec.yaml | 10 +- 274 files changed, 4662 insertions(+), 3241 deletions(-) delete mode 100644 lib/core/module_flags.dart delete mode 100644 lib/modules/settings/core/api.dart create mode 100644 lib/modules/settings/core/state.dart delete mode 100644 lib/modules/settings/core/state_global.dart create mode 100644 lib/modules/settings/modules.dart create mode 100644 lib/modules/settings/modules/backup_restore.dart create mode 100644 lib/modules/settings/modules/backup_restore/route.dart create mode 100644 lib/modules/settings/modules/backup_restore/widgets.dart rename lib/modules/settings/{widgets/general/configuration/backup.dart => modules/backup_restore/widgets/backup_tile.dart} (95%) rename lib/modules/settings/{widgets/general/configuration/restore.dart => modules/backup_restore/widgets/restore_tile.dart} (97%) create mode 100644 lib/modules/settings/modules/customization.dart create mode 100644 lib/modules/settings/modules/customization/route.dart create mode 100644 lib/modules/settings/modules/customization/widgets.dart rename lib/modules/settings/{widgets/modules/lunasea/other_browser_tile.dart => modules/customization/widgets/browser_tile.dart} (93%) create mode 100644 lib/modules/settings/modules/customization_appearance.dart create mode 100644 lib/modules/settings/modules/customization_appearance/route.dart create mode 100644 lib/modules/settings/modules/customization_appearance/widgets.dart rename lib/modules/settings/{widgets/modules/lunasea/appearance_amoled_border_tile.dart => modules/customization_appearance/widgets/amoled_border_tile.dart} (89%) rename lib/modules/settings/{widgets/modules/lunasea/appearance_amoled_tile.dart => modules/customization_appearance/widgets/amoled_tile.dart} (90%) rename lib/modules/settings/{widgets/modules/lunasea => modules/customization_appearance/widgets}/use_24h_time.dart (90%) create mode 100644 lib/modules/settings/modules/customization_calendar.dart create mode 100644 lib/modules/settings/modules/customization_calendar/route.dart create mode 100644 lib/modules/settings/modules/customization_calendar/widgets.dart rename lib/modules/settings/{widgets/modules/home/enable_lidarr.dart => modules/customization_calendar/widgets/enable_lidarr_tile.dart} (76%) rename lib/modules/settings/{widgets/modules/home/enable_radarr.dart => modules/customization_calendar/widgets/enable_radarr_tile.dart} (76%) rename lib/modules/settings/{widgets/modules/home/enable_sonarr.dart => modules/customization_calendar/widgets/enable_sonarr_tile.dart} (76%) rename lib/modules/settings/{widgets/modules/home => modules/customization_calendar/widgets}/start_date_tile.dart (92%) rename lib/modules/settings/{widgets/modules/home => modules/customization_calendar/widgets}/start_size_tile.dart (92%) rename lib/modules/settings/{widgets/modules/home => modules/customization_calendar/widgets}/start_type_tile.dart (92%) create mode 100644 lib/modules/settings/modules/customization_drawer.dart create mode 100644 lib/modules/settings/modules/customization_drawer/route.dart create mode 100644 lib/modules/settings/modules/customization_drawer/widgets.dart rename lib/modules/settings/{widgets/modules/lunasea/drawer_expand_automation_tile.dart => modules/customization_drawer/widgets/expand_automation_tile.dart} (90%) rename lib/modules/settings/{widgets/modules/lunasea/drawer_expand_clients_tile.dart => modules/customization_drawer/widgets/expand_clients_tile.dart} (90%) rename lib/modules/settings/{widgets/modules/lunasea/drawer_expand_monitoring_tile.dart => modules/customization_drawer/widgets/expand_monitoring_tile.dart} (90%) create mode 100644 lib/modules/settings/modules/customization_home.dart create mode 100644 lib/modules/settings/modules/customization_home/route.dart create mode 100644 lib/modules/settings/modules/customization_home/widgets.dart rename lib/modules/settings/{widgets/modules/home/module_brand_colours.dart => modules/customization_home/widgets/brand_colours_tile.dart} (90%) rename lib/modules/settings/{widgets/modules/home/default_page.dart => modules/customization_home/widgets/default_page_tile.dart} (70%) create mode 100644 lib/modules/settings/modules/customization_lidarr.dart create mode 100644 lib/modules/settings/modules/customization_lidarr/route.dart create mode 100644 lib/modules/settings/modules/customization_lidarr/widgets.dart create mode 100644 lib/modules/settings/modules/customization_lidarr/widgets/default_page_tile.dart create mode 100644 lib/modules/settings/modules/customization_nzbget.dart create mode 100644 lib/modules/settings/modules/customization_nzbget/route.dart create mode 100644 lib/modules/settings/modules/customization_nzbget/widgets.dart create mode 100644 lib/modules/settings/modules/customization_nzbget/widgets/default_page_tile.dart create mode 100644 lib/modules/settings/modules/customization_quickactions.dart create mode 100644 lib/modules/settings/modules/customization_quickactions/route.dart create mode 100644 lib/modules/settings/modules/customization_quickactions/widgets.dart create mode 100644 lib/modules/settings/modules/customization_quickactions/widgets/action_tile.dart create mode 100644 lib/modules/settings/modules/customization_radarr.dart create mode 100644 lib/modules/settings/modules/customization_radarr/route.dart create mode 100644 lib/modules/settings/modules/customization_radarr/widgets.dart create mode 100644 lib/modules/settings/modules/customization_radarr/widgets/default_page_tile.dart create mode 100644 lib/modules/settings/modules/customization_sabnzbd.dart create mode 100644 lib/modules/settings/modules/customization_sabnzbd/route.dart create mode 100644 lib/modules/settings/modules/customization_sabnzbd/widgets.dart create mode 100644 lib/modules/settings/modules/customization_sabnzbd/widgets/default_page_tile.dart create mode 100644 lib/modules/settings/modules/customization_search.dart create mode 100644 lib/modules/settings/modules/customization_search/route.dart create mode 100644 lib/modules/settings/modules/customization_search/widgets.dart create mode 100644 lib/modules/settings/modules/customization_search/widgets/hide_adult_categories_tile.dart create mode 100644 lib/modules/settings/modules/customization_sonarr.dart create mode 100644 lib/modules/settings/modules/customization_sonarr/route.dart create mode 100644 lib/modules/settings/modules/customization_sonarr/widgets.dart create mode 100644 lib/modules/settings/modules/customization_sonarr/widgets/default_page_tile.dart create mode 100644 lib/modules/settings/modules/customization_tautulli.dart create mode 100644 lib/modules/settings/modules/customization_tautulli/route.dart create mode 100644 lib/modules/settings/modules/customization_tautulli/widgets.dart create mode 100644 lib/modules/settings/modules/customization_tautulli/widgets/default_page_tile.dart create mode 100644 lib/modules/settings/modules/donations.dart create mode 100644 lib/modules/settings/modules/donations/route.dart create mode 100644 lib/modules/settings/modules/donations/widgets.dart create mode 100644 lib/modules/settings/modules/donations/widgets/iap_tile.dart create mode 100644 lib/modules/settings/modules/donations_thankyou.dart create mode 100644 lib/modules/settings/modules/donations_thankyou/route.dart create mode 100644 lib/modules/settings/modules/logs.dart create mode 100644 lib/modules/settings/modules/logs/route.dart create mode 100644 lib/modules/settings/modules/logs/widgets.dart rename lib/modules/settings/{widgets/general/logs => modules/logs/widgets}/clear_tile.dart (87%) rename lib/modules/settings/{widgets/general/logs => modules/logs/widgets}/export_tile.dart (87%) create mode 100644 lib/modules/settings/modules/logs_details.dart create mode 100644 lib/modules/settings/modules/logs_details/route.dart create mode 100644 lib/modules/settings/modules/logs_details/widgets.dart create mode 100644 lib/modules/settings/modules/logs_details/widgets/log_tile.dart create mode 100644 lib/modules/settings/modules/modules.dart create mode 100644 lib/modules/settings/modules/modules/route.dart create mode 100644 lib/modules/settings/modules/modules/widgets.dart create mode 100644 lib/modules/settings/modules/modules/widgets/enabled_profile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/route.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets/apikey_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets/custom_headers_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets/host_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets/strict_tls_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr/widgets/test_connection_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr_headers.dart create mode 100644 lib/modules/settings/modules/modules_lidarr_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_lidarr_headers/widgets.dart create mode 100644 lib/modules/settings/modules/modules_lidarr_headers/widgets/add_header_tile.dart create mode 100644 lib/modules/settings/modules/modules_lidarr_headers/widgets/header_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/route.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/custom_headers_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/host_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/password_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/strict_tls_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/test_connection_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget/widgets/username_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget_headers.dart create mode 100644 lib/modules/settings/modules/modules_nzbget_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_nzbget_headers/widgets.dart create mode 100644 lib/modules/settings/modules/modules_nzbget_headers/widgets/add_header_tile.dart create mode 100644 lib/modules/settings/modules/modules_nzbget_headers/widgets/header_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr.dart create mode 100644 lib/modules/settings/modules/modules_radarr/route.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets/apikey_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets/custom_headers_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets/host_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets/strict_tls_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr/widgets/test_connection_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr_headers.dart create mode 100644 lib/modules/settings/modules/modules_radarr_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_radarr_headers/widgets.dart create mode 100644 lib/modules/settings/modules/modules_radarr_headers/widgets/add_header_tile.dart create mode 100644 lib/modules/settings/modules/modules_radarr_headers/widgets/header_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/route.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets/apikey_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets/custom_headers_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets/host_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets/strict_tls_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd/widgets/test_connection_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd_headers.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd_headers/widgets.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd_headers/widgets/add_header_tile.dart create mode 100644 lib/modules/settings/modules/modules_sabnzbd_headers/widgets/header_tile.dart create mode 100644 lib/modules/settings/modules/modules_search.dart create mode 100644 lib/modules/settings/modules/modules_search/route.dart create mode 100644 lib/modules/settings/modules/modules_search/widgets.dart create mode 100644 lib/modules/settings/modules/modules_search/widgets/indexer_tile.dart create mode 100644 lib/modules/settings/modules/modules_search_add.dart create mode 100644 lib/modules/settings/modules/modules_search_add/route.dart create mode 100644 lib/modules/settings/modules/modules_search_edit.dart create mode 100644 lib/modules/settings/modules/modules_search_edit/route.dart create mode 100644 lib/modules/settings/modules/modules_search_headers.dart create mode 100644 lib/modules/settings/modules/modules_search_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_sonarr.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/route.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets/apikey_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets/custom_headers_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets/host_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets/strict_tls_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr/widgets/test_connection_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr_headers.dart create mode 100644 lib/modules/settings/modules/modules_sonarr_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_sonarr_headers/widgets.dart create mode 100644 lib/modules/settings/modules/modules_sonarr_headers/widgets/add_header_tile.dart create mode 100644 lib/modules/settings/modules/modules_sonarr_headers/widgets/header_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/route.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets/apikey_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets/custom_headers_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets/host_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets/strict_tls_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli/widgets/test_connection_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli_headers.dart create mode 100644 lib/modules/settings/modules/modules_tautulli_headers/route.dart create mode 100644 lib/modules/settings/modules/modules_tautulli_headers/widgets.dart create mode 100644 lib/modules/settings/modules/modules_tautulli_headers/widgets/add_header_tile.dart create mode 100644 lib/modules/settings/modules/modules_tautulli_headers/widgets/header_tile.dart create mode 100644 lib/modules/settings/modules/modules_wakeonlan.dart create mode 100644 lib/modules/settings/modules/modules_wakeonlan/route.dart create mode 100644 lib/modules/settings/modules/modules_wakeonlan/widgets.dart create mode 100644 lib/modules/settings/modules/modules_wakeonlan/widgets/broadcast_address_tile.dart create mode 100644 lib/modules/settings/modules/modules_wakeonlan/widgets/enabled_tile.dart create mode 100644 lib/modules/settings/modules/modules_wakeonlan/widgets/mac_address_tile.dart create mode 100644 lib/modules/settings/modules/profiles.dart create mode 100644 lib/modules/settings/modules/profiles/route.dart create mode 100644 lib/modules/settings/modules/profiles/widgets.dart rename lib/modules/settings/{widgets/general/profile => modules/profiles/widgets}/add_tile.dart (95%) rename lib/modules/settings/{widgets/general/profile => modules/profiles/widgets}/delete_tile.dart (94%) rename lib/modules/settings/{widgets/general/profile => modules/profiles/widgets}/enabled_tile.dart (77%) rename lib/modules/settings/{widgets/general/profile => modules/profiles/widgets}/rename_tile.dart (96%) create mode 100644 lib/modules/settings/modules/resources.dart create mode 100644 lib/modules/settings/modules/resources/route.dart create mode 100644 lib/modules/settings/modules/settings.dart create mode 100644 lib/modules/settings/modules/settings/route.dart create mode 100644 lib/modules/settings/modules/system.dart create mode 100644 lib/modules/settings/modules/system/route.dart create mode 100644 lib/modules/settings/modules/system/widgets.dart rename lib/modules/settings/{widgets/system => modules/system/widgets}/clear_configuration_tile.dart (100%) rename lib/modules/settings/{widgets/system => modules/system/widgets}/clear_image_cache_tile.dart (100%) create mode 100644 lib/modules/settings/modules/system/widgets/licenses_tile.dart rename lib/modules/settings/{widgets/system/enable_sentry.dart => modules/system/widgets/sentry_tile.dart} (93%) create mode 100644 lib/modules/settings/modules/system/widgets/version_tile.dart delete mode 100644 lib/modules/settings/routes.dart delete mode 100644 lib/modules/settings/routes/general.dart delete mode 100644 lib/modules/settings/routes/logs/logs_details.dart delete mode 100644 lib/modules/settings/routes/logs/logs_types.dart delete mode 100644 lib/modules/settings/routes/logs/logs_view.dart delete mode 100644 lib/modules/settings/routes/modules.dart delete mode 100644 lib/modules/settings/routes/modules/automation_lidarr.dart delete mode 100644 lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr.dart delete mode 100644 lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr_headers.dart delete mode 100644 lib/modules/settings/routes/modules/automation_radarr.dart delete mode 100644 lib/modules/settings/routes/modules/automation_radarr/automation_radarr.dart delete mode 100644 lib/modules/settings/routes/modules/automation_radarr/automation_radarr_headers.dart delete mode 100644 lib/modules/settings/routes/modules/automation_sonarr.dart delete mode 100644 lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr.dart delete mode 100644 lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr_headers.dart delete mode 100644 lib/modules/settings/routes/modules/clients_nzbget.dart delete mode 100644 lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget.dart delete mode 100644 lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget_headers.dart delete mode 100644 lib/modules/settings/routes/modules/clients_sabnzbd.dart delete mode 100644 lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd.dart delete mode 100644 lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd_headers.dart delete mode 100644 lib/modules/settings/routes/modules/general_home.dart delete mode 100644 lib/modules/settings/routes/modules/general_lunasea.dart delete mode 100644 lib/modules/settings/routes/modules/general_lunasea/general_lunasea.dart delete mode 100644 lib/modules/settings/routes/modules/general_lunasea/general_lunasea_quick_actions.dart delete mode 100644 lib/modules/settings/routes/modules/general_search.dart delete mode 100644 lib/modules/settings/routes/modules/general_search_add.dart delete mode 100644 lib/modules/settings/routes/modules/general_search_edit.dart delete mode 100644 lib/modules/settings/routes/modules/general_wake_on_lan.dart delete mode 100644 lib/modules/settings/routes/modules/monitoring_tautulli.dart delete mode 100644 lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli.dart delete mode 100644 lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli_headers.dart delete mode 100644 lib/modules/settings/routes/settings.dart delete mode 100644 lib/modules/settings/routes/system.dart delete mode 100644 lib/modules/settings/routes/system/resources_donations.dart delete mode 100644 lib/modules/settings/routes/system/resources_donations_thankyou.dart delete mode 100644 lib/modules/settings/widgets.dart delete mode 100644 lib/modules/settings/widgets/general.dart delete mode 100644 lib/modules/settings/widgets/general/configuration.dart delete mode 100644 lib/modules/settings/widgets/general/logs.dart delete mode 100644 lib/modules/settings/widgets/general/logs/view_tile.dart delete mode 100644 lib/modules/settings/widgets/general/profile.dart delete mode 100644 lib/modules/settings/widgets/modules.dart delete mode 100644 lib/modules/settings/widgets/modules/home.dart delete mode 100644 lib/modules/settings/widgets/modules/lunasea.dart delete mode 100644 lib/modules/settings/widgets/modules/lunasea/quick_actions_tile.dart delete mode 100644 lib/modules/settings/widgets/navigation_bar.dart delete mode 100644 lib/modules/settings/widgets/system.dart diff --git a/lib/core.dart b/lib/core.dart index 230e58f4..b8c0388d 100644 --- a/lib/core.dart +++ b/lib/core.dart @@ -6,7 +6,6 @@ export 'core/extensions.dart'; export 'core/homescreen_actions.dart'; export 'core/in_app_purchases.dart'; export 'core/logger.dart'; -export 'core/module_flags.dart'; export 'core/module_map.dart'; export 'core/providers.dart'; export 'core/routes.dart'; diff --git a/lib/core/constants.dart b/lib/core/constants.dart index ee6ecf8d..b3deb4fa 100644 --- a/lib/core/constants.dart +++ b/lib/core/constants.dart @@ -74,7 +74,7 @@ class Constants { static const URL_REDDIT = 'https://www.reddit.com/r/LunaSeaApp'; static const URL_WEBSITE = 'https://www.lunasea.app'; static const URL_FEEDBACK = 'https://feedback.lunasea.app'; - static const URL_LICENSES = 'https://github.com/LunaSeaApp/LunaSea/wiki/Licenses'; + static const URL_LICENSES = 'https://docs.lunasea.app/other-resources/licenses'; static const URL_CHANGELOG = 'https://docs.lunasea.app/development/changelog'; static const URL_DISCORD = 'https://discord.com/invite/8MH2N3h'; static const URL_SENTRY = 'https://sentry.io'; diff --git a/lib/core/database/adapters/profile.dart b/lib/core/database/adapters/profile.dart index 836f4d9d..1e8d0f4d 100644 --- a/lib/core/database/adapters/profile.dart +++ b/lib/core/database/adapters/profile.dart @@ -348,27 +348,27 @@ class ProfileHiveObject extends HiveObject { }; List get enabledModules => [ - if(ModuleFlags.AUTOMATION && ModuleFlags.LIDARR && (lidarrEnabled ?? false)) 'lidarr', - if(ModuleFlags.AUTOMATION && ModuleFlags.RADARR && (radarrEnabled ?? false)) 'radarr', - if(ModuleFlags.AUTOMATION && ModuleFlags.SONARR && (sonarrEnabled ?? false)) 'sonarr', - if(ModuleFlags.CLIENTS && ModuleFlags.NZBGET && (nzbgetEnabled ?? false)) 'nzbget', - if(ModuleFlags.CLIENTS && ModuleFlags.SABNZBD && (sabnzbdEnabled ?? false)) 'sabnzbd', - if(ModuleFlags.MONITORING && ModuleFlags.TAUTULLI && (tautulliEnabled ?? false)) 'tautulli', + if(lidarrEnabled ?? false) 'lidarr', + if(radarrEnabled ?? false) 'radarr', + if(sonarrEnabled ?? false) 'sonarr', + if(nzbgetEnabled ?? false) 'nzbget', + if(sabnzbdEnabled ?? false) 'sabnzbd', + if(tautulliEnabled ?? false) 'tautulli', ]; List get enabledAutomationModules => [ - if(ModuleFlags.AUTOMATION && ModuleFlags.LIDARR && (lidarrEnabled ?? false)) 'lidarr', - if(ModuleFlags.AUTOMATION && ModuleFlags.RADARR && (radarrEnabled ?? false)) 'radarr', - if(ModuleFlags.AUTOMATION && ModuleFlags.SONARR && (sonarrEnabled ?? false)) 'sonarr', + if(lidarrEnabled ?? false) 'lidarr', + if(radarrEnabled ?? false) 'radarr', + if(sonarrEnabled ?? false) 'sonarr', ]; List get enabledClientModules => [ - if(ModuleFlags.CLIENTS && ModuleFlags.NZBGET && (nzbgetEnabled ?? false)) 'nzbget', - if(ModuleFlags.CLIENTS && ModuleFlags.SABNZBD && (sabnzbdEnabled ?? false)) 'sabnzbd', + if(nzbgetEnabled ?? false) 'nzbget', + if(sabnzbdEnabled ?? false) 'sabnzbd', ]; List get enabledMonitoringModules => [ - if(ModuleFlags.MONITORING && ModuleFlags.TAUTULLI && (tautulliEnabled ?? false)) 'tautulli', + if(tautulliEnabled ?? false) 'tautulli', ]; bool get anyAutomationEnabled => enabledAutomationModules.isNotEmpty; diff --git a/lib/core/module_flags.dart b/lib/core/module_flags.dart deleted file mode 100644 index 41f7c0cc..00000000 --- a/lib/core/module_flags.dart +++ /dev/null @@ -1,18 +0,0 @@ -class ModuleFlags { - ModuleFlags._(); - //General - static const SEARCH = true; - static const WAKE_ON_LAN = true; - //Automation - static const AUTOMATION = true; - static const LIDARR = true; - static const RADARR = true; - static const SONARR = true; - //Clients - static const CLIENTS = true; - static const SABNZBD = true; - static const NZBGET = true; - //Monitoring - static const MONITORING = true; - static const TAUTULLI = true; -} diff --git a/lib/core/providers.dart b/lib/core/providers.dart index cb1e7551..e5c6ae8d 100644 --- a/lib/core/providers.dart +++ b/lib/core/providers.dart @@ -11,7 +11,7 @@ import 'package:lunasea/modules.dart' show RadarrState, SABnzbdModel, SearchModel, - SettingsModel, + SettingsState, SonarrModel, TautulliState; @@ -19,11 +19,12 @@ class Providers { Providers._(); static void reset(BuildContext context) { - Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(initialize: true); // General - Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(initialize: true); + Provider.of(context, listen: false).reset(initialize: true); // Monitoring - Provider.of(context, listen: false).reset(); + Provider.of(context, listen: false).reset(initialize: true); } static MultiProvider providers({ @required Widget child }) => MultiProvider( @@ -32,7 +33,7 @@ class Providers { // General ChangeNotifierProvider(create: (_) => HomeState()), ChangeNotifierProvider(create: (_) => SearchModel()), - ChangeNotifierProvider(create: (_) => SettingsModel()), + ChangeNotifierProvider(create: (_) => SettingsState()), // Automation ChangeNotifierProvider(create: (_) => SonarrModel()), ChangeNotifierProvider(create: (_) => LidarrModel()), diff --git a/lib/core/routes.dart b/lib/core/routes.dart index 9bd87cb4..3a3c7631 100644 --- a/lib/core/routes.dart +++ b/lib/core/routes.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; import 'package:lunasea/modules/home/routes.dart'; -import 'package:lunasea/modules/settings/routes.dart'; +import 'package:lunasea/modules/settings.dart' show SettingsConstants; import 'package:lunasea/modules/search/routes.dart'; import 'package:lunasea/modules/lidarr/routes.dart'; import 'package:lunasea/modules/radarr/routes.dart'; @@ -15,7 +15,7 @@ class Routes { static Map getRoutes() { return { ..._home, - ..._settings, + ...SettingsConstants.MODULE_ROUTES, ..._search, ..._lidarr, ..._radarr, @@ -34,48 +34,6 @@ class Routes { HomeQuickAccess.ROUTE_NAME: (context) => HomeQuickAccess(), }; - static Map get _settings => { - // /settings - Settings.ROUTE_NAME: (context) => Settings(), - // /settings/* - SettingsGeneral.ROUTE_NAME: (context) => SettingsGeneral(), - SettingsSystem.ROUTE_NAME: (context) => SettingsSystem(), - SettingsModules.ROUTE_NAME: (context) => SettingsModules(), - // /settings/modules/* - // Automation - SettingsModulesLidarr.ROUTE_NAME: (context) => SettingsModulesLidarr(), - SettingsModulesLidarrHeaders.ROUTE_NAME: (context) => SettingsModulesLidarrHeaders(), - SettingsModulesRadarr.ROUTE_NAME: (context) => SettingsModulesRadarr(), - SettingsModulesRadarrHeaders.ROUTE_NAME: (context) => SettingsModulesRadarrHeaders(), - SettingsModulesSonarr.ROUTE_NAME: (context) => SettingsModulesSonarr(), - SettingsModulesSonarrHeaders.ROUTE_NAME: (context) => SettingsModulesSonarrHeaders(), - // Clients - SettingsModulesNZBGet.ROUTE_NAME: (context) => SettingsModulesNZBGet(), - SettingsModulesNZBGetHeaders.ROUTE_NAME: (context) => SettingsModulesNZBGetHeaders(), - SettingsModulesSABnzbd.ROUTE_NAME: (context) => SettingsModulesSABnzbd(), - SettingsModulesSABnzbdHeaders.ROUTE_NAME: (context) => SettingsModulesSABnzbdHeaders(), - // Monitoring - SettingsModulesTautulli.ROUTE_NAME: (context) => SettingsModulesTautulli(), - SettingsModulesTautulliHeaders.ROUTE_NAME: (context) => SettingsModulesTautulliHeaders(), - // General - SettingsModulesHome.ROUTE_NAME: (context) => SettingsModulesHome(), - SettingsModulesLunaSea.ROUTE_NAME: (context) => SettingsModulesLunaSea(), - SettingsModulesSearch.ROUTE_NAME: (context) => SettingsModulesSearch(), - SettingsModulesWakeOnLAN.ROUTE_NAME: (context) => SettingsModulesWakeOnLAN(), - // /settings/modules/lunasea/* - SettingsModulesLunaSeaQuickActions.ROUTE_NAME: (context) => SettingsModulesLunaSeaQuickActions(), - // /settings/modules/indexers/* - SettingsModulesSearchAdd.ROUTE_NAME: (context) => SettingsModulesSearchAdd(), - SettingsModulesSearchEdit.ROUTE_NAME: (context) => SettingsModulesSearchEdit(), - // /settings/general/logs/* - SettingsGeneralLogsTypes.ROUTE_NAME: (context) => SettingsGeneralLogsTypes(), - SettingsGeneralLogsView.ROUTE_NAME: (context) => SettingsGeneralLogsView(), - SettingsGeneralLogsDetails.ROUTE_NAME: (context) => SettingsGeneralLogsDetails(), - // /settings/system/* - SettingsSystemDonations.ROUTE_NAME: (context) => SettingsSystemDonations(), - SettingsSystemDonationsThankYou.ROUTE_NAME: (context) => SettingsSystemDonationsThankYou(), - }; - static Map get _search => { // /search Search.ROUTE_NAME: (context) => Search(), diff --git a/lib/core/ui/navigation/appbar_dropdown.dart b/lib/core/ui/navigation/appbar_dropdown.dart index 87165335..e890feab 100644 --- a/lib/core/ui/navigation/appbar_dropdown.dart +++ b/lib/core/ui/navigation/appbar_dropdown.dart @@ -31,6 +31,12 @@ Widget LSAppBarDropdown({ onSelected: (result) { LunaSeaDatabaseValue.ENABLED_PROFILE.put(result); Providers.reset(context); + LSSnackBar( + context: context, + title: 'Changed Profile', + message: 'Using profile "$result"', + type: SNACKBAR_TYPE.info, + ); }, itemBuilder: (context) { return >[for(String profile in profiles) PopupMenuItem( diff --git a/lib/core/ui/navigation/drawer.dart b/lib/core/ui/navigation/drawer.dart index d50af2ad..57ab2975 100644 --- a/lib/core/ui/navigation/drawer.dart +++ b/lib/core/ui/navigation/drawer.dart @@ -19,7 +19,7 @@ class LSDrawer extends StatelessWidget { ProfileHiveObject profile = Database.profilesBox.get(lunaBox.get(LunaSeaDatabaseValue.ENABLED_PROFILE.key)); return Drawer( child: ListView( - children: _getDrawerEntries(context, profile, (ModuleFlags.SEARCH && (indexerBox as Box).length > 0)), + children: _getDrawerEntries(context, profile, (indexerBox as Box).length > 0), padding: EdgeInsets.fromLTRB(0.0, 0.0, 0.0, 8.0), physics: ClampingScrollPhysics(), ), @@ -56,6 +56,12 @@ class LSDrawer extends StatelessWidget { onSelected: (result) { LunaSeaDatabaseValue.ENABLED_PROFILE.put(result); Providers.reset(context); + LSSnackBar( + context: context, + title: 'Changed Profile', + message: 'Using profile "$result"', + type: SNACKBAR_TYPE.info, + ); }, itemBuilder: (context) { return >[for(String profile in (profilesBox as Box).keys) PopupMenuItem( @@ -106,8 +112,8 @@ class LSDrawer extends StatelessWidget { title: 'Search', route: '/search', ), - if(ModuleFlags.WAKE_ON_LAN && profile.getWakeOnLAN()['enabled']) _buildWakeOnLAN(context: context), - if(ModuleFlags.AUTOMATION && profile.anyAutomationEnabled) ExpansionTile( + if(profile.getWakeOnLAN()['enabled']) _buildWakeOnLAN(context: context), + if(profile.anyAutomationEnabled) ExpansionTile( leading: Icon(CustomIcons.layers), title: Text( 'Automation', @@ -127,7 +133,7 @@ class LSDrawer extends StatelessWidget { ), ), ), - if(ModuleFlags.CLIENTS && profile.anyClientsEnabled) ExpansionTile( + if(profile.anyClientsEnabled) ExpansionTile( leading: Icon(CustomIcons.clients), title: Text( 'Clients', @@ -147,7 +153,7 @@ class LSDrawer extends StatelessWidget { ), ), ), - if(ModuleFlags.MONITORING && profile.anyMonitoringEnabled) ExpansionTile( + if(profile.anyMonitoringEnabled) ExpansionTile( leading: Icon(CustomIcons.monitoring), title: Text( 'Monitoring', diff --git a/lib/modules/home/core/api/api.dart b/lib/modules/home/core/api/api.dart index f328d79e..933b5488 100644 --- a/lib/modules/home/core/api/api.dart +++ b/lib/modules/home/core/api/api.dart @@ -48,20 +48,14 @@ class CalendarAPI extends API { Future> getUpcoming(DateTime today) async { Map _upcoming = {}; if( - ModuleFlags.AUTOMATION && - ModuleFlags.LIDARR && lidarr['enabled'] && HomeDatabaseValue.CALENDAR_ENABLE_LIDARR.data ) await _getLidarrUpcoming(_upcoming, today); if( - ModuleFlags.AUTOMATION && - ModuleFlags.RADARR && radarr['enabled'] && HomeDatabaseValue.CALENDAR_ENABLE_RADARR.data ) await _getRadarrUpcoming(_upcoming, today); if( - ModuleFlags.AUTOMATION && - ModuleFlags.SONARR && sonarr['enabled'] && HomeDatabaseValue.CALENDAR_ENABLE_SONARR.data ) await _getSonarrUpcoming(_upcoming, today); diff --git a/lib/modules/home/routes/quick_access.dart b/lib/modules/home/routes/quick_access.dart index d0e1202f..f89f330e 100644 --- a/lib/modules/home/routes/quick_access.dart +++ b/lib/modules/home/routes/quick_access.dart @@ -27,7 +27,7 @@ class _State extends State with AutomaticKeepAliveClientMixin { } Widget get _body { - bool _hasIndexers = ModuleFlags.SEARCH && Database.indexersBox.length > 0; + bool _hasIndexers = Database.indexersBox.length > 0; int _serviceCount = widget.profile.enabledModules.length + (_hasIndexers ? 2 : 1); return LSListViewBuilder( itemCount: _serviceCount, diff --git a/lib/modules/search/core/api/api.dart b/lib/modules/search/core/api/api.dart index 2da44e11..005bcb1c 100644 --- a/lib/modules/search/core/api/api.dart +++ b/lib/modules/search/core/api/api.dart @@ -9,23 +9,27 @@ class NewznabAPI extends API { final Dio _dio; NewznabAPI._internal(this._values, this._dio); - factory NewznabAPI.from(IndexerHiveObject indexer) => NewznabAPI._internal( - indexer.toMap(), - Dio( - BaseOptions( - method: 'GET', - baseUrl: '${indexer.host}/api', - headers: { - 'User-Agent': Constants.USER_AGENT, - }, - queryParameters: { - if(indexer.key != '') 'apikey': indexer.key, - }, - followRedirects: true, - maxRedirects: 5, + factory NewznabAPI.from(IndexerHiveObject indexer) { + Map _headers = (indexer.headers ?? {}).cast(); + return NewznabAPI._internal( + indexer.toMap(), + Dio( + BaseOptions( + method: 'GET', + baseUrl: '${indexer.host}/api', + headers: { + 'User-Agent': Constants.USER_AGENT, + ..._headers, + }, + queryParameters: { + if(indexer.key != '') 'apikey': indexer.key, + }, + followRedirects: true, + maxRedirects: 5, + ), ), - ), - ); + ); + } String get displayName => _values['displayName']; String get host => _values['host']; diff --git a/lib/modules/settings.dart b/lib/modules/settings.dart index f22c413c..217d5e0b 100644 --- a/lib/modules/settings.dart +++ b/lib/modules/settings.dart @@ -1,3 +1,2 @@ export 'settings/core.dart'; -export 'settings/routes.dart'; -export 'settings/widgets.dart'; +export 'settings/modules.dart'; diff --git a/lib/modules/settings/core.dart b/lib/modules/settings/core.dart index e1155fe7..b81844a3 100644 --- a/lib/modules/settings/core.dart +++ b/lib/modules/settings/core.dart @@ -1,5 +1,4 @@ -export 'core/api.dart'; export 'core/constants.dart'; export 'core/database.dart'; export 'core/dialogs.dart'; -export 'core/state_global.dart'; +export 'core/state.dart'; diff --git a/lib/modules/settings/core/api.dart b/lib/modules/settings/core/api.dart deleted file mode 100644 index db421ba0..00000000 --- a/lib/modules/settings/core/api.dart +++ /dev/null @@ -1,3 +0,0 @@ -class SettingsAPI { - SettingsAPI._(); -} diff --git a/lib/modules/settings/core/constants.dart b/lib/modules/settings/core/constants.dart index 89e21217..d9d32015 100644 --- a/lib/modules/settings/core/constants.dart +++ b/lib/modules/settings/core/constants.dart @@ -1,5 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; +import 'package:lunasea/modules/settings/modules/donations_thankyou/route.dart'; class SettingsConstants { SettingsConstants._(); @@ -14,4 +16,64 @@ class SettingsConstants { route: '/settings', color: Color(Constants.ACCENT_COLOR), ); + + // ignore: non_constant_identifier_names + static final Map MODULE_ROUTES = { + SettingsRoute.ROUTE_NAME: (context) => SettingsRoute(), + // Customization + SettingsCustomizationRoute.ROUTE_NAME: (context) => SettingsCustomizationRoute(), + SettingsCustomizationAppearanceRoute.ROUTE_NAME: (context) => SettingsCustomizationAppearanceRoute(), + SettingsCustomizationCalendarRoute.ROUTE_NAME: (context) => SettingsCustomizationCalendarRoute(), + SettingsCustomizationDrawerRoute.ROUTE_NAME: (context) => SettingsCustomizationDrawerRoute(), + SettingsCustomizationHomeRoute.ROUTE_NAME: (context) => SettingsCustomizationHomeRoute(), + SettingsCustomizationLidarrRoute.ROUTE_NAME: (context) => SettingsCustomizationLidarrRoute(), + SettingsCustomizationNZBGetRoute.ROUTE_NAME: (context) => SettingsCustomizationNZBGetRoute(), + SettingsCustomizationQuickActionsRoute.ROUTE_NAME: (context) => SettingsCustomizationQuickActionsRoute(), + SettingsCustomizationRadarrRoute.ROUTE_NAME: (context) => SettingsCustomizationRadarrRoute(), + SettingsCustomizationSABnzbdRoute.ROUTE_NAME: (context) => SettingsCustomizationSABnzbdRoute(), + SettingsCustomizationSearchRoute.ROUTE_NAME: (context) => SettingsCustomizationSearchRoute(), + SettingsCustomizationSonarrRoute.ROUTE_NAME: (context) => SettingsCustomizationSonarrRoute(), + SettingsCustomizationTautulliRoute.ROUTE_NAME: (context) => SettingsCustomizationTautulliRoute(), + // Modules + SettingsModulesRoute.ROUTE_NAME: (context) => SettingsModulesRoute(), + // modules/Search + SettingsModulesSearchRoute.ROUTE_NAME: (context) => SettingsModulesSearchRoute(), + SettingsModulesSearchAddRoute.ROUTE_NAME: (context) => SettingsModulesSearchAddRoute(), + SettingsModulesSearchEditRoute.ROUTE_NAME: (context) => SettingsModulesSearchEditRoute(), + SettingsModulesSearchHeadersRoute.ROUTE_NAME: (context) => SettingsModulesSearchHeadersRoute(), + // modules/Wake on LAN + SettingsModulesWakeOnLANRoute.ROUTE_NAME: (context) => SettingsModulesWakeOnLANRoute(), + // modules/Lidarr + SettingsModulesLidarrRoute.ROUTE_NAME: (context) => SettingsModulesLidarrRoute(), + SettingsModulesLidarrHeadersRoute.ROUTE_NAME: (context) => SettingsModulesLidarrHeadersRoute(), + // modules/Radarr + SettingsModulesRadarrRoute.ROUTE_NAME: (context) => SettingsModulesRadarrRoute(), + SettingsModulesRadarrHeadersRoute.ROUTE_NAME: (context) => SettingsModulesRadarrHeadersRoute(), + // modules/Sonarr + SettingsModulesSonarrRoute.ROUTE_NAME: (context) => SettingsModulesSonarrRoute(), + SettingsModulesSonarrHeadersRoute.ROUTE_NAME: (context) => SettingsModulesSonarrHeadersRoute(), + // modules/NZBGet + SettingsModulesNZBGetRoute.ROUTE_NAME: (context) => SettingsModulesNZBGetRoute(), + SettingsModulesNZBGetHeadersRoute.ROUTE_NAME: (context) => SettingsModulesNZBGetHeadersRoute(), + // modules/SABnzbd + SettingsModulesSABnzbdRoute.ROUTE_NAME: (context) => SettingsModulesSABnzbdRoute(), + SettingsModulesSABnzbdHeadersRoute.ROUTE_NAME: (context) => SettingsModulesSABnzbdHeadersRoute(), + // modules/Tautulli + SettingsModulesTautulliRoute.ROUTE_NAME: (context) => SettingsModulesTautulliRoute(), + SettingsModulesTautulliHeadersRoute.ROUTE_NAME: (context) => SettingsModulesTautulliHeadersRoute(), + // Profiles + SettingsProfilesRoute.ROUTE_NAME: (context) => SettingsProfilesRoute(), + // Backup & Restore + SettingsBackupRestoreRoute.ROUTE_NAME: (context) => SettingsBackupRestoreRoute(), + // Donations + SettingsDonationsRoute.ROUTE_NAME: (context) => SettingsDonationsRoute(), + SettingsDonationsThankYouRoute.ROUTE_NAME: (context) => SettingsDonationsThankYouRoute(), + // Logs + SettingsLogsRoute.ROUTE_NAME: (context) => SettingsLogsRoute(), + SettingsLogsDetailsRoute.ROUTE_NAME: (context) => SettingsLogsDetailsRoute(), + // Resources + SettingsResourcesRoute.ROUTE_NAME: (context) => SettingsResourcesRoute(), + // System + SettingsSystemRoute.ROUTE_NAME: (context) => SettingsSystemRoute(), + }; } diff --git a/lib/modules/settings/core/state.dart b/lib/modules/settings/core/state.dart new file mode 100644 index 00000000..3dc4b1d2 --- /dev/null +++ b/lib/modules/settings/core/state.dart @@ -0,0 +1,25 @@ +import 'package:flutter/foundation.dart'; + +class SettingsState extends ChangeNotifier { + SettingsState() { + reset(initialize: true); + } + + /// Reset the state of Home back to the default + /// + /// If `initialize` is true, resets everything. + /// If false, the navigation index, etc. are not reset. + void reset({ bool initialize = false }) { + if(initialize) { + _navigationIndex = 0; + } + } + + int _navigationIndex; + int get navigationIndex => _navigationIndex; + set navigationIndex(int navigationIndex) { + assert(navigationIndex != null); + _navigationIndex = navigationIndex; + notifyListeners(); + } +} diff --git a/lib/modules/settings/core/state_global.dart b/lib/modules/settings/core/state_global.dart deleted file mode 100644 index 3fcbd333..00000000 --- a/lib/modules/settings/core/state_global.dart +++ /dev/null @@ -1,11 +0,0 @@ -import 'package:flutter/foundation.dart'; - -class SettingsModel extends ChangeNotifier { - int _navigationIndex = 0; - int get navigationIndex => _navigationIndex; - set navigationIndex(int navigationIndex) { - assert(navigationIndex != null); - _navigationIndex = navigationIndex; - notifyListeners(); - } -} diff --git a/lib/modules/settings/modules.dart b/lib/modules/settings/modules.dart new file mode 100644 index 00000000..7a463a22 --- /dev/null +++ b/lib/modules/settings/modules.dart @@ -0,0 +1,40 @@ +export 'modules/backup_restore.dart'; +export 'modules/customization.dart'; +export 'modules/customization_appearance.dart'; +export 'modules/customization_calendar.dart'; +export 'modules/customization_drawer.dart'; +export 'modules/customization_home.dart'; +export 'modules/customization_lidarr.dart'; +export 'modules/customization_nzbget.dart'; +export 'modules/customization_quickactions.dart'; +export 'modules/customization_radarr.dart'; +export 'modules/customization_sabnzbd.dart'; +export 'modules/customization_search.dart'; +export 'modules/customization_sonarr.dart'; +export 'modules/customization_tautulli.dart'; +export 'modules/donations.dart'; +export 'modules/donations_thankyou.dart'; +export 'modules/logs.dart'; +export 'modules/logs_details.dart'; +export 'modules/modules.dart'; +export 'modules/modules_lidarr.dart'; +export 'modules/modules_lidarr_headers.dart'; +export 'modules/modules_nzbget.dart'; +export 'modules/modules_nzbget_headers.dart'; +export 'modules/modules_radarr.dart'; +export 'modules/modules_radarr_headers.dart'; +export 'modules/modules_sabnzbd.dart'; +export 'modules/modules_sabnzbd_headers.dart'; +export 'modules/modules_search.dart'; +export 'modules/modules_search_add.dart'; +export 'modules/modules_search_edit.dart'; +export 'modules/modules_search_headers.dart'; +export 'modules/modules_sonarr.dart'; +export 'modules/modules_sonarr_headers.dart'; +export 'modules/modules_tautulli.dart'; +export 'modules/modules_tautulli_headers.dart'; +export 'modules/modules_wakeonlan.dart'; +export 'modules/profiles.dart'; +export 'modules/resources.dart'; +export 'modules/settings.dart'; +export 'modules/system.dart'; diff --git a/lib/modules/settings/modules/backup_restore.dart b/lib/modules/settings/modules/backup_restore.dart new file mode 100644 index 00000000..229b2e84 --- /dev/null +++ b/lib/modules/settings/modules/backup_restore.dart @@ -0,0 +1,2 @@ +export 'backup_restore/route.dart'; +export 'backup_restore/widgets.dart'; diff --git a/lib/modules/settings/modules/backup_restore/route.dart b/lib/modules/settings/modules/backup_restore/route.dart new file mode 100644 index 00000000..4a69c3a4 --- /dev/null +++ b/lib/modules/settings/modules/backup_restore/route.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsBackupRestoreRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/backup_restore'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Backup & Restore'); + + Widget get _body => LSListView( + children: [ + SettingsBackupRestoreBackupTile(), + SettingsBackupRestoreRestoreTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/backup_restore/widgets.dart b/lib/modules/settings/modules/backup_restore/widgets.dart new file mode 100644 index 00000000..0b5a672b --- /dev/null +++ b/lib/modules/settings/modules/backup_restore/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/backup_tile.dart'; +export 'widgets/restore_tile.dart'; diff --git a/lib/modules/settings/widgets/general/configuration/backup.dart b/lib/modules/settings/modules/backup_restore/widgets/backup_tile.dart similarity index 95% rename from lib/modules/settings/widgets/general/configuration/backup.dart rename to lib/modules/settings/modules/backup_restore/widgets/backup_tile.dart index cc68b480..1b3b479c 100644 --- a/lib/modules/settings/widgets/general/configuration/backup.dart +++ b/lib/modules/settings/modules/backup_restore/widgets/backup_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralConfigurationBackupTile extends StatelessWidget { +class SettingsBackupRestoreBackupTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( title: LSTitle(text: 'Backup'), diff --git a/lib/modules/settings/widgets/general/configuration/restore.dart b/lib/modules/settings/modules/backup_restore/widgets/restore_tile.dart similarity index 97% rename from lib/modules/settings/widgets/general/configuration/restore.dart rename to lib/modules/settings/modules/backup_restore/widgets/restore_tile.dart index f875fd63..2b63b859 100644 --- a/lib/modules/settings/widgets/general/configuration/restore.dart +++ b/lib/modules/settings/modules/backup_restore/widgets/restore_tile.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralConfigurationRestoreTile extends StatelessWidget { +class SettingsBackupRestoreRestoreTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( title: LSTitle(text: 'Restore'), diff --git a/lib/modules/settings/modules/customization.dart b/lib/modules/settings/modules/customization.dart new file mode 100644 index 00000000..c03149d7 --- /dev/null +++ b/lib/modules/settings/modules/customization.dart @@ -0,0 +1,2 @@ +export 'customization/route.dart'; +export 'customization/widgets.dart'; diff --git a/lib/modules/settings/modules/customization/route.dart b/lib/modules/settings/modules/customization/route.dart new file mode 100644 index 00000000..0bea7ef1 --- /dev/null +++ b/lib/modules/settings/modules/customization/route.dart @@ -0,0 +1,125 @@ +import 'dart:io'; + +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization'; + + SettingsCustomizationRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State with AutomaticKeepAliveClientMixin { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + super.build(context); + return Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + } + + Widget get _appBar => LSAppBar(title: 'Customization'); + + Widget get _body => LSListView( + children: [ + ..._general, + LSDivider(), + ..._modules, + ], + ); + + List get _general => [ + LSCardTile( + title: LSTitle(text: 'Appearance'), + subtitle: LSSubtitle(text: 'Appearance Customizations'), + trailing: LSIconButton(icon: Icons.brush), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationAppearanceRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Drawer'), + subtitle: LSSubtitle(text: 'Drawer Customizations'), + trailing: LSIconButton(icon: Icons.dehaze), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationDrawerRoute.ROUTE_NAME), + ), + if(Platform.isIOS) SettingsCustomizationBrowserTile(), + LSCardTile( + title: LSTitle(text: 'Quick Actions'), + subtitle: LSSubtitle(text: 'Quick Actions on the Home Screen'), + trailing: LSIconButton(icon: Icons.rounded_corner), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationQuickActionsRoute.ROUTE_NAME), + ), + ]; + + List get _modules => [ + LSCardTile( + title: LSTitle(text: 'Calendar'), + subtitle: LSSubtitle(text: 'Calendar Customizations'), + trailing: LSIconButton(icon: CustomIcons.calendar), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationCalendarRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Home'), + subtitle: LSSubtitle(text: 'Home Customizations'), + trailing: LSIconButton(icon: CustomIcons.home), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationHomeRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Search'), + subtitle: LSSubtitle(text: 'Search Customizations'), + trailing: LSIconButton(icon: Icons.search), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationSearchRoute.ROUTE_NAME), + ), + LSDivider(), + LSCardTile( + title: LSTitle(text: 'Lidarr'), + subtitle: LSSubtitle(text: 'Lidarr Customizations'), + trailing: LSIconButton(icon: CustomIcons.music), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationLidarrRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Radarr'), + subtitle: LSSubtitle(text: 'Radarr Customizations'), + trailing: LSIconButton(icon: CustomIcons.movies), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationRadarrRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Sonarr'), + subtitle: LSSubtitle(text: 'Sonarr Customizations'), + trailing: LSIconButton(icon: CustomIcons.television), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationSonarrRoute.ROUTE_NAME), + ), + LSDivider(), + LSCardTile( + title: LSTitle(text: 'NZBGet'), + subtitle: LSSubtitle(text: 'NZBGet Customizations'), + trailing: LSIconButton(icon: CustomIcons.nzbget), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationNZBGetRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'SABnzbd'), + subtitle: LSSubtitle(text: 'SABnzbd Customizations'), + trailing: LSIconButton(icon: CustomIcons.sabnzbd), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationSABnzbdRoute.ROUTE_NAME), + ), + LSDivider(), + LSCardTile( + title: LSTitle(text: 'Tautulli'), + subtitle: LSSubtitle(text: 'Tautulli Customizations'), + trailing: LSIconButton(icon: CustomIcons.tautulli), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationTautulliRoute.ROUTE_NAME), + ), + ]; +} diff --git a/lib/modules/settings/modules/customization/widgets.dart b/lib/modules/settings/modules/customization/widgets.dart new file mode 100644 index 00000000..8ee110f1 --- /dev/null +++ b/lib/modules/settings/modules/customization/widgets.dart @@ -0,0 +1 @@ +export 'widgets/browser_tile.dart'; diff --git a/lib/modules/settings/widgets/modules/lunasea/other_browser_tile.dart b/lib/modules/settings/modules/customization/widgets/browser_tile.dart similarity index 93% rename from lib/modules/settings/widgets/modules/lunasea/other_browser_tile.dart rename to lib/modules/settings/modules/customization/widgets/browser_tile.dart index 7a21ccc3..fbb2523d 100644 --- a/lib/modules/settings/widgets/modules/lunasea/other_browser_tile.dart +++ b/lib/modules/settings/modules/customization/widgets/browser_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsModulesLunaSeaBrowserTile extends StatelessWidget { +class SettingsCustomizationBrowserTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.SELECTED_BROWSER.key]), @@ -20,4 +20,4 @@ class SettingsModulesLunaSeaBrowserTile extends StatelessWidget { List _values = await SettingsDialogs.changeBrowser(context); if(_values[0]) LunaSeaDatabaseValue.SELECTED_BROWSER.put(_values[1]); } -} \ No newline at end of file +} diff --git a/lib/modules/settings/modules/customization_appearance.dart b/lib/modules/settings/modules/customization_appearance.dart new file mode 100644 index 00000000..29db39fe --- /dev/null +++ b/lib/modules/settings/modules/customization_appearance.dart @@ -0,0 +1,2 @@ +export 'customization_appearance/route.dart'; +export 'customization_appearance/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_appearance/route.dart b/lib/modules/settings/modules/customization_appearance/route.dart new file mode 100644 index 00000000..ece4552b --- /dev/null +++ b/lib/modules/settings/modules/customization_appearance/route.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationAppearanceRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/appearance'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Appearance'); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationAppearanceAMOLEDTile(), + SettingsCustomizationAppearanceAMOLEDBorderTile(), + SettingsCustomizationAppearance24HourTimeTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_appearance/widgets.dart b/lib/modules/settings/modules/customization_appearance/widgets.dart new file mode 100644 index 00000000..e6daa92a --- /dev/null +++ b/lib/modules/settings/modules/customization_appearance/widgets.dart @@ -0,0 +1,3 @@ +export 'widgets/amoled_border_tile.dart'; +export 'widgets/amoled_tile.dart'; +export 'widgets/use_24h_time.dart'; diff --git a/lib/modules/settings/widgets/modules/lunasea/appearance_amoled_border_tile.dart b/lib/modules/settings/modules/customization_appearance/widgets/amoled_border_tile.dart similarity index 89% rename from lib/modules/settings/widgets/modules/lunasea/appearance_amoled_border_tile.dart rename to lib/modules/settings/modules/customization_appearance/widgets/amoled_border_tile.dart index 93d8e517..80b6132c 100644 --- a/lib/modules/settings/widgets/modules/lunasea/appearance_amoled_border_tile.dart +++ b/lib/modules/settings/modules/customization_appearance/widgets/amoled_border_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsModulesLunaSeaAMOLEDBorderTile extends StatelessWidget { +class SettingsCustomizationAppearanceAMOLEDBorderTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.THEME_AMOLED_BORDER.key]), diff --git a/lib/modules/settings/widgets/modules/lunasea/appearance_amoled_tile.dart b/lib/modules/settings/modules/customization_appearance/widgets/amoled_tile.dart similarity index 90% rename from lib/modules/settings/widgets/modules/lunasea/appearance_amoled_tile.dart rename to lib/modules/settings/modules/customization_appearance/widgets/amoled_tile.dart index dbffa972..13cfbfbb 100644 --- a/lib/modules/settings/widgets/modules/lunasea/appearance_amoled_tile.dart +++ b/lib/modules/settings/modules/customization_appearance/widgets/amoled_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsModulesLunaSeaAMOLEDTile extends StatelessWidget { +class SettingsCustomizationAppearanceAMOLEDTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.THEME_AMOLED.key]), diff --git a/lib/modules/settings/widgets/modules/lunasea/use_24h_time.dart b/lib/modules/settings/modules/customization_appearance/widgets/use_24h_time.dart similarity index 90% rename from lib/modules/settings/widgets/modules/lunasea/use_24h_time.dart rename to lib/modules/settings/modules/customization_appearance/widgets/use_24h_time.dart index c4d9142b..8fd04ec8 100644 --- a/lib/modules/settings/widgets/modules/lunasea/use_24h_time.dart +++ b/lib/modules/settings/modules/customization_appearance/widgets/use_24h_time.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsModulesLunaSeaUse24HourTimeTile extends StatelessWidget { +class SettingsCustomizationAppearance24HourTimeTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.USE_24_HOUR_TIME.key]), diff --git a/lib/modules/settings/modules/customization_calendar.dart b/lib/modules/settings/modules/customization_calendar.dart new file mode 100644 index 00000000..85832a48 --- /dev/null +++ b/lib/modules/settings/modules/customization_calendar.dart @@ -0,0 +1,2 @@ +export 'customization_calendar/route.dart'; +export 'customization_calendar/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_calendar/route.dart b/lib/modules/settings/modules/customization_calendar/route.dart new file mode 100644 index 00000000..81c16733 --- /dev/null +++ b/lib/modules/settings/modules/customization_calendar/route.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationCalendarRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/calendar'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Calendar'); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationCalendarStartingDateTile(), + SettingsCustomizationCalendarStartingSizeTile(), + SettingsCustomizationCalendarStartingTypeTile(), + LSDivider(), + SettingsCustomizationCalendarEnableLidarrTile(), + SettingsCustomizationCalendarEnableRadarrTile(), + SettingsCustomizationCalendarEnableSonarrTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_calendar/widgets.dart b/lib/modules/settings/modules/customization_calendar/widgets.dart new file mode 100644 index 00000000..3e628f01 --- /dev/null +++ b/lib/modules/settings/modules/customization_calendar/widgets.dart @@ -0,0 +1,6 @@ +export 'widgets/enable_lidarr_tile.dart'; +export 'widgets/enable_radarr_tile.dart'; +export 'widgets/enable_sonarr_tile.dart'; +export 'widgets/start_date_tile.dart'; +export 'widgets/start_size_tile.dart'; +export 'widgets/start_type_tile.dart'; diff --git a/lib/modules/settings/widgets/modules/home/enable_lidarr.dart b/lib/modules/settings/modules/customization_calendar/widgets/enable_lidarr_tile.dart similarity index 76% rename from lib/modules/settings/widgets/modules/home/enable_lidarr.dart rename to lib/modules/settings/modules/customization_calendar/widgets/enable_lidarr_tile.dart index 52405fd2..d114b233 100644 --- a/lib/modules/settings/widgets/modules/home/enable_lidarr.dart +++ b/lib/modules/settings/modules/customization_calendar/widgets/enable_lidarr_tile.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; -class SettingsModulesCalendarEnableLidarrTile extends StatelessWidget { +class SettingsCustomizationCalendarEnableLidarrTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.CALENDAR_ENABLE_LIDARR.key]), builder: (context, box, widget) => LSCardTile( - title: LSTitle(text: 'Lidarr in Calendar'), - subtitle: LSSubtitle(text: 'Show Lidarr calendar entries'), + title: LSTitle(text: 'Show Lidarr'), + subtitle: LSSubtitle(text: 'Show Lidarr Calendar Entries'), trailing: Switch( value: HomeDatabaseValue.CALENDAR_ENABLE_LIDARR.data, onChanged: _changeState, diff --git a/lib/modules/settings/widgets/modules/home/enable_radarr.dart b/lib/modules/settings/modules/customization_calendar/widgets/enable_radarr_tile.dart similarity index 76% rename from lib/modules/settings/widgets/modules/home/enable_radarr.dart rename to lib/modules/settings/modules/customization_calendar/widgets/enable_radarr_tile.dart index dfc02df4..ed37ed8f 100644 --- a/lib/modules/settings/widgets/modules/home/enable_radarr.dart +++ b/lib/modules/settings/modules/customization_calendar/widgets/enable_radarr_tile.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; -class SettingsModulesCalendarEnableRadarrTile extends StatelessWidget { +class SettingsCustomizationCalendarEnableRadarrTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.CALENDAR_ENABLE_RADARR.key]), builder: (context, box, widget) => LSCardTile( - title: LSTitle(text: 'Radarr in Calendar'), - subtitle: LSSubtitle(text: 'Show Radarr calendar entries'), + title: LSTitle(text: 'Show Radarr'), + subtitle: LSSubtitle(text: 'Show Radarr Calendar Entries'), trailing: Switch( value: HomeDatabaseValue.CALENDAR_ENABLE_RADARR.data, onChanged: _changeState, diff --git a/lib/modules/settings/widgets/modules/home/enable_sonarr.dart b/lib/modules/settings/modules/customization_calendar/widgets/enable_sonarr_tile.dart similarity index 76% rename from lib/modules/settings/widgets/modules/home/enable_sonarr.dart rename to lib/modules/settings/modules/customization_calendar/widgets/enable_sonarr_tile.dart index bf4034d8..2404ae32 100644 --- a/lib/modules/settings/widgets/modules/home/enable_sonarr.dart +++ b/lib/modules/settings/modules/customization_calendar/widgets/enable_sonarr_tile.dart @@ -2,13 +2,13 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; -class SettingsModulesCalendarEnableSonarrTile extends StatelessWidget { +class SettingsCustomizationCalendarEnableSonarrTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.CALENDAR_ENABLE_SONARR.key]), builder: (context, box, widget) => LSCardTile( - title: LSTitle(text: 'Sonarr in Calendar'), - subtitle: LSSubtitle(text: 'Show Sonarr calendar entries'), + title: LSTitle(text: 'Show Sonarr'), + subtitle: LSSubtitle(text: 'Show Sonarr Calendar Entries'), trailing: Switch( value: HomeDatabaseValue.CALENDAR_ENABLE_SONARR.data, onChanged: _changeState, diff --git a/lib/modules/settings/widgets/modules/home/start_date_tile.dart b/lib/modules/settings/modules/customization_calendar/widgets/start_date_tile.dart similarity index 92% rename from lib/modules/settings/widgets/modules/home/start_date_tile.dart rename to lib/modules/settings/modules/customization_calendar/widgets/start_date_tile.dart index 32e1c0f5..73933a71 100644 --- a/lib/modules/settings/widgets/modules/home/start_date_tile.dart +++ b/lib/modules/settings/modules/customization_calendar/widgets/start_date_tile.dart @@ -3,7 +3,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsModulesHomeCalendarStartingDateTile extends StatelessWidget { +class SettingsCustomizationCalendarStartingDateTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.CALENDAR_STARTING_DAY.key]), diff --git a/lib/modules/settings/widgets/modules/home/start_size_tile.dart b/lib/modules/settings/modules/customization_calendar/widgets/start_size_tile.dart similarity index 92% rename from lib/modules/settings/widgets/modules/home/start_size_tile.dart rename to lib/modules/settings/modules/customization_calendar/widgets/start_size_tile.dart index d658f30f..5fb3009c 100644 --- a/lib/modules/settings/widgets/modules/home/start_size_tile.dart +++ b/lib/modules/settings/modules/customization_calendar/widgets/start_size_tile.dart @@ -3,7 +3,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsModulesHomeCalendarStartingSizeTile extends StatelessWidget { +class SettingsCustomizationCalendarStartingSizeTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.CALENDAR_STARTING_SIZE.key]), diff --git a/lib/modules/settings/widgets/modules/home/start_type_tile.dart b/lib/modules/settings/modules/customization_calendar/widgets/start_type_tile.dart similarity index 92% rename from lib/modules/settings/widgets/modules/home/start_type_tile.dart rename to lib/modules/settings/modules/customization_calendar/widgets/start_type_tile.dart index 86d75b06..e095cdf6 100644 --- a/lib/modules/settings/widgets/modules/home/start_type_tile.dart +++ b/lib/modules/settings/modules/customization_calendar/widgets/start_type_tile.dart @@ -3,7 +3,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsModulesHomeCalendarStartingTypeTile extends StatelessWidget { +class SettingsCustomizationCalendarStartingTypeTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.CALENDAR_STARTING_TYPE.key]), diff --git a/lib/modules/settings/modules/customization_drawer.dart b/lib/modules/settings/modules/customization_drawer.dart new file mode 100644 index 00000000..4a38ab7e --- /dev/null +++ b/lib/modules/settings/modules/customization_drawer.dart @@ -0,0 +1,2 @@ +export 'customization_drawer/route.dart'; +export 'customization_drawer/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_drawer/route.dart b/lib/modules/settings/modules/customization_drawer/route.dart new file mode 100644 index 00000000..7ee49482 --- /dev/null +++ b/lib/modules/settings/modules/customization_drawer/route.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationDrawerRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/drawer'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Drawer'); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationDrawerExpandAutomationTile(), + SettingsCustomizationDrawerExpandClientsTile(), + SettingsCustomizationDrawerExpandMonitoringTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_drawer/widgets.dart b/lib/modules/settings/modules/customization_drawer/widgets.dart new file mode 100644 index 00000000..99e71780 --- /dev/null +++ b/lib/modules/settings/modules/customization_drawer/widgets.dart @@ -0,0 +1,3 @@ +export 'widgets/expand_automation_tile.dart'; +export 'widgets/expand_clients_tile.dart'; +export 'widgets/expand_monitoring_tile.dart'; diff --git a/lib/modules/settings/widgets/modules/lunasea/drawer_expand_automation_tile.dart b/lib/modules/settings/modules/customization_drawer/widgets/expand_automation_tile.dart similarity index 90% rename from lib/modules/settings/widgets/modules/lunasea/drawer_expand_automation_tile.dart rename to lib/modules/settings/modules/customization_drawer/widgets/expand_automation_tile.dart index f7ae3c57..a2acada9 100644 --- a/lib/modules/settings/widgets/modules/lunasea/drawer_expand_automation_tile.dart +++ b/lib/modules/settings/modules/customization_drawer/widgets/expand_automation_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsDrawerExpandAutomationTile extends StatelessWidget { +class SettingsCustomizationDrawerExpandAutomationTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.DRAWER_EXPAND_AUTOMATION.key]), diff --git a/lib/modules/settings/widgets/modules/lunasea/drawer_expand_clients_tile.dart b/lib/modules/settings/modules/customization_drawer/widgets/expand_clients_tile.dart similarity index 90% rename from lib/modules/settings/widgets/modules/lunasea/drawer_expand_clients_tile.dart rename to lib/modules/settings/modules/customization_drawer/widgets/expand_clients_tile.dart index 1f8b3790..e361c023 100644 --- a/lib/modules/settings/widgets/modules/lunasea/drawer_expand_clients_tile.dart +++ b/lib/modules/settings/modules/customization_drawer/widgets/expand_clients_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsDrawerExpandClientsTile extends StatelessWidget { +class SettingsCustomizationDrawerExpandClientsTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.DRAWER_EXPAND_CLIENTS.key]), diff --git a/lib/modules/settings/widgets/modules/lunasea/drawer_expand_monitoring_tile.dart b/lib/modules/settings/modules/customization_drawer/widgets/expand_monitoring_tile.dart similarity index 90% rename from lib/modules/settings/widgets/modules/lunasea/drawer_expand_monitoring_tile.dart rename to lib/modules/settings/modules/customization_drawer/widgets/expand_monitoring_tile.dart index 5ff7e49d..cf878206 100644 --- a/lib/modules/settings/widgets/modules/lunasea/drawer_expand_monitoring_tile.dart +++ b/lib/modules/settings/modules/customization_drawer/widgets/expand_monitoring_tile.dart @@ -1,7 +1,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsDrawerExpandMonitoringTile extends StatelessWidget { +class SettingsCustomizationDrawerExpandMonitoringTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.DRAWER_EXPAND_MONITORING.key]), diff --git a/lib/modules/settings/modules/customization_home.dart b/lib/modules/settings/modules/customization_home.dart new file mode 100644 index 00000000..7c284359 --- /dev/null +++ b/lib/modules/settings/modules/customization_home.dart @@ -0,0 +1,2 @@ +export 'customization_home/route.dart'; +export 'customization_home/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_home/route.dart b/lib/modules/settings/modules/customization_home/route.dart new file mode 100644 index 00000000..c2b1b89f --- /dev/null +++ b/lib/modules/settings/modules/customization_home/route.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationHomeRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/home'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Home'); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationHomeDefaultPageTile(), + SettingsCustomizationHomeBrandColoursTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_home/widgets.dart b/lib/modules/settings/modules/customization_home/widgets.dart new file mode 100644 index 00000000..5420a93f --- /dev/null +++ b/lib/modules/settings/modules/customization_home/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/brand_colours_tile.dart'; +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/widgets/modules/home/module_brand_colours.dart b/lib/modules/settings/modules/customization_home/widgets/brand_colours_tile.dart similarity index 90% rename from lib/modules/settings/widgets/modules/home/module_brand_colours.dart rename to lib/modules/settings/modules/customization_home/widgets/brand_colours_tile.dart index 008dca1a..9444e388 100644 --- a/lib/modules/settings/widgets/modules/home/module_brand_colours.dart +++ b/lib/modules/settings/modules/customization_home/widgets/brand_colours_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; -class SettingsModulesHomeBrandColours extends StatelessWidget { +class SettingsCustomizationHomeBrandColoursTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.MODULES_BRAND_COLOURS.key]), diff --git a/lib/modules/settings/widgets/modules/home/default_page.dart b/lib/modules/settings/modules/customization_home/widgets/default_page_tile.dart similarity index 70% rename from lib/modules/settings/widgets/modules/home/default_page.dart rename to lib/modules/settings/modules/customization_home/widgets/default_page_tile.dart index 6cb48c95..0011c9d8 100644 --- a/lib/modules/settings/widgets/modules/home/default_page.dart +++ b/lib/modules/settings/modules/customization_home/widgets/default_page_tile.dart @@ -2,16 +2,14 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/home.dart'; -class SettingsModulesHomeDefaultPageTile extends StatelessWidget { +class SettingsCustomizationHomeDefaultPageTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.NAVIGATION_INDEX.key]), builder: (context, box, _) => LSCardTile( title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: HomeNavigationBar.titles[HomeDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), + subtitle: LSSubtitle(text: HomeNavigationBar.titles[HomeDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: HomeNavigationBar.icons[HomeDatabaseValue.NAVIGATION_INDEX.data]), onTap: () async => _defaultPage(context), ), ); @@ -20,4 +18,4 @@ class SettingsModulesHomeDefaultPageTile extends StatelessWidget { List _values = await HomeDialogs.defaultPage(context); if(_values[0]) HomeDatabaseValue.NAVIGATION_INDEX.put(_values[1]); } -} \ No newline at end of file +} diff --git a/lib/modules/settings/modules/customization_lidarr.dart b/lib/modules/settings/modules/customization_lidarr.dart new file mode 100644 index 00000000..bdc577dc --- /dev/null +++ b/lib/modules/settings/modules/customization_lidarr.dart @@ -0,0 +1,2 @@ +export 'customization_lidarr/route.dart'; +export 'customization_lidarr/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_lidarr/route.dart b/lib/modules/settings/modules/customization_lidarr/route.dart new file mode 100644 index 00000000..738a1605 --- /dev/null +++ b/lib/modules/settings/modules/customization_lidarr/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationLidarrRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/lidarr'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Lidarr', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesLidarrRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationLidarrDefaultPageTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_lidarr/widgets.dart b/lib/modules/settings/modules/customization_lidarr/widgets.dart new file mode 100644 index 00000000..cf719210 --- /dev/null +++ b/lib/modules/settings/modules/customization_lidarr/widgets.dart @@ -0,0 +1 @@ +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/modules/customization_lidarr/widgets/default_page_tile.dart b/lib/modules/settings/modules/customization_lidarr/widgets/default_page_tile.dart new file mode 100644 index 00000000..63758a69 --- /dev/null +++ b/lib/modules/settings/modules/customization_lidarr/widgets/default_page_tile.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/lidarr.dart'; + +class SettingsCustomizationLidarrDefaultPageTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [LidarrDatabaseValue.NAVIGATION_INDEX.key]), + builder: (context, box, _) => LSCardTile( + title: LSTitle(text: 'Default Page'), + subtitle: LSSubtitle(text: LidarrNavigationBar.titles[LidarrDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: LidarrNavigationBar.icons[LidarrDatabaseValue.NAVIGATION_INDEX.data]), + onTap: () async => _defaultPage(context), + ), + ); + + Future _defaultPage(BuildContext context) async { + List _values = await LidarrDialogs.defaultPage(context); + if(_values[0]) LidarrDatabaseValue.NAVIGATION_INDEX.put(_values[1]); + } +} diff --git a/lib/modules/settings/modules/customization_nzbget.dart b/lib/modules/settings/modules/customization_nzbget.dart new file mode 100644 index 00000000..c8252eec --- /dev/null +++ b/lib/modules/settings/modules/customization_nzbget.dart @@ -0,0 +1,2 @@ +export 'customization_nzbget/route.dart'; +export 'customization_nzbget/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_nzbget/route.dart b/lib/modules/settings/modules/customization_nzbget/route.dart new file mode 100644 index 00000000..a759749f --- /dev/null +++ b/lib/modules/settings/modules/customization_nzbget/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationNZBGetRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/nzbget'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'NZBGet', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesNZBGetRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationNZBGetDefaultPageTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_nzbget/widgets.dart b/lib/modules/settings/modules/customization_nzbget/widgets.dart new file mode 100644 index 00000000..cf719210 --- /dev/null +++ b/lib/modules/settings/modules/customization_nzbget/widgets.dart @@ -0,0 +1 @@ +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/modules/customization_nzbget/widgets/default_page_tile.dart b/lib/modules/settings/modules/customization_nzbget/widgets/default_page_tile.dart new file mode 100644 index 00000000..0bc554a1 --- /dev/null +++ b/lib/modules/settings/modules/customization_nzbget/widgets/default_page_tile.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/nzbget.dart'; + +class SettingsCustomizationNZBGetDefaultPageTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [NZBGetDatabaseValue.NAVIGATION_INDEX.key]), + builder: (context, box, _) => LSCardTile( + title: LSTitle(text: 'Default Page'), + subtitle: LSSubtitle(text: NZBGetNavigationBar.titles[NZBGetDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: NZBGetNavigationBar.icons[NZBGetDatabaseValue.NAVIGATION_INDEX.data]), + onTap: () async => _defaultPage(context), + ), + ); + + Future _defaultPage(BuildContext context) async { + List _values = await NZBGetDialogs.defaultPage(context); + if(_values[0]) NZBGetDatabaseValue.NAVIGATION_INDEX.put(_values[1]); + } +} diff --git a/lib/modules/settings/modules/customization_quickactions.dart b/lib/modules/settings/modules/customization_quickactions.dart new file mode 100644 index 00000000..e8d6cae1 --- /dev/null +++ b/lib/modules/settings/modules/customization_quickactions.dart @@ -0,0 +1,2 @@ +export 'customization_quickactions/route.dart'; +export 'customization_quickactions/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_quickactions/route.dart b/lib/modules/settings/modules/customization_quickactions/route.dart new file mode 100644 index 00000000..07650143 --- /dev/null +++ b/lib/modules/settings/modules/customization_quickactions/route.dart @@ -0,0 +1,63 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationQuickActionsRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/quick_actions'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Quick Actions'); + + Widget get _body => LSListView( + children: [ + LSHeader( + text: 'Modules', + subtitle: 'Only four quick actions will appear, and are added in the order below. Enabling more than four modules will have no effect.', + ), + SettingsCustomizationQuickActionTile( + title: 'Search', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_SEARCH, + ), + LSDivider(), + SettingsCustomizationQuickActionTile( + title: 'Lidarr', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_LIDARR, + ), + SettingsCustomizationQuickActionTile( + title: 'Radarr', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_RADARR, + ), + SettingsCustomizationQuickActionTile( + title: 'Sonarr', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_SONARR, + ), + LSDivider(), + SettingsCustomizationQuickActionTile( + title: 'NZBGet', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_NZBGET, + ), + SettingsCustomizationQuickActionTile( + title: 'SABnzbd', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_SABNZBD, + ), + LSDivider(), + SettingsCustomizationQuickActionTile( + title: 'Tautulli', + action: LunaSeaDatabaseValue.QUICK_ACTIONS_TAUTULLI, + ), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_quickactions/widgets.dart b/lib/modules/settings/modules/customization_quickactions/widgets.dart new file mode 100644 index 00000000..5bb78e70 --- /dev/null +++ b/lib/modules/settings/modules/customization_quickactions/widgets.dart @@ -0,0 +1 @@ +export 'widgets/action_tile.dart'; diff --git a/lib/modules/settings/modules/customization_quickactions/widgets/action_tile.dart b/lib/modules/settings/modules/customization_quickactions/widgets/action_tile.dart new file mode 100644 index 00000000..6289835f --- /dev/null +++ b/lib/modules/settings/modules/customization_quickactions/widgets/action_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsCustomizationQuickActionTile extends StatelessWidget { + final String title; + final LunaSeaDatabaseValue action; + + SettingsCustomizationQuickActionTile({ + Key key, + @required this.title, + @required this.action, + }): super(key: key); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: title), + trailing: ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [action.key]), + builder: (context, box, _) => Switch( + value: action.data, + onChanged: (value) { + action.put(value); + HomescreenActions.setShortcutItems(); + } + ), + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/customization_radarr.dart b/lib/modules/settings/modules/customization_radarr.dart new file mode 100644 index 00000000..d21958e6 --- /dev/null +++ b/lib/modules/settings/modules/customization_radarr.dart @@ -0,0 +1,2 @@ +export 'customization_radarr/route.dart'; +export 'customization_radarr/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_radarr/route.dart b/lib/modules/settings/modules/customization_radarr/route.dart new file mode 100644 index 00000000..279a4aea --- /dev/null +++ b/lib/modules/settings/modules/customization_radarr/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationRadarrRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/radarr'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Radarr', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesRadarrRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationRadarrDefaultPageTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_radarr/widgets.dart b/lib/modules/settings/modules/customization_radarr/widgets.dart new file mode 100644 index 00000000..cf719210 --- /dev/null +++ b/lib/modules/settings/modules/customization_radarr/widgets.dart @@ -0,0 +1 @@ +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/modules/customization_radarr/widgets/default_page_tile.dart b/lib/modules/settings/modules/customization_radarr/widgets/default_page_tile.dart new file mode 100644 index 00000000..e8e4bc05 --- /dev/null +++ b/lib/modules/settings/modules/customization_radarr/widgets/default_page_tile.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/radarr.dart'; + +class SettingsCustomizationRadarrDefaultPageTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [RadarrDatabaseValue.NAVIGATION_INDEX.key]), + builder: (context, box, _) => LSCardTile( + title: LSTitle(text: 'Default Page'), + subtitle: LSSubtitle(text: RadarrNavigationBar.titles[RadarrDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: RadarrNavigationBar.icons[RadarrDatabaseValue.NAVIGATION_INDEX.data]), + onTap: () async => _defaultPage(context), + ), + ); + + Future _defaultPage(BuildContext context) async { + List _values = await RadarrDialogs.defaultPage(context); + if(_values[0]) RadarrDatabaseValue.NAVIGATION_INDEX.put(_values[1]); + } +} diff --git a/lib/modules/settings/modules/customization_sabnzbd.dart b/lib/modules/settings/modules/customization_sabnzbd.dart new file mode 100644 index 00000000..980112c5 --- /dev/null +++ b/lib/modules/settings/modules/customization_sabnzbd.dart @@ -0,0 +1,2 @@ +export 'customization_sabnzbd/route.dart'; +export 'customization_sabnzbd/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_sabnzbd/route.dart b/lib/modules/settings/modules/customization_sabnzbd/route.dart new file mode 100644 index 00000000..8bba1382 --- /dev/null +++ b/lib/modules/settings/modules/customization_sabnzbd/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationSABnzbdRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/sabnzbd'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'SABnzbd', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesSABnzbdRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationSABnzbdDefaultPageTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_sabnzbd/widgets.dart b/lib/modules/settings/modules/customization_sabnzbd/widgets.dart new file mode 100644 index 00000000..cf719210 --- /dev/null +++ b/lib/modules/settings/modules/customization_sabnzbd/widgets.dart @@ -0,0 +1 @@ +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/modules/customization_sabnzbd/widgets/default_page_tile.dart b/lib/modules/settings/modules/customization_sabnzbd/widgets/default_page_tile.dart new file mode 100644 index 00000000..1a678b61 --- /dev/null +++ b/lib/modules/settings/modules/customization_sabnzbd/widgets/default_page_tile.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sabnzbd.dart'; + +class SettingsCustomizationSABnzbdDefaultPageTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [SABnzbdDatabaseValue.NAVIGATION_INDEX.key]), + builder: (context, box, _) => LSCardTile( + title: LSTitle(text: 'Default Page'), + subtitle: LSSubtitle(text: SABnzbdNavigationBar.titles[SABnzbdDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: SABnzbdNavigationBar.icons[SABnzbdDatabaseValue.NAVIGATION_INDEX.data]), + onTap: () async => _defaultPage(context), + ), + ); + + Future _defaultPage(BuildContext context) async { + List _values = await SABnzbdDialogs.defaultPage(context); + if(_values[0]) SABnzbdDatabaseValue.NAVIGATION_INDEX.put(_values[1]); + } +} diff --git a/lib/modules/settings/modules/customization_search.dart b/lib/modules/settings/modules/customization_search.dart new file mode 100644 index 00000000..bf3ed65d --- /dev/null +++ b/lib/modules/settings/modules/customization_search.dart @@ -0,0 +1,2 @@ +export 'customization_search/route.dart'; +export 'customization_search/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_search/route.dart b/lib/modules/settings/modules/customization_search/route.dart new file mode 100644 index 00000000..69d801e8 --- /dev/null +++ b/lib/modules/settings/modules/customization_search/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationSearchRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/search'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Search', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesSearchRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationSearchHideAdultCategoriesTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_search/widgets.dart b/lib/modules/settings/modules/customization_search/widgets.dart new file mode 100644 index 00000000..b2863f55 --- /dev/null +++ b/lib/modules/settings/modules/customization_search/widgets.dart @@ -0,0 +1 @@ +export 'widgets/hide_adult_categories_tile.dart'; diff --git a/lib/modules/settings/modules/customization_search/widgets/hide_adult_categories_tile.dart b/lib/modules/settings/modules/customization_search/widgets/hide_adult_categories_tile.dart new file mode 100644 index 00000000..0fcbca1d --- /dev/null +++ b/lib/modules/settings/modules/customization_search/widgets/hide_adult_categories_tile.dart @@ -0,0 +1,18 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/search.dart'; + +class SettingsCustomizationSearchHideAdultCategoriesTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [SearchDatabaseValue.HIDE_XXX.key]), + builder: (context, box, widget) => LSCardTile( + title: LSTitle(text: 'Hide Adult Categories'), + subtitle: LSSubtitle(text: 'Hide Categories Containing Adult Content'), + trailing: Switch( + value: SearchDatabaseValue.HIDE_XXX.data, + onChanged: (value) => SearchDatabaseValue.HIDE_XXX.put(value), + ), + ), + ); +} diff --git a/lib/modules/settings/modules/customization_sonarr.dart b/lib/modules/settings/modules/customization_sonarr.dart new file mode 100644 index 00000000..e49b262b --- /dev/null +++ b/lib/modules/settings/modules/customization_sonarr.dart @@ -0,0 +1,2 @@ +export 'customization_sonarr/route.dart'; +export 'customization_sonarr/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_sonarr/route.dart b/lib/modules/settings/modules/customization_sonarr/route.dart new file mode 100644 index 00000000..1d196ab8 --- /dev/null +++ b/lib/modules/settings/modules/customization_sonarr/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationSonarrRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/sonarr'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Sonarr', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesSonarrRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationSonarrDefaultPageTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_sonarr/widgets.dart b/lib/modules/settings/modules/customization_sonarr/widgets.dart new file mode 100644 index 00000000..cf719210 --- /dev/null +++ b/lib/modules/settings/modules/customization_sonarr/widgets.dart @@ -0,0 +1 @@ +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/modules/customization_sonarr/widgets/default_page_tile.dart b/lib/modules/settings/modules/customization_sonarr/widgets/default_page_tile.dart new file mode 100644 index 00000000..6374b9db --- /dev/null +++ b/lib/modules/settings/modules/customization_sonarr/widgets/default_page_tile.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +class SettingsCustomizationSonarrDefaultPageTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.NAVIGATION_INDEX.key]), + builder: (context, box, _) => LSCardTile( + title: LSTitle(text: 'Default Page'), + subtitle: LSSubtitle(text: SonarrNavigationBar.titles[SonarrDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: SonarrNavigationBar.icons[SonarrDatabaseValue.NAVIGATION_INDEX.data]), + onTap: () async => _defaultPage(context), + ), + ); + + Future _defaultPage(BuildContext context) async { + List _values = await SonarrDialogs.defaultPage(context); + if(_values[0]) SonarrDatabaseValue.NAVIGATION_INDEX.put(_values[1]); + } +} diff --git a/lib/modules/settings/modules/customization_tautulli.dart b/lib/modules/settings/modules/customization_tautulli.dart new file mode 100644 index 00000000..4f22fc32 --- /dev/null +++ b/lib/modules/settings/modules/customization_tautulli.dart @@ -0,0 +1,2 @@ +export 'customization_tautulli/route.dart'; +export 'customization_tautulli/widgets.dart'; diff --git a/lib/modules/settings/modules/customization_tautulli/route.dart b/lib/modules/settings/modules/customization_tautulli/route.dart new file mode 100644 index 00000000..727e8930 --- /dev/null +++ b/lib/modules/settings/modules/customization_tautulli/route.dart @@ -0,0 +1,36 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsCustomizationTautulliRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/customization/tautulli'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Tautulli', + actions: [ + LSIconButton( + icon: Icons.settings, + onPressed: () async => Navigator.of(context).pushNamed(SettingsModulesTautulliRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => LSListView( + children: [ + SettingsCustomizationTautulliDefaultPageTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/customization_tautulli/widgets.dart b/lib/modules/settings/modules/customization_tautulli/widgets.dart new file mode 100644 index 00000000..cf719210 --- /dev/null +++ b/lib/modules/settings/modules/customization_tautulli/widgets.dart @@ -0,0 +1 @@ +export 'widgets/default_page_tile.dart'; diff --git a/lib/modules/settings/modules/customization_tautulli/widgets/default_page_tile.dart b/lib/modules/settings/modules/customization_tautulli/widgets/default_page_tile.dart new file mode 100644 index 00000000..0e685530 --- /dev/null +++ b/lib/modules/settings/modules/customization_tautulli/widgets/default_page_tile.dart @@ -0,0 +1,21 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class SettingsCustomizationTautulliDefaultPageTile extends StatelessWidget { + @override + Widget build(BuildContext context) => ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [TautulliDatabaseValue.NAVIGATION_INDEX.key]), + builder: (context, box, _) => LSCardTile( + title: LSTitle(text: 'Default Page'), + subtitle: LSSubtitle(text: TautulliNavigationBar.titles[TautulliDatabaseValue.NAVIGATION_INDEX.data]), + trailing: LSIconButton(icon: TautulliNavigationBar.icons[TautulliDatabaseValue.NAVIGATION_INDEX.data]), + onTap: () async => _defaultPage(context), + ), + ); + + Future _defaultPage(BuildContext context) async { + List _values = await TautulliDialogs.defaultPage(context); + if(_values[0]) TautulliDatabaseValue.NAVIGATION_INDEX.put(_values[1]); + } +} diff --git a/lib/modules/settings/modules/donations.dart b/lib/modules/settings/modules/donations.dart new file mode 100644 index 00000000..e71fbae3 --- /dev/null +++ b/lib/modules/settings/modules/donations.dart @@ -0,0 +1,2 @@ +export 'donations/route.dart'; +export 'donations/widgets.dart'; diff --git a/lib/modules/settings/modules/donations/route.dart b/lib/modules/settings/modules/donations/route.dart new file mode 100644 index 00000000..450ee051 --- /dev/null +++ b/lib/modules/settings/modules/donations/route.dart @@ -0,0 +1,70 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:in_app_purchase/in_app_purchase.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsDonationsRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/donations'; + + SettingsDonationsRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + static StreamSubscription> purchaseStream; + + @override + void initState() { + super.initState(); + purchaseStream = InAppPurchases.connection.purchaseUpdatedStream.listen(_purchasedCallback); + } + + @override + void dispose() { + purchaseStream?.cancel(); + super.dispose(); + } + + Future _purchasedCallback(List purchases) async { + for(var purchase in purchases) { + if(purchase.pendingCompletePurchase) { + switch(purchase.status) { + case PurchaseStatus.error: _purchaseFailed(); break; + case PurchaseStatus.purchased: _purchasedSuccess(); break; + default: break; + } + } + } + } + + void _purchasedSuccess() => Navigator.of(context).pushNamed(SettingsDonationsThankYouRoute.ROUTE_NAME); + + void _purchaseFailed() => LSSnackBar( + context: context, + title: 'Transaction Failure', + message: 'The transaction has failed, please try again', + type: SNACKBAR_TYPE.failure, + ); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Donations'); + + Widget get _body => InAppPurchases.available && InAppPurchases.products.length != 0 + ? LSListViewBuilder( + itemCount: InAppPurchases.products.length, + itemBuilder: (context, index) => SettingsDonationsIAPTile(product: InAppPurchases.products[index]), + ) + : LSGenericMessage(text: 'In-App Purchases Unavailable'); +} diff --git a/lib/modules/settings/modules/donations/widgets.dart b/lib/modules/settings/modules/donations/widgets.dart new file mode 100644 index 00000000..f25fa296 --- /dev/null +++ b/lib/modules/settings/modules/donations/widgets.dart @@ -0,0 +1 @@ +export 'widgets/iap_tile.dart'; diff --git a/lib/modules/settings/modules/donations/widgets/iap_tile.dart b/lib/modules/settings/modules/donations/widgets/iap_tile.dart new file mode 100644 index 00000000..a4d3b3a2 --- /dev/null +++ b/lib/modules/settings/modules/donations/widgets/iap_tile.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:in_app_purchase/in_app_purchase.dart'; +import 'package:lunasea/core.dart'; + +class SettingsDonationsIAPTile extends StatelessWidget { + final ProductDetails product; + + SettingsDonationsIAPTile({ + Key key, + @required this.product, + }) : super(key: key); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: product.ls_Name), + subtitle: LSSubtitle(text: product.ls_Description), + trailing: LSIconButton(icon: product.ls_Icon), + onTap: () async => await _purchase(), + ); + + Future _purchase() async { + final PurchaseParam _parameters = PurchaseParam(productDetails: product, sandboxTesting: false); + await InAppPurchases.connection.buyConsumable(purchaseParam: _parameters, autoConsume: true); + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/donations_thankyou.dart b/lib/modules/settings/modules/donations_thankyou.dart new file mode 100644 index 00000000..ea4d52fb --- /dev/null +++ b/lib/modules/settings/modules/donations_thankyou.dart @@ -0,0 +1 @@ +export 'donations_thankyou/route.dart'; diff --git a/lib/modules/settings/modules/donations_thankyou/route.dart b/lib/modules/settings/modules/donations_thankyou/route.dart new file mode 100644 index 00000000..b05cf31b --- /dev/null +++ b/lib/modules/settings/modules/donations_thankyou/route.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:flare_flutter/flare_actor.dart'; + +class SettingsDonationsThankYouRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/donations/thankyou'; + + SettingsDonationsThankYouRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Donations'); + + Widget get _body => Padding( + child: Column( + children: [ + LSHeader( + text: 'Thank You', + subtitle: [ + "Thank you for supporting the open-source community! ", + "LunaSea was and still is a passion project built for the community, and will remain entirely open-source.", + "\n\n", + "Donations are never expected or assumed, so thank you for giving back and helping LunaSea remain free, forever!", + ].join(), + ), + Container( + height: MediaQuery.of(context).size.height/3, + width: MediaQuery.of(context).size.width, + child: FlareActor( + RiveAnimations.CODER['path'], + shouldClip: false, + alignment: Alignment.center, + fit: BoxFit.contain, + animation: RiveAnimations.CODER['animation'], + ), + ), + ], + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisAlignment: MainAxisAlignment.spaceBetween, + ), + padding: EdgeInsets.only(top: 6.0), + ); +} diff --git a/lib/modules/settings/modules/logs.dart b/lib/modules/settings/modules/logs.dart new file mode 100644 index 00000000..1de871a3 --- /dev/null +++ b/lib/modules/settings/modules/logs.dart @@ -0,0 +1,2 @@ +export 'logs/route.dart'; +export 'logs/widgets.dart'; diff --git a/lib/modules/settings/modules/logs/route.dart b/lib/modules/settings/modules/logs/route.dart new file mode 100644 index 00000000..f8003d65 --- /dev/null +++ b/lib/modules/settings/modules/logs/route.dart @@ -0,0 +1,68 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsLogsRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/logs'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Logs'); + + Widget get _body => LSListView( + children: [ + ..._logs, + LSDivider(), + ..._other, + ], + ); + + List get _logs => [ + LSCardTile( + title: LSTitle(text: 'All Logs'), + subtitle: LSSubtitle(text: 'View Logs of All Types'), + trailing: LSIconButton(icon: Icons.developer_mode), + onTap: () async => _viewLogs('All'), + ), + LSCardTile( + title: LSTitle(text: 'Warning'), + subtitle: LSSubtitle(text: 'View Warning Logs'), + trailing: LSIconButton(icon: Icons.warning), + onTap: () async => _viewLogs('Warning'), + ), + LSCardTile( + title: LSTitle(text: 'Error'), + subtitle: LSSubtitle(text: 'View Error Logs'), + trailing: LSIconButton(icon: Icons.report), + onTap: () async => _viewLogs('Error'), + ), + LSCardTile( + title: LSTitle(text: 'Fatal'), + subtitle: LSSubtitle(text: 'View Fatal Logs'), + trailing: LSIconButton(icon: Icons.new_releases), + onTap: () async => _viewLogs('Fatal'), + ), + ]; + + List get _other => [ + SettingsLogsExportTile(), + SettingsLogsClearTile(), + ]; + + Future _viewLogs(String type) async => Navigator.of(context).pushNamed( + SettingsLogsDetailsRoute.ROUTE_NAME, + arguments: SettingsLogsDetailsRouteArguments(type: type), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/logs/widgets.dart b/lib/modules/settings/modules/logs/widgets.dart new file mode 100644 index 00000000..a8e43e8f --- /dev/null +++ b/lib/modules/settings/modules/logs/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/clear_tile.dart'; +export 'widgets/export_tile.dart'; diff --git a/lib/modules/settings/widgets/general/logs/clear_tile.dart b/lib/modules/settings/modules/logs/widgets/clear_tile.dart similarity index 87% rename from lib/modules/settings/widgets/general/logs/clear_tile.dart rename to lib/modules/settings/modules/logs/widgets/clear_tile.dart index 5084bea6..bb6e9d84 100644 --- a/lib/modules/settings/widgets/general/logs/clear_tile.dart +++ b/lib/modules/settings/modules/logs/widgets/clear_tile.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralClearLogsTile extends StatelessWidget { +class SettingsLogsClearTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( - title: LSTitle(text: 'Clear Logs'), + title: LSTitle(text: 'Clear'), subtitle: LSSubtitle(text: 'Clear All Recorded Logs'), trailing: LSIconButton(icon: Icons.delete), onTap: () async => _clearLogs(context), diff --git a/lib/modules/settings/widgets/general/logs/export_tile.dart b/lib/modules/settings/modules/logs/widgets/export_tile.dart similarity index 87% rename from lib/modules/settings/widgets/general/logs/export_tile.dart rename to lib/modules/settings/modules/logs/widgets/export_tile.dart index d1aff097..11acd803 100644 --- a/lib/modules/settings/widgets/general/logs/export_tile.dart +++ b/lib/modules/settings/modules/logs/widgets/export_tile.dart @@ -2,10 +2,10 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralExportLogsTile extends StatelessWidget { +class SettingsLogsExportTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( - title: LSTitle(text: 'Export Logs'), + title: LSTitle(text: 'Export'), subtitle: LSSubtitle(text: 'Export All Recorded Logs'), trailing: LSIconButton(icon: Icons.file_download), onTap: () async => _exportLogs(context), diff --git a/lib/modules/settings/modules/logs_details.dart b/lib/modules/settings/modules/logs_details.dart new file mode 100644 index 00000000..dcbcb333 --- /dev/null +++ b/lib/modules/settings/modules/logs_details.dart @@ -0,0 +1,2 @@ +export 'logs_details/route.dart'; +export 'logs_details/widgets.dart'; diff --git a/lib/modules/settings/modules/logs_details/route.dart b/lib/modules/settings/modules/logs_details/route.dart new file mode 100644 index 00000000..f073225a --- /dev/null +++ b/lib/modules/settings/modules/logs_details/route.dart @@ -0,0 +1,92 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:f_logs/f_logs.dart' as FLog; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsLogsDetailsRouteArguments { + final String type; + + SettingsLogsDetailsRouteArguments({ + @required this.type, + }); +} + +class SettingsLogsDetailsRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/logs/details'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + SettingsLogsDetailsRouteArguments _arguments; + List levels = []; + + @override + void initState() { + super.initState(); + SchedulerBinding.instance.scheduleFrameCallback((_) async { + _arguments = ModalRoute.of(context).settings.arguments; + _setLogLevel(); + setState(() {}); + }); + } + + void _setLogLevel() { + switch(_arguments?.type) { + case 'All': levels = []; break; + case 'Warning': levels = [FLog.LogLevel.WARNING.toString()]; break; + case 'Error': levels = [FLog.LogLevel.ERROR.toString()]; break; + case 'Fatal': levels = [FLog.LogLevel.FATAL.toString()]; break; + default: levels = []; break; + } + } + + @override + Widget build(BuildContext context) => _arguments == null + ? Scaffold() + : Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: '${_arguments?.type ?? 'Unknown'} Logs'); + + Widget get _body => FutureBuilder( + future: FLog.FLog.getAllLogsByFilter(logLevels: levels), + builder: (BuildContext context, AsyncSnapshot> snapshot) { + switch(snapshot.connectionState) { + case ConnectionState.done: + if(snapshot.hasError) { + Logger.error( + 'SettingsLogsDetailsRoute', + '_body', + 'Unable to fetch logs', + snapshot.error, + StackTrace.current, + ); + return LSErrorMessage(onTapHandler: () => {}); + } + if(snapshot.hasData) return snapshot.data.length == 0 + ? _noLogs + : _list(snapshot.data); + break; + case ConnectionState.none: + case ConnectionState.waiting: + case ConnectionState.active: + default: return LSLoader(); + } + return LSLoader(); + }, + ); + + Widget _list(List logs) => LSListViewBuilder( + itemCount: logs.length, + itemBuilder: (context, index) => SettingsLogsDetailsLogTile(log: logs[index]) + ); + + Widget get _noLogs => LSGenericMessage(text: 'No Logs Found'); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/logs_details/widgets.dart b/lib/modules/settings/modules/logs_details/widgets.dart new file mode 100644 index 00000000..10629077 --- /dev/null +++ b/lib/modules/settings/modules/logs_details/widgets.dart @@ -0,0 +1 @@ +export 'widgets/log_tile.dart'; diff --git a/lib/modules/settings/modules/logs_details/widgets/log_tile.dart b/lib/modules/settings/modules/logs_details/widgets/log_tile.dart new file mode 100644 index 00000000..3156270e --- /dev/null +++ b/lib/modules/settings/modules/logs_details/widgets/log_tile.dart @@ -0,0 +1,123 @@ +import 'package:expandable/expandable.dart'; +import 'package:f_logs/f_logs.dart' as FLog; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsLogsDetailsLogTile extends StatelessWidget { + final FLog.Log log; + final ExpandableController _controller = ExpandableController(); + + SettingsLogsDetailsLogTile({ + @required this.log, + }); + + @override + Widget build(BuildContext context) => LSExpandable( + controller: _controller, + collapsed: _collapsed(context), + expanded: _expanded(context), + ); + + Widget _collapsed(BuildContext context) => LSCardTile( + title: LSTitle(text: log.text), + subtitle: RichText( + text: TextSpan( + style: TextStyle( + fontSize: Constants.UI_FONT_SIZE_SUBTITLE, + color: Colors.white70, + ), + children: [ + TextSpan(text: log.timestamp), + TextSpan(text: '\n'), + TextSpan( + style: TextStyle( + color: log.logLevel.lsFLogLogLevel_color(), + fontWeight: FontWeight.bold, + ), + text: log.logLevel.lsFLogLogLevel_name(), + ) + ], + ), + ), + padContent: true, + onTap: () => _controller.toggle(), + + ); + + Widget _expanded(BuildContext context) => LSCard( + child: InkWell( + child: Row( + children: [ + Expanded( + child: Padding( + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + LSTitle(text: log.text, softWrap: true, maxLines: 12), + Padding( + child: Wrap( + direction: Axis.horizontal, + runSpacing: 10.0, + children: [ + LSTextHighlighted( + text: log.logLevel.lsFLogLogLevel_name(), + bgColor: log.logLevel.lsFLogLogLevel_color(), + ), + ], + ), + padding: EdgeInsets.only(top: 8.0, bottom: 2.0), + ), + Padding( + child: RichText( + text: TextSpan( + style: TextStyle( + color: Colors.white70, + fontSize: Constants.UI_FONT_SIZE_SUBTITLE, + ), + children: [ + TextSpan(text: log.timestamp), + TextSpan(text: '\n'), + TextSpan(text: log.className), + TextSpan(text: '\n'), + TextSpan(text: log.methodName), + ], + ), + ), + padding: EdgeInsets.only(top: 6.0, bottom: 10.0), + ), + Padding( + child: Row( + mainAxisSize: MainAxisSize.min, + children: [ + Expanded( + child: LSButtonSlim( + text: 'Exception', + backgroundColor: LSColors.red, + onTap: () async => GlobalDialogs.textPreview(context, 'Exception', log?.exception ?? 'Unavailable', alignLeft: true), + margin: EdgeInsets.only(right: 6.0), + ), + ), + Expanded( + child: LSButtonSlim( + text: 'Stack Trace', + backgroundColor: LSColors.blue, + onTap: () async => GlobalDialogs.textPreview(context, 'Stack Trace', log?.stacktrace ?? 'Unavailable', alignLeft: true), + margin: EdgeInsets.only(left: 6.0), + ), + ), + ], + ), + padding: EdgeInsets.only(bottom: 2.0), + ), + ], + ), + padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0), + ), + ), + ], + ), + borderRadius: BorderRadius.circular(Constants.UI_BORDER_RADIUS), + onTap: () => _controller.toggle(), + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules.dart b/lib/modules/settings/modules/modules.dart new file mode 100644 index 00000000..36b205e5 --- /dev/null +++ b/lib/modules/settings/modules/modules.dart @@ -0,0 +1,2 @@ +export 'modules/route.dart'; +export 'modules/widgets.dart'; diff --git a/lib/modules/settings/modules/modules/route.dart b/lib/modules/settings/modules/modules/route.dart new file mode 100644 index 00000000..8189b67d --- /dev/null +++ b/lib/modules/settings/modules/modules/route.dart @@ -0,0 +1,77 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules.dart'; + +class SettingsModulesRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules'; + + SettingsModulesRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State with AutomaticKeepAliveClientMixin { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + super.build(context); + return Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + } + + Widget get _appBar => LSAppBar( + title: 'Modules', + actions: [ + SettingsModulesEnabledProfileButton(), + ], + ); + + Widget get _body => LSListView( + children: [ + ..._general, + LSDivider(), + ..._automation, + LSDivider(), + ..._clients, + LSDivider(), + ..._monitoring, + ], + ); + + List get _general => [ + _tileFromModuleMap(SearchConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesSearchRoute.ROUTE_NAME)), + _tileFromModuleMap(WakeOnLANConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesWakeOnLANRoute.ROUTE_NAME)), + ]; + + List get _automation => [ + _tileFromModuleMap(LidarrConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesLidarrRoute.ROUTE_NAME)), + _tileFromModuleMap(RadarrConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesRadarrRoute.ROUTE_NAME)), + _tileFromModuleMap(SonarrConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesSonarrRoute.ROUTE_NAME)), + ]; + + List get _clients => [ + _tileFromModuleMap(NZBGetConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesNZBGetRoute.ROUTE_NAME)), + _tileFromModuleMap(SABnzbdConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesSABnzbdRoute.ROUTE_NAME)), + ]; + + List get _monitoring => [ + _tileFromModuleMap(TautulliConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesTautulliRoute.ROUTE_NAME)), + ]; + + Widget _tileFromModuleMap(ModuleMap map, Function onTap) => LSCardTile( + title: LSTitle(text: map.name), + subtitle: LSSubtitle(text: map.settingsDescription), + trailing: LSIconButton(icon: map.icon), + onTap: onTap, + ); +} diff --git a/lib/modules/settings/modules/modules/widgets.dart b/lib/modules/settings/modules/modules/widgets.dart new file mode 100644 index 00000000..30e51b8f --- /dev/null +++ b/lib/modules/settings/modules/modules/widgets.dart @@ -0,0 +1 @@ +export 'widgets/enabled_profile.dart'; diff --git a/lib/modules/settings/modules/modules/widgets/enabled_profile.dart b/lib/modules/settings/modules/modules/widgets/enabled_profile.dart new file mode 100644 index 00000000..a91a62fc --- /dev/null +++ b/lib/modules/settings/modules/modules/widgets/enabled_profile.dart @@ -0,0 +1,30 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesEnabledProfileButton extends StatelessWidget { + @override + Widget build(BuildContext context) => LSIconButton( + icon: Icons.person, + onPressed: () async => _changeProfile(context), + ); + + Future _changeProfile(BuildContext context) async { + List values = await SettingsDialogs.enabledProfile( + context, + Database.profilesBox.keys.map((x) => x as String).toList()..sort((a,b) => a.toLowerCase().compareTo(b.toLowerCase())), + ); + if(values[0]) { + if(values[1] != LunaSeaDatabaseValue.ENABLED_PROFILE.data) { + LunaSeaDatabaseValue.ENABLED_PROFILE.put(values[1]); + Providers.reset(context); + } + LSSnackBar( + context: context, + title: 'Changed Profile', + message: 'Using profile "${values[1]}"', + type: SNACKBAR_TYPE.info, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_lidarr.dart b/lib/modules/settings/modules/modules_lidarr.dart new file mode 100644 index 00000000..c2115b91 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr.dart @@ -0,0 +1,2 @@ +export 'modules_lidarr/route.dart'; +export 'modules_lidarr/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_lidarr/route.dart b/lib/modules/settings/modules/modules_lidarr/route.dart new file mode 100644 index 00000000..f684d62b --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/route.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/lidarr'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Lidarr', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationLidarrRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + LSDivider(), + SettingsModulesLidarrTestConnectionTile(), + ..._advanced, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesLidarrEnabledTile(), + SettingsModulesLidarrHostTile(), + SettingsModulesLidarrAPIKeyTile(), + ]; + + List get _advanced => [ + LSHeader( + text: 'Advanced', + subtitle: 'Options for non-standard networking configurations', + ), + SettingsModulesLidarrCustomHeadersTile(), + SettingsModulesLidarrStrictTLSTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_lidarr/widgets.dart b/lib/modules/settings/modules/modules_lidarr/widgets.dart new file mode 100644 index 00000000..84d587e2 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets.dart @@ -0,0 +1,6 @@ +export 'widgets/apikey_tile.dart'; +export 'widgets/custom_headers_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/host_tile.dart'; +export 'widgets/strict_tls_tile.dart'; +export 'widgets/test_connection_tile.dart'; diff --git a/lib/modules/settings/modules/modules_lidarr/widgets/apikey_tile.dart b/lib/modules/settings/modules/modules_lidarr/widgets/apikey_tile.dart new file mode 100644 index 00000000..0b56bee8 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets/apikey_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesLidarrAPIKeyTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'API Key'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.lidarrKey == null || Database.currentProfileObject.lidarrKey == '' + ? 'Not Set' + : '••••••••••••' + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeKey(context), + ); + + Future _changeKey(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'Lidarr API Key', + prefill: Database.currentProfileObject.lidarrKey ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.lidarrKey = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_lidarr/widgets/custom_headers_tile.dart b/lib/modules/settings/modules/modules_lidarr/widgets/custom_headers_tile.dart new file mode 100644 index 00000000..dfdab28f --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets/custom_headers_tile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrCustomHeadersTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesLidarrHeadersRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_lidarr/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_lidarr/widgets/enabled_tile.dart new file mode 100644 index 00000000..c80ca87e --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesLidarrEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable Lidarr'), + trailing: Switch( + value: Database.currentProfileObject.lidarrEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.lidarrEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_lidarr/widgets/host_tile.dart b/lib/modules/settings/modules/modules_lidarr/widgets/host_tile.dart new file mode 100644 index 00000000..b2ee6f80 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets/host_tile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrHostTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Host'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.lidarrHost == null || Database.currentProfileObject.lidarrHost == '' + ? 'Not Set' + : Database.currentProfileObject.lidarrHost + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeHost(context), + ); + + Future _changeHost(BuildContext context) async { + List _values = await SettingsDialogs.editHost( + context, + 'Lidarr Host', + prefill: Database.currentProfileObject.lidarrHost ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.lidarrHost = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_lidarr/widgets/strict_tls_tile.dart b/lib/modules/settings/modules/modules_lidarr/widgets/strict_tls_tile.dart new file mode 100644 index 00000000..53f77a9e --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets/strict_tls_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrStrictTLSTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Strict SSL/TLS Validation'), + subtitle: LSSubtitle(text: 'For Invalid Certificates'), + trailing: Switch( + value: Database.currentProfileObject.lidarrStrictTLS ?? true, + onChanged: (value) async => _onChanged(context, value), + ), + ); + + Future _onChanged(BuildContext context, bool value) async { + if(value) { + Database.currentProfileObject.lidarrStrictTLS = value; + Database.currentProfileObject.save(context: context); + } else { + List _values = await SettingsDialogs.toggleStrictTLS(context); + if(_values[0]) { + Database.currentProfileObject.lidarrStrictTLS = value; + Database.currentProfileObject.save(context: context); + } + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_lidarr/widgets/test_connection_tile.dart b/lib/modules/settings/modules/modules_lidarr/widgets/test_connection_tile.dart new file mode 100644 index 00000000..c53ad968 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr/widgets/test_connection_tile.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/lidarr.dart'; + +class SettingsModulesLidarrTestConnectionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Test Connection', + onTap: () async => _testConnection(context), + ); + + Future _testConnection(BuildContext context) async => await LidarrAPI.from(Database.currentProfileObject).testConnection() + ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'Lidarr is ready to use with LunaSea', type: SNACKBAR_TYPE.success) + : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); +} diff --git a/lib/modules/settings/modules/modules_lidarr_headers.dart b/lib/modules/settings/modules/modules_lidarr_headers.dart new file mode 100644 index 00000000..c5cacbd7 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr_headers.dart @@ -0,0 +1,2 @@ +export 'modules_lidarr_headers/route.dart'; +export 'modules_lidarr_headers/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_lidarr_headers/route.dart b/lib/modules/settings/modules/modules_lidarr_headers/route.dart new file mode 100644 index 00000000..0eddd73a --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr_headers/route.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/lidarr/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, profile, _) => LSListView( + children: _headers, + ), + ); + + List get _headers => [ + if((Database.currentProfileObject.lidarrHeaders ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + SettingsModulesLidarrHeadersAddHeaderTile(), + ]; + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (Database.currentProfileObject.lidarrHeaders ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(SettingsModulesLidarrHeadersHeaderTile( + headerKey: key.toString(), + headerValue: value.toString(), + ))); + list.sort((a,b) => a.headerKey.toLowerCase().compareTo(b.headerKey.toLowerCase())); + return list; + } +} diff --git a/lib/modules/settings/modules/modules_lidarr_headers/widgets.dart b/lib/modules/settings/modules/modules_lidarr_headers/widgets.dart new file mode 100644 index 00000000..fc17a9b4 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr_headers/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/add_header_tile.dart'; +export 'widgets/header_tile.dart'; diff --git a/lib/modules/settings/modules/modules_lidarr_headers/widgets/add_header_tile.dart b/lib/modules/settings/modules/modules_lidarr_headers/widgets/add_header_tile.dart new file mode 100644 index 00000000..3daa57c3 --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr_headers/widgets/add_header_tile.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrHeadersAddHeaderTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Add Header', + onTap: () async => _addPrompt(context), + ); + + Future _addPrompt(BuildContext context) async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesLidarrHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.lidarrHeaders ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + Database.currentProfileObject.lidarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.lidarrHeaders ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + Database.currentProfileObject.lidarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_lidarr_headers/widgets/header_tile.dart b/lib/modules/settings/modules/modules_lidarr_headers/widgets/header_tile.dart new file mode 100644 index 00000000..0378a94f --- /dev/null +++ b/lib/modules/settings/modules/modules_lidarr_headers/widgets/header_tile.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesLidarrHeadersHeaderTile extends StatelessWidget { + final String headerKey; + final String headerValue; + + SettingsModulesLidarrHeadersHeaderTile({ + @required this.headerKey, + @required this.headerValue, + }); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: headerKey), + subtitle: LSSubtitle(text: headerValue), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _deleteHeader(context), + ), + ); + + Future _deleteHeader(BuildContext context) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.lidarrHeaders ?? {}).cast(); + _headers.remove(headerKey); + Database.currentProfileObject.lidarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + LSSnackBar( + context: context, + message: headerKey, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_nzbget.dart b/lib/modules/settings/modules/modules_nzbget.dart new file mode 100644 index 00000000..f642a359 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget.dart @@ -0,0 +1,2 @@ +export 'modules_nzbget/route.dart'; +export 'modules_nzbget/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_nzbget/route.dart b/lib/modules/settings/modules/modules_nzbget/route.dart new file mode 100644 index 00000000..8aa0789b --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/route.dart @@ -0,0 +1,64 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/nzbget'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'NZBGet', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationNZBGetRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + LSDivider(), + SettingsModulesNZBGetTestConnectionTile(), + ..._advanced, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesNZBGetEnabledTile(), + SettingsModulesNZBGetHostTile(), + SettingsModulesNZBGetUsernameTile(), + SettingsModulesNZBGetPasswordTile(), + + ]; + + List get _advanced => [ + LSHeader( + text: 'Advanced', + subtitle: 'Options for non-standard networking configurations', + ), + SettingsModulesNZBGetCustomHeadersTile(), + SettingsModulesNZBGetStrictTLSTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_nzbget/widgets.dart b/lib/modules/settings/modules/modules_nzbget/widgets.dart new file mode 100644 index 00000000..206523ed --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets.dart @@ -0,0 +1,7 @@ +export 'widgets/username_tile.dart'; +export 'widgets/custom_headers_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/host_tile.dart'; +export 'widgets/password_tile.dart'; +export 'widgets/strict_tls_tile.dart'; +export 'widgets/test_connection_tile.dart'; diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/custom_headers_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/custom_headers_tile.dart new file mode 100644 index 00000000..97299bec --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/custom_headers_tile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetCustomHeadersTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesNZBGetHeadersRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/enabled_tile.dart new file mode 100644 index 00000000..5c2915d8 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesNZBGetEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable NZBGet'), + trailing: Switch( + value: Database.currentProfileObject.nzbgetEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.nzbgetEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/host_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/host_tile.dart new file mode 100644 index 00000000..6e819238 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/host_tile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetHostTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Host'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.nzbgetHost == null || Database.currentProfileObject.nzbgetHost == '' + ? 'Not Set' + : Database.currentProfileObject.nzbgetHost + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeHost(context), + ); + + Future _changeHost(BuildContext context) async { + List _values = await SettingsDialogs.editHost( + context, + 'NZBGet Host', + prefill: Database.currentProfileObject.nzbgetHost ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.nzbgetHost = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/password_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/password_tile.dart new file mode 100644 index 00000000..6e1bc321 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/password_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesNZBGetPasswordTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Password'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.nzbgetPass == null || Database.currentProfileObject.nzbgetPass == '' + ? 'Not Set' + : '••••••••••••' + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changePassword(context), + ); + + Future _changePassword(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'NZBGet Password', + prefill: Database.currentProfileObject.nzbgetPass ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.nzbgetPass = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/strict_tls_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/strict_tls_tile.dart new file mode 100644 index 00000000..6cce218e --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/strict_tls_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetStrictTLSTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Strict SSL/TLS Validation'), + subtitle: LSSubtitle(text: 'For Invalid Certificates'), + trailing: Switch( + value: Database.currentProfileObject.nzbgetStrictTLS ?? true, + onChanged: (value) async => _onChanged(context, value), + ), + ); + + Future _onChanged(BuildContext context, bool value) async { + if(value) { + Database.currentProfileObject.nzbgetStrictTLS = value; + Database.currentProfileObject.save(context: context); + } else { + List _values = await SettingsDialogs.toggleStrictTLS(context); + if(_values[0]) { + Database.currentProfileObject.nzbgetStrictTLS = value; + Database.currentProfileObject.save(context: context); + } + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/test_connection_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/test_connection_tile.dart new file mode 100644 index 00000000..a6e57a6e --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/test_connection_tile.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/nzbget.dart'; + +class SettingsModulesNZBGetTestConnectionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Test Connection', + onTap: () async => _testConnection(context), + ); + + Future _testConnection(BuildContext context) async => await NZBGetAPI.from(Database.currentProfileObject).testConnection() + ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'NZBGet is ready to use with LunaSea', type: SNACKBAR_TYPE.success) + : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); +} diff --git a/lib/modules/settings/modules/modules_nzbget/widgets/username_tile.dart b/lib/modules/settings/modules/modules_nzbget/widgets/username_tile.dart new file mode 100644 index 00000000..291b0640 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget/widgets/username_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesNZBGetUsernameTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Username'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.nzbgetUser == null || Database.currentProfileObject.nzbgetUser == '' + ? 'Not Set' + : Database.currentProfileObject.nzbgetUser + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeUsername(context), + ); + + Future _changeUsername(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'NZBGet Username', + prefill: Database.currentProfileObject.nzbgetUser ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.nzbgetUser = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} diff --git a/lib/modules/settings/modules/modules_nzbget_headers.dart b/lib/modules/settings/modules/modules_nzbget_headers.dart new file mode 100644 index 00000000..959e5aaf --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget_headers.dart @@ -0,0 +1,2 @@ +export 'modules_nzbget_headers/route.dart'; +export 'modules_nzbget_headers/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_nzbget_headers/route.dart b/lib/modules/settings/modules/modules_nzbget_headers/route.dart new file mode 100644 index 00000000..806e8261 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget_headers/route.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/nzbget/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, profile, _) => LSListView( + children: _headers, + ), + ); + + List get _headers => [ + if((Database.currentProfileObject.nzbgetHeaders ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + SettingsModulesNZBGetHeadersAddHeaderTile(), + ]; + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (Database.currentProfileObject.nzbgetHeaders ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(SettingsModulesNZBGetHeadersHeaderTile( + headerKey: key.toString(), + headerValue: value.toString(), + ))); + list.sort((a,b) => a.headerKey.toLowerCase().compareTo(b.headerKey.toLowerCase())); + return list; + } +} diff --git a/lib/modules/settings/modules/modules_nzbget_headers/widgets.dart b/lib/modules/settings/modules/modules_nzbget_headers/widgets.dart new file mode 100644 index 00000000..fc17a9b4 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget_headers/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/add_header_tile.dart'; +export 'widgets/header_tile.dart'; diff --git a/lib/modules/settings/modules/modules_nzbget_headers/widgets/add_header_tile.dart b/lib/modules/settings/modules/modules_nzbget_headers/widgets/add_header_tile.dart new file mode 100644 index 00000000..05b27959 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget_headers/widgets/add_header_tile.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetHeadersAddHeaderTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Add Header', + onTap: () async => _addPrompt(context), + ); + + Future _addPrompt(BuildContext context) async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesNZBGetHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.nzbgetHeaders ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + Database.currentProfileObject.nzbgetHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.nzbgetHeaders ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + Database.currentProfileObject.nzbgetHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_nzbget_headers/widgets/header_tile.dart b/lib/modules/settings/modules/modules_nzbget_headers/widgets/header_tile.dart new file mode 100644 index 00000000..3c67d788 --- /dev/null +++ b/lib/modules/settings/modules/modules_nzbget_headers/widgets/header_tile.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesNZBGetHeadersHeaderTile extends StatelessWidget { + final String headerKey; + final String headerValue; + + SettingsModulesNZBGetHeadersHeaderTile({ + @required this.headerKey, + @required this.headerValue, + }); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: headerKey), + subtitle: LSSubtitle(text: headerValue), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _deleteHeader(context), + ), + ); + + Future _deleteHeader(BuildContext context) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.nzbgetHeaders ?? {}).cast(); + _headers.remove(headerKey); + Database.currentProfileObject.nzbgetHeaders = _headers; + Database.currentProfileObject.save(context: context); + LSSnackBar( + context: context, + message: headerKey, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_radarr.dart b/lib/modules/settings/modules/modules_radarr.dart new file mode 100644 index 00000000..eff04074 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr.dart @@ -0,0 +1,2 @@ +export 'modules_radarr/route.dart'; +export 'modules_radarr/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_radarr/route.dart b/lib/modules/settings/modules/modules_radarr/route.dart new file mode 100644 index 00000000..25326ea8 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/route.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/radarr'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Radarr', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationRadarrRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + LSDivider(), + SettingsModulesRadarrTestConnectionTile(), + ..._advanced, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesRadarrEnabledTile(), + SettingsModulesRadarrHostTile(), + SettingsModulesRadarrAPIKeyTile(), + ]; + + List get _advanced => [ + LSHeader( + text: 'Advanced', + subtitle: 'Options for non-standard networking configurations', + ), + SettingsModulesRadarrCustomHeadersTile(), + SettingsModulesRadarrStrictTLSTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_radarr/widgets.dart b/lib/modules/settings/modules/modules_radarr/widgets.dart new file mode 100644 index 00000000..84d587e2 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets.dart @@ -0,0 +1,6 @@ +export 'widgets/apikey_tile.dart'; +export 'widgets/custom_headers_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/host_tile.dart'; +export 'widgets/strict_tls_tile.dart'; +export 'widgets/test_connection_tile.dart'; diff --git a/lib/modules/settings/modules/modules_radarr/widgets/apikey_tile.dart b/lib/modules/settings/modules/modules_radarr/widgets/apikey_tile.dart new file mode 100644 index 00000000..b199d448 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets/apikey_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesRadarrAPIKeyTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'API Key'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.radarrKey == null || Database.currentProfileObject.radarrKey == '' + ? 'Not Set' + : '••••••••••••' + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeKey(context), + ); + + Future _changeKey(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'Radarr API Key', + prefill: Database.currentProfileObject.radarrKey ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.radarrKey = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_radarr/widgets/custom_headers_tile.dart b/lib/modules/settings/modules/modules_radarr/widgets/custom_headers_tile.dart new file mode 100644 index 00000000..d2e35c81 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets/custom_headers_tile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrCustomHeadersTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesRadarrHeadersRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_radarr/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_radarr/widgets/enabled_tile.dart new file mode 100644 index 00000000..21ff2d91 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesRadarrEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable Radarr'), + trailing: Switch( + value: Database.currentProfileObject.radarrEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.radarrEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_radarr/widgets/host_tile.dart b/lib/modules/settings/modules/modules_radarr/widgets/host_tile.dart new file mode 100644 index 00000000..751737a6 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets/host_tile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrHostTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Host'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.radarrHost == null || Database.currentProfileObject.radarrHost == '' + ? 'Not Set' + : Database.currentProfileObject.radarrHost + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeHost(context), + ); + + Future _changeHost(BuildContext context) async { + List _values = await SettingsDialogs.editHost( + context, + 'Radarr Host', + prefill: Database.currentProfileObject.radarrHost ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.radarrHost = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_radarr/widgets/strict_tls_tile.dart b/lib/modules/settings/modules/modules_radarr/widgets/strict_tls_tile.dart new file mode 100644 index 00000000..ebbeff92 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets/strict_tls_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrStrictTLSTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Strict SSL/TLS Validation'), + subtitle: LSSubtitle(text: 'For Invalid Certificates'), + trailing: Switch( + value: Database.currentProfileObject.radarrStrictTLS ?? true, + onChanged: (value) async => _onChanged(context, value), + ), + ); + + Future _onChanged(BuildContext context, bool value) async { + if(value) { + Database.currentProfileObject.radarrStrictTLS = value; + Database.currentProfileObject.save(context: context); + } else { + List _values = await SettingsDialogs.toggleStrictTLS(context); + if(_values[0]) { + Database.currentProfileObject.radarrStrictTLS = value; + Database.currentProfileObject.save(context: context); + } + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_radarr/widgets/test_connection_tile.dart b/lib/modules/settings/modules/modules_radarr/widgets/test_connection_tile.dart new file mode 100644 index 00000000..ec826f42 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr/widgets/test_connection_tile.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/radarr.dart'; + +class SettingsModulesRadarrTestConnectionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Test Connection', + onTap: () async => _testConnection(context), + ); + + Future _testConnection(BuildContext context) async => await RadarrAPI.from(Database.currentProfileObject).testConnection() + ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'Radarr is ready to use with LunaSea', type: SNACKBAR_TYPE.success) + : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); +} diff --git a/lib/modules/settings/modules/modules_radarr_headers.dart b/lib/modules/settings/modules/modules_radarr_headers.dart new file mode 100644 index 00000000..60d88556 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr_headers.dart @@ -0,0 +1,2 @@ +export 'modules_radarr_headers/route.dart'; +export 'modules_radarr_headers/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_radarr_headers/route.dart b/lib/modules/settings/modules/modules_radarr_headers/route.dart new file mode 100644 index 00000000..51dac3c4 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr_headers/route.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/radarr/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, profile, _) => LSListView( + children: _headers, + ), + ); + + List get _headers => [ + if((Database.currentProfileObject.radarrHeaders ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + SettingsModulesRadarrHeadersAddHeaderTile(), + ]; + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (Database.currentProfileObject.radarrHeaders ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(SettingsModulesRadarrHeadersHeaderTile( + headerKey: key.toString(), + headerValue: value.toString(), + ))); + list.sort((a,b) => a.headerKey.toLowerCase().compareTo(b.headerKey.toLowerCase())); + return list; + } +} diff --git a/lib/modules/settings/modules/modules_radarr_headers/widgets.dart b/lib/modules/settings/modules/modules_radarr_headers/widgets.dart new file mode 100644 index 00000000..fc17a9b4 --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr_headers/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/add_header_tile.dart'; +export 'widgets/header_tile.dart'; diff --git a/lib/modules/settings/modules/modules_radarr_headers/widgets/add_header_tile.dart b/lib/modules/settings/modules/modules_radarr_headers/widgets/add_header_tile.dart new file mode 100644 index 00000000..4f6ceeac --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr_headers/widgets/add_header_tile.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrHeadersAddHeaderTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Add Header', + onTap: () async => _addPrompt(context), + ); + + Future _addPrompt(BuildContext context) async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesRadarrHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.radarrHeaders ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + Database.currentProfileObject.radarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.radarrHeaders ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + Database.currentProfileObject.radarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_radarr_headers/widgets/header_tile.dart b/lib/modules/settings/modules/modules_radarr_headers/widgets/header_tile.dart new file mode 100644 index 00000000..ba44865e --- /dev/null +++ b/lib/modules/settings/modules/modules_radarr_headers/widgets/header_tile.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesRadarrHeadersHeaderTile extends StatelessWidget { + final String headerKey; + final String headerValue; + + SettingsModulesRadarrHeadersHeaderTile({ + @required this.headerKey, + @required this.headerValue, + }); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: headerKey), + subtitle: LSSubtitle(text: headerValue), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _deleteHeader(context), + ), + ); + + Future _deleteHeader(BuildContext context) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.radarrHeaders ?? {}).cast(); + _headers.remove(headerKey); + Database.currentProfileObject.radarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + LSSnackBar( + context: context, + message: headerKey, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_sabnzbd.dart b/lib/modules/settings/modules/modules_sabnzbd.dart new file mode 100644 index 00000000..62c56b90 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd.dart @@ -0,0 +1,2 @@ +export 'modules_sabnzbd/route.dart'; +export 'modules_sabnzbd/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_sabnzbd/route.dart b/lib/modules/settings/modules/modules_sabnzbd/route.dart new file mode 100644 index 00000000..eac25f56 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/route.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/sabnzbd'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'SABnzbd', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationSABnzbdRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + LSDivider(), + SettingsModulesSABnzbdTestConnectionTile(), + ..._advanced, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesSABnzbdEnabledTile(), + SettingsModulesSABnzbdHostTile(), + SettingsModulesSABnzbdAPIKeyTile(), + ]; + + List get _advanced => [ + LSHeader( + text: 'Advanced', + subtitle: 'Options for non-standard networking configurations', + ), + SettingsModulesSABnzbdCustomHeadersTile(), + SettingsModulesSABnzbdStrictTLSTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets.dart new file mode 100644 index 00000000..84d587e2 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets.dart @@ -0,0 +1,6 @@ +export 'widgets/apikey_tile.dart'; +export 'widgets/custom_headers_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/host_tile.dart'; +export 'widgets/strict_tls_tile.dart'; +export 'widgets/test_connection_tile.dart'; diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets/apikey_tile.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets/apikey_tile.dart new file mode 100644 index 00000000..c8bec585 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets/apikey_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesSABnzbdAPIKeyTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'API Key'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.sabnzbdKey == null || Database.currentProfileObject.sabnzbdKey == '' + ? 'Not Set' + : '••••••••••••' + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeKey(context), + ); + + Future _changeKey(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'SABnzbd API Key', + prefill: Database.currentProfileObject.sabnzbdKey ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.sabnzbdKey = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets/custom_headers_tile.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets/custom_headers_tile.dart new file mode 100644 index 00000000..4d31b606 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets/custom_headers_tile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdCustomHeadersTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesSABnzbdHeadersRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets/enabled_tile.dart new file mode 100644 index 00000000..e8185032 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesSABnzbdEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable SABnzbd'), + trailing: Switch( + value: Database.currentProfileObject.sabnzbdEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.sabnzbdEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets/host_tile.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets/host_tile.dart new file mode 100644 index 00000000..ef45eac2 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets/host_tile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdHostTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Host'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.sabnzbdHost == null || Database.currentProfileObject.sabnzbdHost == '' + ? 'Not Set' + : Database.currentProfileObject.sabnzbdHost + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeHost(context), + ); + + Future _changeHost(BuildContext context) async { + List _values = await SettingsDialogs.editHost( + context, + 'SABnzbd Host', + prefill: Database.currentProfileObject.sabnzbdHost ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.sabnzbdHost = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets/strict_tls_tile.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets/strict_tls_tile.dart new file mode 100644 index 00000000..f6e703a7 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets/strict_tls_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdStrictTLSTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Strict SSL/TLS Validation'), + subtitle: LSSubtitle(text: 'For Invalid Certificates'), + trailing: Switch( + value: Database.currentProfileObject.sabnzbdStrictTLS ?? true, + onChanged: (value) async => _onChanged(context, value), + ), + ); + + Future _onChanged(BuildContext context, bool value) async { + if(value) { + Database.currentProfileObject.sabnzbdStrictTLS = value; + Database.currentProfileObject.save(context: context); + } else { + List _values = await SettingsDialogs.toggleStrictTLS(context); + if(_values[0]) { + Database.currentProfileObject.sabnzbdStrictTLS = value; + Database.currentProfileObject.save(context: context); + } + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sabnzbd/widgets/test_connection_tile.dart b/lib/modules/settings/modules/modules_sabnzbd/widgets/test_connection_tile.dart new file mode 100644 index 00000000..9ae3462f --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd/widgets/test_connection_tile.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sabnzbd.dart'; + +class SettingsModulesSABnzbdTestConnectionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Test Connection', + onTap: () async => _testConnection(context), + ); + + Future _testConnection(BuildContext context) async => await SABnzbdAPI.from(Database.currentProfileObject).testConnection() + ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'SABnzbd is ready to use with LunaSea', type: SNACKBAR_TYPE.success) + : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); +} diff --git a/lib/modules/settings/modules/modules_sabnzbd_headers.dart b/lib/modules/settings/modules/modules_sabnzbd_headers.dart new file mode 100644 index 00000000..690a7421 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd_headers.dart @@ -0,0 +1,2 @@ +export 'modules_sabnzbd_headers/route.dart'; +export 'modules_sabnzbd_headers/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_sabnzbd_headers/route.dart b/lib/modules/settings/modules/modules_sabnzbd_headers/route.dart new file mode 100644 index 00000000..3886d249 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd_headers/route.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/sabnzbd/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, profile, _) => LSListView( + children: _headers, + ), + ); + + List get _headers => [ + if((Database.currentProfileObject.sabnzbdHeaders ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + SettingsModulesSABnzbdHeadersAddHeaderTile(), + ]; + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (Database.currentProfileObject.sabnzbdHeaders ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(SettingsModulesSABnzbdHeadersHeaderTile( + headerKey: key.toString(), + headerValue: value.toString(), + ))); + list.sort((a,b) => a.headerKey.toLowerCase().compareTo(b.headerKey.toLowerCase())); + return list; + } +} diff --git a/lib/modules/settings/modules/modules_sabnzbd_headers/widgets.dart b/lib/modules/settings/modules/modules_sabnzbd_headers/widgets.dart new file mode 100644 index 00000000..fc17a9b4 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd_headers/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/add_header_tile.dart'; +export 'widgets/header_tile.dart'; diff --git a/lib/modules/settings/modules/modules_sabnzbd_headers/widgets/add_header_tile.dart b/lib/modules/settings/modules/modules_sabnzbd_headers/widgets/add_header_tile.dart new file mode 100644 index 00000000..1db3a075 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd_headers/widgets/add_header_tile.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdHeadersAddHeaderTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Add Header', + onTap: () async => _addPrompt(context), + ); + + Future _addPrompt(BuildContext context) async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesSABnzbdHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.sabnzbdHeaders ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + Database.currentProfileObject.sabnzbdHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.sabnzbdHeaders ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + Database.currentProfileObject.sabnzbdHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sabnzbd_headers/widgets/header_tile.dart b/lib/modules/settings/modules/modules_sabnzbd_headers/widgets/header_tile.dart new file mode 100644 index 00000000..1ba79744 --- /dev/null +++ b/lib/modules/settings/modules/modules_sabnzbd_headers/widgets/header_tile.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSABnzbdHeadersHeaderTile extends StatelessWidget { + final String headerKey; + final String headerValue; + + SettingsModulesSABnzbdHeadersHeaderTile({ + @required this.headerKey, + @required this.headerValue, + }); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: headerKey), + subtitle: LSSubtitle(text: headerValue), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _deleteHeader(context), + ), + ); + + Future _deleteHeader(BuildContext context) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.sabnzbdHeaders ?? {}).cast(); + _headers.remove(headerKey); + Database.currentProfileObject.sabnzbdHeaders = _headers; + Database.currentProfileObject.save(context: context); + LSSnackBar( + context: context, + message: headerKey, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_search.dart b/lib/modules/settings/modules/modules_search.dart new file mode 100644 index 00000000..787771a5 --- /dev/null +++ b/lib/modules/settings/modules/modules_search.dart @@ -0,0 +1,2 @@ +export 'modules_search/route.dart'; +export 'modules_search/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_search/route.dart b/lib/modules/settings/modules/modules_search/route.dart new file mode 100644 index 00000000..66ef9812 --- /dev/null +++ b/lib/modules/settings/modules/modules_search/route.dart @@ -0,0 +1,61 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSearchRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/search'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Search', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationSearchRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.indexersBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + LSHeader( + text: 'Newznab Indexers', + subtitle: 'Supports all standard newznab-based indexers, including NZBHydra2', + ), + if(Database.indexersBox.isEmpty) _noIndexers, + ..._indexerList, + LSDivider(), + _addIndexer, + ], + ), + ); + + List get _indexerList { + List list = List.generate(Database.indexersBox.length, (index) => SettingsModulesSearchIndexerTile( + indexer: Database.indexersBox.getAt(index), + )); + list.sort((a,b) => a.indexer.displayName.toLowerCase().trim().compareTo(b.indexer.displayName.toLowerCase().trim())); + return list; + } + + Widget get _noIndexers => LSGenericMessage(text: 'No Indexers Added'); + + Widget get _addIndexer => LSButton( + text: 'Add New Indexer', + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesSearchAddRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_search/widgets.dart b/lib/modules/settings/modules/modules_search/widgets.dart new file mode 100644 index 00000000..5a8f0042 --- /dev/null +++ b/lib/modules/settings/modules/modules_search/widgets.dart @@ -0,0 +1 @@ +export 'widgets/indexer_tile.dart'; diff --git a/lib/modules/settings/modules/modules_search/widgets/indexer_tile.dart b/lib/modules/settings/modules/modules_search/widgets/indexer_tile.dart new file mode 100644 index 00000000..fd185198 --- /dev/null +++ b/lib/modules/settings/modules/modules_search/widgets/indexer_tile.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSearchIndexerTile extends StatelessWidget { + final IndexerHiveObject indexer; + + SettingsModulesSearchIndexerTile({ + Key key, + @required this.indexer, + }) : super(key: key); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: indexer.displayName), + subtitle: LSSubtitle(text: indexer.host), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _enterIndexer(context), + ); + + Future _enterIndexer(BuildContext context) async => await Navigator.of(context).pushNamed( + SettingsModulesSearchEditRoute.ROUTE_NAME, + arguments: SettingsModulesSearchEditRouteArguments(indexer: indexer), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_search_add.dart b/lib/modules/settings/modules/modules_search_add.dart new file mode 100644 index 00000000..ceee7b53 --- /dev/null +++ b/lib/modules/settings/modules/modules_search_add.dart @@ -0,0 +1 @@ +export 'modules_search_add/route.dart'; diff --git a/lib/modules/settings/modules/modules_search_add/route.dart b/lib/modules/settings/modules/modules_search_add/route.dart new file mode 100644 index 00000000..9ee74ba1 --- /dev/null +++ b/lib/modules/settings/modules/modules_search_add/route.dart @@ -0,0 +1,124 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSearchAddRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/search/add'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + IndexerHiveObject indexer = IndexerHiveObject.empty(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Add Indexer'); + + Widget get _body => LSListView( + children: [ + _displayName, + _apiURL, + _apiKey, + _headers, + LSDivider(), + _addIndexer, + ], + ); + + Widget get _displayName => LSCardTile( + title: LSTitle(text: 'Display Name'), + subtitle: LSSubtitle( + text: indexer.displayName == null || indexer.displayName.isEmpty + ? 'Not Set' + : indexer.displayName, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + List _values = await GlobalDialogs.editText(context, 'Display Name', prefill: indexer.displayName); + setState(() => indexer.displayName = _values[0] + ? _values[1] + : indexer.displayName + ); + }, + ); + + Widget get _apiURL => LSCardTile( + title: LSTitle(text: 'Indexer API Host'), + subtitle: LSSubtitle( + text: indexer.host == null || indexer.host.isEmpty + ? 'Not Set' + : indexer.host, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + List _values = await GlobalDialogs.editText(context, 'Indexer API Host', prefill: indexer.host); + setState(() => indexer.host = _values[0] + ? _values[1] + : indexer.host + ); + }, + ); + + Widget get _apiKey => LSCardTile( + title: LSTitle(text: 'Indexer API Key'), + subtitle: LSSubtitle( + text: indexer.key == null || indexer.key.isEmpty + ? 'Not Set' + : indexer.key, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + List _values = await GlobalDialogs.editText(context, 'Indexer API Key', prefill: indexer.key); + setState(() => indexer.key = _values[0] + ? _values[1] + : indexer.key + ); + }, + ); + + Widget get _headers => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () => Navigator.of(context).pushNamed( + SettingsModulesSearchHeadersRoute.ROUTE_NAME, + arguments: SettingsModulesSearchHeadersRouteArguments( + indexer: indexer, + saveAfterAction: false, + ), + ), + ); + + Widget get _addIndexer => LSButton( + text: 'Add Indexer', + onTap: () async => _add(), + ); + + Future _add() async { + if(indexer.displayName == '' || indexer.host == '' || indexer.key == '') { + LSSnackBar( + context: context, + title: 'Failed to Add Indexer', + message: 'All fields are required', + type: SNACKBAR_TYPE.failure, + ); + } else { + Database.indexersBox.add(indexer); + LSSnackBar( + context: context, + title: 'Indexer Added', + message: indexer.displayName, + type: SNACKBAR_TYPE.success, + ); + Navigator.of(context).pop(); + } + } +} diff --git a/lib/modules/settings/modules/modules_search_edit.dart b/lib/modules/settings/modules/modules_search_edit.dart new file mode 100644 index 00000000..31a99c23 --- /dev/null +++ b/lib/modules/settings/modules/modules_search_edit.dart @@ -0,0 +1 @@ +export 'modules_search_edit/route.dart'; diff --git a/lib/modules/settings/modules/modules_search_edit/route.dart b/lib/modules/settings/modules/modules_search_edit/route.dart new file mode 100644 index 00000000..4b5bc4e3 --- /dev/null +++ b/lib/modules/settings/modules/modules_search_edit/route.dart @@ -0,0 +1,144 @@ +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSearchEditRouteArguments { + final IndexerHiveObject indexer; + + SettingsModulesSearchEditRouteArguments({ + @required this.indexer, + }); +} + +class SettingsModulesSearchEditRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/search/edit'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + SettingsModulesSearchEditRouteArguments _arguments; + + @override + void initState() { + super.initState(); + SchedulerBinding.instance.scheduleFrameCallback((_) => setState(() { + _arguments = ModalRoute.of(context).settings.arguments; + })); + } + + @override + Widget build(BuildContext context) => _arguments == null + ? Scaffold() + : Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Edit Indexer'); + + Widget get _body => LSListView( + children: [ + _displayName, + _apiURL, + _apiKey, + _headers, + LSDivider(), + _deleteIndexer, + ], + ); + + Widget get _displayName => LSCardTile( + title: LSTitle(text: 'Display Name'), + subtitle: LSSubtitle( + text: _arguments.indexer.displayName == null || _arguments.indexer.displayName.isEmpty + ? 'Not Set' + : _arguments.indexer.displayName, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + List _values = await GlobalDialogs.editText(context, 'Display Name', prefill: _arguments.indexer.displayName); + setState(() => _arguments.indexer.displayName = _values[0] + ? _values[1] + : _arguments.indexer.displayName + ); + _arguments.indexer.save(); + }, + ); + + Widget get _apiURL => LSCardTile( + title: LSTitle(text: 'Indexer API Host'), + subtitle: LSSubtitle( + text: _arguments.indexer.host == null || _arguments.indexer.host.isEmpty + ? 'Not Set' + : _arguments.indexer.host, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + List _values = await GlobalDialogs.editText(context, 'Indexer API Host', prefill: _arguments.indexer.host); + setState(() => _arguments.indexer.host = _values[0] + ? _values[1] + : _arguments.indexer.host + ); + _arguments.indexer.save(); + }, + ); + + Widget get _apiKey => LSCardTile( + title: LSTitle(text: 'Indexer API Key'), + subtitle: LSSubtitle( + text: _arguments.indexer.key == null || _arguments.indexer.key.isEmpty + ? 'Not Set' + : _arguments.indexer.key, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + List _values = await GlobalDialogs.editText(context, 'Indexer API Key', prefill: _arguments.indexer.key); + setState(() => _arguments.indexer.key = _values[0] + ? _values[1] + : _arguments.indexer.key + ); + _arguments.indexer.save(); + }, + ); + + Widget get _headers => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async { + Navigator.of(context).pushNamed( + SettingsModulesSearchHeadersRoute.ROUTE_NAME, + arguments: SettingsModulesSearchHeadersRouteArguments( + indexer: _arguments.indexer, + saveAfterAction: true, + ), + ); + _arguments.indexer.save(); + }, + ); + + Widget get _deleteIndexer => LSButton( + text: 'Delete Indexer', + backgroundColor: LSColors.red, + onTap: () async => _delete(), + ); + + Future _delete() async { + List _values = await SettingsDialogs.deleteIndexer(context); + if(_values[0]) { + LSSnackBar( + context: context, + title: 'Indexer Deleted', + message: _arguments.indexer.displayName, + type: SNACKBAR_TYPE.success, + ); + _arguments.indexer.delete(); + Navigator.of(context).pop(); + } + } +} diff --git a/lib/modules/settings/modules/modules_search_headers.dart b/lib/modules/settings/modules/modules_search_headers.dart new file mode 100644 index 00000000..5207b5f1 --- /dev/null +++ b/lib/modules/settings/modules/modules_search_headers.dart @@ -0,0 +1 @@ +export 'modules_search_headers/route.dart'; diff --git a/lib/modules/settings/modules/modules_search_headers/route.dart b/lib/modules/settings/modules/modules_search_headers/route.dart new file mode 100644 index 00000000..b75e19b1 --- /dev/null +++ b/lib/modules/settings/modules/modules_search_headers/route.dart @@ -0,0 +1,151 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:flutter/scheduler.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSearchHeadersRouteArguments { + final IndexerHiveObject indexer; + final bool saveAfterAction; + + SettingsModulesSearchHeadersRouteArguments({ + @required this.indexer, + @required this.saveAfterAction, + }); +} + +class SettingsModulesSearchHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/search/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + SettingsModulesSearchHeadersRouteArguments _arguments; + + @override + void initState() { + super.initState(); + SchedulerBinding.instance.scheduleFrameCallback((_) => setState(() { + _arguments = ModalRoute.of(context).settings.arguments; + })); + } + + @override + Widget build(BuildContext context) => _arguments == null + ? Scaffold() + : Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => LSListView( + children: [ + if((_arguments.indexer.headers ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + _addHeader, + ], + ); + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (_arguments.indexer.headers ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(_header(key.toString(), value.toString()))); + list.sort((a,b) => (a.title as LSTitle).text.toLowerCase().compareTo((b.title as LSTitle).text.toLowerCase())); + return list; + } + + Widget _header(String key, String value) => LSCardTile( + title: LSTitle(text: key.toString()), + subtitle: LSSubtitle(text: value.toString()), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _delete(key), + ), + ); + + Widget get _addHeader => LSButton( + text: 'Add Header', + onTap: () async => _add(), + ); + + Future _add() async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesLidarrHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (_arguments.indexer.headers ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + _arguments.indexer.headers = _headers; + if(_arguments.saveAfterAction) _arguments.indexer.save(); + LSSnackBar( + context: context, + message: 'Authorization', + title: 'Header Added', + type: SNACKBAR_TYPE.success, + ); + setState(() {}); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (_arguments.indexer.headers ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + _arguments.indexer.headers = _headers; + if(_arguments.saveAfterAction) _arguments.indexer.save(); + LSSnackBar( + context: context, + message: results[1], + title: 'Header Added', + type: SNACKBAR_TYPE.success, + ); + setState(() {}); + } + } + + Future _delete(String key) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (_arguments.indexer.headers ?? {}).cast(); + _headers.remove(key); + _arguments.indexer.headers = _headers; + if(_arguments.saveAfterAction) _arguments.indexer.save(); + LSSnackBar( + context: context, + message: key, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + setState(() {}); + } + } +} diff --git a/lib/modules/settings/modules/modules_sonarr.dart b/lib/modules/settings/modules/modules_sonarr.dart new file mode 100644 index 00000000..a5f2873c --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr.dart @@ -0,0 +1,2 @@ +export 'modules_sonarr/route.dart'; +export 'modules_sonarr/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_sonarr/route.dart b/lib/modules/settings/modules/modules_sonarr/route.dart new file mode 100644 index 00000000..40710c27 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/route.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/sonarr'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Sonarr', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationSonarrRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + LSDivider(), + SettingsModulesSonarrTestConnectionTile(), + ..._advanced, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesSonarrEnabledTile(), + SettingsModulesSonarrHostTile(), + SettingsModulesSonarrAPIKeyTile(), + ]; + + List get _advanced => [ + LSHeader( + text: 'Advanced', + subtitle: 'Options for non-standard networking configurations', + ), + SettingsModulesSonarrCustomHeadersTile(), + SettingsModulesSonarrStrictTLSTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_sonarr/widgets.dart b/lib/modules/settings/modules/modules_sonarr/widgets.dart new file mode 100644 index 00000000..84d587e2 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets.dart @@ -0,0 +1,6 @@ +export 'widgets/apikey_tile.dart'; +export 'widgets/custom_headers_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/host_tile.dart'; +export 'widgets/strict_tls_tile.dart'; +export 'widgets/test_connection_tile.dart'; diff --git a/lib/modules/settings/modules/modules_sonarr/widgets/apikey_tile.dart b/lib/modules/settings/modules/modules_sonarr/widgets/apikey_tile.dart new file mode 100644 index 00000000..4bdb55eb --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets/apikey_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesSonarrAPIKeyTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'API Key'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.sonarrKey == null || Database.currentProfileObject.sonarrKey == '' + ? 'Not Set' + : '••••••••••••' + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeKey(context), + ); + + Future _changeKey(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'Sonarr API Key', + prefill: Database.currentProfileObject.sonarrKey ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.sonarrKey = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sonarr/widgets/custom_headers_tile.dart b/lib/modules/settings/modules/modules_sonarr/widgets/custom_headers_tile.dart new file mode 100644 index 00000000..218d1ba5 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets/custom_headers_tile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrCustomHeadersTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesSonarrHeadersRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_sonarr/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_sonarr/widgets/enabled_tile.dart new file mode 100644 index 00000000..014bc578 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesSonarrEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable Sonarr'), + trailing: Switch( + value: Database.currentProfileObject.sonarrEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.sonarrEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sonarr/widgets/host_tile.dart b/lib/modules/settings/modules/modules_sonarr/widgets/host_tile.dart new file mode 100644 index 00000000..9b929bbf --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets/host_tile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrHostTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Host'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.sonarrHost == null || Database.currentProfileObject.sonarrHost == '' + ? 'Not Set' + : Database.currentProfileObject.sonarrHost + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeHost(context), + ); + + Future _changeHost(BuildContext context) async { + List _values = await SettingsDialogs.editHost( + context, + 'Sonarr Host', + prefill: Database.currentProfileObject.sonarrHost ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.sonarrHost = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sonarr/widgets/strict_tls_tile.dart b/lib/modules/settings/modules/modules_sonarr/widgets/strict_tls_tile.dart new file mode 100644 index 00000000..40b42e4c --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets/strict_tls_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrStrictTLSTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Strict SSL/TLS Validation'), + subtitle: LSSubtitle(text: 'For Invalid Certificates'), + trailing: Switch( + value: Database.currentProfileObject.sonarrStrictTLS ?? true, + onChanged: (value) async => _onChanged(context, value), + ), + ); + + Future _onChanged(BuildContext context, bool value) async { + if(value) { + Database.currentProfileObject.sonarrStrictTLS = value; + Database.currentProfileObject.save(context: context); + } else { + List _values = await SettingsDialogs.toggleStrictTLS(context); + if(_values[0]) { + Database.currentProfileObject.sonarrStrictTLS = value; + Database.currentProfileObject.save(context: context); + } + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sonarr/widgets/test_connection_tile.dart b/lib/modules/settings/modules/modules_sonarr/widgets/test_connection_tile.dart new file mode 100644 index 00000000..e43797a5 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr/widgets/test_connection_tile.dart @@ -0,0 +1,15 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +class SettingsModulesSonarrTestConnectionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Test Connection', + onTap: () async => _testConnection(context), + ); + + Future _testConnection(BuildContext context) async => await SonarrAPI.from(Database.currentProfileObject).testConnection() + ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'Sonarr is ready to use with LunaSea', type: SNACKBAR_TYPE.success) + : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); +} diff --git a/lib/modules/settings/modules/modules_sonarr_headers.dart b/lib/modules/settings/modules/modules_sonarr_headers.dart new file mode 100644 index 00000000..28c85722 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr_headers.dart @@ -0,0 +1,2 @@ +export 'modules_sonarr_headers/route.dart'; +export 'modules_sonarr_headers/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_sonarr_headers/route.dart b/lib/modules/settings/modules/modules_sonarr_headers/route.dart new file mode 100644 index 00000000..84c5ab37 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr_headers/route.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/sonarr/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, profile, _) => LSListView( + children: _headers, + ), + ); + + List get _headers => [ + if((Database.currentProfileObject.sonarrHeaders ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + SettingsModulesSonarrHeadersAddHeaderTile(), + ]; + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (Database.currentProfileObject.sonarrHeaders ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(SettingsModulesSonarrHeadersHeaderTile( + headerKey: key.toString(), + headerValue: value.toString(), + ))); + list.sort((a,b) => a.headerKey.toLowerCase().compareTo(b.headerKey.toLowerCase())); + return list; + } +} diff --git a/lib/modules/settings/modules/modules_sonarr_headers/widgets.dart b/lib/modules/settings/modules/modules_sonarr_headers/widgets.dart new file mode 100644 index 00000000..fc17a9b4 --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr_headers/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/add_header_tile.dart'; +export 'widgets/header_tile.dart'; diff --git a/lib/modules/settings/modules/modules_sonarr_headers/widgets/add_header_tile.dart b/lib/modules/settings/modules/modules_sonarr_headers/widgets/add_header_tile.dart new file mode 100644 index 00000000..2517822f --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr_headers/widgets/add_header_tile.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrHeadersAddHeaderTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Add Header', + onTap: () async => _addPrompt(context), + ); + + Future _addPrompt(BuildContext context) async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesSonarrHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.sonarrHeaders ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + Database.currentProfileObject.sonarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.sonarrHeaders ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + Database.currentProfileObject.sonarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_sonarr_headers/widgets/header_tile.dart b/lib/modules/settings/modules/modules_sonarr_headers/widgets/header_tile.dart new file mode 100644 index 00000000..b8714dac --- /dev/null +++ b/lib/modules/settings/modules/modules_sonarr_headers/widgets/header_tile.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesSonarrHeadersHeaderTile extends StatelessWidget { + final String headerKey; + final String headerValue; + + SettingsModulesSonarrHeadersHeaderTile({ + @required this.headerKey, + @required this.headerValue, + }); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: headerKey), + subtitle: LSSubtitle(text: headerValue), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _deleteHeader(context), + ), + ); + + Future _deleteHeader(BuildContext context) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.sonarrHeaders ?? {}).cast(); + _headers.remove(headerKey); + Database.currentProfileObject.sonarrHeaders = _headers; + Database.currentProfileObject.save(context: context); + LSSnackBar( + context: context, + message: headerKey, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_tautulli.dart b/lib/modules/settings/modules/modules_tautulli.dart new file mode 100644 index 00000000..c33cec9c --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli.dart @@ -0,0 +1,2 @@ +export 'modules_tautulli/route.dart'; +export 'modules_tautulli/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_tautulli/route.dart b/lib/modules/settings/modules/modules_tautulli/route.dart new file mode 100644 index 00000000..48344b1a --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/route.dart @@ -0,0 +1,62 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/tautulli'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar( + title: 'Tautulli', + actions: [ + LSIconButton( + icon: Icons.brush, + onPressed: () async => Navigator.of(context).pushNamed(SettingsCustomizationTautulliRoute.ROUTE_NAME), + ), + ] + ); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + LSDivider(), + SettingsModulesTautulliTestConnectionTile(), + ..._advanced, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesTautulliEnabledTile(), + SettingsModulesTautulliHostTile(), + SettingsModulesTautulliAPIKeyTile(), + ]; + + List get _advanced => [ + LSHeader( + text: 'Advanced', + subtitle: 'Options for non-standard networking configurations', + ), + SettingsModulesTautulliCustomHeadersTile(), + SettingsModulesTautulliStrictTLSTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_tautulli/widgets.dart b/lib/modules/settings/modules/modules_tautulli/widgets.dart new file mode 100644 index 00000000..84d587e2 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets.dart @@ -0,0 +1,6 @@ +export 'widgets/apikey_tile.dart'; +export 'widgets/custom_headers_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/host_tile.dart'; +export 'widgets/strict_tls_tile.dart'; +export 'widgets/test_connection_tile.dart'; diff --git a/lib/modules/settings/modules/modules_tautulli/widgets/apikey_tile.dart b/lib/modules/settings/modules/modules_tautulli/widgets/apikey_tile.dart new file mode 100644 index 00000000..1723b875 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets/apikey_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesTautulliAPIKeyTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'API Key'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.tautulliKey == null || Database.currentProfileObject.tautulliKey == '' + ? 'Not Set' + : '••••••••••••' + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeKey(context), + ); + + Future _changeKey(BuildContext context) async { + List _values = await GlobalDialogs.editText( + context, + 'Tautulli API Key', + prefill: Database.currentProfileObject.tautulliKey ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.tautulliKey = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_tautulli/widgets/custom_headers_tile.dart b/lib/modules/settings/modules/modules_tautulli/widgets/custom_headers_tile.dart new file mode 100644 index 00000000..cacb1d01 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets/custom_headers_tile.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliCustomHeadersTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Custom Headers'), + subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesTautulliHeadersRoute.ROUTE_NAME), + ); +} diff --git a/lib/modules/settings/modules/modules_tautulli/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_tautulli/widgets/enabled_tile.dart new file mode 100644 index 00000000..a9e7ef78 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesTautulliEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable Tautulli'), + trailing: Switch( + value: Database.currentProfileObject.tautulliEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.tautulliEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_tautulli/widgets/host_tile.dart b/lib/modules/settings/modules/modules_tautulli/widgets/host_tile.dart new file mode 100644 index 00000000..cf015eca --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets/host_tile.dart @@ -0,0 +1,29 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliHostTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Host'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.tautulliHost == null || Database.currentProfileObject.tautulliHost == '' + ? 'Not Set' + : Database.currentProfileObject.tautulliHost + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeHost(context), + ); + + Future _changeHost(BuildContext context) async { + List _values = await SettingsDialogs.editHost( + context, + 'Tautulli Host', + prefill: Database.currentProfileObject.tautulliHost ?? '', + ); + if(_values[0]) { + Database.currentProfileObject.tautulliHost = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_tautulli/widgets/strict_tls_tile.dart b/lib/modules/settings/modules/modules_tautulli/widgets/strict_tls_tile.dart new file mode 100644 index 00000000..5180209e --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets/strict_tls_tile.dart @@ -0,0 +1,28 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliStrictTLSTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Strict SSL/TLS Validation'), + subtitle: LSSubtitle(text: 'For Invalid Certificates'), + trailing: Switch( + value: Database.currentProfileObject.tautulliStrictTLS ?? true, + onChanged: (value) async => _onChanged(context, value), + ), + ); + + Future _onChanged(BuildContext context, bool value) async { + if(value) { + Database.currentProfileObject.tautulliStrictTLS = value; + Database.currentProfileObject.save(context: context); + } else { + List _values = await SettingsDialogs.toggleStrictTLS(context); + if(_values[0]) { + Database.currentProfileObject.tautulliStrictTLS = value; + Database.currentProfileObject.save(context: context); + } + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_tautulli/widgets/test_connection_tile.dart b/lib/modules/settings/modules/modules_tautulli/widgets/test_connection_tile.dart new file mode 100644 index 00000000..ddd2f02d --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli/widgets/test_connection_tile.dart @@ -0,0 +1,34 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class SettingsModulesTautulliTestConnectionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Test Connection', + onTap: () async => _testConnection(context), + ); + + Future _testConnection(BuildContext context) async { + TautulliState state = Provider.of(context, listen: false); + if(!state.enabled) { + LSSnackBar(context: context, title: 'Tautulli Not Enabled', message: 'Tautulli needs to be enabled', type: SNACKBAR_TYPE.failure); + return; + } + if(state.host == null || state.host.isEmpty) { + LSSnackBar(context: context, title: 'Host Required', message: 'Host is required to connect to Tautulli', type: SNACKBAR_TYPE.failure); + return; + } + if(state.apiKey == null || state.apiKey.isEmpty) { + LSSnackBar(context: context, title: 'API Key Required', message: 'API key is required to connect to Tautulli', type: SNACKBAR_TYPE.failure); + return; + } + state.api.miscellaneous.arnold() + .then((_) { + LSSnackBar(context: context, title: 'Connected Successfully', message: 'Tautulli is ready to use with LunaSea', type: SNACKBAR_TYPE.success); + }).catchError((error, trace) { + Logger.error('SettingsModulesTautulli', '_testConnection', 'Failed Connection', error, trace, uploadToSentry: false); + LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); + }); + } +} diff --git a/lib/modules/settings/modules/modules_tautulli_headers.dart b/lib/modules/settings/modules/modules_tautulli_headers.dart new file mode 100644 index 00000000..4696e4f1 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli_headers.dart @@ -0,0 +1,2 @@ +export 'modules_tautulli_headers/route.dart'; +export 'modules_tautulli_headers/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_tautulli_headers/route.dart b/lib/modules/settings/modules/modules_tautulli_headers/route.dart new file mode 100644 index 00000000..8090dc8c --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli_headers/route.dart @@ -0,0 +1,50 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliHeadersRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/tautulli/headers'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Custom Headers'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, profile, _) => LSListView( + children: _headers, + ), + ); + + List get _headers => [ + if((Database.currentProfileObject.tautulliHeaders ?? {}).isEmpty) _noHeaders, + ..._list, + LSDivider(), + SettingsModulesTautulliHeadersAddHeaderTile(), + ]; + + Widget get _noHeaders => LSGenericMessage(text: 'No Custom Headers Added'); + + List get _list { + Map headers = (Database.currentProfileObject.tautulliHeaders ?? {}).cast(); + List list = []; + headers.forEach((key, value) => list.add(SettingsModulesTautulliHeadersHeaderTile( + headerKey: key.toString(), + headerValue: value.toString(), + ))); + list.sort((a,b) => a.headerKey.toLowerCase().compareTo(b.headerKey.toLowerCase())); + return list; + } +} diff --git a/lib/modules/settings/modules/modules_tautulli_headers/widgets.dart b/lib/modules/settings/modules/modules_tautulli_headers/widgets.dart new file mode 100644 index 00000000..fc17a9b4 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli_headers/widgets.dart @@ -0,0 +1,2 @@ +export 'widgets/add_header_tile.dart'; +export 'widgets/header_tile.dart'; diff --git a/lib/modules/settings/modules/modules_tautulli_headers/widgets/add_header_tile.dart b/lib/modules/settings/modules/modules_tautulli_headers/widgets/add_header_tile.dart new file mode 100644 index 00000000..79d86c12 --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli_headers/widgets/add_header_tile.dart @@ -0,0 +1,52 @@ +import 'dart:convert'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliHeadersAddHeaderTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSButton( + text: 'Add Header', + onTap: () async => _addPrompt(context), + ); + + Future _addPrompt(BuildContext context) async { + List results = await SettingsDialogs.addHeader(context); + if(results[0]) switch(results[1]) { + case 1: + _showAuthenticationPrompt(context); + break; + case 100: + _showCustomPrompt(context); + break; + default: + Logger.warning( + 'SettingsModulesTautulliHeadersAddHeaderTile', + '_addPrompt', + 'Unknown case: ${results[1]}', + ); + break; + } + } + + Future _showAuthenticationPrompt(BuildContext context) async { + List results = await SettingsDialogs.addAuthenticationHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.tautulliHeaders ?? {}).cast(); + String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); + _headers.addAll({'Authorization': 'Basic $_auth'}); + Database.currentProfileObject.tautulliHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } + + Future _showCustomPrompt(BuildContext context) async { + List results = await SettingsDialogs.addCustomHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.tautulliHeaders ?? {}).cast(); + _headers.addAll({results[1]: results[2]}); + Database.currentProfileObject.tautulliHeaders = _headers; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_tautulli_headers/widgets/header_tile.dart b/lib/modules/settings/modules/modules_tautulli_headers/widgets/header_tile.dart new file mode 100644 index 00000000..c8c9a48b --- /dev/null +++ b/lib/modules/settings/modules/modules_tautulli_headers/widgets/header_tile.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesTautulliHeadersHeaderTile extends StatelessWidget { + final String headerKey; + final String headerValue; + + SettingsModulesTautulliHeadersHeaderTile({ + @required this.headerKey, + @required this.headerValue, + }); + + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: headerKey), + subtitle: LSSubtitle(text: headerValue), + trailing: LSIconButton( + icon: Icons.delete, + color: LSColors.red, + onPressed: () async => _deleteHeader(context), + ), + ); + + Future _deleteHeader(BuildContext context) async { + List results = await SettingsDialogs.deleteHeader(context); + if(results[0]) { + Map _headers = (Database.currentProfileObject.tautulliHeaders ?? {}).cast(); + _headers.remove(headerKey); + Database.currentProfileObject.tautulliHeaders = _headers; + Database.currentProfileObject.save(context: context); + LSSnackBar( + context: context, + message: headerKey, + title: 'Header Deleted', + type: SNACKBAR_TYPE.success, + ); + } + } +} diff --git a/lib/modules/settings/modules/modules_wakeonlan.dart b/lib/modules/settings/modules/modules_wakeonlan.dart new file mode 100644 index 00000000..98f9e13f --- /dev/null +++ b/lib/modules/settings/modules/modules_wakeonlan.dart @@ -0,0 +1,2 @@ +export 'modules_wakeonlan/route.dart'; +export 'modules_wakeonlan/widgets.dart'; diff --git a/lib/modules/settings/modules/modules_wakeonlan/route.dart b/lib/modules/settings/modules/modules_wakeonlan/route.dart new file mode 100644 index 00000000..1e9e36cf --- /dev/null +++ b/lib/modules/settings/modules/modules_wakeonlan/route.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesWakeOnLANRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/modules/wakeonlan'; + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Wake on LAN'); + + Widget get _body => ValueListenableBuilder( + valueListenable: Database.profilesBox.listenable(), + builder: (context, box, _) => LSListView( + children: [ + ..._mandatory, + ], + ), + ); + + List get _mandatory => [ + LSHeader( + text: 'Mandatory', + subtitle: 'Configuration that is required for functionality', + ), + SettingsModulesWakeOnLANEnabledTile(), + SettingsModulesWakeOnLANBroadcastAddressTile(), + SettingsModulesWakeOnLANMACAddressTile(), + ]; +} diff --git a/lib/modules/settings/modules/modules_wakeonlan/widgets.dart b/lib/modules/settings/modules/modules_wakeonlan/widgets.dart new file mode 100644 index 00000000..58015265 --- /dev/null +++ b/lib/modules/settings/modules/modules_wakeonlan/widgets.dart @@ -0,0 +1,3 @@ +export 'widgets/broadcast_address_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/mac_address_tile.dart'; diff --git a/lib/modules/settings/modules/modules_wakeonlan/widgets/broadcast_address_tile.dart b/lib/modules/settings/modules/modules_wakeonlan/widgets/broadcast_address_tile.dart new file mode 100644 index 00000000..64007fb3 --- /dev/null +++ b/lib/modules/settings/modules/modules_wakeonlan/widgets/broadcast_address_tile.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesWakeOnLANBroadcastAddressTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Broadcast Address'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.wakeOnLANBroadcastAddress == null || Database.currentProfileObject.wakeOnLANBroadcastAddress == '' + ? 'Not Set' + : Database.currentProfileObject.wakeOnLANBroadcastAddress, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeAddress(context), + ); + + Future _changeAddress(BuildContext context) async { + List _values = await SettingsDialogs.editBroadcastAddress(context, Database.currentProfileObject.wakeOnLANBroadcastAddress ?? ''); + if(_values[0]) { + Database.currentProfileObject.wakeOnLANBroadcastAddress = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_wakeonlan/widgets/enabled_tile.dart b/lib/modules/settings/modules/modules_wakeonlan/widgets/enabled_tile.dart new file mode 100644 index 00000000..f71fb9d6 --- /dev/null +++ b/lib/modules/settings/modules/modules_wakeonlan/widgets/enabled_tile.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsModulesWakeOnLANEnabledTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Enable Wake on LAN'), + trailing: Switch( + value: Database.currentProfileObject.wakeOnLANEnabled ?? false, + onChanged: (value) { + Database.currentProfileObject.wakeOnLANEnabled = value; + Database.currentProfileObject.save(context: context); + }, + ), + ); +} \ No newline at end of file diff --git a/lib/modules/settings/modules/modules_wakeonlan/widgets/mac_address_tile.dart b/lib/modules/settings/modules/modules_wakeonlan/widgets/mac_address_tile.dart new file mode 100644 index 00000000..ebb94f81 --- /dev/null +++ b/lib/modules/settings/modules/modules_wakeonlan/widgets/mac_address_tile.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsModulesWakeOnLANMACAddressTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Device MAC Address'), + subtitle: LSSubtitle( + text: Database.currentProfileObject.wakeOnLANMACAddress == null || Database.currentProfileObject.wakeOnLANMACAddress == '' + ? 'Not Set' + : Database.currentProfileObject.wakeOnLANMACAddress, + ), + trailing: LSIconButton(icon: Icons.arrow_forward_ios), + onTap: () async => _changeAddress(context), + ); + + Future _changeAddress(BuildContext context) async { + List _values = await SettingsDialogs.editMACAddress(context, Database.currentProfileObject.wakeOnLANMACAddress ?? ''); + if(_values[0]) { + Database.currentProfileObject.wakeOnLANMACAddress = _values[1]; + Database.currentProfileObject.save(context: context); + } + } +} \ No newline at end of file diff --git a/lib/modules/settings/modules/profiles.dart b/lib/modules/settings/modules/profiles.dart new file mode 100644 index 00000000..2bc826e0 --- /dev/null +++ b/lib/modules/settings/modules/profiles.dart @@ -0,0 +1,2 @@ +export 'profiles/route.dart'; +export 'profiles/widgets.dart'; diff --git a/lib/modules/settings/modules/profiles/route.dart b/lib/modules/settings/modules/profiles/route.dart new file mode 100644 index 00000000..19539021 --- /dev/null +++ b/lib/modules/settings/modules/profiles/route.dart @@ -0,0 +1,40 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsProfilesRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/profiles'; + + SettingsProfilesRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State with AutomaticKeepAliveClientMixin { + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + super.build(context); + return Scaffold( + appBar: _appBar, + body: _body, + ); + } + + Widget get _appBar => LSAppBar(title: 'Profiles'); + + Widget get _body => LSListView( + children: [ + SettingsProfileEnabledTile(), + LSDivider(), + SettingsProfileAddTile(), + SettingsProfileRenameTile(), + SettingsProfileDeleteTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/profiles/widgets.dart b/lib/modules/settings/modules/profiles/widgets.dart new file mode 100644 index 00000000..ae548f96 --- /dev/null +++ b/lib/modules/settings/modules/profiles/widgets.dart @@ -0,0 +1,4 @@ +export 'widgets/add_tile.dart'; +export 'widgets/delete_tile.dart'; +export 'widgets/enabled_tile.dart'; +export 'widgets/rename_tile.dart'; diff --git a/lib/modules/settings/widgets/general/profile/add_tile.dart b/lib/modules/settings/modules/profiles/widgets/add_tile.dart similarity index 95% rename from lib/modules/settings/widgets/general/profile/add_tile.dart rename to lib/modules/settings/modules/profiles/widgets/add_tile.dart index f51f8d66..5da31a4d 100644 --- a/lib/modules/settings/widgets/general/profile/add_tile.dart +++ b/lib/modules/settings/modules/profiles/widgets/add_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralAddProfileTile extends StatelessWidget { +class SettingsProfileAddTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( title: LSTitle(text: 'Add'), diff --git a/lib/modules/settings/widgets/general/profile/delete_tile.dart b/lib/modules/settings/modules/profiles/widgets/delete_tile.dart similarity index 94% rename from lib/modules/settings/widgets/general/profile/delete_tile.dart rename to lib/modules/settings/modules/profiles/widgets/delete_tile.dart index 63d7e749..5906f5b2 100644 --- a/lib/modules/settings/widgets/general/profile/delete_tile.dart +++ b/lib/modules/settings/modules/profiles/widgets/delete_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralDeleteProfileTile extends StatelessWidget { +class SettingsProfileDeleteTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( title: LSTitle(text: 'Delete'), diff --git a/lib/modules/settings/widgets/general/profile/enabled_tile.dart b/lib/modules/settings/modules/profiles/widgets/enabled_tile.dart similarity index 77% rename from lib/modules/settings/widgets/general/profile/enabled_tile.dart rename to lib/modules/settings/modules/profiles/widgets/enabled_tile.dart index 46b4f382..a2a0c8d0 100644 --- a/lib/modules/settings/widgets/general/profile/enabled_tile.dart +++ b/lib/modules/settings/modules/profiles/widgets/enabled_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralEnabledProfileTile extends StatelessWidget { +class SettingsProfileEnabledTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( title: LSTitle(text: 'Enabled Profile'), @@ -10,7 +10,7 @@ class SettingsGeneralEnabledProfileTile extends StatelessWidget { valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.ENABLED_PROFILE.key]), builder: (context, box, widget) => LSSubtitle(text: box.get(LunaSeaDatabaseValue.ENABLED_PROFILE.key)), ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), + trailing: LSIconButton(icon: Icons.person), onTap: () => _changeProfile(context), ); @@ -24,6 +24,12 @@ class SettingsGeneralEnabledProfileTile extends StatelessWidget { LunaSeaDatabaseValue.ENABLED_PROFILE.put(values[1]); Providers.reset(context); } + LSSnackBar( + context: context, + title: 'Changed Profile', + message: 'Using profile "${values[1]}"', + type: SNACKBAR_TYPE.info, + ); } } } diff --git a/lib/modules/settings/widgets/general/profile/rename_tile.dart b/lib/modules/settings/modules/profiles/widgets/rename_tile.dart similarity index 96% rename from lib/modules/settings/widgets/general/profile/rename_tile.dart rename to lib/modules/settings/modules/profiles/widgets/rename_tile.dart index a4e27578..ba42dae7 100644 --- a/lib/modules/settings/widgets/general/profile/rename_tile.dart +++ b/lib/modules/settings/modules/profiles/widgets/rename_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsGeneralRenameProfileTile extends StatelessWidget { +class SettingsProfileRenameTile extends StatelessWidget { @override Widget build(BuildContext context) => LSCardTile( title: LSTitle(text: 'Rename'), diff --git a/lib/modules/settings/modules/resources.dart b/lib/modules/settings/modules/resources.dart new file mode 100644 index 00000000..7cb48dc9 --- /dev/null +++ b/lib/modules/settings/modules/resources.dart @@ -0,0 +1 @@ +export 'resources/route.dart'; diff --git a/lib/modules/settings/modules/resources/route.dart b/lib/modules/settings/modules/resources/route.dart new file mode 100644 index 00000000..9b0a469c --- /dev/null +++ b/lib/modules/settings/modules/resources/route.dart @@ -0,0 +1,74 @@ +import 'dart:io'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsResourcesRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/resources'; + + SettingsResourcesRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Resources'); + + Widget get _body => LSListView( + children: [ + LSCardTile( + title: LSTitle(text: 'Discord'), + subtitle: LSSubtitle(text: 'Chat & Discussions'), + trailing: LSIconButton(icon: CustomIcons.discord), + onTap: () async => await Constants.URL_DISCORD.lsLinks_OpenLink(), + ), + LSCardTile( + title: LSTitle(text: 'Documentation'), + subtitle: LSSubtitle(text: 'View the Documentation'), + trailing: LSIconButton(icon: CustomIcons.documentation), + onTap: () async => await Constants.URL_DOCUMENTATION.lsLinks_OpenLink(), + ), + LSCardTile( + title: LSTitle(text: 'Feedback Board'), + subtitle: LSSubtitle(text: 'Request New Features'), + trailing: LSIconButton(icon: Icons.speaker_notes), + onTap: () async => await Constants.URL_FEEDBACK.lsLinks_OpenLink(), + ), + LSCardTile( + title: LSTitle(text: 'GitHub'), + subtitle: LSSubtitle(text: 'View the Source Code'), + trailing: LSIconButton(icon: CustomIcons.github), + onTap: () async => await Constants.URL_GITHUB.lsLinks_OpenLink(), + ), + LSCardTile( + title: LSTitle(text: 'Reddit'), + subtitle: LSSubtitle(text: 'Ask Questions & Get Support'), + trailing: LSIconButton(icon: CustomIcons.reddit), + onTap: () async => await Constants.URL_REDDIT.lsLinks_OpenLink(), + ), + if(Platform.isIOS) LSCardTile( + title: LSTitle(text: 'TestFlight'), + subtitle: LSSubtitle(text: 'Join the TestFlight Beta'), + trailing: LSIconButton(icon: Icons.developer_board), + onTap: () async => await Constants.URL_TESTFLIGHT.lsLinks_OpenLink() + ), + LSCardTile( + title: LSTitle(text: 'Website'), + subtitle: LSSubtitle(text: 'Visit LunaSea\'s Website'), + trailing: LSIconButton(icon: CustomIcons.home), + onTap: () async => await Constants.URL_WEBSITE.lsLinks_OpenLink(), + ), + ], + ); +} diff --git a/lib/modules/settings/modules/settings.dart b/lib/modules/settings/modules/settings.dart new file mode 100644 index 00000000..82b784ec --- /dev/null +++ b/lib/modules/settings/modules/settings.dart @@ -0,0 +1 @@ +export 'settings/route.dart'; diff --git a/lib/modules/settings/modules/settings/route.dart b/lib/modules/settings/modules/settings/route.dart new file mode 100644 index 00000000..fc6ba66b --- /dev/null +++ b/lib/modules/settings/modules/settings/route.dart @@ -0,0 +1,89 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings'; + + SettingsRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + + Widget get _appBar => LSAppBar(title: 'Settings'); + + Widget get _body => LSListView( + children: [ + ..._leading, + LSDivider(), + ..._trailing, + ], + ); + + List get _leading => [ + LSCardTile( + title: LSTitle(text: 'Customization'), + subtitle: LSSubtitle(text: 'Customize LunaSea & Modules'), + trailing: LSIconButton(icon: Icons.brush), + onTap: () async => Navigator.of(context).pushNamed(SettingsCustomizationRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Modules'), + subtitle: LSSubtitle(text: 'Configure & Setup Modules'), + trailing: LSIconButton(icon: Icons.device_hub), + onTap: () async => Navigator.of(context).pushNamed(SettingsModulesRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Profiles'), + subtitle: LSSubtitle(text: 'Manage Your Profiles'), + trailing: LSIconButton(icon: Icons.person), + onTap: () async => Navigator.of(context).pushNamed(SettingsProfilesRoute.ROUTE_NAME), + ), + ]; + + List get _trailing => [ + LSCardTile( + title: LSTitle(text: 'Backup & Restore'), + subtitle: LSSubtitle(text: 'Backup & Restore Your Configuration'), + trailing: LSIconButton(icon: Icons.settings_backup_restore), + onTap: () async => Navigator.of(context).pushNamed(SettingsBackupRestoreRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Donations'), + subtitle: LSSubtitle(text: 'Donate to the Developer'), + trailing: LSIconButton(icon: Icons.attach_money), + onTap: () async => Navigator.of(context).pushNamed(SettingsDonationsRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Logs'), + subtitle: LSSubtitle(text: 'View, Export, & Clear Logs'), + trailing: LSIconButton(icon: Icons.developer_mode), + onTap: () async => Navigator.of(context).pushNamed(SettingsLogsRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'Resources'), + subtitle: LSSubtitle(text: 'Useful Resources & Links'), + trailing: LSIconButton(icon: Icons.help_outline), + onTap: () async => Navigator.of(context).pushNamed(SettingsResourcesRoute.ROUTE_NAME), + ), + LSCardTile( + title: LSTitle(text: 'System'), + subtitle: LSSubtitle(text: 'System Utilities & Information'), + trailing: LSIconButton(icon: Icons.settings), + onTap: () async => Navigator.of(context).pushNamed(SettingsSystemRoute.ROUTE_NAME), + ), + ]; +} diff --git a/lib/modules/settings/modules/system.dart b/lib/modules/settings/modules/system.dart new file mode 100644 index 00000000..df2d0ce6 --- /dev/null +++ b/lib/modules/settings/modules/system.dart @@ -0,0 +1,2 @@ +export 'system/route.dart'; +export 'system/widgets.dart'; diff --git a/lib/modules/settings/modules/system/route.dart b/lib/modules/settings/modules/system/route.dart new file mode 100644 index 00000000..3b878cb3 --- /dev/null +++ b/lib/modules/settings/modules/system/route.dart @@ -0,0 +1,44 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; + +class SettingsSystemRoute extends StatefulWidget { + static const ROUTE_NAME = '/settings/system'; + + SettingsSystemRoute({ + Key key, + }): super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State with AutomaticKeepAliveClientMixin { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + bool get wantKeepAlive => true; + + @override + Widget build(BuildContext context) { + super.build(context); + return Scaffold( + key: _scaffoldKey, + appBar: _appBar, + body: _body, + ); + } + + Widget get _appBar => LSAppBar(title: 'System'); + + Widget get _body => LSListView( + children: [ + SettingsSystemLicensesTile(), + SettingsSystemVersionTile(), + LSDivider(), + SettingsSystemEnableSentryTile(), + SettingsSystemClearImageCacheTile(), + SettingsSystemClearConfigurationTile(), + ], + ); +} diff --git a/lib/modules/settings/modules/system/widgets.dart b/lib/modules/settings/modules/system/widgets.dart new file mode 100644 index 00000000..020416b3 --- /dev/null +++ b/lib/modules/settings/modules/system/widgets.dart @@ -0,0 +1,5 @@ +export 'widgets/clear_configuration_tile.dart'; +export 'widgets/clear_image_cache_tile.dart'; +export 'widgets/licenses_tile.dart'; +export 'widgets/sentry_tile.dart'; +export 'widgets/version_tile.dart'; diff --git a/lib/modules/settings/widgets/system/clear_configuration_tile.dart b/lib/modules/settings/modules/system/widgets/clear_configuration_tile.dart similarity index 100% rename from lib/modules/settings/widgets/system/clear_configuration_tile.dart rename to lib/modules/settings/modules/system/widgets/clear_configuration_tile.dart diff --git a/lib/modules/settings/widgets/system/clear_image_cache_tile.dart b/lib/modules/settings/modules/system/widgets/clear_image_cache_tile.dart similarity index 100% rename from lib/modules/settings/widgets/system/clear_image_cache_tile.dart rename to lib/modules/settings/modules/system/widgets/clear_image_cache_tile.dart diff --git a/lib/modules/settings/modules/system/widgets/licenses_tile.dart b/lib/modules/settings/modules/system/widgets/licenses_tile.dart new file mode 100644 index 00000000..d26874b2 --- /dev/null +++ b/lib/modules/settings/modules/system/widgets/licenses_tile.dart @@ -0,0 +1,12 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class SettingsSystemLicensesTile extends StatelessWidget { + @override + Widget build(BuildContext context) => LSCardTile( + title: LSTitle(text: 'Licenses'), + subtitle: LSSubtitle(text: 'License Attributions'), + trailing: LSIconButton(icon: Icons.description), + onTap: () async => Constants.URL_LICENSES.lsLinks_OpenLink(), + ); +} diff --git a/lib/modules/settings/widgets/system/enable_sentry.dart b/lib/modules/settings/modules/system/widgets/sentry_tile.dart similarity index 93% rename from lib/modules/settings/widgets/system/enable_sentry.dart rename to lib/modules/settings/modules/system/widgets/sentry_tile.dart index ddb0887a..08e043e2 100644 --- a/lib/modules/settings/widgets/system/enable_sentry.dart +++ b/lib/modules/settings/modules/system/widgets/sentry_tile.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsSystemEnableSentry extends StatelessWidget { +class SettingsSystemEnableSentryTile extends StatelessWidget { @override Widget build(BuildContext context) => ValueListenableBuilder( valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.ENABLED_SENTRY.key]), diff --git a/lib/modules/settings/modules/system/widgets/version_tile.dart b/lib/modules/settings/modules/system/widgets/version_tile.dart new file mode 100644 index 00000000..7cf0ece3 --- /dev/null +++ b/lib/modules/settings/modules/system/widgets/version_tile.dart @@ -0,0 +1,20 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:package_info/package_info.dart'; + +class SettingsSystemVersionTile extends StatelessWidget { + @override + Widget build(BuildContext context) => FutureBuilder( + future: PackageInfo.fromPlatform(), + builder: (context, AsyncSnapshot snapshot) => LSCardTile( + title: LSTitle( + text: snapshot.hasData + ? 'Version: ${snapshot.data.version} (${snapshot.data.buildNumber})' + : 'Version: Loading...', + ), + subtitle: LSSubtitle(text: 'View Recent Changes'), + trailing: LSIconButton(icon: Icons.system_update), + onTap: () async => await Constants.URL_CHANGELOG.lsLinks_OpenLink(), + ), + ); +} diff --git a/lib/modules/settings/routes.dart b/lib/modules/settings/routes.dart deleted file mode 100644 index 6ea7d57c..00000000 --- a/lib/modules/settings/routes.dart +++ /dev/null @@ -1,24 +0,0 @@ -export 'routes/settings.dart'; -export 'routes/general.dart'; -export 'routes/system.dart'; -export 'routes/modules.dart'; -// Modules -export 'routes/modules/automation_lidarr.dart'; -export 'routes/modules/automation_radarr.dart'; -export 'routes/modules/automation_sonarr.dart'; -export 'routes/modules/clients_nzbget.dart'; -export 'routes/modules/clients_sabnzbd.dart'; -export 'routes/modules/monitoring_tautulli.dart'; -export 'routes/modules/general_home.dart'; -export 'routes/modules/general_lunasea.dart'; -export 'routes/modules/general_search.dart'; -export 'routes/modules/general_search_add.dart'; -export 'routes/modules/general_search_edit.dart'; -export 'routes/modules/general_wake_on_lan.dart'; -// Logs -export 'routes/logs/logs_details.dart'; -export 'routes/logs/logs_types.dart'; -export 'routes/logs/logs_view.dart'; -// System -export 'routes/system/resources_donations.dart'; -export 'routes/system/resources_donations_thankyou.dart'; diff --git a/lib/modules/settings/routes/general.dart b/lib/modules/settings/routes/general.dart deleted file mode 100644 index 99b2ebb6..00000000 --- a/lib/modules/settings/routes/general.dart +++ /dev/null @@ -1,63 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsGeneral extends StatefulWidget { - static const ROUTE_NAME = '/settings/general'; - - @override - State createState() => _State(); -} - -class _State extends State with AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - return Scaffold( - body: _body, - ); - } - - Widget get _body => LSListView( - children: [ - ..._profile, - ..._configuration, - ..._logs, - ], - ); - - List get _profile => [ - LSHeader( - text: 'Profile', - subtitle: 'Profiles allow you to use multiple instances of modules within LunaSea', - ), - SettingsGeneralEnabledProfileTile(), - LSDivider(), - SettingsGeneralAddProfileTile(), - SettingsGeneralRenameProfileTile(), - SettingsGeneralDeleteProfileTile(), - ]; - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Backup and restore your module configurations (Does not backup or restore customization options)', - ), - SettingsGeneralConfigurationBackupTile(), - SettingsGeneralConfigurationRestoreTile(), - ]; - - List get _logs => [ - LSHeader( - text: 'Logs', - subtitle: 'View, export, and clear your on-device logs (Logs are never sent off your device within LunaSea)', - ), - SettingsGeneralViewLogsTile(), - LSDivider(), - SettingsGeneralExportLogsTile(), - SettingsGeneralClearLogsTile(), - ]; -} diff --git a/lib/modules/settings/routes/logs/logs_details.dart b/lib/modules/settings/routes/logs/logs_details.dart deleted file mode 100644 index b5acaae0..00000000 --- a/lib/modules/settings/routes/logs/logs_details.dart +++ /dev/null @@ -1,76 +0,0 @@ -import 'package:f_logs/f_logs.dart' as FLog; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:lunasea/core.dart'; - -class SettingsGeneralLogsDetailsArguments { - final FLog.Log log; - - SettingsGeneralLogsDetailsArguments({ - @required this.log, - }); -} - -class SettingsGeneralLogsDetails extends StatefulWidget { - static const ROUTE_NAME = '/settings/general/logs/details'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - SettingsGeneralLogsDetailsArguments _arguments; - - @override - void initState() { - super.initState(); - SchedulerBinding.instance.addPostFrameCallback((_) => - setState(() => _arguments = ModalRoute.of(context).settings.arguments) - ); - } - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _arguments == null ? null : _body, - ); - - Widget get _appBar => LSAppBar(title: 'Log Details'); - - Widget get _body => LSListView( - children: [ - LSCardTile( - title: LSTitle(text: 'Class'), - subtitle: LSSubtitle(text: _arguments?.log?.className ?? 'Unknown', maxLines: 1), - ), - LSCardTile( - title: LSTitle(text: 'Method'), - subtitle: LSSubtitle(text: _arguments?.log?.methodName ?? 'Unknown', maxLines: 1), - ), - LSCardTile( - title: LSTitle(text: 'Timestamp'), - subtitle: LSSubtitle(text: _arguments?.log?.timestamp ?? 'Unknown', maxLines: 1), - ), - LSCardTile( - title: LSTitle(text: 'Message'), - subtitle: LSSubtitle(text: _arguments?.log?.text ?? 'Unknown', maxLines: 1), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => GlobalDialogs.textPreview(context, 'Message', _arguments?.log?.text), - ), - if(_arguments?.log?.exception != 'null') LSCardTile( - title: LSTitle(text: 'Exception'), - subtitle: LSSubtitle(text: _arguments?.log?.exception ?? 'Unknown', maxLines: 1), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => GlobalDialogs.textPreview(context, 'Exception', _arguments?.log?.exception, alignLeft: true), - ), - if(_arguments?.log?.stacktrace != 'null') LSCardTile( - title: LSTitle(text: 'Stack Trace'), - subtitle: LSSubtitle(text: _arguments?.log?.stacktrace ?? 'Unknown', maxLines: 1), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => GlobalDialogs.textPreview(context, 'Stack Trace', _arguments?.log?.stacktrace, alignLeft: true), - ), - ], - ); -} diff --git a/lib/modules/settings/routes/logs/logs_types.dart b/lib/modules/settings/routes/logs/logs_types.dart deleted file mode 100644 index 40d0c555..00000000 --- a/lib/modules/settings/routes/logs/logs_types.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsGeneralLogsTypes extends StatefulWidget { - static const ROUTE_NAME = '/settings/general/logs/types'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Log Types'); - - Widget get _body => LSListView( - children: [ - LSCardTile( - title: LSTitle(text: 'All Logs'), - subtitle: LSSubtitle(text: 'View Logs of All Types'), - trailing: LSIconButton(icon: Icons.developer_mode), - onTap: () async => _viewLogs('All'), - ), - LSDivider(), - LSCardTile( - title: LSTitle(text: 'Warning'), - subtitle: LSSubtitle(text: 'View Warning Logs'), - trailing: LSIconButton(icon: Icons.warning), - onTap: () async => _viewLogs('Warning'), - ), - LSCardTile( - title: LSTitle(text: 'Error'), - subtitle: LSSubtitle(text: 'View Error Logs'), - trailing: LSIconButton(icon: Icons.report), - onTap: () async => _viewLogs('Error'), - ), - LSCardTile( - title: LSTitle(text: 'Fatal'), - subtitle: LSSubtitle(text: 'View Fatal Logs'), - trailing: LSIconButton(icon: Icons.new_releases), - onTap: () async => _viewLogs('Fatal'), - ), - ], - ); - - Future _viewLogs(String type) async => Navigator.of(context).pushNamed( - SettingsGeneralLogsView.ROUTE_NAME, - arguments: SettingsGeneralLogsViewArguments(type: type), - ); -} diff --git a/lib/modules/settings/routes/logs/logs_view.dart b/lib/modules/settings/routes/logs/logs_view.dart deleted file mode 100644 index 1fe40c96..00000000 --- a/lib/modules/settings/routes/logs/logs_view.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:f_logs/f_logs.dart' as FLog; -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsGeneralLogsViewArguments { - final String type; - - SettingsGeneralLogsViewArguments({ - @required this.type - }); -} - -class SettingsGeneralLogsView extends StatefulWidget { - static const ROUTE_NAME = '/settings/general/logs/view'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - SettingsGeneralLogsViewArguments _arguments; - List _logs = []; - List levels = []; - - @override - void initState() { - super.initState(); - SchedulerBinding.instance.addPostFrameCallback((_) async { - _arguments = ModalRoute.of(context).settings.arguments; - _setLogLevel(); - await _fetchLogs(); - setState(() {}); - }); - } - - void _setLogLevel() { - switch(_arguments?.type) { - case 'All': levels = []; break; - case 'Warning': levels = [FLog.LogLevel.WARNING.toString()]; break; - case 'Error': levels = [FLog.LogLevel.ERROR.toString()]; break; - case 'Fatal': levels = [FLog.LogLevel.FATAL.toString()]; break; - default: levels = []; break; - } - } - - Future _fetchLogs() async { - _logs = await FLog.FLog.getAllLogsByFilter(logLevels: levels); - _logs.sort((a, b) => b.timeInMillis.compareTo(a.timeInMillis)); - } - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _arguments == null ? null : _body, - ); - - Widget get _appBar => LSAppBar(title: '${_arguments?.type} Logs'); - - Widget get _body => _logs.length == 0 - ? LSGenericMessage(text: 'No Logs Found') - : LSListViewBuilder( - itemCount: _logs.length, - itemBuilder: (context, index) => _entry(_logs[index]), - ); - - Widget _entry(FLog.Log log) => LSCardTile( - title: LSTitle(text: log.text), - subtitle: RichText( - text: TextSpan( - style: TextStyle( - color: Colors.white70, - fontSize: Constants.UI_FONT_SIZE_SUBTITLE, - ), - children: [ - TextSpan(text: log.timestamp), - TextSpan( - text: '\n${log.logLevel.lsFLogLogLevel_name()}', - style: TextStyle( - color: log.logLevel.lsFLogLogLevel_color(), - fontWeight: FontWeight.bold, - ), - ) - //_getLogLevel(log.logLevel), - ], - ), - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _logDetails(log), - padContent: true, - ); - - Future _logDetails(FLog.Log log) async => await Navigator.of(context).pushNamed( - SettingsGeneralLogsDetails.ROUTE_NAME, - arguments: SettingsGeneralLogsDetailsArguments(log: log), - ); -} diff --git a/lib/modules/settings/routes/modules.dart b/lib/modules/settings/routes/modules.dart deleted file mode 100644 index 1d8756da..00000000 --- a/lib/modules/settings/routes/modules.dart +++ /dev/null @@ -1,82 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules.dart'; - -class SettingsModules extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules'; - - @override - State createState() => _State(); -} - -class _State extends State with AutomaticKeepAliveClientMixin { - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - return Scaffold( - body: _body, - ); - } - - Widget get _body => LSListView( - children: [ - ..._general, - if(ModuleFlags.AUTOMATION) ..._automation, - if(ModuleFlags.CLIENTS) ..._clients, - if(ModuleFlags.MONITORING) ..._monitoring, - ], - ); - - List get _general => [ - LSHeader( - text: 'General', - subtitle: 'Configure and customize general modules in LunaSea', - ), - LSCardTile( - title: LSTitle(text: Constants.APPLICATION_NAME), - subtitle: LSSubtitle(text: 'Configure Global Options'), - trailing: LSIconButton(icon: CustomIcons.code), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesLunaSea.ROUTE_NAME), - ), - _tileFromModuleMap(HomeConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesHome.ROUTE_NAME)), - if(ModuleFlags.SEARCH) _tileFromModuleMap(SearchConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesSearch.ROUTE_NAME)), - if(ModuleFlags.WAKE_ON_LAN) _tileFromModuleMap(WakeOnLANConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesWakeOnLAN.ROUTE_NAME)), - ]; - - List get _automation => [ - LSHeader( - text: 'Automation', - subtitle: 'Configure and customize automation modules', - ), - if(ModuleFlags.LIDARR) _tileFromModuleMap(LidarrConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesLidarr.ROUTE_NAME)), - if(ModuleFlags.RADARR) _tileFromModuleMap(RadarrConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesRadarr.ROUTE_NAME)), - if(ModuleFlags.SONARR) _tileFromModuleMap(SonarrConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesSonarr.ROUTE_NAME)), - ]; - - List get _clients => [ - LSHeader( - text: 'Clients', - subtitle: 'Configure and customize client modules', - ), - if(ModuleFlags.NZBGET) _tileFromModuleMap(NZBGetConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesNZBGet.ROUTE_NAME)), - if(ModuleFlags.SABNZBD) _tileFromModuleMap(SABnzbdConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesSABnzbd.ROUTE_NAME)), - ]; - - List get _monitoring => [ - LSHeader( - text: 'Monitoring', - subtitle: 'Configure and customize monitoring modules', - ), - if(ModuleFlags.TAUTULLI) _tileFromModuleMap(TautulliConstants.MODULE_MAP, () async => Navigator.of(context).pushNamed(SettingsModulesTautulli.ROUTE_NAME)), - ]; - - Widget _tileFromModuleMap(ModuleMap map, Function onTap) => LSCardTile( - title: LSTitle(text: map.name), - subtitle: LSSubtitle(text: map.settingsDescription), - trailing: LSIconButton(icon: map.icon), - onTap: onTap, - ); -} diff --git a/lib/modules/settings/routes/modules/automation_lidarr.dart b/lib/modules/settings/routes/modules/automation_lidarr.dart deleted file mode 100644 index 3dea68d4..00000000 --- a/lib/modules/settings/routes/modules/automation_lidarr.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'automation_lidarr/automation_lidarr.dart'; -export 'automation_lidarr/automation_lidarr_headers.dart'; diff --git a/lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr.dart b/lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr.dart deleted file mode 100644 index 15da2f8d..00000000 --- a/lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr.dart +++ /dev/null @@ -1,156 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/lidarr.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesLidarr extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/lidarr'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'Lidarr'); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for Lidarr functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable Lidarr'), - subtitle: null, - trailing: Switch( - value: _profile.lidarrEnabled ?? false, - onChanged: (value) { - _profile.lidarrEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Host'), - subtitle: LSSubtitle( - text: _profile.lidarrHost == null || _profile.lidarrHost == '' - ? 'Not Set' - : _profile.lidarrHost - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeHost, - ), - LSCardTile( - title: LSTitle(text: 'API Key'), - subtitle: LSSubtitle( - text: _profile.lidarrKey == null || _profile.lidarrKey == '' - ? 'Not Set' - : '••••••••••••' - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeKey, - ), - LSDivider(), - LSButton( - text: 'Test Connection', - onTap: _testConnection, - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize Lidarr to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [LidarrDatabaseValue.NAVIGATION_INDEX.key]), - builder: (context, box, _) => LSCardTile( - title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: LidarrNavigationBar.titles[LidarrDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _defaultPage(), - ), - ), - ]; - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced options for users with non-standard networking configurations', - ), - LSCardTile( - title: LSTitle(text: 'Custom Headers'), - subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesLidarrHeaders.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Strict SSL/TLS Validation'), - subtitle: LSSubtitle(text: 'For Invalid Certificates'), - trailing: Switch( - value: _profile.lidarrStrictTLS ?? true, - onChanged: (value) async { - if(value) { - _profile.lidarrStrictTLS = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.toggleStrictTLS(context); - if(_values[0]) { - _profile.lidarrStrictTLS = value; - _profile.save(context: context); - } - } - }, - ), - ), - ]; - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ..._customization, - ..._advanced, - ], - ); - }, - ); - - Future _changeHost() async { - List _values = await SettingsDialogs.editHost(context, 'Lidarr Host', prefill: _profile.lidarrHost ?? ''); - if(_values[0]) { - _profile.lidarrHost = _values[1]; - _profile.save(context: context); - } - } - - Future _changeKey() async { - List _values = await GlobalDialogs.editText(context, 'Lidarr API Key', prefill: _profile.lidarrKey ?? ''); - if(_values[0]) { - _profile.lidarrKey = _values[1]; - _profile.save(context: context); - } - } - - Future _defaultPage() async { - List _values = await LidarrDialogs.defaultPage(context); - if(_values[0]) LidarrDatabaseValue.NAVIGATION_INDEX.put(_values[1]); - } - - Future _testConnection() async => await LidarrAPI.from(_profile).testConnection() - ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'Lidarr is ready to use with LunaSea', type: SNACKBAR_TYPE.success) - : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); -} diff --git a/lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr_headers.dart b/lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr_headers.dart deleted file mode 100644 index a74a722b..00000000 --- a/lib/modules/settings/routes/modules/automation_lidarr/automation_lidarr_headers.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesLidarrHeaders extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/lidarr/headers'; - - @override - State createState() => _State(); -} - -class _State extends State { - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Custom Headers'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, profile, widget) => LSListView( - children: [ - ..._headers, - ], - ), - ); - - List get _headers => [ - LSHeader( - text: 'Custom Headers', - subtitle: 'Define custom headers that will be attached to every request made to the module', - ), - if((_profile.getLidarr()['headers'] as Map).isEmpty) LSGenericMessage( - text: 'No Custom Headers Added', - ), - ..._list, - LSDivider(), - LSButton( - text: 'Add Header', - onTap: () async => _showAddPrompt(), - ), - ]; - - List get _list { - Map headers = Map.from(_profile.getLidarr()['headers']); - List list = []; - headers.forEach((key, value) => list.add(LSCardTile( - title: LSTitle(text: key.toString()), - subtitle: LSSubtitle(text: value.toString()), - trailing: LSIconButton( - icon: Icons.delete, - color: LSColors.red, - onPressed: () async => _deleteIndexer(key.toString(), value.toString()), - ), - ))); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _showAddPrompt() async { - List results = await SettingsDialogs.addHeader(context); - if(results[0]) switch(results[1]) { - case 1: _showAuthenticationPrompt(); break; - case 100: _showCustomPrompt(); break; - default: break; - } - } - - Future _showAuthenticationPrompt() async { - List results = await SettingsDialogs.addAuthenticationHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getLidarr()['headers']); - String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); - _headers.addAll({'Authorization': 'Basic $_auth'}); - _profile.lidarrHeaders = _headers; - _profile.save(context: context); - } - } - - Future _showCustomPrompt() async { - List results = await SettingsDialogs.addCustomHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getLidarr()['headers']); - _headers.addAll({results[1]: results[2]}); - _profile.lidarrHeaders = _headers; - _profile.save(context: context); - } - } - - Future _deleteIndexer(String key, String value) async { - List results = await SettingsDialogs.deleteHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getLidarr()['headers']); - _headers.remove(key); - _profile.lidarrHeaders = _headers; - _profile.save(context: context); - LSSnackBar( - context: context, - message: key, - title: 'Header Deleted', - type: SNACKBAR_TYPE.success, - ); - } - } -} diff --git a/lib/modules/settings/routes/modules/automation_radarr.dart b/lib/modules/settings/routes/modules/automation_radarr.dart deleted file mode 100644 index 261736a0..00000000 --- a/lib/modules/settings/routes/modules/automation_radarr.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'automation_radarr/automation_radarr.dart'; -export 'automation_radarr/automation_radarr_headers.dart'; diff --git a/lib/modules/settings/routes/modules/automation_radarr/automation_radarr.dart b/lib/modules/settings/routes/modules/automation_radarr/automation_radarr.dart deleted file mode 100644 index c9defa33..00000000 --- a/lib/modules/settings/routes/modules/automation_radarr/automation_radarr.dart +++ /dev/null @@ -1,156 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/radarr.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesRadarr extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/radarr'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'Radarr'); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for Radarr functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable Radarr'), - subtitle: null, - trailing: Switch( - value: _profile.radarrEnabled ?? false, - onChanged: (value) { - _profile.radarrEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Host'), - subtitle: LSSubtitle( - text: _profile.radarrHost == null || _profile.radarrHost == '' - ? 'Not Set' - : _profile.radarrHost - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeHost, - ), - LSCardTile( - title: LSTitle(text: 'API Key'), - subtitle: LSSubtitle( - text: _profile.radarrKey == null || _profile.radarrKey == '' - ? 'Not Set' - : '••••••••••••' - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeKey, - ), - LSDivider(), - LSButton( - text: 'Test Connection', - onTap: _testConnection, - ), - ]; - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced options for users with non-standard networking configurations', - ), - LSCardTile( - title: LSTitle(text: 'Custom Headers'), - subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesRadarrHeaders.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Strict SSL/TLS Validation'), - subtitle: LSSubtitle(text: 'For Invalid Certificates'), - trailing: Switch( - value: _profile.radarrStrictTLS ?? true, - onChanged: (value) async { - if(value) { - _profile.radarrStrictTLS = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.toggleStrictTLS(context); - if(_values[0]) { - _profile.radarrStrictTLS = value; - _profile.save(context: context); - } - } - }, - ), - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize Radarr to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [RadarrDatabaseValue.NAVIGATION_INDEX.key]), - builder: (context, box, _) => LSCardTile( - title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: RadarrNavigationBar.titles[RadarrDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _defaultPage(), - ), - ), - ]; - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ..._customization, - ..._advanced, - ], - ); - }, - ); - - Future _changeHost() async { - List _values = await SettingsDialogs.editHost(context, 'Radarr Host', prefill: _profile.radarrHost ?? ''); - if(_values[0]) { - _profile.radarrHost = _values[1]; - _profile.save(context: context); - } - } - - Future _changeKey() async { - List _values = await GlobalDialogs.editText(context, 'Radarr API Key', prefill: _profile.radarrKey ?? ''); - if(_values[0]) { - _profile.radarrKey = _values[1]; - _profile.save(context: context); - } - } - - Future _defaultPage() async { - List _values = await RadarrDialogs.defaultPage(context); - if(_values[0]) RadarrDatabaseValue.NAVIGATION_INDEX.put(_values[1]); - } - - Future _testConnection() async => await RadarrAPI.from(_profile).testConnection() - ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'Radarr is ready to use with LunaSea', type: SNACKBAR_TYPE.success) - : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); -} diff --git a/lib/modules/settings/routes/modules/automation_radarr/automation_radarr_headers.dart b/lib/modules/settings/routes/modules/automation_radarr/automation_radarr_headers.dart deleted file mode 100644 index beb8e2bc..00000000 --- a/lib/modules/settings/routes/modules/automation_radarr/automation_radarr_headers.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesRadarrHeaders extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/radarr/headers'; - - @override - State createState() => _State(); -} - -class _State extends State { - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Custom Headers'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, profile, widget) => LSListView( - children: [ - ..._headers, - ], - ), - ); - - List get _headers => [ - LSHeader( - text: 'Custom Headers', - subtitle: 'Define custom headers that will be attached to every request made to the module', - ), - if((_profile.getRadarr()['headers'] as Map).isEmpty) LSGenericMessage( - text: 'No Custom Headers Added', - ), - ..._list, - LSDivider(), - LSButton( - text: 'Add Header', - onTap: () async => _showAddPrompt(), - ), - ]; - - List get _list { - Map headers = Map.from(_profile.getRadarr()['headers']); - List list = []; - headers.forEach((key, value) => list.add(LSCardTile( - title: LSTitle(text: key.toString()), - subtitle: LSSubtitle(text: value.toString()), - trailing: LSIconButton( - icon: Icons.delete, - color: LSColors.red, - onPressed: () async => _deleteIndexer(key.toString(), value.toString()), - ), - ))); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _showAddPrompt() async { - List results = await SettingsDialogs.addHeader(context); - if(results[0]) switch(results[1]) { - case 1: _showAuthenticationPrompt(); break; - case 100: _showCustomPrompt(); break; - default: break; - } - } - - Future _showAuthenticationPrompt() async { - List results = await SettingsDialogs.addAuthenticationHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getRadarr()['headers']); - String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); - _headers.addAll({'Authorization': 'Basic $_auth'}); - _profile.radarrHeaders = _headers; - _profile.save(context: context); - } - } - - Future _showCustomPrompt() async { - List results = await SettingsDialogs.addCustomHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getRadarr()['headers']); - _headers.addAll({results[1]: results[2]}); - _profile.radarrHeaders = _headers; - _profile.save(context: context); - } - } - - Future _deleteIndexer(String key, String value) async { - List results = await SettingsDialogs.deleteHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getRadarr()['headers']); - _headers.remove(key); - _profile.radarrHeaders = _headers; - _profile.save(context: context); - LSSnackBar( - context: context, - message: key, - title: 'Header Deleted', - type: SNACKBAR_TYPE.success, - ); - } - } -} diff --git a/lib/modules/settings/routes/modules/automation_sonarr.dart b/lib/modules/settings/routes/modules/automation_sonarr.dart deleted file mode 100644 index 6fe10550..00000000 --- a/lib/modules/settings/routes/modules/automation_sonarr.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'automation_sonarr/automation_sonarr.dart'; -export 'automation_sonarr/automation_sonarr_headers.dart'; diff --git a/lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr.dart b/lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr.dart deleted file mode 100644 index 9da4ff87..00000000 --- a/lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr.dart +++ /dev/null @@ -1,167 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/sonarr.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesSonarr extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/sonarr'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'Sonarr'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ..._customization, - ..._advanced, - ], - ); - }, - ); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for Sonarr functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable Sonarr'), - subtitle: null, - trailing: Switch( - value: _profile.sonarrEnabled ?? false, - onChanged: (value) { - _profile.sonarrEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Host'), - subtitle: LSSubtitle( - text: _profile.sonarrHost == null || _profile.sonarrHost == '' - ? 'Not Set' - : _profile.sonarrHost - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeHost, - ), - LSCardTile( - title: LSTitle(text: 'API Key'), - subtitle: LSSubtitle( - text: _profile.sonarrKey == null || _profile.sonarrKey == '' - ? 'Not Set' - : '••••••••••••' - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeKey, - ), - // LSCardTile( - // title: LSTitle(text: 'Sonarr v3'), - // subtitle: LSSubtitle(text: 'Enable Sonarr v3 Features'), - // trailing: Switch( - // value: _profile.sonarrVersion3 ?? false, - // onChanged: (value) async { - // _profile.sonarrVersion3 = value; - // _profile.save(context: context); - // }, - // ), - // ), - LSDivider(), - LSButton( - text: 'Test Connection', - onTap: _testConnection, - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize Sonarr to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.NAVIGATION_INDEX.key]), - builder: (context, box, _) => LSCardTile( - title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: SonarrNavigationBar.titles[SonarrDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _defaultPage(), - ), - ), - ]; - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced options for users with non-standard networking configurations', - ), - LSCardTile( - title: LSTitle(text: 'Custom Headers'), - subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesSonarrHeaders.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Strict SSL/TLS Validation'), - subtitle: LSSubtitle(text: 'For Invalid Certificates'), - trailing: Switch( - value: _profile.sonarrStrictTLS ?? true, - onChanged: (value) async { - if(value) { - _profile.sonarrStrictTLS = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.toggleStrictTLS(context); - if(_values[0]) { - _profile.sonarrStrictTLS = value; - _profile.save(context: context); - } - } - }, - ), - ), - ]; - - Future _changeHost() async { - List _values = await SettingsDialogs.editHost(context, 'Sonarr Host', prefill: _profile.sonarrHost ?? ''); - if(_values[0]) { - _profile.sonarrHost = _values[1]; - _profile.save(context: context); - } - } - - Future _changeKey() async { - List _values = await GlobalDialogs.editText(context, 'Sonarr API Key', prefill: _profile.sonarrKey ?? ''); - if(_values[0]) { - _profile.sonarrKey = _values[1]; - _profile.save(context: context); - } - } - - Future _defaultPage() async { - List _values = await SonarrDialogs.defaultPage(context); - if(_values[0]) SonarrDatabaseValue.NAVIGATION_INDEX.put(_values[1]); - } - - Future _testConnection() async => await SonarrAPI.from(_profile).testConnection() - ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'Sonarr is ready to use with LunaSea', type: SNACKBAR_TYPE.success) - : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); -} diff --git a/lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr_headers.dart b/lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr_headers.dart deleted file mode 100644 index 26fe1005..00000000 --- a/lib/modules/settings/routes/modules/automation_sonarr/automation_sonarr_headers.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesSonarrHeaders extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/sonarr/headers'; - - @override - State createState() => _State(); -} - -class _State extends State { - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Custom Headers'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, profile, widget) => LSListView( - children: [ - ..._headers, - ], - ), - ); - - List get _headers => [ - LSHeader( - text: 'Custom Headers', - subtitle: 'Define custom headers that will be attached to every request made to the module', - ), - if((_profile.getSonarr()['headers'] as Map).isEmpty) LSGenericMessage( - text: 'No Custom Headers Added', - ), - ..._list, - LSDivider(), - LSButton( - text: 'Add Header', - onTap: () async => _showAddPrompt(), - ), - ]; - - List get _list { - Map headers = Map.from(_profile.getSonarr()['headers']); - List list = []; - headers.forEach((key, value) => list.add(LSCardTile( - title: LSTitle(text: key.toString()), - subtitle: LSSubtitle(text: value.toString()), - trailing: LSIconButton( - icon: Icons.delete, - color: LSColors.red, - onPressed: () async => _deleteIndexer(key.toString(), value.toString()), - ), - ))); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _showAddPrompt() async { - List results = await SettingsDialogs.addHeader(context); - if(results[0]) switch(results[1]) { - case 1: _showAuthenticationPrompt(); break; - case 100: _showCustomPrompt(); break; - default: break; - } - } - - Future _showAuthenticationPrompt() async { - List results = await SettingsDialogs.addAuthenticationHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getSonarr()['headers']); - String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); - _headers.addAll({'Authorization': 'Basic $_auth'}); - _profile.sonarrHeaders = _headers; - _profile.save(context: context); - } - } - - Future _showCustomPrompt() async { - List results = await SettingsDialogs.addCustomHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getSonarr()['headers']); - _headers.addAll({results[1]: results[2]}); - _profile.sonarrHeaders = _headers; - _profile.save(context: context); - } - } - - Future _deleteIndexer(String key, String value) async { - List results = await SettingsDialogs.deleteHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getSonarr()['headers']); - _headers.remove(key); - _profile.sonarrHeaders = _headers; - _profile.save(context: context); - LSSnackBar( - context: context, - message: key, - title: 'Header Deleted', - type: SNACKBAR_TYPE.success, - ); - } - } -} diff --git a/lib/modules/settings/routes/modules/clients_nzbget.dart b/lib/modules/settings/routes/modules/clients_nzbget.dart deleted file mode 100644 index 61ac060f..00000000 --- a/lib/modules/settings/routes/modules/clients_nzbget.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'clients_nzbget/clients_nzbget.dart'; -export 'clients_nzbget/clients_nzbget_headers.dart'; diff --git a/lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget.dart b/lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget.dart deleted file mode 100644 index 5a427854..00000000 --- a/lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget.dart +++ /dev/null @@ -1,193 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/nzbget.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesNZBGet extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/nzbget'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'NZBGet'); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for NZBGet functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable NZBGet'), - subtitle: null, - trailing: Switch( - value: _profile.nzbgetEnabled ?? false, - onChanged: (value) { - _profile.nzbgetEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Host'), - subtitle: LSSubtitle( - text: _profile.nzbgetHost == null || _profile.nzbgetHost == '' - ? 'Not Set' - : _profile.nzbgetHost - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeHost, - ), - LSCardTile( - title: LSTitle(text: 'Username'), - subtitle: LSSubtitle( - text: _profile.nzbgetUser == null || _profile.nzbgetUser == '' - ? 'Not Set' - : _profile.nzbgetUser - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeUser, - ), - LSCardTile( - title: LSTitle(text: 'Password'), - subtitle: LSSubtitle( - text: _profile.nzbgetPass == null || _profile.nzbgetPass == '' - ? 'Not Set' - : '••••••••••••' - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changePass, - ), - LSDivider(), - LSButton( - text: 'Test Connection', - onTap: _testConnection, - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize NZBGet to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [NZBGetDatabaseValue.NAVIGATION_INDEX.key]), - builder: (context, box, _) => LSCardTile( - title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: NZBGetNavigationBar.titles[NZBGetDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _defaultPage(), - ), - ), - ]; - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced options for users with non-standard networking configurations', - ), - LSCardTile( - title: LSTitle(text: 'Custom Headers'), - subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesNZBGetHeaders.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Strict SSL/TLS Validation'), - subtitle: LSSubtitle(text: 'For Invalid Certificates'), - trailing: Switch( - value: _profile.nzbgetStrictTLS ?? true, - onChanged: (value) async { - if(value) { - _profile.nzbgetStrictTLS = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.toggleStrictTLS(context); - if(_values[0]) { - _profile.nzbgetStrictTLS = value; - _profile.save(context: context); - } - } - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Use Basic Authentication'), - subtitle: LSSubtitle(text: 'Different Authentication Method'), - trailing: Switch( - value: _profile.nzbgetBasicAuth ?? false, - onChanged: (value) async { - if(!value) { - _profile.nzbgetBasicAuth = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.nzbgetBasicAuthentication(context); - if(_values[0]) { - _profile.nzbgetBasicAuth = value; - _profile.save(context: context); - } - } - }, - ), - ), - ]; - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ..._customization, - ..._advanced, - ], - ); - }, - ); - - Future _changeHost() async { - List _values = await SettingsDialogs.editHost(context, 'NZBGet Host', prefill: _profile.nzbgetHost ?? ''); - if(_values[0]) { - _profile.nzbgetHost = _values[1]; - _profile.save(context: context); - } - } - - Future _changeUser() async { - List _values = await GlobalDialogs.editText(context, 'NZBGet Username', prefill: _profile.nzbgetUser ?? ''); - if(_values[0]) { - _profile.nzbgetUser = _values[1]; - _profile.save(context: context); - } - } - - Future _changePass() async { - List _values = await GlobalDialogs.editText(context, 'NZBGet Password', prefill: _profile.nzbgetPass ?? ''); - if(_values[0]) { - _profile.nzbgetPass = _values[1]; - _profile.save(context: context); - } - } - - Future _defaultPage() async { - List _values = await NZBGetDialogs.defaultPage(context); - if(_values[0]) NZBGetDatabaseValue.NAVIGATION_INDEX.put(_values[1]); - } - - Future _testConnection() async => await NZBGetAPI.from(_profile).testConnection() - ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'NZBGet is ready to use with LunaSea', type: SNACKBAR_TYPE.success) - : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); -} diff --git a/lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget_headers.dart b/lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget_headers.dart deleted file mode 100644 index 0ecec369..00000000 --- a/lib/modules/settings/routes/modules/clients_nzbget/clients_nzbget_headers.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesNZBGetHeaders extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/nzbget/headers'; - - @override - State createState() => _State(); -} - -class _State extends State { - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Custom Headers'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, profile, widget) => LSListView( - children: [ - ..._headers, - ], - ), - ); - - List get _headers => [ - LSHeader( - text: 'Custom Headers', - subtitle: 'Define custom headers that will be attached to every request made to the module', - ), - if((_profile.getNZBGet()['headers'] as Map).isEmpty) LSGenericMessage( - text: 'No Custom Headers Added', - ), - ..._list, - LSDivider(), - LSButton( - text: 'Add Header', - onTap: () async => _showAddPrompt(), - ), - ]; - - List get _list { - Map headers = Map.from(_profile.getNZBGet()['headers']); - List list = []; - headers.forEach((key, value) => list.add(LSCardTile( - title: LSTitle(text: key.toString()), - subtitle: LSSubtitle(text: value.toString()), - trailing: LSIconButton( - icon: Icons.delete, - color: LSColors.red, - onPressed: () async => _deleteIndexer(key.toString(), value.toString()), - ), - ))); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _showAddPrompt() async { - List results = await SettingsDialogs.addHeader(context); - if(results[0]) switch(results[1]) { - case 1: _showAuthenticationPrompt(); break; - case 100: _showCustomPrompt(); break; - default: break; - } - } - - Future _showAuthenticationPrompt() async { - List results = await SettingsDialogs.addAuthenticationHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getNZBGet()['headers']); - String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); - _headers.addAll({'Authorization': 'Basic $_auth'}); - _profile.nzbgetHeaders = _headers; - _profile.save(context: context); - } - } - - Future _showCustomPrompt() async { - List results = await SettingsDialogs.addCustomHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getNZBGet()['headers']); - _headers.addAll({results[1]: results[2]}); - _profile.nzbgetHeaders = _headers; - _profile.save(context: context); - } - } - - Future _deleteIndexer(String key, String value) async { - List results = await SettingsDialogs.deleteHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getNZBGet()['headers']); - _headers.remove(key); - _profile.nzbgetHeaders = _headers; - _profile.save(context: context); - LSSnackBar( - context: context, - message: key, - title: 'Header Deleted', - type: SNACKBAR_TYPE.success, - ); - } - } -} diff --git a/lib/modules/settings/routes/modules/clients_sabnzbd.dart b/lib/modules/settings/routes/modules/clients_sabnzbd.dart deleted file mode 100644 index 2b6aed77..00000000 --- a/lib/modules/settings/routes/modules/clients_sabnzbd.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'clients_sabnzbd/clients_sabnzbd.dart'; -export 'clients_sabnzbd/clients_sabnzbd_headers.dart'; diff --git a/lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd.dart b/lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd.dart deleted file mode 100644 index 7343030b..00000000 --- a/lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd.dart +++ /dev/null @@ -1,156 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/sabnzbd.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesSABnzbd extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/sabnzbd'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'SABnzbd'); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for SABnzbd functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable SABnzbd'), - subtitle: null, - trailing: Switch( - value: _profile.sabnzbdEnabled ?? false, - onChanged: (value) { - _profile.sabnzbdEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Host'), - subtitle: LSSubtitle( - text: _profile.sabnzbdHost == null || _profile.sabnzbdHost == '' - ? 'Not Set' - : _profile.sabnzbdHost - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeHost, - ), - LSCardTile( - title: LSTitle(text: 'API Key'), - subtitle: LSSubtitle( - text: _profile.sabnzbdKey == null || _profile.sabnzbdKey == '' - ? 'Not Set' - : '••••••••••••' - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeKey, - ), - LSDivider(), - LSButton( - text: 'Test Connection', - onTap: _testConnection, - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize SABnzbd to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [SABnzbdDatabaseValue.NAVIGATION_INDEX.key]), - builder: (context, box, _) => LSCardTile( - title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: SABnzbdNavigationBar.titles[SABnzbdDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _defaultPage(), - ), - ), - ]; - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced options for users with non-standard networking configurations', - ), - LSCardTile( - title: LSTitle(text: 'Custom Headers'), - subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesSABnzbdHeaders.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Strict SSL/TLS Validation'), - subtitle: LSSubtitle(text: 'For Invalid Certificates'), - trailing: Switch( - value: _profile.sabnzbdStrictTLS ?? true, - onChanged: (value) async { - if(value) { - _profile.sabnzbdStrictTLS = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.toggleStrictTLS(context); - if(_values[0]) { - _profile.sabnzbdStrictTLS = value; - _profile.save(context: context); - } - } - }, - ), - ), - ]; - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ..._customization, - ..._advanced, - ], - ); - }, - ); - - Future _changeHost() async { - List _values = await SettingsDialogs.editHost(context, 'SABnzbd Host', prefill: _profile.sabnzbdHost ?? ''); - if(_values[0]) { - _profile.sabnzbdHost = _values[1]; - _profile.save(context: context); - } - } - - Future _changeKey() async { - List _values = await GlobalDialogs.editText(context, 'SABnzbd API Key', prefill: _profile.sabnzbdKey ?? ''); - if(_values[0]) { - _profile.sabnzbdKey = _values[1]; - _profile.save(context: context); - } - } - - Future _defaultPage() async { - List _values = await SABnzbdDialogs.defaultPage(context); - if(_values[0]) SABnzbdDatabaseValue.NAVIGATION_INDEX.put(_values[1]); - } - - Future _testConnection() async => await SABnzbdAPI.from(_profile).testConnection() - ? LSSnackBar(context: context, title: 'Connected Successfully', message: 'SABnzbd is ready to use with LunaSea', type: SNACKBAR_TYPE.success) - : LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); -} diff --git a/lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd_headers.dart b/lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd_headers.dart deleted file mode 100644 index bb670aad..00000000 --- a/lib/modules/settings/routes/modules/clients_sabnzbd/clients_sabnzbd_headers.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesSABnzbdHeaders extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/sabnzbd/headers'; - - @override - State createState() => _State(); -} - -class _State extends State { - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Custom Headers'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, profile, widget) => LSListView( - children: [ - ..._headers, - ], - ), - ); - - List get _headers => [ - LSHeader( - text: 'Custom Headers', - subtitle: 'Define custom headers that will be attached to every request made to the module', - ), - if((_profile.getSABnzbd()['headers'] as Map).isEmpty) LSGenericMessage( - text: 'No Custom Headers Added', - ), - ..._list, - LSDivider(), - LSButton( - text: 'Add Header', - onTap: () async => _showAddPrompt(), - ), - ]; - - List get _list { - Map headers = Map.from(_profile.getSABnzbd()['headers']); - List list = []; - headers.forEach((key, value) => list.add(LSCardTile( - title: LSTitle(text: key.toString()), - subtitle: LSSubtitle(text: value.toString()), - trailing: LSIconButton( - icon: Icons.delete, - color: LSColors.red, - onPressed: () async => _deleteIndexer(key.toString(), value.toString()), - ), - ))); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _showAddPrompt() async { - List results = await SettingsDialogs.addHeader(context); - if(results[0]) switch(results[1]) { - case 1: _showAuthenticationPrompt(); break; - case 100: _showCustomPrompt(); break; - default: break; - } - } - - Future _showAuthenticationPrompt() async { - List results = await SettingsDialogs.addAuthenticationHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getSABnzbd()['headers']); - String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); - _headers.addAll({'Authorization': 'Basic $_auth'}); - _profile.sabnzbdHeaders = _headers; - _profile.save(context: context); - } - } - - Future _showCustomPrompt() async { - List results = await SettingsDialogs.addCustomHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getSABnzbd()['headers']); - _headers.addAll({results[1]: results[2]}); - _profile.sabnzbdHeaders = _headers; - _profile.save(context: context); - } - } - - Future _deleteIndexer(String key, String value) async { - List results = await SettingsDialogs.deleteHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getSABnzbd()['headers']); - _headers.remove(key); - _profile.sabnzbdHeaders = _headers; - _profile.save(context: context); - LSSnackBar( - context: context, - message: key, - title: 'Header Deleted', - type: SNACKBAR_TYPE.success, - ); - } - } -} diff --git a/lib/modules/settings/routes/modules/general_home.dart b/lib/modules/settings/routes/modules/general_home.dart deleted file mode 100644 index 89bb5559..00000000 --- a/lib/modules/settings/routes/modules/general_home.dart +++ /dev/null @@ -1,60 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesHome extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/home'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'Home'); - - Widget get _body => LSListView( - children: [ - ..._customization, - ..._calendarCustomization, - ..._quickLinksCustomization, - ], - ); - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Make the home screen fit your needs', - ), - SettingsModulesHomeDefaultPageTile(), - ]; - - List get _calendarCustomization => [ - LSHeader( - text: 'Calendar Customization', - subtitle: 'Make the calendar fit your needs', - ), - SettingsModulesHomeCalendarStartingDateTile(), - SettingsModulesHomeCalendarStartingSizeTile(), - SettingsModulesHomeCalendarStartingTypeTile(), - if(ModuleFlags.LIDARR) SettingsModulesCalendarEnableLidarrTile(), - if(ModuleFlags.RADARR) SettingsModulesCalendarEnableRadarrTile(), - if(ModuleFlags.SONARR) SettingsModulesCalendarEnableSonarrTile(), - ]; - - List get _quickLinksCustomization => [ - LSHeader( - text: 'Modules Customization', - subtitle: 'Make the modules fit your needs', - ), - SettingsModulesHomeBrandColours(), - ]; -} diff --git a/lib/modules/settings/routes/modules/general_lunasea.dart b/lib/modules/settings/routes/modules/general_lunasea.dart deleted file mode 100644 index 77fb85ff..00000000 --- a/lib/modules/settings/routes/modules/general_lunasea.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'general_lunasea/general_lunasea.dart'; -export 'general_lunasea/general_lunasea_quick_actions.dart'; diff --git a/lib/modules/settings/routes/modules/general_lunasea/general_lunasea.dart b/lib/modules/settings/routes/modules/general_lunasea/general_lunasea.dart deleted file mode 100644 index 6157e171..00000000 --- a/lib/modules/settings/routes/modules/general_lunasea/general_lunasea.dart +++ /dev/null @@ -1,61 +0,0 @@ -import 'dart:io'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesLunaSea extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/lunasea'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: Constants.APPLICATION_NAME); - - Widget get _body => LSListView( - children: [ - ..._appearance, - ..._drawer, - ..._other, - ], - ); - - List get _appearance => [ - LSHeader( - text: 'Appearance', - subtitle: 'Customize the appearance of ${Constants.APPLICATION_NAME} to fit your needs', - ), - SettingsModulesLunaSeaAMOLEDTile(), - SettingsModulesLunaSeaAMOLEDBorderTile(), - SettingsModulesLunaSeaUse24HourTimeTile(), - ]; - - List get _other => [ - LSHeader( - text: 'Other', - subtitle: 'All other customizable options', - ), - SettingsModulesQuickActionsTile(), - if(Platform.isIOS) SettingsModulesLunaSeaBrowserTile(), - ]; - - List get _drawer => [ - LSHeader( - text: 'Drawer', - subtitle: 'Customize the drawer to fit your needs', - ), - SettingsDrawerExpandAutomationTile(), - SettingsDrawerExpandClientsTile(), - SettingsDrawerExpandMonitoringTile(), - ]; -} diff --git a/lib/modules/settings/routes/modules/general_lunasea/general_lunasea_quick_actions.dart b/lib/modules/settings/routes/modules/general_lunasea/general_lunasea_quick_actions.dart deleted file mode 100644 index 1a470a1e..00000000 --- a/lib/modules/settings/routes/modules/general_lunasea/general_lunasea_quick_actions.dart +++ /dev/null @@ -1,58 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; - -class SettingsModulesLunaSeaQuickActions extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/lunasea/quick_actions'; - - @override - State createState() => _State(); -} - -class _State extends State { - final GlobalKey _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Quick Actions'); - - Widget get _body => LSListView( - children: [ - LSHeader( - text: 'Modules', - subtitle: 'Only four quick actions will appear, and are added in the order below. Enabling more than four modules will have no effect.', - ), - _tile(title: 'Search', action: LunaSeaDatabaseValue.QUICK_ACTIONS_SEARCH), - LSDivider(), - _tile(title: 'Lidarr', action: LunaSeaDatabaseValue.QUICK_ACTIONS_LIDARR), - _tile(title: 'Radarr', action: LunaSeaDatabaseValue.QUICK_ACTIONS_RADARR), - _tile(title: 'Sonarr', action: LunaSeaDatabaseValue.QUICK_ACTIONS_SONARR), - LSDivider(), - _tile(title: 'NZBGet', action: LunaSeaDatabaseValue.QUICK_ACTIONS_NZBGET), - _tile(title: 'SABnzbd', action: LunaSeaDatabaseValue.QUICK_ACTIONS_SABNZBD), - LSDivider(), - _tile(title: 'Tautulli', action: LunaSeaDatabaseValue.QUICK_ACTIONS_TAUTULLI), - ], - ); - - Widget _tile({ - @required String title, - @required LunaSeaDatabaseValue action, - }) => LSCardTile( - title: LSTitle(text: title), - trailing: ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [action.key]), - builder: (context, box, _) => Switch( - value: action.data, - onChanged: (value) { - action.put(value); - HomescreenActions.setShortcutItems(); - } - ), - ), - ); -} diff --git a/lib/modules/settings/routes/modules/general_search.dart b/lib/modules/settings/routes/modules/general_search.dart deleted file mode 100644 index 006d3696..00000000 --- a/lib/modules/settings/routes/modules/general_search.dart +++ /dev/null @@ -1,95 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/search/core/database.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesSearch extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/search'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: ValueListenableBuilder( - valueListenable: Database.indexersBox.listenable(), - builder: (context, box, widget) => _body, - ), - ); - - Widget get _appBar => LSAppBar(title: 'Search'); - - Widget get _body => LSListView( - children: [ - ..._indexers, - ..._customization, - ], - ); - - List get _indexers => [ - LSHeader( - text: 'Newznab Indexers', - subtitle: 'LunaSea supports all standard newznab-based indexers, including NZBHydra2', - ), - if(Database.indexersBox.length == 0) LSGenericMessage(text: 'No Indexers Added'), - ..._indexerList, - LSDivider(), - LSButton( - text: 'Add New Indexer', - onTap: () async => _enterAddIndexer(), - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize search to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [SearchDatabaseValue.HIDE_XXX.key]), - builder: (context, box, widget) => LSCardTile( - title: LSTitle(text: 'Hide Adult Categories'), - subtitle: LSSubtitle(text: 'Hide Categories Containing Adult Content'), - trailing: Switch( - value: SearchDatabaseValue.HIDE_XXX.data, - onChanged: (value) => SearchDatabaseValue.HIDE_XXX.put(value), - ), - ), - ), - ]; - - List get _indexerList { - List list = List.generate(Database.indexersBox.length, (index) { - IndexerHiveObject indexer = Database.indexersBox.getAt(index); - return LSCardTile( - title: LSTitle(text: indexer.displayName), - subtitle: LSSubtitle(text: indexer.host), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _enterEditIndexer(indexer), - ); - }); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _enterAddIndexer() async { - final dynamic result = await Navigator.of(context).pushNamed(SettingsModulesSearchAdd.ROUTE_NAME); - if(result != null && result[0] == 'indexer_added') - LSSnackBar(context: context, title: 'Indexer Added', message: result[1], type: SNACKBAR_TYPE.success); - } - - Future _enterEditIndexer(IndexerHiveObject indexer) async { - final dynamic result = await Navigator.of(context).pushNamed( - SettingsModulesSearchEdit.ROUTE_NAME, - arguments: SettingsModulesSearchEditArguments(indexer: indexer), - ); - if(result != null && result[0] == 'indexer_deleted') - LSSnackBar(context: context, title: 'Indexer Deleted', message: result[1], type: SNACKBAR_TYPE.success); - } -} diff --git a/lib/modules/settings/routes/modules/general_search_add.dart b/lib/modules/settings/routes/modules/general_search_add.dart deleted file mode 100644 index 88411ab5..00000000 --- a/lib/modules/settings/routes/modules/general_search_add.dart +++ /dev/null @@ -1,84 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core/database.dart'; -import 'package:lunasea/core.dart'; - -class SettingsModulesSearchAdd extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/search/add'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - IndexerHiveObject indexer = IndexerHiveObject.empty(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Add Indexer'); - - Widget get _body => LSListView( - children: [ - LSCardTile( - title: LSTitle(text: 'Display Name'), - subtitle: LSSubtitle(text: indexer.displayName == '' ? 'Not Set' : indexer.displayName), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async { - List _values = await GlobalDialogs.editText(context, 'Display Name', prefill: indexer.displayName); - setState(() => indexer.displayName = _values[0] - ? _values[1] - : indexer.displayName - ); - } - ), - LSCardTile( - title: LSTitle(text: 'Indexer API URL'), - subtitle: LSSubtitle(text: indexer.host == '' ? 'Not Set' : indexer.host), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async { - List _values = await GlobalDialogs.editText(context, 'Indexer API URL', prefill: indexer.host); - setState(() => indexer.host = _values[0] - ? _values[1] - : indexer.host - ); - } - ), - LSCardTile( - title: LSTitle(text: 'Indexer API Key'), - subtitle: LSSubtitle(text: indexer.key == '' ? 'Not Set' : indexer.key), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async { - List _values = await GlobalDialogs.editText(context, 'Indexer API Key', prefill: indexer.key); - setState(() => indexer.key = _values[0] - ? _values[1] - : indexer.key - ); - } - ), - LSDivider(), - LSButton( - text: 'Add Indexer', - onTap: () => _addIndexer(), - ), - ], - ); - - void _addIndexer() { - if(indexer.displayName == '' || indexer.host == '' || indexer.key == '') { - LSSnackBar( - context: context, - title: 'Failed to Add Indexer', - message: 'All fields are required', - type: SNACKBAR_TYPE.failure, - ); - } else { - Database.indexersBox.add(indexer); - Navigator.of(context).pop(['indexer_added', indexer.displayName]); - } - } -} diff --git a/lib/modules/settings/routes/modules/general_search_edit.dart b/lib/modules/settings/routes/modules/general_search_edit.dart deleted file mode 100644 index d028c45c..00000000 --- a/lib/modules/settings/routes/modules/general_search_edit.dart +++ /dev/null @@ -1,100 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:flutter/scheduler.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesSearchEditArguments { - final IndexerHiveObject indexer; - - SettingsModulesSearchEditArguments({ - @required this.indexer, - }); -} - -class SettingsModulesSearchEdit extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/search/edit'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - SettingsModulesSearchEditArguments _arguments; - - @override - void initState() { - super.initState(); - SchedulerBinding.instance.addPostFrameCallback((_) { - _arguments = ModalRoute.of(context).settings.arguments; - setState(() {}); - }); - } - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _arguments == null ? null : _body, - ); - - Widget get _appBar => LSAppBar(title: 'Edit Indexer'); - - Widget get _body => LSListView( - children: [ - LSCardTile( - title: LSTitle(text: 'Display Name'), - subtitle: LSSubtitle(text: _arguments?.indexer?.displayName == '' ? 'Not Set' : _arguments?.indexer?.displayName ?? ''), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async { - List _values = await GlobalDialogs.editText(context, 'Display Name', prefill: _arguments?.indexer?.displayName); - setState(() => _arguments?.indexer?.displayName = _values[0] - ? _values[1] - : _arguments?.indexer?.displayName - ); - _arguments?.indexer?.save(); - } - ), - LSCardTile( - title: LSTitle(text: 'URL'), - subtitle: LSSubtitle(text: _arguments?.indexer?.host == '' ? 'Not Set' : _arguments?.indexer?.host ?? ''), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async { - List _values = await GlobalDialogs.editText(context, 'URL', prefill: _arguments?.indexer?.host); - setState(() => _arguments?.indexer?.host = _values[0] - ? _values[1] - : _arguments?.indexer?.host - ); - _arguments?.indexer?.save(); - } - ), - LSCardTile( - title: LSTitle(text: 'API Key'), - subtitle: LSSubtitle(text: _arguments?.indexer?.key == '' ? 'Not Set' : _arguments?.indexer?.key ?? ''), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async { - List _values = await GlobalDialogs.editText(context, 'API Key', prefill: _arguments?.indexer?.key); - setState(() => _arguments?.indexer?.key = _values[0] - ? _values[1] - : _arguments?.indexer?.key - ); - _arguments?.indexer?.save(); - } - ), - LSDivider(), - LSButton( - text: 'Delete Indexer', - backgroundColor: LSColors.red, - onTap: () async => _deleteIndexer(), - ) - ], - ); - - Future _deleteIndexer() async { - List _values = await SettingsDialogs.deleteIndexer(context); - if(_values[0]) { - _arguments?.indexer?.delete(); - Navigator.of(context).pop(['indexer_deleted', _arguments?.indexer?.displayName]); - } - } -} diff --git a/lib/modules/settings/routes/modules/general_wake_on_lan.dart b/lib/modules/settings/routes/modules/general_wake_on_lan.dart deleted file mode 100644 index d145552e..00000000 --- a/lib/modules/settings/routes/modules/general_wake_on_lan.dart +++ /dev/null @@ -1,89 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesWakeOnLAN extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/wakeonlan'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'Wake on LAN'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ], - ); - }, - ); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for Wake on LAN functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable Wake on LAN'), - subtitle: null, - trailing: Switch( - value: _profile.wakeOnLANEnabled ?? false, - onChanged: (value) { - _profile.wakeOnLANEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Broadcast Address'), - subtitle: LSSubtitle( - text: _profile.wakeOnLANBroadcastAddress == null || _profile.wakeOnLANBroadcastAddress == '' - ? 'Not Set' - : _profile.wakeOnLANBroadcastAddress - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeBroadcastAddress, - ), - LSCardTile( - title: LSTitle(text: 'Device MAC Address'), - subtitle: LSSubtitle( - text: _profile.wakeOnLANMACAddress == null || _profile.wakeOnLANMACAddress == '' - ? 'Not Set' - : _profile.wakeOnLANMACAddress - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeMACAddress, - ), - ]; - - Future _changeBroadcastAddress() async { - List _values = await SettingsDialogs.editBroadcastAddress(context, _profile.wakeOnLANBroadcastAddress ?? ''); - if(_values[0]) { - _profile.wakeOnLANBroadcastAddress = _values[1]; - _profile.save(context: context); - } - } - - Future _changeMACAddress() async { - List _values = await SettingsDialogs.editMACAddress(context, _profile.wakeOnLANMACAddress ?? ''); - if(_values[0]) { - _profile.wakeOnLANMACAddress = _values[1]; - _profile.save(context: context); - } - } -} diff --git a/lib/modules/settings/routes/modules/monitoring_tautulli.dart b/lib/modules/settings/routes/modules/monitoring_tautulli.dart deleted file mode 100644 index 8a429e03..00000000 --- a/lib/modules/settings/routes/modules/monitoring_tautulli.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'monitoring_tautulli/monitoring_tautulli.dart'; -export 'monitoring_tautulli/monitoring_tautulli_headers.dart'; diff --git a/lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli.dart b/lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli.dart deleted file mode 100644 index 73dee249..00000000 --- a/lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli.dart +++ /dev/null @@ -1,175 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/tautulli.dart' hide Tautulli; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesTautulli extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/tautulli'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - ); - - Widget get _appBar => LSAppBar(title: 'Tautulli'); - - List get _configuration => [ - LSHeader( - text: 'Configuration', - subtitle: 'Mandatory configuration for Tautulli functionality', - ), - LSCardTile( - title: LSTitle(text: 'Enable Tautulli'), - subtitle: null, - trailing: Switch( - value: _profile.tautulliEnabled ?? false, - onChanged: (value) { - _profile.tautulliEnabled = value; - _profile.save(context: context); - }, - ), - ), - LSCardTile( - title: LSTitle(text: 'Host'), - subtitle: LSSubtitle( - text: _profile.tautulliHost == null || _profile.tautulliHost == '' - ? 'Not Set' - : _profile.tautulliHost - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeHost, - ), - LSCardTile( - title: LSTitle(text: 'API Key'), - subtitle: LSSubtitle( - text: _profile.tautulliKey == null || _profile.tautulliKey == '' - ? 'Not Set' - : '••••••••••••' - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: _changeKey, - ), - LSDivider(), - LSButton( - text: 'Test Connection', - onTap: _testConnection, - ), - ]; - - List get _customization => [ - LSHeader( - text: 'Customization', - subtitle: 'Customize Tautulli to fit your needs', - ), - ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [TautulliDatabaseValue.NAVIGATION_INDEX.key]), - builder: (context, box, _) => LSCardTile( - title: LSTitle(text: 'Default Page'), - subtitle: LSSubtitle( - text: TautulliNavigationBar.titles[TautulliDatabaseValue.NAVIGATION_INDEX.data], - ), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _defaultPage(), - ), - ), - ]; - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced options for users with non-standard networking configurations', - ), - LSCardTile( - title: LSTitle(text: 'Custom Headers'), - subtitle: LSSubtitle(text: 'Add Custom Headers to Requests'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => Navigator.of(context).pushNamed(SettingsModulesTautulliHeaders.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Strict SSL/TLS Validation'), - subtitle: LSSubtitle(text: 'For Invalid Certificates'), - trailing: Switch( - value: _profile.tautulliStrictTLS ?? true, - onChanged: (value) async { - if(value) { - _profile.tautulliStrictTLS = value; - _profile.save(context: context); - } else { - List _values = await SettingsDialogs.toggleStrictTLS(context); - if(_values[0]) { - _profile.tautulliStrictTLS = value; - _profile.save(context: context); - } - } - }, - ), - ), - ]; - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, box, widget) { - return LSListView( - children: [ - ..._configuration, - ..._customization, - ..._advanced, - ], - ); - }, - ); - - Future _changeHost() async { - List _values = await SettingsDialogs.editHost(context, 'Tautulli Host', prefill: _profile.tautulliHost ?? ''); - if(_values[0]) { - _profile.tautulliHost = _values[1]; - _profile.save(context: context); - } - } - - Future _changeKey() async { - List _values = await GlobalDialogs.editText(context, 'Tautulli API Key', prefill: _profile.tautulliKey ?? ''); - if(_values[0]) { - _profile.tautulliKey = _values[1]; - _profile.save(context: context); - } - } - - Future _defaultPage() async { - List _values = await TautulliDialogs.defaultPage(context); - if(_values[0]) TautulliDatabaseValue.NAVIGATION_INDEX.put(_values[1]); - } - - Future _testConnection() async { - TautulliState state = Provider.of(context, listen: false); - if(!state.enabled) { - LSSnackBar(context: context, title: 'Tautulli Not Enabled', message: 'Tautulli needs to be enabled', type: SNACKBAR_TYPE.failure); - return; - } - if(_profile.tautulliHost == null || _profile.tautulliHost.isEmpty) { - LSSnackBar(context: context, title: 'Host Required', message: 'Host is required to connect to Tautulli', type: SNACKBAR_TYPE.failure); - return; - } - if(_profile.tautulliKey == null || _profile.tautulliKey.isEmpty) { - LSSnackBar(context: context, title: 'API Key Required', message: 'API key is required to connect to Tautulli', type: SNACKBAR_TYPE.failure); - return; - } - state.api.miscellaneous.arnold() - .then((_) { - LSSnackBar(context: context, title: 'Connected Successfully', message: 'Tautulli is ready to use with LunaSea', type: SNACKBAR_TYPE.success); - }).catchError((error, trace) { - Logger.error('SettingsModulesTautulli', '_testConnection', 'Failed Connection', error, trace, uploadToSentry: false); - LSSnackBar(context: context, title: 'Connection Test Failed', message: Constants.CHECK_LOGS_MESSAGE, type: SNACKBAR_TYPE.failure); - }); - } -} diff --git a/lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli_headers.dart b/lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli_headers.dart deleted file mode 100644 index 423727f0..00000000 --- a/lib/modules/settings/routes/modules/monitoring_tautulli/monitoring_tautulli_headers.dart +++ /dev/null @@ -1,110 +0,0 @@ -import 'dart:convert'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesTautulliHeaders extends StatefulWidget { - static const ROUTE_NAME = '/settings/modules/tautulli/headers'; - - @override - State createState() => _State(); -} - -class _State extends State { - ProfileHiveObject _profile = Database.currentProfileObject; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: _appBar, - body: _body, - ); - - Widget get _appBar => LSAppBar(title: 'Custom Headers'); - - Widget get _body => ValueListenableBuilder( - valueListenable: Database.profilesBox.listenable(), - builder: (context, profile, widget) => LSListView( - children: [ - ..._headers, - ], - ), - ); - - List get _headers => [ - LSHeader( - text: 'Custom Headers', - subtitle: 'Define custom headers that will be attached to every request made to the module', - ), - if((_profile.getTautulli()['headers'] as Map).isEmpty) LSGenericMessage( - text: 'No Custom Headers Added', - ), - ..._list, - LSDivider(), - LSButton( - text: 'Add Header', - onTap: () async => _showAddPrompt(), - ), - ]; - - List get _list { - Map headers = Map.from(_profile.getTautulli()['headers']); - List list = []; - headers.forEach((key, value) => list.add(LSCardTile( - title: LSTitle(text: key.toString()), - subtitle: LSSubtitle(text: value.toString()), - trailing: LSIconButton( - icon: Icons.delete, - color: LSColors.red, - onPressed: () async => _deleteIndexer(key.toString(), value.toString()), - ), - ))); - list.sort((a,b) => (a.title as LSTitle).text.compareTo((b.title as LSTitle).text)); - return list; - } - - Future _showAddPrompt() async { - List results = await SettingsDialogs.addHeader(context); - if(results[0]) switch(results[1]) { - case 1: _showAuthenticationPrompt(); break; - case 100: _showCustomPrompt(); break; - default: break; - } - } - - Future _showAuthenticationPrompt() async { - List results = await SettingsDialogs.addAuthenticationHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getTautulli()['headers']); - String _auth = base64.encode(utf8.encode('${results[1]}:${results[2]}')); - _headers.addAll({'Authorization': 'Basic $_auth'}); - _profile.tautulliHeaders = _headers; - _profile.save(context: context); - } - } - - Future _showCustomPrompt() async { - List results = await SettingsDialogs.addCustomHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getTautulli()['headers']); - _headers.addAll({results[1]: results[2]}); - _profile.tautulliHeaders = _headers; - _profile.save(context: context); - } - } - - Future _deleteIndexer(String key, String value) async { - List results = await SettingsDialogs.deleteHeader(context); - if(results[0]) { - Map _headers = Map.from(_profile.getTautulli()['headers']); - _headers.remove(key); - _profile.tautulliHeaders = _headers; - _profile.save(context: context); - LSSnackBar( - context: context, - message: key, - title: 'Header Deleted', - type: SNACKBAR_TYPE.success, - ); - } - } -} diff --git a/lib/modules/settings/routes/settings.dart b/lib/modules/settings/routes/settings.dart deleted file mode 100644 index cf457d68..00000000 --- a/lib/modules/settings/routes/settings.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - - -class Settings extends StatefulWidget { - static const ROUTE_NAME = '/settings'; - - @override - State createState() => _State(); -} - -class _State extends State { - final _scaffoldKey = GlobalKey(); - final _pageController = PageController(); - - @override - void initState() { - super.initState(); - Future.microtask(() => Provider.of(context, listen: false).navigationIndex = 0); - } - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - body: _body, - appBar: _appBar, - bottomNavigationBar: _bottomNavigationBar, - ); - - Widget get _appBar => LSAppBar(title: 'Settings'); - - Widget get _body => PageView( - controller: _pageController, - children: _tabs, - onPageChanged: _onPageChanged, - physics: AlwaysScrollableScrollPhysics(), - ); - - Widget get _bottomNavigationBar => SettingsNavigationBar(pageController: _pageController); - - List get _tabs => [ - SettingsGeneral(), - SettingsModules(), - SettingsSystem(), - ]; - - void _onPageChanged(int index) => Provider.of(context, listen: false).navigationIndex = index; -} diff --git a/lib/modules/settings/routes/system.dart b/lib/modules/settings/routes/system.dart deleted file mode 100644 index 417c8366..00000000 --- a/lib/modules/settings/routes/system.dart +++ /dev/null @@ -1,138 +0,0 @@ -import 'dart:io'; - -import 'package:flutter/material.dart'; -import 'package:lunasea/modules/settings/widgets/system/enable_sentry.dart'; -import 'package:package_info/package_info.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsSystem extends StatefulWidget { - static const ROUTE_NAME = '/settings/system'; - - @override - State createState() => _State(); -} - -class _State extends State with AutomaticKeepAliveClientMixin { - final _scaffoldKey = GlobalKey(); - String _version = '1.0.0'; - String _buildNumber = '1'; - - @override - bool get wantKeepAlive => true; - - @override - Widget build(BuildContext context) { - super.build(context); - return Scaffold( - key: _scaffoldKey, - body: _body, - ); - } - - @override - void initState() { - super.initState(); - _fetchVersion(); - } - - void _fetchVersion() async { - PackageInfo info = await PackageInfo.fromPlatform(); - if(mounted) setState(() { - _version = info.version; - _buildNumber = info.buildNumber; - }); - } - - Widget get _body => LSListView( - children: [ - ..._resources, - ..._system, - ..._advanced, - ], - ); - - List get _advanced => [ - LSHeader( - text: 'Advanced', - subtitle: 'Advanced system functionality for LunaSea', - ), - SettingsSystemEnableSentry(), - SettingsSystemClearImageCacheTile(), - SettingsSystemClearConfigurationTile(), - ]; - - List get _system => [ - LSHeader( - text: 'System', - subtitle: 'System information and utilities for LunaSea', - ), - LSCardTile( - title: LSTitle(text: 'Version: $_version ($_buildNumber)'), - subtitle: LSSubtitle(text: 'View Recent Changes'), - trailing: LSIconButton(icon: Icons.system_update), - onTap: () async => await Constants.URL_CHANGELOG.lsLinks_OpenLink(), - ), - LSCardTile( - title: LSTitle(text: 'Donations'), - subtitle: LSSubtitle(text: 'Donate to the Developer'), - trailing: LSIconButton(icon: Icons.attach_money), - onTap: () async => await Navigator.of(context).pushNamed(SettingsSystemDonations.ROUTE_NAME), - ), - LSCardTile( - title: LSTitle(text: 'Licenses'), - subtitle: LSSubtitle(text: 'License Attributions'), - trailing: LSIconButton(icon: Icons.description), - onTap: () async => await Constants.URL_LICENSES.lsLinks_OpenLink(), - ), - ]; - - List get _resources => [ - LSHeader( - text: 'Resources', - subtitle: 'Useful resources to get the most out of LunaSea', - ), - LSCardTile( - title: LSTitle(text: 'Discord'), - subtitle: LSSubtitle(text: 'Chat & Discussions'), - trailing: LSIconButton(icon: CustomIcons.discord), - onTap: () async => await Constants.URL_DISCORD.lsLinks_OpenLink(), - ), - LSCardTile( - title: LSTitle(text: 'Documentation'), - subtitle: LSSubtitle(text: 'View the Documentation'), - trailing: LSIconButton(icon: CustomIcons.documentation), - onTap: () async => await Constants.URL_DOCUMENTATION.lsLinks_OpenLink(), - ), - LSCardTile( - title: LSTitle(text: 'Feedback Board'), - subtitle: LSSubtitle(text: 'Request New Features'), - trailing: LSIconButton(icon: Icons.speaker_notes), - onTap: () async => await Constants.URL_FEEDBACK.lsLinks_OpenLink(), - ), - LSCardTile( - title: LSTitle(text: 'GitHub'), - subtitle: LSSubtitle(text: 'View the Source Code'), - trailing: LSIconButton(icon: CustomIcons.github), - onTap: () async => await Constants.URL_GITHUB.lsLinks_OpenLink(), - ), - LSCardTile( - title: LSTitle(text: 'Reddit'), - subtitle: LSSubtitle(text: 'Ask Questions & Get Support'), - trailing: LSIconButton(icon: CustomIcons.reddit), - onTap: () async => await Constants.URL_REDDIT.lsLinks_OpenLink(), - ), - if(Platform.isIOS) LSCardTile( - title: LSTitle(text: 'TestFlight'), - subtitle: LSSubtitle(text: 'Join the TestFlight Beta'), - trailing: LSIconButton(icon: Icons.developer_board), - onTap: () async => await Constants.URL_TESTFLIGHT.lsLinks_OpenLink() - ), - LSCardTile( - title: LSTitle(text: 'Website'), - subtitle: LSSubtitle(text: 'Visit LunaSea\'s Website'), - trailing: LSIconButton(icon: CustomIcons.home), - onTap: () async => await Constants.URL_WEBSITE.lsLinks_OpenLink(), - ), - ]; -} diff --git a/lib/modules/settings/routes/system/resources_donations.dart b/lib/modules/settings/routes/system/resources_donations.dart deleted file mode 100644 index b2e6c42b..00000000 --- a/lib/modules/settings/routes/system/resources_donations.dart +++ /dev/null @@ -1,85 +0,0 @@ -import 'dart:async'; -import 'package:flutter/material.dart'; -import 'package:in_app_purchase/in_app_purchase.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -const _MESSAGE = '''Thank you to everyone who has or will support the development of LunaSea!\n -Donations are not required to unlock any features within LunaSea.'''; - -class SettingsSystemDonations extends StatefulWidget { - static const ROUTE_NAME = '/settings/system/donations'; - - @override - State createState() => _State(); -} - -class _State extends State { - static StreamSubscription> purchaseStream; - - @override - Widget build(BuildContext context) => Scaffold( - appBar: LSAppBar(title: 'Donations'), - body: LSListView( - children: [ - LSHeader( - text: 'Donate to the Developer', - subtitle: _MESSAGE), - if(InAppPurchases.available) ..._optionsAvailable, - if(!InAppPurchases.available) ..._optionsUnavailable, - ], - ), - ); - - @override - void initState() { - super.initState(); - purchaseStream = InAppPurchases.connection.purchaseUpdatedStream.listen(_purchasedCallback); - } - - @override - void dispose() { - purchaseStream?.cancel(); - super.dispose(); - } - - Future _purchasedCallback(List purchases) async { - for(var purchase in purchases) { - if(purchase.pendingCompletePurchase) { - switch(purchase.status) { - case PurchaseStatus.error: _purchaseFailed(); break; - case PurchaseStatus.purchased: _purchasedSuccess(); break; - default: break; - } - } - } - } - - void _purchasedSuccess() => Navigator.of(context).pushNamed(SettingsSystemDonationsThankYou.ROUTE_NAME); - - void _purchaseFailed() => LSSnackBar( - context: context, - title: 'Transaction Failure', - message: 'The transaction has failed, please try again', - type: SNACKBAR_TYPE.failure, - ); - - - List get _optionsAvailable => [ - if(InAppPurchases.products.length == 0) ..._optionsUnavailable, - for(var i =0; i < InAppPurchases.products.length; i++) LSCardTile( - title: LSTitle(text: InAppPurchases.products[i].ls_Name), - subtitle: LSSubtitle(text: InAppPurchases.products[i].ls_Description), - leading: LSIconButton(icon: InAppPurchases.products[i].ls_Icon, color: LSColors.list(i)), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => await _purchase(InAppPurchases.products[i]), - ), - ]; - - List get _optionsUnavailable => [LSGenericMessage(text: 'In-App Purchases Unavailable')]; - - Future _purchase(ProductDetails product) async { - final PurchaseParam _parameters = PurchaseParam(productDetails: product, sandboxTesting: false); - await InAppPurchases.connection.buyConsumable(purchaseParam: _parameters, autoConsume: true); - } -} diff --git a/lib/modules/settings/routes/system/resources_donations_thankyou.dart b/lib/modules/settings/routes/system/resources_donations_thankyou.dart deleted file mode 100644 index 659249a0..00000000 --- a/lib/modules/settings/routes/system/resources_donations_thankyou.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:flare_flutter/flare_actor.dart'; - -const _MESSAGE = '''Thank you for supporting the open-source community! LunaSea was and still is a passion project built for the community, and will remain entirely open-source.\n -Donations are never expected or assumed, so thank you for giving back and helping LunaSea remain free, forever!'''; - -class SettingsSystemDonationsThankYou extends StatefulWidget { - static const ROUTE_NAME = '/settings/system/donations/thankyou'; - - @override - State createState() => _State(); -} - -class _State extends State { - @override - Widget build(BuildContext context) => Scaffold( - appBar: LSAppBar(title: 'Donations'), - body: Padding( - child: Column( - children: [ - Column( - children: [ - LSHeader( - text: 'Thank You', - subtitle: _MESSAGE, - ), - ], - crossAxisAlignment: CrossAxisAlignment.start, - ), - Container( - height: MediaQuery.of(context).size.height/3, - width: MediaQuery.of(context).size.width, - child: FlareActor( - RiveAnimations.CODER['path'], - shouldClip: false, - alignment: Alignment.center, - fit: BoxFit.contain, - animation: RiveAnimations.CODER['animation'], - ), - ), - ], - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisAlignment: MainAxisAlignment.spaceBetween, - ), - padding: EdgeInsets.only(top: 6.0), - ), - ); -} diff --git a/lib/modules/settings/widgets.dart b/lib/modules/settings/widgets.dart deleted file mode 100644 index 002cdbb1..00000000 --- a/lib/modules/settings/widgets.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'widgets/general.dart'; -export 'widgets/modules.dart'; -export 'widgets/navigation_bar.dart'; -export 'widgets/system.dart'; diff --git a/lib/modules/settings/widgets/general.dart b/lib/modules/settings/widgets/general.dart deleted file mode 100644 index 5ebfbda5..00000000 --- a/lib/modules/settings/widgets/general.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'general/configuration.dart'; -export 'general/logs.dart'; -export 'general/profile.dart'; diff --git a/lib/modules/settings/widgets/general/configuration.dart b/lib/modules/settings/widgets/general/configuration.dart deleted file mode 100644 index 61195c15..00000000 --- a/lib/modules/settings/widgets/general/configuration.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'configuration/backup.dart'; -export 'configuration/restore.dart'; diff --git a/lib/modules/settings/widgets/general/logs.dart b/lib/modules/settings/widgets/general/logs.dart deleted file mode 100644 index 1b35196d..00000000 --- a/lib/modules/settings/widgets/general/logs.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'logs/clear_tile.dart'; -export 'logs/export_tile.dart'; -export 'logs/view_tile.dart'; diff --git a/lib/modules/settings/widgets/general/logs/view_tile.dart b/lib/modules/settings/widgets/general/logs/view_tile.dart deleted file mode 100644 index 181ecd8a..00000000 --- a/lib/modules/settings/widgets/general/logs/view_tile.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsGeneralViewLogsTile extends StatelessWidget { - @override - Widget build(BuildContext context) => LSCardTile( - title: LSTitle(text: 'View Logs'), - subtitle: LSSubtitle(text: 'View All Recorded Logs'), - trailing: LSIconButton(icon: Icons.developer_mode), - onTap: () async => _viewLogs(context), - ); - - Future _viewLogs(BuildContext context) async => Navigator.of(context).pushNamed(SettingsGeneralLogsTypes.ROUTE_NAME); -} diff --git a/lib/modules/settings/widgets/general/profile.dart b/lib/modules/settings/widgets/general/profile.dart deleted file mode 100644 index 4401785c..00000000 --- a/lib/modules/settings/widgets/general/profile.dart +++ /dev/null @@ -1,4 +0,0 @@ -export 'profile/add_tile.dart'; -export 'profile/delete_tile.dart'; -export 'profile/enabled_tile.dart'; -export 'profile/rename_tile.dart'; diff --git a/lib/modules/settings/widgets/modules.dart b/lib/modules/settings/widgets/modules.dart deleted file mode 100644 index 697d4bda..00000000 --- a/lib/modules/settings/widgets/modules.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'modules/home.dart'; -export 'modules/lunasea.dart'; diff --git a/lib/modules/settings/widgets/modules/home.dart b/lib/modules/settings/widgets/modules/home.dart deleted file mode 100644 index ed6b81e4..00000000 --- a/lib/modules/settings/widgets/modules/home.dart +++ /dev/null @@ -1,8 +0,0 @@ -export 'home/start_date_tile.dart'; -export 'home/start_size_tile.dart'; -export 'home/start_type_tile.dart'; -export 'home/enable_lidarr.dart'; -export 'home/enable_radarr.dart'; -export 'home/enable_sonarr.dart'; -export 'home/module_brand_colours.dart'; -export 'home/default_page.dart'; diff --git a/lib/modules/settings/widgets/modules/lunasea.dart b/lib/modules/settings/widgets/modules/lunasea.dart deleted file mode 100644 index a03490dd..00000000 --- a/lib/modules/settings/widgets/modules/lunasea.dart +++ /dev/null @@ -1,8 +0,0 @@ -export 'lunasea/appearance_amoled_tile.dart'; -export 'lunasea/appearance_amoled_border_tile.dart'; -export 'lunasea/drawer_expand_automation_tile.dart'; -export 'lunasea/drawer_expand_clients_tile.dart'; -export 'lunasea/drawer_expand_monitoring_tile.dart'; -export 'lunasea/other_browser_tile.dart'; -export 'lunasea/quick_actions_tile.dart'; -export 'lunasea/use_24h_time.dart'; diff --git a/lib/modules/settings/widgets/modules/lunasea/quick_actions_tile.dart b/lib/modules/settings/widgets/modules/lunasea/quick_actions_tile.dart deleted file mode 100644 index a0244843..00000000 --- a/lib/modules/settings/widgets/modules/lunasea/quick_actions_tile.dart +++ /dev/null @@ -1,15 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsModulesQuickActionsTile extends StatelessWidget { - @override - Widget build(BuildContext context) => LSCardTile( - title: LSTitle(text: 'Quick Actions'), - subtitle: LSSubtitle(text: 'Enable Quick Actions on the Home Screen'), - trailing: LSIconButton(icon: Icons.arrow_forward_ios), - onTap: () async => _onTap(context), - ); - - Future _onTap(BuildContext context) async => Navigator.of(context).pushNamed(SettingsModulesLunaSeaQuickActions.ROUTE_NAME); -} diff --git a/lib/modules/settings/widgets/navigation_bar.dart b/lib/modules/settings/widgets/navigation_bar.dart deleted file mode 100644 index 930356d6..00000000 --- a/lib/modules/settings/widgets/navigation_bar.dart +++ /dev/null @@ -1,49 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/settings.dart'; - -class SettingsNavigationBar extends StatefulWidget { - final PageController pageController; - - SettingsNavigationBar({ - Key key, - @required this.pageController, - }): super(key: key); - - @override - State createState() => _State(); -} - -class _State extends State { - static const List _navbarTitles = [ - Constants.APPLICATION_NAME, - 'Modules', - 'System', - ]; - - static const List _navbarIcons = [ - CustomIcons.user, - CustomIcons.modules, - CustomIcons.code, - ]; - - @override - Widget build(BuildContext context) => Selector( - selector: (_, model) => model.navigationIndex, - builder: (context, index, _) => LSBottomNavigationBar( - index: index, - icons: _navbarIcons, - titles: _navbarTitles, - onTap: _navOnTap, - ), - ); - - Future _navOnTap(int index) async { - await widget.pageController.animateToPage( - index, - duration: Duration(milliseconds: Constants.UI_NAVIGATION_SPEED), - curve: Curves.easeOutSine, - ); - Provider.of(context, listen: false).navigationIndex = index; - } -} \ No newline at end of file diff --git a/lib/modules/settings/widgets/system.dart b/lib/modules/settings/widgets/system.dart deleted file mode 100644 index 1ae562a6..00000000 --- a/lib/modules/settings/widgets/system.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'system/clear_configuration_tile.dart'; -export 'system/clear_image_cache_tile.dart'; diff --git a/pubspec.lock b/pubspec.lock index 9d06dc9e..ab6da957 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -77,7 +77,7 @@ packages: name: build_runner url: "https://pub.dartlang.org" source: hosted - version: "1.10.1" + version: "1.10.2" build_runner_core: dependency: transitive description: @@ -301,7 +301,7 @@ packages: name: fl_chart url: "https://pub.dartlang.org" source: hosted - version: "0.11.0" + version: "0.11.1" flare_dart: dependency: transitive description: @@ -376,7 +376,7 @@ packages: name: flutter_sticky_header url: "https://pub.dartlang.org" source: hosted - version: "0.4.5" + version: "0.4.6" flutter_svg: dependency: "direct main" description: @@ -918,7 +918,7 @@ packages: name: url_launcher url: "https://pub.dartlang.org" source: hosted - version: "5.5.0" + version: "5.5.2" url_launcher_linux: dependency: transitive description: @@ -939,14 +939,14 @@ packages: name: url_launcher_platform_interface url: "https://pub.dartlang.org" source: hosted - version: "1.0.7" + version: "1.0.8" url_launcher_web: dependency: transitive description: name: url_launcher_web url: "https://pub.dartlang.org" source: hosted - version: "0.1.2" + version: "0.1.3+1" usage: dependency: transitive description: @@ -960,7 +960,14 @@ packages: name: uuid url: "https://pub.dartlang.org" source: hosted - version: "2.2.0" + version: "2.2.2" + value_layout_builder: + dependency: transitive + description: + name: value_layout_builder + url: "https://pub.dartlang.org" + source: hosted + version: "0.1.0" vector_math: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index aa2a5ed8..e2b2cb51 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: lunasea description: Self Hosted Manager -version: 4.0.0+400004 +version: 4.0.0+400005 publish_to: 'none' environment: sdk: ">=2.7.0 <3.0.0" @@ -20,9 +20,9 @@ dependencies: sdk: flutter flutter_cache_manager: ^1.4.1 flutter_spinkit: ^4.1.2+1 - flutter_sticky_header: ^0.4.5 + flutter_sticky_header: ^0.4.6 flutter_svg: ^0.18.1 - fl_chart: ^0.11.0 + fl_chart: ^0.11.1 f_logs: ^1.3.0-alpha-02 google_fonts: ^1.1.0 google_nav_bar: ^3.0.0 @@ -40,8 +40,8 @@ dependencies: stack_trace: ^1.9.5 table_calendar: ^2.2.3 tuple: ^1.0.3 - url_launcher: ^5.5.0 - uuid: ^2.2.0 + url_launcher: ^5.5.2 + uuid: ^2.2.2 xml_parser: ^0.1.2 # LunaTools Packages tautulli: ^1.0.3