From 3860a5e75970d75cae88ea94e9ca5e9be7b509b1 Mon Sep 17 00:00:00 2001 From: Jagandeep Brar Date: Mon, 29 Nov 2021 21:15:44 -0500 Subject: [PATCH] chore(release): v6.0.0+60000002 (#504) NEW - [Sonarr] (Episode Sheet) Show the absolute episode number when available - [Sonarr] (Episode Sheet) Show queue tile when the episode has queued releases - [Sonarr] (Releases) Ability to sort by preferred word score - [Sonarr] (Series Details) Ability to pull-to-refresh series on the season list - [Sonarr] (Queue) Re-added ability to view all queued releases - [Sonarr] (Queue) Option to remove from download client and add to blocklist on remove TWEAKS - [UI/UX] (Icons) Ensure all icons are of the "rounded" family - [UI/UX] (List Tiles) Improve consistency in padding between different tile sizes FIXES - [Radarr] (Files) Could fail to load with files without media information - [Sonarr] (Queue) Check monitored download status on pull to refresh - [Sonarr] (Releases) Correctly display negative preferred word scores - [Tautulli] (Updates) Checking for updates could fail in some cases - [UI/UX] (List Tiles) Fix cases where trailing icons were not vertically centered in collapsed tiles --- CHANGELOG.md | 26 ++ README.md | 2 - assets/changelog.json | 82 +--- assets/localization/de.json | 5 +- assets/localization/en.json | 29 ++ assets/localization/es.json | 426 ++++++++++++++++++ assets/localization/fr.json | 5 +- assets/localization/nl.json | 206 +++++++++ assets/localization/pt.json | 13 + assets/localization/ru.json | 5 +- assets/localization/zh-Hans.json | 426 ++++++++++++++++++ lib/core.dart | 1 + lib/core/extensions/iap_product_details.dart | 10 +- lib/core/ui/button.dart | 2 +- lib/core/ui/dialog.dart | 2 +- lib/core/ui/drawer/drawer_header.dart | 2 +- lib/core/ui/icons/icon_button.dart | 2 +- lib/core/ui/input_bar.dart | 4 +- lib/core/ui/list_tile/list_tile.dart | 47 +- lib/core/ui/list_view/paged_list_view.dart | 4 +- lib/core/ui/snackbar/snackbar.dart | 11 +- lib/core/widgets/expandable_list_tile.dart | 47 +- .../core/adapters/calendar_starting_size.dart | 6 +- .../core/adapters/calendar_starting_type.dart | 2 +- .../dashboard/core/api/data/lidarr.dart | 2 +- .../dashboard/core/api/data/radarr.dart | 2 +- lib/modules/lidarr/core/dialogs.dart | 22 +- lib/modules/lidarr/routes/add_details.dart | 2 +- lib/modules/lidarr/routes/details_album.dart | 2 +- lib/modules/lidarr/routes/lidarr.dart | 4 +- .../lidarr/widgets/catalogue_hide_button.dart | 4 +- .../widgets/catalogue_sorting_button.dart | 6 +- .../lidarr/widgets/catalogue_tile.dart | 4 +- .../lidarr/widgets/details_album_tile.dart | 4 +- .../lidarr/widgets/details_edit_button.dart | 2 +- .../lidarr/widgets/details_hide_button.dart | 4 +- .../widgets/details_settings_button.dart | 2 +- lib/modules/lidarr/widgets/missing_tile.dart | 2 +- .../lidarr/widgets/releases_hide_button.dart | 8 +- .../widgets/releases_sorting_button.dart | 10 +- .../lidarr/widgets/search_result_tile.dart | 11 +- lib/modules/nzbget/core/api/data/sort.dart | 12 +- lib/modules/nzbget/core/dialogs.dart | 66 +-- lib/modules/nzbget/routes/nzbget.dart | 2 +- .../nzbget/widgets/history_hide_button.dart | 4 +- lib/modules/nzbget/widgets/history_tile.dart | 6 +- lib/modules/radarr/core/dialogs.dart | 6 +- .../core/extensions/radarr_event_type.dart | 12 +- .../radarr/core/types/settings_global.dart | 10 +- .../radarr/core/types/settings_movie.dart | 10 +- .../add_movie/widgets/navigation_bar.dart | 4 +- .../routes/catalogue/widgets/movie_tile.dart | 15 +- .../widgets/search_bar_sort_button.dart | 6 +- .../routes/history/widgets/history_tile.dart | 26 +- .../widgets/import_tile.dart | 6 +- .../routes/missing/widgets/missing_tile.dart | 2 +- .../radarr/routes/movie_details/route.dart | 2 +- .../widgets/appbar_settings_action.dart | 2 +- .../widgets/files_file_block.dart | 105 +++-- .../routes/queue/widgets/queue_tile.dart | 6 +- .../widgets/appbar_add_movie_action.dart | 2 +- .../appbar_global_settings_action.dart | 2 +- .../routes/radarr/widgets/navigation_bar.dart | 2 +- .../routes/releases/widgets/release_tile.dart | 6 +- .../widgets/search_bar_sort_button.dart | 6 +- .../system_status/widgets/health_tile.dart | 6 +- .../tags/widgets/appbar_action_add_tag.dart | 2 +- .../radarr/routes/tags/widgets/tag_tile.dart | 2 +- .../upcoming/widgets/upcoming_tile.dart | 2 +- lib/modules/sabnzbd/core/dialogs.dart | 106 ++--- lib/modules/sabnzbd/routes/sabnzbd.dart | 2 +- .../sabnzbd/widgets/history_hide_button.dart | 4 +- lib/modules/sabnzbd/widgets/history_tile.dart | 8 +- lib/modules/search/core/dialogs.dart | 2 +- lib/modules/search/core/models/category.dart | 16 +- .../search/routes/categories/route.dart | 2 +- lib/modules/search/routes/results/route.dart | 2 +- .../routes/results/widgets/result_tile.dart | 6 +- .../search/routes/subcategories/route.dart | 2 +- lib/modules/settings/core/dialogs.dart | 10 +- lib/modules/settings/core/pages/headers.dart | 4 +- lib/modules/settings/core/types/header.dart | 4 +- .../routes/account/pages/password_reset.dart | 2 +- .../routes/account/pages/signed_in.dart | 2 +- .../routes/account/pages/signed_out.dart | 15 +- .../settings/routes/account/route.dart | 2 +- .../settings/routes/configuration/route.dart | 4 +- .../configuration_externalmodules/route.dart | 2 +- .../routes/configuration_lidarr/route.dart | 2 +- .../configuration_localization/route.dart | 2 +- .../routes/configuration_nzbget/route.dart | 2 +- .../routes/configuration_overseerr/route.dart | 2 +- .../configuration_quickactions/route.dart | 2 +- .../routes/configuration_radarr/route.dart | 2 +- .../routes/configuration_sabnzbd/route.dart | 2 +- .../pages/add_indexer_headers.dart | 2 +- .../pages/edit_indexer_headers.dart | 2 +- .../routes/configuration_search/route.dart | 2 +- .../routes/configuration_sonarr/route.dart | 2 +- .../routes/configuration_tautulli/route.dart | 6 +- .../routes/configuration_wakeonlan/route.dart | 2 +- lib/modules/settings/routes/profiles.dart | 10 +- .../settings/routes/resources/route.dart | 6 +- .../settings/routes/settings/route.dart | 2 +- lib/modules/settings/routes/system/route.dart | 6 +- .../settings/routes/system_logs/route.dart | 6 +- .../routes/system_logs/widgets/log_tile.dart | 16 +- lib/modules/sonarr/core/api_controller.dart | 44 +- lib/modules/sonarr/core/database.dart | 26 +- lib/modules/sonarr/core/dialogs.dart | 137 +++++- lib/modules/sonarr/core/extensions.dart | 2 + .../core/extensions/sonarr_episode.dart | 22 +- .../core/extensions/sonarr_event_type.dart | 12 +- .../core/extensions/sonarr_history.dart | 9 +- .../core/extensions/sonarr_protocol.dart | 27 ++ .../core/extensions/sonarr_queue_record.dart | 140 ++++-- .../core/extensions/sonarr_queue_status.dart | 26 ++ .../core/extensions/sonarr_release.dart | 18 +- lib/modules/sonarr/core/state.dart | 29 +- .../sonarr/core/types/settings_episode.dart | 10 +- .../sonarr/core/types/settings_global.dart | 10 +- .../sonarr/core/types/settings_season.dart | 4 +- .../sonarr/core/types/settings_series.dart | 10 +- .../sonarr/core/types/sorting_releases.dart | 19 + .../sonarr/core/types/sorting_releases.g.dart | 5 + .../sonarr/routes/add_series/state.dart | 3 +- .../widgets/search_bar_sort_button.dart | 6 +- .../routes/history/widgets/history_tile.dart | 8 +- .../routes/missing/widgets/missing_tile.dart | 2 +- lib/modules/sonarr/routes/more/route.dart | 3 +- lib/modules/sonarr/routes/queue.dart | 1 + lib/modules/sonarr/routes/queue/route.dart | 69 ++- lib/modules/sonarr/routes/queue/state.dart | 55 +++ lib/modules/sonarr/routes/queue/widgets.dart | 1 + .../routes/queue/widgets/queue_tile.dart | 237 ++++++++++ .../routes/releases/widgets/release_tile.dart | 16 +- .../widgets/search_bar_sort_button.dart | 6 +- .../sonarr/routes/season_details/route.dart | 14 +- .../sheets/episode_details.dart | 128 ++++-- .../sonarr/routes/season_details/state.dart | 88 +++- .../season_details/widgets/episode_tile.dart | 28 +- .../season_details/widgets/page_episodes.dart | 34 +- .../sonarr/routes/series_details/route.dart | 14 +- .../widgets/appbar_settings_action.dart | 2 +- .../series_details/widgets/page_seasons.dart | 44 +- .../widgets/season_all_tile.dart | 2 +- .../series_details/widgets/season_tile.dart | 6 +- .../widgets/appbar_add_series_action.dart | 2 +- .../appbar_global_settings_action.dart | 2 +- .../routes/sonarr/widgets/navigation_bar.dart | 2 +- .../tags/widgets/appbar_action_add_tag.dart | 2 +- .../sonarr/routes/tags/widgets/tag_tile.dart | 14 +- .../extensions/tautulli_history_record.dart | 6 +- .../core/extensions/tautulli_session.dart | 13 +- lib/modules/tautulli/core/graphs/graph.dart | 2 +- .../tautulli/core/types/settings_global.dart | 12 +- .../widgets/appbar_metadata_action.dart | 2 +- .../widgets/appbar_user_action.dart | 2 +- .../routes/graphs/widgets/navigation_bar.dart | 2 +- .../routes/graphs/widgets/type_button.dart | 2 +- .../history_details/widgets/metadata.dart | 2 +- .../routes/history_details/widgets/user.dart | 2 +- .../widgets/navigation_bar.dart | 4 +- .../routes/logs_logins/widgets/log_tile.dart | 3 +- .../logs_newsletters/widgets/log_tile.dart | 4 +- .../logs_notifications/widgets/log_tile.dart | 4 +- .../widgets/log_tile.dart | 6 +- .../widgets/log_tile.dart | 6 +- .../logs_tautulli/widgets/log_tile.dart | 6 +- .../media_details/widgets/navigation_bar.dart | 2 +- .../statistics/widgets/time_range_button.dart | 2 +- .../statistics/widgets/type_button.dart | 2 +- .../appbar_global_settings_action.dart | 2 +- .../tautulli/widgets/navigation_bar.dart | 2 +- .../routes/users/widgets/user_tile.dart | 4 +- .../users_details/widgets/navigation_bar.dart | 4 +- localization/sonarr/en.json | 29 ++ packages/sonarr/example/main.dart | 2 +- packages/sonarr/lib/commands.dart | 93 ---- packages/sonarr/lib/controllers.dart | 94 ++++ packages/sonarr/lib/models.dart | 1 + packages/sonarr/lib/sonarr.dart | 94 ++-- packages/sonarr/lib/src/commands/command.dart | 82 ---- packages/sonarr/lib/src/commands/queue.dart | 24 - .../lib/src/commands/queue/delete_queue.dart | 10 - .../lib/src/commands/queue/get_queue.dart | 6 - .../sonarr/lib/src/commands/root_folder.dart | 16 - packages/sonarr/lib/src/commands/system.dart | 16 - packages/sonarr/lib/src/commands/tag.dart | 56 --- .../{commands => controllers}/calendar.dart | 6 +- .../calendar/get_calendar.dart | 0 .../sonarr/lib/src/controllers/command.dart | 87 ++++ .../command/backup.dart | 0 .../command/episode_search.dart | 0 .../command/missing_episode_search.dart | 0 .../command/queue.dart | 0 .../command/refresh_monitored_downloads.dart | 0 .../command/refresh_series.dart | 0 .../command/rescan_series.dart | 0 .../command/rss_sync.dart | 0 .../command/season_search.dart | 0 .../{commands => controllers}/episode.dart | 6 +- .../episode/get_episode.dart | 0 .../episode/get_episodes.dart | 0 .../episode/set_monitored.dart | 0 .../episode/update_episode.dart | 0 .../episode_file.dart | 6 +- .../episode_file/delete_episode_file.dart | 0 .../episode_file/get_episode_file.dart | 0 .../get_series_episode_files.dart | 0 .../{commands => controllers}/history.dart | 6 +- .../history/get_history.dart | 0 .../history/get_history_by_series.dart | 0 .../import_list.dart | 8 +- .../import_list/get_exclusion_list.dart | 0 .../{commands => controllers}/profile.dart | 6 +- .../profile/get_language_profiles.dart | 0 .../profile/get_quality_profiles.dart | 0 .../sonarr/lib/src/controllers/queue.dart | 66 +++ .../src/controllers/queue/delete_queue.dart | 13 + .../lib/src/controllers/queue/get_queue.dart | 24 + .../controllers/queue/get_queue_details.dart | 19 + .../{commands => controllers}/release.dart | 6 +- .../release/add_release.dart | 0 .../release/get_release.dart | 0 .../release/get_season_release.dart | 0 .../lib/src/controllers/root_folder.dart | 16 + .../root_folder/get_root_folders.dart | 0 .../src/{commands => controllers}/series.dart | 6 +- .../series/add_series.dart | 0 .../series/delete_series.dart | 0 .../series/get_all_series.dart | 0 .../series/get_series.dart | 0 .../series/update_series.dart | 0 .../series_lookup.dart | 6 +- .../series_lookup/lookup.dart | 0 .../sonarr/lib/src/controllers/system.dart | 16 + .../system/get_status.dart | 0 packages/sonarr/lib/src/controllers/tag.dart | 48 ++ .../tag/add_tag.dart | 0 .../tag/delete_tag.dart | 0 .../tag/get_all_tags.dart | 0 .../tag/get_tag.dart | 0 .../tag/update_tag.dart | 0 .../src/{commands => controllers}/wanted.dart | 6 +- .../wanted/get_missing.dart | 0 .../sonarr/lib/src/models/queue/queue.dart | 43 ++ .../sonarr/lib/src/models/queue/queue.g.dart | 36 ++ .../lib/src/models/queue/queue_record.dart | 97 ++-- .../lib/src/models/queue/queue_record.g.dart | 50 +- .../sonarr/lib/src/types/queue_sort_key.dart | 81 ++++ .../lib/src/types/queue_status_type.dart | 60 +++ .../queue_tracked_download_state_type.dart | 40 ++ .../queue_tracked_download_status_type.dart | 35 ++ packages/sonarr/lib/types.dart | 4 + packages/sonarr/lib/utilities.dart | 19 +- .../lib/src/models/system/pms_update.dart | 146 +++--- packages/tautulli/pubspec.yaml | 2 +- pubspec.yaml | 2 +- 259 files changed, 3792 insertions(+), 1191 deletions(-) create mode 100644 assets/localization/es.json create mode 100644 assets/localization/nl.json create mode 100644 assets/localization/zh-Hans.json create mode 100644 lib/modules/sonarr/core/extensions/sonarr_protocol.dart create mode 100644 lib/modules/sonarr/core/extensions/sonarr_queue_status.dart create mode 100644 lib/modules/sonarr/routes/queue/state.dart create mode 100644 lib/modules/sonarr/routes/queue/widgets/queue_tile.dart delete mode 100644 packages/sonarr/lib/commands.dart create mode 100644 packages/sonarr/lib/controllers.dart delete mode 100644 packages/sonarr/lib/src/commands/command.dart delete mode 100644 packages/sonarr/lib/src/commands/queue.dart delete mode 100644 packages/sonarr/lib/src/commands/queue/delete_queue.dart delete mode 100644 packages/sonarr/lib/src/commands/queue/get_queue.dart delete mode 100644 packages/sonarr/lib/src/commands/root_folder.dart delete mode 100644 packages/sonarr/lib/src/commands/system.dart delete mode 100644 packages/sonarr/lib/src/commands/tag.dart rename packages/sonarr/lib/src/{commands => controllers}/calendar.dart (83%) rename packages/sonarr/lib/src/{commands => controllers}/calendar/get_calendar.dart (100%) create mode 100644 packages/sonarr/lib/src/controllers/command.dart rename packages/sonarr/lib/src/{commands => controllers}/command/backup.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/episode_search.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/missing_episode_search.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/queue.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/refresh_monitored_downloads.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/refresh_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/rescan_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/rss_sync.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/command/season_search.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode.dart (90%) rename packages/sonarr/lib/src/{commands => controllers}/episode/get_episode.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode/get_episodes.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode/set_monitored.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode/update_episode.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode_file.dart (88%) rename packages/sonarr/lib/src/{commands => controllers}/episode_file/delete_episode_file.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode_file/get_episode_file.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/episode_file/get_series_episode_files.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/history.dart (90%) rename packages/sonarr/lib/src/{commands => controllers}/history/get_history.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/history/get_history_by_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/import_list.dart (52%) rename packages/sonarr/lib/src/{commands => controllers}/import_list/get_exclusion_list.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/profile.dart (80%) rename packages/sonarr/lib/src/{commands => controllers}/profile/get_language_profiles.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/profile/get_quality_profiles.dart (100%) create mode 100644 packages/sonarr/lib/src/controllers/queue.dart create mode 100644 packages/sonarr/lib/src/controllers/queue/delete_queue.dart create mode 100644 packages/sonarr/lib/src/controllers/queue/get_queue.dart create mode 100644 packages/sonarr/lib/src/controllers/queue/get_queue_details.dart rename packages/sonarr/lib/src/{commands => controllers}/release.dart (88%) rename packages/sonarr/lib/src/{commands => controllers}/release/add_release.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/release/get_release.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/release/get_season_release.dart (100%) create mode 100644 packages/sonarr/lib/src/controllers/root_folder.dart rename packages/sonarr/lib/src/{commands => controllers}/root_folder/get_root_folders.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/series.dart (93%) rename packages/sonarr/lib/src/{commands => controllers}/series/add_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/series/delete_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/series/get_all_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/series/get_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/series/update_series.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/series_lookup.dart (76%) rename packages/sonarr/lib/src/{commands => controllers}/series_lookup/lookup.dart (100%) create mode 100644 packages/sonarr/lib/src/controllers/system.dart rename packages/sonarr/lib/src/{commands => controllers}/system/get_status.dart (100%) create mode 100644 packages/sonarr/lib/src/controllers/tag.dart rename packages/sonarr/lib/src/{commands => controllers}/tag/add_tag.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/tag/delete_tag.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/tag/get_all_tags.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/tag/get_tag.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/tag/update_tag.dart (100%) rename packages/sonarr/lib/src/{commands => controllers}/wanted.dart (85%) rename packages/sonarr/lib/src/{commands => controllers}/wanted/get_missing.dart (100%) create mode 100644 packages/sonarr/lib/src/models/queue/queue.dart create mode 100644 packages/sonarr/lib/src/models/queue/queue.g.dart create mode 100644 packages/sonarr/lib/src/types/queue_sort_key.dart create mode 100644 packages/sonarr/lib/src/types/queue_status_type.dart create mode 100644 packages/sonarr/lib/src/types/queue_tracked_download_state_type.dart create mode 100644 packages/sonarr/lib/src/types/queue_tracked_download_status_type.dart diff --git a/CHANGELOG.md b/CHANGELOG.md index a89c8e07..1ae94cd2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,31 @@ # LunaSea Changelog +## v6.0.0 (60000002) + +#### NEW + +- `[Sonarr]` (Episode Sheet) Show the absolute episode number when available +- `[Sonarr]` (Episode Sheet) Show queue tile when the episode has queued releases +- `[Sonarr]` (Releases) Ability to sort by preferred word score +- `[Sonarr]` (Series Details) Ability to pull-to-refresh series on the season list +- `[Sonarr]` (Queue) Re-added ability to view all queued releases +- `[Sonarr]` (Queue) Option to remove from download client and add to blocklist on remove + +#### TWEAKS + +- `[UI/UX]` (Icons) Ensure all icons are of the "rounded" family +- `[UI/UX]` (List Tiles) Improve consistency in padding between different tile sizes + +#### FIXES + +- `[Radarr]` (Files) Could fail to load with files without media information +- `[Sonarr]` (Queue) Check monitored download status on pull to refresh +- `[Sonarr]` (Releases) Correctly display negative preferred word scores +- `[Tautulli]` (Updates) Checking for updates could fail in some cases +- `[UI/UX]` (List Tiles) Fix cases where trailing icons were not vertically centered in collapsed tiles + +--- + ## v6.0.0 (60000001) #### NEW diff --git a/README.md b/README.md index 983d3648..13a2da12 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,5 @@ # LunaSea  LunaSea - - [![App Store](https://img.shields.io/badge/%20Download-iOS-red?logo=app-store&color=%232196F3&logoColor=white&style=flat)](https://www.lunasea.app/appstore) [![Play Store](https://img.shields.io/badge/%20Download-Android-red?logo=google-play&color=%234CAF50&logoColor=white&style=flat)](https://www.lunasea.app/playstore) [![License](https://img.shields.io/github/license/CometTools/LunaSea?style=flat)](https://github.com/CometTools/LunaSea/blob/production/LICENSE) diff --git a/assets/changelog.json b/assets/changelog.json index 14066efd..1d887c91 100644 --- a/assets/changelog.json +++ b/assets/changelog.json @@ -1,101 +1,51 @@ { - "motd": "Welcome to LunaSea v6.0.0!\n\nSonarr has had many foundational changes and now only supports v3.0.0+ of Sonarr as LunaSea now only utilizes the v3 API routes to make the module much more performant. The episode view has been revamped to now include file media information and single episode history, and you can now view all, series-specific, or season-specific history with the new history tiles that contain much more information!\n\nMany additional changes (and reintroducing removed features such as the queue and multi-episode select) will come soon in additional builds of v6.0.0 in the coming weeks!", + "motd": "This build's key new feature is the reintroduction of the queue in Sonarr with expanded functionality including being able to view and manage queued content from the episode sheet itself!", "new": [ - { - "module": "Dashboard", - "changes": [ - "(Calendar) Use different marker colours depending on how much content is missing" - ] - }, - { - "module": "Notifications", - "changes": [ - "Support time-sensitive notifications" - ] - }, - { - "module": "Settings", - "changes": [ - "(Sonarr) Removed toggle to enable v3 features" - ] - }, { "module": "Sonarr", "changes": [ - "(Catalogue) Many additional sorting and filtering options", - "(Catalogue) Ability to set default filtering method", - "(Episodes) Entirely revamped details view", - "(Episodes) View media info for downloaded episodes", - "(Episodes) View history for a single episode", - "(Season Details) View history for a single season", - "(Series Details) View history for a single series", - "(History) Now an infinite scrolling list", - "(History) Tiles are now expandable tiles with much more detail", - "(Home) \"History\" tab has been replaced with a \"More\" tab", - "(Releases) Ability to set default filtering method", - "(Releases) Now shows preferred word score" + "(Episode Sheet) Show the absolute episode number when available", + "(Episode Sheet) Show queue tile when the episode has queued releases", + "(Releases) Ability to sort by preferred word score", + "(Series Details) Ability to pull-to-refresh series on the season list", + "(Queue) Re-added ability to view all queued releases", + "(Queue) Option to remove from download client and add to blocklist on remove" ] } ], "tweaks": [ - { - "module": "Dashboard", - "changes": [ - "(Modules) Always use module's brand colour for module list" - ] - }, { "module": "UI/UX", "changes": [ - "(Drawer) Use module's brand colour for highlighted colour" + "(Icons) Ensure all icons are of the \"rounded\" family", + "(List Tiles) Improve consistency in padding between different tile sizes" ] } ], "fixes": [ { - "module": "Dashboard", + "module": "Radarr", "changes": [ - "Only show calendar type switcher icon when on the calendar page" - ] - }, - { - "module": "Flutter", - "changes": [ - "Update packages", - "Upgrade to Firebase SDK v8.9.0" - ] - }, - { - "module": "Settings", - "changes": [ - "(Calendar) Starting type would have incorrect icons", - "(Notifications) Overseerr would not be displayed" + "(Files) Could fail to load with files without media information" ] }, { "module": "Sonarr", "changes": [ - "Now only utilizes v3 API routes", - "(Edit) Vastly speed up response time on editing a series", - "(Seasons) Now correctly calculates available episode count in season list" + "(Queue) Check monitored download status on pull to refresh", + "(Releases) Correctly display negative preferred word scores" ] }, { - "module": "Networking", + "module": "Tautulli", "changes": [ - "TLS v1.3 is now fully supported" + "(Updates) Checking for updates could fail in some cases" ] }, { "module": "UI/UX", "changes": [ - "(Bottom Sheet) Tightly size all bottom sheets to the content", - "(ListView) Make padding around the end of infinite list loaders and icons more consistent", - "(Popup Menu) Positioning could get unaligned or broken if opened in specific views", - "(Router) Slide transitions between pages could not occur on some devices", - "(Snackbar) Snackbars would not be shown in some cases", - "(Theme) Remove deprecated theme values", - "Many minor fixes in the user interface and experience" + "(List Tiles) Fix cases where trailing icons were not vertically centered in collapsed tiles" ] } ], diff --git a/assets/localization/de.json b/assets/localization/de.json index c59b2339..b9dafaef 100644 --- a/assets/localization/de.json +++ b/assets/localization/de.json @@ -419,5 +419,8 @@ "overseerr.UnknownUser": "Unbekannter Benutzer", "overseerr.NoUsersFound": "Keine Benutzer gefunden", "overseerr.NoRequestsFound": "Keine Anfragen gefunden", - "overseerr.Requests": "Anfragen" + "overseerr.Requests": "Anfragen", + "overseerr.NoRequests": "Keine Anfragen", + "overseerr.OneRequest": "1 Anfrage", + "overseerr.SomeRequests": "{} Anfragen" } \ No newline at end of file diff --git a/assets/localization/en.json b/assets/localization/en.json index b28031e7..257e772f 100644 --- a/assets/localization/en.json +++ b/assets/localization/en.json @@ -435,6 +435,7 @@ "sonarr.AddedOn": "Added On", "sonarr.AddedSeries": "Added Series", "sonarr.AddedTag": "Added Tag", + "sonarr.AddReleaseToBlocklist": "Add Release to Blocklist", "sonarr.AddSeries": "Add Series", "sonarr.AddToExclusionList": "Add to Exclusion List", "sonarr.Age": "Age", @@ -450,6 +451,7 @@ "sonarr.Bitrate": "Bitrate", "sonarr.BitDepth": "Bit Depth", "sonarr.Channels": "Channels", + "sonarr.CheckDownloadClient": "Check download client for more details", "sonarr.Codec": "Codec", "sonarr.Client": "Client", "sonarr.Continuing": "Continuing", @@ -463,11 +465,21 @@ "sonarr.Destination": "Destination", "sonarr.DestinationRelative": "Destination Relative", "sonarr.Download": "Download", + "sonarr.Downloaded": "Downloaded", + "sonarr.DownloadedImporting": "Downloaded: Importing", + "sonarr.DownloadedWaitingToImport": "Downloaded: Waiting to Import", + "sonarr.DownloadedWaitingToProcess": "Downloaded: Waiting to Process", + "sonarr.Downloading": "Downloading", + "sonarr.DownloadingWithMessage": "Downloading: {}", "sonarr.DownloadingRelease": "Downloading Release…", + "sonarr.DownloadClientUnavailable": "Download Client is navailable", "sonarr.DownloadFailed": "Download Failed", "sonarr.DownloadID": "Download ID", "sonarr.DownloadIgnored": "Download Ignored", + "sonarr.DownloadWarning": "Download Warning", + "sonarr.DownloadWarningWithMessage": "Download Warning: {}", "sonarr.EditSeries": "Edit Series", + "sonarr.EmptyQueue": "Empty Queue", "sonarr.Ended": "Ended", "sonarr.Episode": "Episode", "sonarr.Episodes": "Episodes", @@ -485,6 +497,7 @@ "sonarr.FailedToMonitorSeason": "Failed to Monitor Season", "sonarr.FailedToMonitorSeries": "Failed to Monitor Series", "sonarr.FailedToRefresh": "Failed to Refresh", + "sonarr.FailedToRemoveFromQueue": "Failed to Remove From Queue", "sonarr.FailedToRemoveSeries": "Failed to Remove Series", "sonarr.FailedToRunRSSSync": "Failed to Run RSS Sync", "sonarr.FailedToSeasonSearch": "Failed to Season Search", @@ -494,12 +507,15 @@ "sonarr.FailedToUnmonitorSeries": "Failed to Unmonitor Series", "sonarr.FailedToUpdateLibrary": "Failed to Update Library", "sonarr.FailedToUpdateSeries": "Failed to Update Series", + "sonarr.Files": "Files", "sonarr.FilterCatalogue": "Filter Catalogue", "sonarr.FilterReleases": "Filter Releases", "sonarr.FPS": "FPS", "sonarr.GrabbedFrom": "Grabbed from {}", "sonarr.History": "History", "sonarr.HistoryDescription": "View Recent Activity", + "sonarr.Import": "Import", + "sonarr.ImportFailed": "Imported Failed", "sonarr.ImportedTo": "Imported To", "sonarr.Indexer": "Indexer", "sonarr.InfoURL": "Info URL", @@ -514,6 +530,7 @@ "sonarr.ManySeasons": "{} Seasons", "sonarr.MediaInfo": "Media Info", "sonarr.Message": "Message", + "sonarr.Messages": "Messages", "sonarr.Missing": "Missing", "sonarr.MissingEpisodes": "Missing Episodes", "sonarr.MissingEpisodesHint1": "Are you sure you want to search for all missing episodes?", @@ -528,6 +545,7 @@ "sonarr.NoEpisodesFound": "No Episodes Found", "sonarr.NoHistoryFound": "No History Found", "sonarr.NoLongerMonitoring": "No Longer Monitoring", + "sonarr.NoMessagesFound": "No Messages Found", "sonarr.NoReleasesFound": "No Releases Found", "sonarr.NoResultsFound": "No Results Found", "sonarr.NoSeasonsFound": "No Seasons Found", @@ -538,10 +556,14 @@ "sonarr.Other": "Other", "sonarr.Overview": "Overview", "sonarr.Path": "Path", + "sonarr.Paused": "Paused", + "sonarr.Pending": "Pending", + "sonarr.PendingWithMessage": "Pending: {}", "sonarr.PublishedDate": "Published Date", "sonarr.Quality": "Quality", "sonarr.QualityProfile": "Quality Profile", "sonarr.Queue": "Queue", + "sonarr.Queued": "Queued", "sonarr.QueueDescription": "View Active & Queued Content", "sonarr.Reason": "Reason", "sonarr.RefreshSeries": "Refresh Series", @@ -549,6 +571,9 @@ "sonarr.RelativePath": "Relative Path", "sonarr.Releases": "Releases", "sonarr.ReleaseGroup": "Release Group", + "sonarr.RemoveFromQueue": "Remove From Queue", + "sonarr.RemovedFromQueue": "Removed From Queue", + "sonarr.RemoveFromDownloadClient": "Remove From Download Client", "sonarr.RemoveSeries": "Remove Series", "sonarr.RemovedSeries": "Removed Series", "sonarr.RemovedSeriesWithFiles": "Removed Series (With Files)", @@ -596,6 +621,9 @@ "sonarr.SystemStatusDescription": "System Status & Disk Space", "sonarr.Tags": "Tags", "sonarr.TagsDescription": "Manage Your Tags", + "sonarr.TimeLeft": "Time Left", + "sonarr.Title": "Title", + "sonarr.Torrent": "Torrent", "sonarr.Unaired": "Unaired", "sonarr.Unmonitored": "Unmonitored", "sonarr.UnmonitorSeries": "Unmonitor Series", @@ -606,6 +634,7 @@ "sonarr.UpdatingLibrary": "Updating Library", "sonarr.UpdatingLibraryDescription": "Updating library in the background", "sonarr.UpdatedSeries": "Updated Series", + "sonarr.Usenet": "Usenet", "sonarr.UseSeasonFolders": "Use Season Folders", "sonarr.UseSeasonFoldersDescription": "Sort episodes into season folders", "sonarr.Video": "Video", diff --git a/assets/localization/es.json b/assets/localization/es.json new file mode 100644 index 00000000..345ff9eb --- /dev/null +++ b/assets/localization/es.json @@ -0,0 +1,426 @@ +{ + "settings.BroadcastAddressHint1": "Esta es la dirección de transmisión de su red local", + "settings.AccountHelp": "Cuenta LunaSea", + "settings.AddHeader": "Añadir cabecera", + "settings.AddProfile": "Añadir perfil", + "settings.AllFieldsAreRequired": "Todos los campos son requeridos", + "settings.AmoledTheme": "Tema AMOLED", + "settings.AmoledThemeBorders": "Bordes de tema AMOLED", + "settings.AmoledThemeBordersDescription": "Añade borde sutil a través del UI", + "settings.AmoledThemeDescription": "Tema puro negro oscuro", + "settings.ApiKey": "Llave API", + "settings.ApiKeyRequired": "Clave API requerida", + "settings.ApiKeyRequiredMessage": "Clave API es requerida para conectarse a {}", + "settings.Appearance": "Apariencia", + "settings.AppearanceDescription": "Personaliza la apariencia", + "settings.AutomaticallyManageOrderDescription": "Listar módulos alfabéticamente", + "settings.AddModule": "Añadir módulo", + "settings.AddModuleFailed": "Fallo al añadir el módulo", + "settings.AddModuleSuccess": "Módulo añadido", + "settings.BackgroundImageOpacity": "Opacidad de la imagen de fondo", + "settings.BackupConfigurationHint1": "Todas las copias de seguridad se cifran antes de exportarse", + "settings.BackupConfigurationHint2": "La clave de cifrado debe tener al menos 8 caracteres", + "settings.BackupToCloud": "Copia de seguridad en la nube", + "settings.BackupToCloudFailure": "Copia de seguridad fallida", + "settings.BannersNotificationModuleSupportHeader": "Módulos compatibles", + "settings.BasicAuthentication": "Autenticación básica", + "settings.BasicAuthenticationHint2": "La contraseña puede tener does puntos", + "settings.BasicAuthenticationHint3": "El nombre de usuario y la contraseña se convierten automáticamente a codificación base64", + "settings.BroadcastAddress": "Dirección de transmisión", + "settings.BroadcastAddressHint2": "Por lo general, esta es la dirección IP de su máquina con el último octeto en 255", + "settings.BroadcastAddressValidation": "Dirección de transmisión invalida", + "settings.ClearConfiguration": "Borrar la configuración", + "settings.ClearConfigurationHint1": "¿Está seguro de que desea borrar su configuración?", + "settings.ClearConfigurationHint2": "Comenzará desde cero, ¡primero asegúrese de hacer una copia de seguridad de su configuración actual!", + "settings.ClearConfigurationHint3": "Si ha iniciado sesión en una cuenta de LunaSea, se cerrará la sesión.", + "settings.ClearLogs": "Limpiar registros", + "settings.ConfigureModule": "Configurar {}", + "settings.Configuration": "Configuración", + "settings.ConfigurationDescription": "Configurar LunaSea", + "settings.ConnectedSuccessfully": "Conectado exitosamente", + "settings.ConnectedSuccessfullyMessage": "{} está listo para usar con LunaSea!", + "settings.ConnectionDetails": "Detalles de conexión", + "settings.ConnectionDetailsDescription": "Detalles de conexión para {}", + "settings.ConnectionTestFailed": "Prueba de conexión fallida", + "settings.CustomHeader": "Cabecera personalizada", + "settings.CustomHeaders": "Cabeceras personalizadas", + "settings.CustomHeadersDescription": "Añadir cabeceras personalizadas a las solicitudes", + "settings.DecryptBackupHint1": "Introduzca la clave de cifrado para esta copia de seguridad.", + "settings.DebugMenu": "Menú de depuración", + "settings.DebugMenuDescription": "Utilidades de depuración y desarrollo", + "settings.DeleteCloudBackupDescription": "Eliminar archivo de configuración", + "settings.DeleteCloudBackupFailure": "Eliminación fallida", + "settings.BackupToCloudSuccess": "Copia de seguridad exitosa", + "settings.DefaultPage": "Página por defecto", + "settings.DecryptBackup": "Descifrar copia de seguridad", + "settings.BackupToCloudDescription": "Respalda los datos de configuración", + "settings.DeleteHeader": "Eliminar cabecera", + "settings.DeleteIndexer": "Eliminar indexador", + "settings.DeleteIndexerHint1": "¿Estás seguro de que quieres eliminar este indexador?", + "settings.DeleteModuleHint1": "¿Está seguro de que desea eliminar este módulo externo?", + "settings.DeleteModuleSuccess": "Módulo eliminado", + "settings.DeleteProfile": "Eliminar perfil", + "settings.DismissBanners": "Descartar los banners", + "settings.DismissBannersHint1": "¿Estás segura de que quieres descartar todos los banners?", + "settings.Donations": "Donaciones", + "settings.DonationsDescription": "Donar al desarrollador", + "settings.Drawer": "Cajón", + "settings.DrawerDescription": "Personalizar el cajón", + "settings.EditModule": "Editar módulo", + "settings.EmailSentFailure": "Falla al restablecer la contraseña", + "settings.EmailSentSuccess": "Email enviado", + "settings.EmailSentSuccessMessage": "¡Se ha enviado un email sobre cómo restablecer su contraseña!", + "settings.EnabledProfile": "Perfil activado", + "settings.EncryptionKey": "Clave de cifrado", + "settings.FirebaseCrashlyticsHint5": "Es necesario reiniciar LunaSea para que los cambios hagan efecto.", + "settings.ForgotYourPassword": "¿Olvidaste tu contraseña?", + "settings.HeaderAdded": "Cabecera añadida", + "settings.HeaderDeleted": "Cabecera eliminada", + "settings.HeaderKey": "Clave de cabecera", + "settings.HeaderKeyValidation": "Clave de cabecera requerida", + "settings.HeaderValueValidation": "Valor de cabecera requerido", + "settings.Host": "Servidor", + "settings.HostHint1": "Esta es la URL en la que accede a la GUI web del servicio", + "settings.HostHint2": "Debe incluir http:// o https://", + "settings.HostHint4": "Cuando no utilice un proxy inverso, incluya el puerto", + "settings.HostRequired": "Servidor requerido", + "settings.HostRequiredMessage": "Servidor es requerido para conectarse a {}", + "settings.HostValidation": "Servidor debe incluir http:// o https://", + "settings.DisplayName": "Nombre para mostrar", + "settings.FirebaseCrashlytics": "Firebase Crashlytics", + "settings.FirebaseCrashlyticsHint2": "Firebase Crashlytics es una herramienta que se utiliza para capturar fallos y errores.", + "settings.FirebaseCrashlyticsHint4": "A continuación encontrará un enlace al sitio web de Firebase para obtener más información que le ayude a tomar una decisión informada.", + "settings.ImageBackgroundOpacity": "Opacidad de las imágenes de fondo", + "settings.InvalidEmail": "Email invalido", + "settings.InvalidEmailMessage": "La dirección de correo es invalida", + "settings.InvalidPasswordMessage": "La contraseña es invalida", + "settings.Language": "Idioma", + "settings.Localization": "Localización", + "settings.LocalizationDescription": "Personalice su configuración regional", + "settings.MACAddress": "Dirección MAC", + "settings.MACAddressHint1": "Esta es la dirección MAC de la máquina que desea despertar", + "settings.MACAddressHint3": "Los dígitos hexadecimales van de 0 a 9 y A a F", + "settings.MACAddressHint4": "Cada octeto hexadecimal debe estar separado por dos puntos", + "settings.MinimumCharacters": "Minimo de {} caracteres", + "settings.ModuleNotFound": "Módulo no encontrado", + "settings.Notifications": "Notificaciones", + "settings.NoBackupsFound": "Copias de seguridad no encontradas", + "settings.NoExternalModulesFound": "Módulos externos no encontrados", + "settings.NoHeadersAdded": "Sin cabeceras agregadas", + "settings.Password": "Contraseña", + "settings.PasswordValidation": "Contraseña requerida", + "settings.Profiles": "Perfiles", + "settings.ProfilesDescription": "Administre sus perfiles", + "settings.ProfileAlreadyExists": "Perfil ya existe", + "settings.ProfileName": "Nombre de perfil", + "settings.QuickActions": "Acciones rápidas", + "settings.QuickActionsDescription": "Acciones rápidas en la pantalla principal", + "settings.RegisteredFailure": "Registro fallido", + "settings.RegisteredSuccess": "Registrado exitosamente", + "settings.RenameProfile": "Renombrar perfil", + "settings.ResetPassword": "Restablecer contraseña", + "settings.Resources": "Recursos", + "settings.RestoreFromCloudSuccess": "Restaurado exitosamente", + "settings.RestoreFromCloudSuccessMessage": "Tu configuración ha sido restaurada", + "settings.SignedInFailure": "Error al iniciar sesión", + "settings.SignedInSuccess": "Inicio sesión exitosamente", + "settings.SignedOutFailure": "No se pudo cerrar la sesión", + "settings.SignedOutSuccess": "Sesión cerrada", + "settings.ImageBackgroundOpacityHint2": "Para desactivar completamente la pedida de imágenes de fondo, establezca el valor en 0.", + "settings.NotificationsDescription": "Configuración de Webhooks para notificaciones push", + "settings.SignedOutSuccessMessage": "Salió de su cuenta de LunaSea", + "settings.SignIn": "Iniciar sesión", + "settings.SignOut": "Cerrar Sesión", + "settings.SignOutHint1": "¿Estás seguro de que quieres cerrar sesión en su cuenta de LunaSea?", + "settings.ShowCalendarEntries": "Mostrar {} entradas de calendario", + "settings.StartingDay": "Día de inicio", + "settings.StartingSize": "Tamaño inicial", + "settings.StartingType": "Tipo inicial", + "settings.System": "Sistema", + "settings.SystemDescription": "Utilidades e información del sistema", + "settings.TestConnection": "Probar conexión", + "settings.Username": "Usuario", + "settings.UsernameValidation": "Usuario requerido", + "settings.MustBeValueBetween": "Debe ser un valor entre {} y {}", + "settings.AccountHelpHint1": "LunaSea ofrece una cuenta gratuita para hacer una copia de seguridad de su configuración en la nube, ¡con funciones adicionales en el futuro!", + "settings.BackupList": "Lista de copias de seguridad", + "settings.AccountDescription": "Su cuenta LunaSea", + "settings.AutomaticallyManageOrder": "Gestionar orden automáticamente", + "settings.BasicAuthenticationHint1": "El nombre de usuario no debe contener dos puntos", + "settings.Account": "Cuenta", + "settings.BroadcastAddressHint3": "Por ejemplo, dada una dirección IP de máquina de 192.168.1.111, la dirección IP de transmisión resulta ser 192.168.1.255", + "settings.BackupConfiguration": "Backup la configuración", + "settings.RestoreFromCloud": "Restaurar desde la nube", + "settings.ResourcesDescription": "Recursos y enlaces útiles", + "settings.Email": "Email", + "settings.ClearLogsHint1": "¿Está seguro de que desea borrar todos los registros grabados?\n\nLos registros pueden ser útiles para informes de errores y depuración.", + "settings.Custom": "Personalizar…", + "settings.DeleteHeaderHint1": "¿Está seguro de que desea eliminar esta cabecera?", + "settings.DeleteCloudBackup": "Borrar copia de seguridad en la nube", + "settings.DeleteCloudBackupSuccess": "Eliminado exitosamente", + "settings.DismissBannersHint2": "Los banners le darán consejos y sugerencias sobre las funciones disponibles en LunaSea.", + "settings.DeleteModule": "Eliminar módulo", + "settings.ImageBackgroundOpacityHint1": "Configura la opacidad de las imágenes de fondo.", + "settings.HeaderValue": "Valor de cabecera", + "settings.HostHint5": "Para agregar autenticación básica, utilice la función de cabecera personalizadas", + "settings.OpenLinksIn": "Abrir enlaces en…", + "settings.HostHint3": "No use localhost o 127.0.0.1", + "settings.MACAddressValidation": "Dirección MAC invalida", + "settings.ProfileNameRequired": "Nombre del perfil requerido", + "settings.Register": "Registrarse", + "settings.InvalidPassword": "Contraseña invalida", + "settings.MACAddressHint2": "Las direcciones MAC contenían seis bloques de dos caracteres hexadecimales (un octeto)", + "settings.RestoreFromCloudDescription": "Restaurar datos de configuración", + "settings.RestoreFromCloudFailure": "Falló la restauración", + "settings.BannersNotificationModuleSupportBody": "Actualmente, las notificaciones basadas en webhook solo se admiten en los módulos que se enumeran a continuación.\n\n¡El soporte para módulos adicionales vendrá en el futuro!", + "settings.FirebaseCrashlyticsHint1": "Los errores y los stacktraces no contienen absolutamente ninguna información de identificación de ningún usuario.", + "settings.FirebaseCrashlyticsHint3": "Para reservar tu derecho a la privacidad, tienes la opción de deshabilitar el seguimiento de errores y fallos, ¡pero debes saber que estos errores y stacktraces son increíblemente útiles para detectar y localizar fallos!", + "lunasea.Add": "Añadir", + "lunasea.AnErrorHasOccurred": "Se ha producido un error", + "lunasea.BackUp": "Respaldar", + "lunasea.Cancel": "Cancelar", + "lunasea.ChangeProfiles": "Cambiar perfiles", + "lunasea.CheckLogsMessage": "Consulte los registros para más detalles", + "lunasea.Clear": "Borrar", + "lunasea.ComingSoon": "Próximamente", + "lunasea.Dashboard": "Tablero", + "lunasea.Delete": "Eliminar", + "lunasea.Disable": "Desactivar", + "lunasea.Disabled": "Desactivado", + "lunasea.Dismiss": "Descartar", + "lunasea.ExternalModules": "Módulos externos", + "lunasea.GoBack": "Regresar", + "lunasea.GoToSettings": "Ve a Configuración", + "lunasea.IncorrectEncryptionKey": "Clave de cifrado incorrecta", + "lunasea.Module": "Módulo", + "lunasea.ModuleIsNotEnabled": "{} No está habilitado", + "lunasea.NoModulesEnabled": "Sin módulos habilitados", + "lunasea.NotSet": "No establecido", + "lunasea.Page": "Página", + "lunasea.Refresh": "Actualizar", + "lunasea.Rename": "Renombrar", + "lunasea.Restore": "Restaurar", + "lunasea.ReturnToDashboard": "Regresar al Tablero", + "lunasea.SearchTextBar": "Buscar…", + "lunasea.Set": "Establecer", + "lunasea.Settings": "Configuración", + "lunasea.TryAgain": "Volver a intentar", + "lunasea.Unknown": "Desconocido", + "lunasea.UnknownError": "Error desconocido", + "lunasea.UnknownModule": "Módulo desconocido", + "lunasea.Website": "Sitio web", + "radarr.AddMovie": "Añadir película", + "radarr.AddMovieAndSearch": "Añadir y Buscar", + "radarr.Age": "Edad", + "radarr.All": "Todo", + "radarr.Alphabetical": "Alfabético", + "radarr.Approved": "Aprobado", + "radarr.Automatic": "Automático", + "radarr.AvailabilityUnknown": "Disponibilidad desconocida", + "radarr.AvailableIn": "Disponible en {}", + "radarr.AvailableToday": "Disponible hoy", + "radarr.BackupDatabase": "Respaldar base de datos", + "radarr.CinemaDateUnknown": "Fecha de cine desconocida", + "radarr.Configure": "Configurar", + "radarr.Copy": "Copiar", + "radarr.CopyFull": "Enlazar/Copiar archivos", + "radarr.CutoffUnmet": "Límite no alcanzado", + "radarr.DateAdded": "Fecha añadida", + "radarr.DigitalRelease": "Publicación digital", + "radarr.DirectoryNotFound": "Directorio no encontrado", + "radarr.Discover": "Descubra", + "radarr.DownloadFailed": "Descarga fracasó", + "radarr.DownloadIgnored": "Descarga ignorada", + "radarr.EditMovie": "Editar película", + "radarr.FileBrowser": "Explorador de archivos…", + "radarr.FilterCatalogue": "Catálogo de filtros", + "radarr.GrabbedFrom": "Tomada de {}", + "radarr.History": "Historia", + "radarr.HistoryDescription": "Ver actividad reciente", + "radarr.Import": "Importar", + "radarr.ImportMode": "Modo de importación", + "radarr.InCinemas": "En cines", + "radarr.InCinemasIn": "En cines en {}", + "radarr.InCinemasToday": "En cines hoy", + "radarr.Interactive": "Interactivo", + "radarr.Language": "Idioma", + "radarr.Languages": "Idiomas", + "radarr.ManualImport": "Importación manual", + "radarr.ManualImportDescription": "Importar películas desde el sistema de archivos", + "radarr.MinimumAvailability": "Disponibilidad mínima", + "radarr.Missing": "Falta", + "radarr.MonitorMovie": "Monitorear película", + "radarr.Monitored": "Monitoreada", + "radarr.MonitoredDescription": "Monitorear nuevos lanzamientos", + "radarr.More": "Más", + "radarr.Move": "Mover", + "radarr.MoveFull": "Mover archivos", + "radarr.Movie": "Película", + "radarr.MovieFileDeleted": "Archivo de película eliminado", + "radarr.MovieFileRenamed": "Archivo de película renombrado", + "radarr.MovieImported": "Película importada ({})", + "radarr.MovieNotFound": "Película no encontrada", + "radarr.MoviePath": "Ruta de la película", + "radarr.Movies": "Películas", + "radarr.NoFilesFound": "No se encontraron archivos", + "radarr.NoHistoryFound": "No se encontró historial", + "radarr.NoMoviesFound": "No se encontraron películas", + "radarr.NoResultsFound": "No se encontraron resultados", + "radarr.NoSubdirectoriesFound": "No se encontraron subdirectorios", + "radarr.NoSummaryIsAvailable": "No hay resumen disponible.", + "radarr.ParentDirectory": "Directorio principal", + "radarr.PhysicalRelease": "Estreno Físico", + "radarr.Quality": "Calidad", + "radarr.QualityProfile": "Perfil de calidad", + "radarr.Queue": "Cola", + "radarr.QueueDescription": "Ver contenido activo y en cola", + "radarr.Quick": "Rápidamente", + "radarr.RefreshMovie": "Actualizar película", + "radarr.Rejected": "Rechazado", + "radarr.Released": "Estrenada", + "radarr.ReleasedToday": "Estrena hoy", + "radarr.RemoveMovie": "Eliminar película", + "radarr.RootFolder": "Carpeta raíz", + "radarr.RunRSSSync": "Ejecutar sincronización RSS", + "radarr.Runtime": "Duración", + "radarr.Search": "Buscar", + "radarr.SearchAllMissing": "Búsqueda que falta", + "radarr.SearchFor": "Buscar {}", + "radarr.Seeders": "Seeders", + "radarr.SelectLanguage": "Seleccionar idiomas", + "radarr.SelectMovie": "Seleccionar película", + "radarr.SelectQuality": "Seleccionar calidad", + "radarr.Size": "Tamaño", + "radarr.SortCatalogue": "Ordenar catálogo", + "radarr.Studio": "Estudio", + "radarr.SystemStatus": "Estado del sistema", + "radarr.SystemStatusDescription": "Estado del sistema y tamaño de disco", + "radarr.Tags": "Etiquetas", + "radarr.TagsDescription": "Administre sus etiquetas", + "radarr.Type": "Tipo", + "radarr.UnmonitorMovie": "No monitorear", + "radarr.Unmonitored": "No monitoreadas", + "radarr.Upcoming": "Próximamente", + "radarr.UpdateLibrary": "Actualizar librería", + "radarr.UpdateMovie": "Actualizar película", + "radarr.ViewWebGUI": "Ver GUI web", + "radarr.Wanted": "Se busca", + "radarr.Weight": "Peso", + "radarr.Year": "Año", + "search.Alphabetical": "Alfabética", + "search.Category": "Categoria", + "search.Comments": "Comentarios", + "search.Download": "Descarga", + "search.Downloading": "Descargando…", + "search.DownloadingNZBToDevice": "Descargando NZB a su dispositivo", + "search.DownloadToDevice": "Descargar al dispositivo", + "search.FailedToDownloadNZB": "Descarga NZB fallida", + "search.FailedToSend": "Fallo al enviar", + "search.NoCategoriesFound": "Categorias no encontradas", + "search.NoResultsFound": "Resultados no encontrados", + "search.Search": "Búsqueda", + "search.SentNZBData": "Data NZB enviada", + "search.SentTo": "Enviada a {}", + "search.Size": "Tamaño", + "search.Subcategories": "Subcategorías", + "search.AllSubcategories": "Todas las subcategorías", + "search.Age": "Edad", + "search.Categories": "Categorias", + "search.NoSubcategoriesFound": "Subcategorías no encontradas", + "search.Results": "Resultados", + "dashboard.PastDays": "Días pasados", + "dashboard.PastDaysDescription": "Ajustar el número de días en el pasado para buscar entradas en el calendario.", + "dashboard.OneWeek": "Una semana", + "dashboard.Calendar": "Calendario", + "dashboard.Friday": "Viernes", + "dashboard.FutureDays": "Días futuros", + "dashboard.MinimumOfOneDay": "Mínimo de un día", + "dashboard.Saturday": "Sábado", + "dashboard.Schedule": "Horario", + "dashboard.Sunday": "Domingo", + "dashboard.Thursday": "Jueves", + "dashboard.Tuesday": "Martes", + "dashboard.TwoWeeks": "Dos semanas", + "dashboard.Wednesday": "Miércoles", + "dashboard.FutureDaysDescription": "Ajustar el número de días en el futuro para buscar entradas en el calendario.", + "dashboard.Modules": "Modulos", + "dashboard.Monday": "Lunes", + "dashboard.NoNewContent": "No contenido nuevo", + "dashboard.OneMonth": "Un mes", + "tautulli.Quality": "Calidad", + "tautulli.None": "Ninguno", + "tautulli.Terminate": "Terminar", + "tautulli.Metadata": "Metadatos", + "tautulli.Platform": "Plataforma", + "tautulli.Product": "Producto", + "tautulli.Season": "Temporada {}", + "tautulli.SessionEnded": "Sesión terminada", + "tautulli.Sessions": "Sesiones", + "tautulli.SessionsOne": "1 sesión", + "tautulli.SessionsMany": "{} sesiones", + "tautulli.Subtitle": "Subtítulo", + "tautulli.TerminationConfirmMessage": "¿Quieres terminar esta sesión?", + "tautulli.Location": "Ubicación", + "tautulli.Activity": "Actividad", + "tautulli.ActivityDetails": "Detalles de actividad", + "tautulli.Audio": "Audio", + "tautulli.BackingUpConfiguration": "Haciendo copia de seguridad…", + "tautulli.BackingUpConfigurationFailed": "Error al hacer la copia de seguridad", + "tautulli.BackingUpDatabase": "Haciendo la copia de seguridad de la base de datos…", + "tautulli.BackingUpDatabaseDescription": "Haciendo la copia de seguridad de la bases de datos en el fondo", + "tautulli.BackingUpDatabaseFailed": "Error al hacer la copia de seguridad de la base de datos", + "tautulli.BackupConfiguration": "Hacer copia de seguridad", + "tautulli.BackupDatabase": "Backup base de datos", + "tautulli.Bandwidth": "Banda ancha", + "tautulli.Container": "Contenedor", + "tautulli.Copy": "Copiar", + "tautulli.DeleteCache": "Eliminar caché", + "tautulli.DeleteImageCache": "Eliminar caché de imágenes", + "tautulli.DeleteTemporarySessions": "Eliminar sesiones temporales", + "tautulli.DeletingCache": "Eliminando caché…", + "tautulli.DeletingCacheDescription": "El caché de Tautulli está siendo eliminando", + "tautulli.DeletingCacheFailed": "Error al eliminar caché", + "tautulli.DeletingImageCache": "Eliminando caché de imágenes…", + "tautulli.DeletingImageCacheDescription": "La caché de imágenes de Tautulli está siendo eliminando", + "tautulli.DeletingImageCacheFailed": "Error al eliminar caché de imágenes", + "tautulli.Burn": "Quemar", + "tautulli.BackingUpConfigurationDescription": "Haciendo copia de seguridad en el fondo", + "tautulli.DeletingTemporarySessions": "Eliminando sesiones temporales…", + "tautulli.DeletingTemporarySessionsDescription": "Las sesiones temporales están siendo eliminadas", + "tautulli.DeletingTemporarySessionsFailed": "Error al eliminar sesiones temporales", + "tautulli.Duration": "Duración", + "tautulli.Episode": "Episodio {}", + "tautulli.History": "Historia", + "tautulli.Library": "Librería", + "tautulli.More": "Más", + "tautulli.TerminatedSession": "Sesión terminada", + "tautulli.TerminateSession": "Terminar sesión", + "tautulli.TerminateSessionFailed": "Error al terminar la sesión", + "tautulli.Title": "Título", + "tautulli.User": "Usuario", + "tautulli.Users": "Usuarios", + "tautulli.Video": "Video", + "tautulli.ViewWebGUI": "Ver GUI web", + "tautulli.Year": "Año", + "tautulli.DirectPlay": "Reproducción directa", + "tautulli.DirectStream": "Transmisión directa", + "tautulli.DirectStreams": "Transmisiones directas", + "tautulli.DirectPlays": "Reproducciones directas", + "tautulli.NoActiveStreams": "Sin transmisiones activas", + "tautulli.Player": "Reproductor", + "tautulli.Stream": "Transmisión", + "tautulli.TerminationAttachMessage": "Opcionalmente, puedes añadir un mensaje de terminación abajo.", + "tautulli.TerminationMessage": "Mensaje de terminación", + "tautulli.Throttled": "Acelerado", + "tautulli.Transcode": "Transcodificar", + "tautulli.Transcodes": "Transcodificaciones", + "tautulli.ETA": "Tiempo Restante", + "overseerr.NoRequests": "Sin solicitudes", + "overseerr.OneRequest": "1 solicitud", + "overseerr.SomeRequests": "{} solicitudes", + "overseerr.Requests": "Solicitudes", + "overseerr.NoRequestsFound": "No se encontraron solicitudes", + "overseerr.UnknownUser": "Usuario desconocido", + "overseerr.NoUsersFound": "No se encontraron usuarios", + "overseerr.Users": "Usuarios" +} \ No newline at end of file diff --git a/assets/localization/fr.json b/assets/localization/fr.json index 3d58a318..9badab8a 100644 --- a/assets/localization/fr.json +++ b/assets/localization/fr.json @@ -419,5 +419,8 @@ "overseerr.UnknownUser": "Utilisateur inconnu", "overseerr.NoUsersFound": "Aucun utilisateur trouvé", "overseerr.Requests": "Requêtes", - "overseerr.NoRequestsFound": "Aucune demande trouvée" + "overseerr.NoRequestsFound": "Aucune demande trouvée", + "overseerr.NoRequests": "Aucune demande", + "overseerr.OneRequest": "1 demande", + "overseerr.SomeRequests": "{} demandes" } \ No newline at end of file diff --git a/assets/localization/nl.json b/assets/localization/nl.json new file mode 100644 index 00000000..65e4ea85 --- /dev/null +++ b/assets/localization/nl.json @@ -0,0 +1,206 @@ +{ + "settings.AddModuleFailed": "Module Toevoegen Gefaald", + "settings.AccountDescription": "Uw LunaSea Account", + "settings.AccountHelp": "LunaSea Account", + "settings.AddModule": "Module Toevoegen", + "settings.AddModuleSuccess": "Module Toegevoegd", + "settings.AddProfile": "Profiel Toevoegen", + "settings.Account": "Account", + "settings.AccountHelpHint1": "LunaSea biedt een gratis account aan om van uw instellingen een back-up te maken in de Cloud, met extra functies komend in de toekomst!", + "settings.AddHeader": "Header Toevoegen", + "settings.AllFieldsAreRequired": "Alle velden zijn vereist", + "settings.AmoledTheme": "AMOLED Thema", + "settings.AmoledThemeBorders": "AMOLED Thema Randen", + "lunasea.Add": "Voeg Toe", + "lunasea.AnErrorHasOccurred": "Een Fout Is Opgetreden", + "lunasea.BackUp": "Back Up", + "lunasea.Cancel": "Annuleer", + "lunasea.ChangeProfiles": "Verander Profielen", + "lunasea.CheckLogsMessage": "Kijk in de logboeken voor meer informatie", + "lunasea.Clear": "Wis", + "lunasea.ComingSoon": "Komt Binnekort", + "lunasea.Dashboard": "Dashboard", + "lunasea.Delete": "Verwijder", + "lunasea.Disable": "Schakel Uit", + "lunasea.Disabled": "Uitgeschakeld", + "lunasea.Dismiss": "Sluit", + "lunasea.ExternalModules": "Externe Modulen", + "lunasea.GoBack": "Ga Terug", + "lunasea.GoToSettings": "Naar Instellingen", + "lunasea.IncorrectEncryptionKey": "Onjuiste encryptiesleutel", + "lunasea.Module": "Module", + "lunasea.ModuleIsNotEnabled": "{} Is Niet Ingeschakeld", + "lunasea.NoModulesEnabled": "Geen Modulen Ingeschakeld", + "lunasea.NotSet": "Niet Ingesteld", + "lunasea.Page": "Pagina", + "lunasea.Refresh": "Vernieuw", + "lunasea.Rename": "Hernoem", + "lunasea.Restore": "Herstel", + "lunasea.ReturnToDashboard": "Terug naar Dashboard", + "lunasea.SearchTextBar": "Zoek…", + "lunasea.Set": "Stel in", + "lunasea.Settings": "Instellingen", + "lunasea.TryAgain": "Probeer Opnieuw", + "lunasea.Unknown": "Onbekend", + "lunasea.UnknownError": "Onbekend Probleem", + "lunasea.UnknownModule": "Onbekende Module", + "lunasea.Website": "Website", + "radarr.AddMovie": "Film Toevoegen", + "radarr.AddMovieAndSearch": "Voeg Toe + Zoek", + "radarr.Age": "Leeftijd", + "radarr.All": "Alle", + "radarr.Alphabetical": "Alfabetisch", + "radarr.Approved": "Goedgekeurd", + "radarr.Automatic": "Automatisch", + "radarr.AvailabilityUnknown": "Beschikbaarheid Onbekend", + "radarr.AvailableIn": "Beschikbaar over {}", + "radarr.AvailableToday": "Vandaag Beschikbaar", + "radarr.BackupDatabase": "Backup Database", + "radarr.CinemaDateUnknown": "Bioscoop Datum Onbekend", + "radarr.Configure": "Instellen", + "radarr.Copy": "Kopiëren", + "radarr.CopyFull": "Hardlink/Kopieer Bestanden", + "radarr.CutoffUnmet": "Grens Niet Bereikt", + "radarr.DateAdded": "Datum Toegevoegd", + "radarr.DigitalRelease": "Digitale Uitgave", + "radarr.DirectoryNotFound": "Directory Niet Gevonden", + "radarr.Discover": "Ontdekken", + "radarr.DownloadFailed": "Download Gefaald", + "radarr.DownloadIgnored": "Download Genegeerd", + "radarr.EditMovie": "Bewerk Film", + "radarr.FileBrowser": "Bestand Browser…", + "radarr.FilterCatalogue": "Filter Catalogus", + "radarr.GrabbedFrom": "Gepakt van {}", + "radarr.History": "Geschiedenis", + "radarr.HistoryDescription": "Bekijk Recente Activiteit", + "radarr.Import": "Importeer", + "radarr.ImportMode": "Importeer Modus", + "radarr.InCinemas": "In de Bioscopen", + "radarr.InCinemasIn": "In de Bioscopen over {}", + "radarr.InCinemasToday": "Vandaag in de Bioscoop", + "radarr.Interactive": "Interactief", + "radarr.Language": "Taal", + "radarr.Languages": "Talen", + "radarr.ManualImport": "Importeer Handmatig", + "radarr.ManualImportDescription": "Importeer Films van het Bestandssysteem", + "radarr.MinimumAvailability": "Minimale Beschikbaarheid", + "radarr.Missing": "Ontbreekt", + "radarr.MonitorMovie": "Controleer Film", + "radarr.Monitored": "Gecontroleerd", + "radarr.MonitoredDescription": "Controleer op nieuwe uitgaven", + "radarr.More": "Meer", + "radarr.Move": "Verplaats", + "radarr.MoveFull": "Verplaats Bestanden", + "radarr.Movie": "Film", + "radarr.MovieFileDeleted": "Filmbestand Verwijderd", + "radarr.MovieFileRenamed": "Filmbestand Hernoemd", + "radarr.MovieImported": "Film geïmporteerd ({})", + "radarr.MovieNotFound": "Film Niet Gevonden", + "radarr.MoviePath": "Film Pad", + "radarr.Movies": "Films", + "radarr.NoFilesFound": "Geen Bestanden Gevonden", + "radarr.NoHistoryFound": "Geen Geschiedenis Gevonden", + "radarr.NoMoviesFound": "Geen Films Gevonden", + "radarr.NoResultsFound": "Geen Resultaten Gevonden", + "radarr.NoSubdirectoriesFound": "Geen Subdirectories Gevonden", + "radarr.NoSummaryIsAvailable": "Geen samenvatting beschikbaar.", + "radarr.ParentDirectory": "Parent Directory", + "radarr.PhysicalRelease": "Fysieke Release", + "radarr.Quality": "Kwaliteit", + "radarr.QualityProfile": "Kwaliteitsprofiel", + "radarr.Queue": "Wachtrij", + "radarr.QueueDescription": "Bekijk Actieve & Wachtende Inhoud", + "radarr.Quick": "Snel", + "radarr.RefreshMovie": "Ververs Film", + "radarr.Rejected": "Afgewezen", + "radarr.Released": "Uitgebracht", + "radarr.ReleasedToday": "Vandaag Uitgebracht", + "radarr.RemoveMovie": "Verwijder Film", + "radarr.RootFolder": "Hoofdmap", + "radarr.RunRSSSync": "RSS Synchronisatie Uitvoeren", + "radarr.Runtime": "Looptijd", + "radarr.Search": "Zoek", + "radarr.SearchAllMissing": "Zoek Alle Missende", + "radarr.SearchFor": "Zoek voor {}", + "radarr.Seeders": "Seeders", + "radarr.SelectLanguage": "Selecteer Talen", + "radarr.SelectMovie": "Selecteer Film", + "radarr.SelectQuality": "Selecteer Kwaliteit", + "radarr.Size": "Grootte", + "radarr.SortCatalogue": "Sorteer Catalogus", + "radarr.Studio": "Studio", + "radarr.SystemStatus": "Systeem Status", + "radarr.SystemStatusDescription": "Systeem Status & Opslagruimte", + "radarr.Tags": "Labels", + "radarr.TagsDescription": "Beheer Uw Labels", + "radarr.Type": "Type", + "radarr.UnmonitorMovie": "Film Niet Meer Controleren", + "radarr.Unmonitored": "Ongecontroleerd", + "radarr.Upcoming": "Aankomend", + "radarr.UpdateLibrary": "Vernieuw Bibliotheek", + "radarr.UpdateMovie": "Vernieuw Film", + "radarr.ViewWebGUI": "Bekijk Web GUI", + "radarr.Wanted": "Gezocht", + "radarr.Weight": "Gewicht", + "radarr.Year": "Jaar", + "search.Age": "Leeftijd", + "search.AllSubcategories": "Alle Subcategorieën", + "search.Alphabetical": "Alfabetisch", + "search.Category": "Categorie", + "search.Categories": "Categorieën", + "search.Comments": "Opmerkingen", + "search.Download": "Download", + "search.Downloading": "Downloaden…", + "search.DownloadToDevice": "Download naar Apparaat", + "search.FailedToDownloadNZB": "NZB Downloaden Gefaald", + "search.DownloadingNZBToDevice": "NZB naar uw apparaat downloaden", + "search.FailedToSend": "Verzenden Gefaald", + "search.NoCategoriesFound": "Geen Categorieën Gevonden", + "search.NoResultsFound": "Geen Resultaten Gevonden", + "search.NoSubcategoriesFound": "Geen Subcategorieën Gevonden", + "search.Results": "Resultaten", + "search.Search": "Zoek", + "search.SentNZBData": "Verstuur NZB Gegevens", + "search.SentTo": "Verzonden naar {}", + "search.Size": "Grootte", + "search.Subcategories": "Subcategorieën", + "dashboard.FutureDays": "Toekomstige Dagen", + "dashboard.FutureDaysDescription": "Stel het aantal dagen in de toekomst in om kalendergegevens voor op te halen.", + "dashboard.MinimumOfOneDay": "Minimum van 1 Dag", + "dashboard.Modules": "Modulen", + "dashboard.Monday": "Maandag", + "dashboard.NoNewContent": "Geen Nieuwe Inhoud", + "dashboard.PastDays": "Afgelopen Dagen", + "dashboard.PastDaysDescription": "Stel het aantal dagen in het verleden in om kalendergegevens voor op te halen.", + "dashboard.Saturday": "Zaterdag", + "dashboard.Schedule": "Planning", + "dashboard.Sunday": "Zondag", + "dashboard.Thursday": "Donderdag", + "dashboard.Tuesday": "Dinsdag", + "dashboard.TwoWeeks": "Twee Weken", + "dashboard.Wednesday": "Woensdag", + "dashboard.Calendar": "Kalender", + "dashboard.Friday": "Vrijdag", + "dashboard.OneMonth": "Een Maand", + "dashboard.OneWeek": "Een Week", + "tautulli.Activity": "Activiteit", + "tautulli.ActivityDetails": "Activiteit Details", + "tautulli.Audio": "Geluid", + "tautulli.BackingUpDatabase": "Back-up maken van Database…", + "tautulli.BackingUpDatabaseDescription": "Back-up maken van database op de achtergrond", + "tautulli.BackingUpDatabaseFailed": "Back-up Database Gefaald", + "tautulli.BackupConfiguration": "Back-up Configuratie", + "tautulli.BackingUpConfiguration": "Back-up maken van Configuratie…", + "tautulli.BackingUpConfigurationDescription": "Back-up maken van configuratie op de achtergrond", + "tautulli.BackingUpConfigurationFailed": "Back-up Configuratie Gefaald", + "tautulli.BackupDatabase": "Back-up Database", + "tautulli.Bandwidth": "Bandbreedte", + "overseerr.NoRequests": "Geen Verzoeken", + "overseerr.OneRequest": "1 Verzoek", + "overseerr.Requests": "Verzoeken", + "overseerr.NoRequestsFound": "Geen Verzoeken Gevonden", + "overseerr.NoUsersFound": "Geen Gebruikers Gevonden", + "overseerr.UnknownUser": "Onbekende Gebruiker", + "overseerr.Users": "Gebruikers", + "overseerr.SomeRequests": "{} Verzoeken" +} \ No newline at end of file diff --git a/assets/localization/pt.json b/assets/localization/pt.json index 59f140e8..98d3c60e 100644 --- a/assets/localization/pt.json +++ b/assets/localization/pt.json @@ -208,6 +208,19 @@ "lunasea.UnknownError": "Erro Desconhecido", "lunasea.UnknownModule": "Módulo Desconhecido", "lunasea.Website": "Website", + "radarr.AddMovie": "Adicionar Filme", + "radarr.Age": "Idade", + "radarr.All": "Todos", + "radarr.Alphabetical": "Alfabética", + "radarr.Approved": "Aprovado", + "radarr.Automatic": "Automático", + "radarr.AvailabilityUnknown": "Disponibilidade Desconhecida", + "radarr.AvailableIn": "Disponível em {}", + "radarr.AvailableToday": "Disponível Hoje", + "radarr.CinemaDateUnknown": "Data nos Cinemas Desconhecida", + "radarr.Configure": "Configurar", + "radarr.Copy": "Copiar", + "radarr.CopyFull": "Cópia Física/Copiar Arquivos", "search.Subcategories": "Subcategorias", "search.Size": "Tamanho", "search.SentTo": "Enviar para {}", diff --git a/assets/localization/ru.json b/assets/localization/ru.json index eb0c8a9d..7b9401ff 100644 --- a/assets/localization/ru.json +++ b/assets/localization/ru.json @@ -188,5 +188,8 @@ "overseerr.UnknownUser": "Неизвестный пользователь", "overseerr.NoUsersFound": "Пользователи не найдены", "overseerr.NoRequestsFound": "Запросы не найдены", - "overseerr.Requests": "Запросы" + "overseerr.Requests": "Запросы", + "overseerr.NoRequests": "Нет запросов", + "overseerr.OneRequest": "1 запрос", + "overseerr.SomeRequests": "{} запросов" } \ No newline at end of file diff --git a/assets/localization/zh-Hans.json b/assets/localization/zh-Hans.json new file mode 100644 index 00000000..ad4345de --- /dev/null +++ b/assets/localization/zh-Hans.json @@ -0,0 +1,426 @@ +{ + "settings.AccountDescription": "你的LunaSea账户", + "settings.AccountHelp": "LunaSea账户", + "settings.AddModule": "添加模块", + "settings.AddModuleFailed": "添加模块失败", + "settings.AddModuleSuccess": "增加模块", + "settings.AddProfile": "添加配置文件", + "settings.AllFieldsAreRequired": "所有资料必需填写", + "settings.AmoledTheme": "AMOLED主题", + "settings.AmoledThemeBorders": "AMOLED主题边框", + "settings.AmoledThemeBordersDescription": "在UI中添加细微的边框", + "settings.AmoledThemeDescription": "纯黑暗主题", + "settings.AddHeader": "添加标题", + "settings.ApiKeyRequiredMessage": "需要API密钥才能连接到", + "settings.Appearance": "外观", + "settings.AppearanceDescription": "定制界面外观", + "settings.AutomaticallyManageOrder": "自动管理顺序", + "settings.AutomaticallyManageOrderDescription": "按字母顺序列出模块", + "settings.BackupConfiguration": "备份配置", + "settings.BackupConfigurationHint1": "所有备份在导出之前加密", + "settings.BackupConfigurationHint2": "加密密钥必须至少为8个字符", + "settings.BackupList": "备份列表", + "settings.BackupToCloud": "备份至云端", + "settings.BackupToCloudDescription": "备份配置数据", + "settings.BackupToCloudFailure": "备份失败", + "settings.BackupToCloudSuccess": "备份成功", + "settings.BasicAuthentication": "基础认证", + "settings.BasicAuthenticationHint1": "用户名不能包含冒号", + "settings.BasicAuthenticationHint2": "密码可以包含冒号", + "settings.BasicAuthenticationHint3": "用户名和密码将自动转换为base64编码", + "settings.BroadcastAddress": "广播地址", + "settings.BroadcastAddressHint1": "这是本地网络的广播地址", + "settings.BroadcastAddressHint2": "通常这是您机器的 IP 地址,最后一个八位字节设置为 255", + "settings.BroadcastAddressHint3": "给定一个示例机器 IP 地址 192.168.1.111,得到的广播 IP 地址是 192.168.1.255", + "settings.BroadcastAddressValidation": "无效的广播地址", + "settings.ClearConfiguration": "清除配置", + "settings.ClearConfigurationHint1": "确定要清除您的配置吗?", + "settings.ClearConfigurationHint3": "如果您登录到LunaSea帐户,您将被注销。", + "settings.ClearLogs": "清除日志", + "settings.ClearLogsHint1": "是否确定要清除所有记录的日志?\n\n日志对于错误报告和调试非常有用。", + "settings.ConfigureModule": "设定 {}", + "settings.Configuration": "配置", + "settings.ConfigurationDescription": "配置和设置 LunaSea", + "settings.ConnectedSuccessfully": "连接成功", + "settings.ConnectedSuccessfullyMessage": "{} 已准备好与 LunaSea 一起使用!", + "settings.ConnectionDetails": "连接详情", + "settings.ConnectionDetailsDescription": "{} 的连接详情", + "settings.ConnectionTestFailed": "连接测试失败", + "settings.Custom": "自定义…", + "settings.CustomHeader": "自定义请求头", + "settings.CustomHeaders": "自定义消息头", + "settings.CustomHeadersDescription": "向请求添加自定义消息头", + "settings.DefaultPage": "默认页", + "settings.DecryptBackup": "解密备份", + "settings.DebugMenu": "调试菜单", + "settings.DebugMenuDescription": "调试和开发实用程序", + "settings.DeleteCloudBackup": "删除云端备份", + "settings.DeleteCloudBackupFailure": "删除失败", + "settings.DeleteCloudBackupSuccess": "删除成功", + "settings.DeleteIndexer": "删除索引器", + "settings.DeleteIndexerHint1": "您确定要删除此索引器吗?", + "settings.DeleteModule": "删除模块", + "settings.DeleteModuleHint1": "您确定要删除此外部模块吗?", + "settings.DeleteModuleSuccess": "模块已删除", + "settings.DeleteProfile": "删除配置文件", + "settings.DismissBannersHint1": "您确定要关闭所有工具提示横幅吗?", + "settings.DisplayName": "显示名称", + "settings.Donations": "捐款", + "settings.DonationsDescription": "捐赠给开发商", + "settings.EditModule": "编辑模块", + "settings.Email": "电子邮件", + "settings.EmailSentFailure": "重置密码失败", + "settings.EmailSentSuccess": "邮件已发送", + "settings.EmailSentSuccessMessage": "重置密码的电子邮件已发送!", + "settings.EnabledProfile": "启用配置文件", + "settings.EncryptionKey": "加密密钥", + "settings.FirebaseCrashlyticsHint2": "Firebase Crashlytics 是一种用于捕获崩溃和错误的工具。", + "settings.FirebaseCrashlyticsHint4": "以下是Firebase网站的链接,以获取更多信息,帮助做出明智的决定。", + "settings.FirebaseCrashlyticsHint5": "要使更改生效,需要重新启动LunaSea。", + "settings.Drawer": "抽屉", + "settings.DrawerDescription": "自定义抽屉", + "settings.DeleteHeaderHint1": "您确定要删除此标题吗?", + "settings.DeleteHeader": "删除标题", + "settings.FirebaseCrashlytics": "Firebase Crashlytics", + "settings.HostHint1": "这是您访问服务的 Web GUI 的 URL", + "settings.HostHint2": "您必须包含 http:// 或 https://", + "settings.HostHint4": "不使用反向代理时,请包括端口", + "settings.HostHint5": "要添加基本身份验证,请使用自定义标题功能", + "settings.HostRequired": "需要主机", + "settings.ImageBackgroundOpacity": "图像背景不透明度", + "settings.ImageBackgroundOpacityHint1": "设置背景图像的不透明度。", + "settings.ImageBackgroundOpacityHint2": "要完全禁用获取背景图像,请将值设置为 0。", + "settings.InvalidEmail": "无效电子邮件", + "settings.InvalidEmailMessage": "电子邮件地址无效", + "settings.InvalidPasswordMessage": "密码无效", + "settings.Language": "语言", + "settings.Localization": "本地化", + "settings.LocalizationDescription": "自定义您的语言环境", + "settings.MACAddress": "MAC地址", + "settings.MACAddressHint1": "这是你要唤醒的机器的MAC地址", + "settings.MACAddressHint2": "MAC 地址包含六个两位数的十六进制半字节(一个八位字节)", + "settings.MACAddressValidation": "无效的 MAC 地址", + "settings.MinimumCharacters": "最少 {}个字符", + "settings.ModuleNotFound": "未找到模块", + "settings.Notifications": "通知", + "settings.NotificationsDescription": "为推送通知设置 Webhook", + "settings.NoBackupsFound": "未找到备份", + "settings.NoExternalModulesFound": "未找到外部模块", + "settings.NoHeadersAdded": "未添加响应头", + "settings.OpenLinksIn": "在…中打开链接", + "settings.Password": "密码", + "settings.PasswordValidation": "需要密码", + "settings.Profiles": "简介", + "settings.ProfilesDescription": "管理您的个人资料", + "settings.ProfileAlreadyExists": "配置文件已存在", + "settings.ProfileName": "个人资料名称", + "settings.HeaderAdded": "标题已添加", + "settings.HeaderDeleted": "标题已删除", + "settings.HeaderKey": "标题键", + "settings.HeaderValueValidation": "需要标题值", + "settings.Host": "主机", + "settings.ProfileNameRequired": "需要配置文件名称", + "settings.Register": "注册", + "settings.RegisteredFailure": "注册失败", + "settings.RegisteredSuccess": "注册成功", + "settings.RenameProfile": "重命名配置文件", + "settings.ResetPassword": "重置密码", + "settings.Resources": "资源", + "settings.ResourcesDescription": "有用的资源和链接", + "settings.RestoreFromCloudDescription": "恢复配置数据", + "settings.MustBeValueBetween": "必须是 {} 和 {} 之间的值", + "settings.RestoreFromCloudFailure": "无法恢复", + "settings.RestoreFromCloudSuccess": "恢复成功", + "settings.SignedInFailure": "登录失败", + "settings.SignedInSuccess": "登录成功", + "settings.SignedOutFailure": "退出失败", + "settings.SignedOutSuccess": "退出", + "settings.SignedOutSuccessMessage": "退出您的 LunaSea 帐户", + "settings.SignIn": "登入", + "settings.SignOut": "退出", + "settings.SignOutHint1": "您确定要退出您的 LunaSea 帐户吗?", + "settings.StartingDay": "开始日", + "settings.StartingSize": "起始大小", + "settings.StartingType": "起始类型", + "settings.System": "系统", + "settings.SystemDescription": "系统实用程序和信息", + "settings.TestConnection": "测试连接", + "settings.Username": "用户名", + "settings.UsernameValidation": "需要用户名", + "settings.Account": "账户", + "settings.AccountHelpHint1": "LunaSea 提供了一个免费帐户来将您的配置备份到云端,未来还会有更多功能!", + "settings.ApiKey": "API密钥", + "settings.ApiKeyRequired": "需要API密钥", + "settings.DismissBannersHint2": "工具提示横幅将为您提供有关 LunaSea 中可用功能的提示和提示。", + "settings.BackgroundImageOpacity": "背景图像不透明度", + "settings.BannersNotificationModuleSupportHeader": "支持的模块", + "settings.BannersNotificationModuleSupportBody": "当前仅在下面列出的模块中支持基于 Webhook 的通知。\n\n将来会提供额外的模块支持!", + "settings.ClearConfigurationHint2": "您将从头开始,请确保备份当前配置!", + "settings.DismissBanners": "关闭横幅", + "settings.FirebaseCrashlyticsHint3": "为了保留您的隐私权,您可以选择禁用错误和崩溃跟踪,但请注意,这些错误和堆栈跟踪对于捕获和查明错误非常有用!", + "settings.DecryptBackupHint1": "请输入此备份的加密密钥。", + "settings.DeleteCloudBackupDescription": "删除配置文件", + "settings.FirebaseCrashlyticsHint1": "错误和堆栈跟踪绝对不包含任何用户的识别信息。", + "settings.ForgotYourPassword": "忘记密码了?", + "settings.HostHint3": "不要使用本地主机或 127.0.0.1", + "settings.InvalidPassword": "无效的密码", + "settings.HostRequiredMessage": "主机需要连接到 {}", + "settings.HostValidation": "主机必须包含 http:// 或 https://", + "settings.MACAddressHint3": "十六进制数字范围从 0-9 和 A-F", + "settings.ShowCalendarEntries": "显示 {} 日历条目", + "settings.QuickActionsDescription": "主屏幕上的快速操作", + "settings.MACAddressHint4": "每个十六进制八位字节应由冒号分隔", + "settings.QuickActions": "快速操作", + "settings.RestoreFromCloudSuccessMessage": "您的配置已恢复", + "settings.RestoreFromCloud": "从云端恢复", + "settings.HeaderKeyValidation": "需要标题键", + "settings.HeaderValue": "标题值", + "lunasea.Add": "添加", + "lunasea.AnErrorHasOccurred": "发生了错误", + "lunasea.BackUp": "备份", + "lunasea.Cancel": "取消", + "lunasea.ChangeProfiles": "更改配置文件", + "lunasea.CheckLogsMessage": "检查日志以获取更多详细信息", + "lunasea.Clear": "清除", + "lunasea.ComingSoon": "即将推出", + "lunasea.Dashboard": "仪表盘", + "lunasea.Delete": "删除", + "lunasea.Disable": "禁用", + "lunasea.Disabled": "不可用", + "lunasea.Dismiss": "解散", + "lunasea.ExternalModules": "外部模块", + "lunasea.GoBack": "返回", + "lunasea.GoToSettings": "前往设置", + "lunasea.IncorrectEncryptionKey": "不正确的加密密匙", + "lunasea.Module": "模块", + "lunasea.ModuleIsNotEnabled": "{}未启用", + "lunasea.NoModulesEnabled": "未启用模块", + "lunasea.NotSet": "未设置", + "lunasea.Page": "页", + "lunasea.Refresh": "刷新", + "lunasea.Rename": "重命名", + "lunasea.Restore": "恢复", + "lunasea.ReturnToDashboard": "返回仪表板", + "lunasea.SearchTextBar": "搜索…", + "lunasea.Set": "确定", + "lunasea.Settings": "设置", + "lunasea.TryAgain": "再试一次", + "lunasea.Unknown": "未知", + "lunasea.UnknownError": "未知错误", + "lunasea.UnknownModule": "未知模块", + "lunasea.Website": "网站", + "radarr.AddMovie": "添加电影", + "radarr.AddMovieAndSearch": "添加搜索", + "radarr.Age": "年代", + "radarr.All": "全部", + "radarr.Alphabetical": "按字母顺序", + "radarr.Approved": "同意", + "radarr.Automatic": "自动", + "radarr.AvailabilityUnknown": "可用性未知", + "radarr.AvailableIn": "在 {} 中可用", + "radarr.AvailableToday": "今日发售", + "radarr.BackupDatabase": "备份数据库", + "radarr.CinemaDateUnknown": "上映日期未知", + "radarr.Configure": "配置", + "radarr.Copy": "复制", + "radarr.CopyFull": "硬链接/复制文件", + "radarr.CutoffUnmet": "截止未满足", + "radarr.DateAdded": "添加日期", + "radarr.DigitalRelease": "数字发行", + "radarr.DirectoryNotFound": "找不到目录", + "radarr.Discover": "发现", + "radarr.DownloadFailed": "下载失败", + "radarr.DownloadIgnored": "下载被忽略", + "radarr.EditMovie": "编辑电影", + "radarr.FileBrowser": "文件浏览器…", + "radarr.FilterCatalogue": "过滤器目录", + "radarr.GrabbedFrom": "从 {} 抓取", + "radarr.History": "历史", + "radarr.HistoryDescription": "查看最近的活动", + "radarr.Import": "导入", + "radarr.ImportMode": "导入方式", + "radarr.InCinemas": "在电影院", + "radarr.InCinemasIn": "在 {} 的电影院", + "radarr.InCinemasToday": "今天在电影院", + "radarr.Interactive": "互动", + "radarr.Language": "语言", + "radarr.Languages": "语言文字", + "radarr.ManualImport": "手动导入", + "radarr.ManualImportDescription": "从文件系统导入电影", + "radarr.MinimumAvailability": "最低可用性", + "radarr.Missing": "丢失的", + "radarr.MonitorMovie": "监控电影", + "radarr.Monitored": "监控", + "radarr.MonitoredDescription": "监控新版本", + "radarr.More": "更多", + "radarr.Move": "移动", + "radarr.MoveFull": "移动文件", + "radarr.Movie": "电影", + "radarr.MovieFileDeleted": "电影文件已删除", + "radarr.MovieFileRenamed": "电影文件重命名", + "radarr.MovieImported": "导入的电影 ({})", + "radarr.MovieNotFound": "未找到电影", + "radarr.MoviePath": "电影路径", + "radarr.Movies": "影视", + "radarr.NoFilesFound": "未找到文件", + "radarr.NoHistoryFound": "未找到历史记录", + "radarr.NoMoviesFound": "没有找到电影", + "radarr.NoResultsFound": "未找到结果", + "radarr.NoSubdirectoriesFound": "未找到子目录", + "radarr.NoSummaryIsAvailable": "没有可用的摘要。", + "radarr.ParentDirectory": "父目录", + "radarr.PhysicalRelease": "物理释放", + "radarr.Quality": "画质", + "radarr.QualityProfile": "画质介绍", + "radarr.Queue": "队列", + "radarr.QueueDescription": "查看活动和队列的内容", + "radarr.Quick": "快", + "radarr.RefreshMovie": "刷新电影", + "radarr.Rejected": "拒绝了", + "radarr.Released": "发布", + "radarr.ReleasedToday": "今天发布", + "radarr.RemoveMovie": "删除电影", + "radarr.RootFolder": "根文件夹", + "radarr.RunRSSSync": "运行RSS同步", + "radarr.Runtime": "运行时间", + "radarr.Search": "搜索", + "radarr.SearchAllMissing": "搜索所有缺失的", + "radarr.SearchFor": "搜索 {}", + "radarr.Seeders": "播种者", + "radarr.SelectLanguage": "选择语言", + "radarr.SelectMovie": "选择电影", + "radarr.SelectQuality": "选择画质", + "radarr.Size": "大小", + "radarr.SortCatalogue": "目录排序", + "radarr.Studio": "电影公司", + "radarr.SystemStatus": "系统状态", + "radarr.SystemStatusDescription": "系统状态和磁盘空间", + "radarr.Tags": "标签", + "radarr.TagsDescription": "管理您的标签", + "radarr.Type": "类型", + "radarr.UnmonitorMovie": "监控电影", + "radarr.Unmonitored": "不受监控", + "radarr.Upcoming": "即将到来", + "radarr.UpdateLibrary": "更新库", + "radarr.UpdateMovie": "更新电影", + "radarr.ViewWebGUI": "查看网页图形用户界面", + "radarr.Wanted": "需要", + "radarr.Weight": "轻重", + "radarr.Year": "年", + "search.AllSubcategories": "所有子类别", + "search.Alphabetical": "字母顺序", + "search.Categories": "类别", + "search.Category": "种类", + "search.Comments": "评论", + "search.Downloading": "正在下载…", + "search.DownloadingNZBToDevice": "将NZB下载到您的设备", + "search.DownloadToDevice": "下载到设备", + "search.FailedToDownloadNZB": "NZB下载失败", + "search.FailedToSend": "发送失败", + "search.NoCategoriesFound": "未找到类别", + "search.NoResultsFound": "未找到任何结果", + "search.NoSubcategoriesFound": "未找到子类别", + "search.Results": "结果", + "search.Search": "搜索", + "search.SentNZBData": "发送 NZB 数据", + "search.SentTo": "发送到 {}", + "search.Size": "大小", + "search.Subcategories": "子类别", + "search.Age": "年龄", + "search.Download": "下载", + "dashboard.Calendar": "日历", + "dashboard.Friday": "星期五", + "dashboard.FutureDays": "未来的日子", + "dashboard.FutureDaysDescription": "设置未来要获取日历条目的天数。", + "dashboard.MinimumOfOneDay": "最少 1 天", + "dashboard.Modules": "模块", + "dashboard.Monday": "星期一", + "dashboard.NoNewContent": "没有新内容", + "dashboard.OneMonth": "一个月", + "dashboard.OneWeek": "一周", + "dashboard.PastDays": "过去的日子", + "dashboard.Saturday": "星期六", + "dashboard.Schedule": "星期六", + "dashboard.Sunday": "星期天", + "dashboard.Thursday": "星期四", + "dashboard.TwoWeeks": "两周", + "dashboard.Wednesday": "星期三", + "dashboard.PastDaysDescription": "设置过去的天数以获取日历条目。", + "dashboard.Tuesday": "星期二", + "tautulli.Activity": "活动", + "tautulli.Audio": "音频", + "tautulli.BackingUpConfiguration": "正在备份配置…", + "tautulli.BackingUpConfigurationDescription": "在后台备份您的配置", + "tautulli.BackingUpConfigurationFailed": "备份配置失败", + "tautulli.BackingUpDatabase": "正在备份数据库…", + "tautulli.BackingUpDatabaseDescription": "在后台备份您的数据库", + "tautulli.BackingUpDatabaseFailed": "备份数据库失败", + "tautulli.BackupConfiguration": "备份配置", + "tautulli.BackupDatabase": "备份数据库", + "tautulli.Bandwidth": "带宽", + "tautulli.Burn": "燃烧", + "tautulli.Container": "容器", + "tautulli.Copy": "复制", + "tautulli.DeleteCache": "删除缓存", + "tautulli.DeleteImageCache": "删除图像缓存", + "tautulli.DeleteTemporarySessions": "删除临时会话", + "tautulli.DeletingCache": "正在删除缓存…", + "tautulli.DeletingCacheDescription": "正在删除 Tautulli 缓存", + "tautulli.DeletingCacheFailed": "删除缓存失败", + "tautulli.DeletingImageCacheDescription": "正在删除 Tautulli 图片缓存", + "tautulli.ActivityDetails": "活动详情", + "tautulli.DeletingImageCacheFailed": "删除图片缓存失败", + "tautulli.DeletingTemporarySessionsDescription": "正在删除临时会话", + "tautulli.DeletingTemporarySessionsFailed": "删除临时会话失败", + "tautulli.DirectPlay": "直接播放", + "tautulli.DirectPlays": "直接播放", + "tautulli.DirectStream": "直播", + "tautulli.DirectStreams": "直接流", + "tautulli.Duration": "持续时间", + "tautulli.Episode": "剧集{}", + "tautulli.ETA": "预计到达时间", + "tautulli.History": "历史", + "tautulli.Library": "图书馆", + "tautulli.Location": "定位", + "tautulli.Metadata": "元数据", + "tautulli.More": "更多", + "tautulli.None": "没有", + "tautulli.Platform": "平台", + "tautulli.Player": "播放器", + "tautulli.Product": "产品", + "tautulli.Quality": "画质", + "tautulli.SessionEnded": "会话结束", + "tautulli.Sessions": "会话", + "tautulli.SessionsOne": "1 节", + "tautulli.SessionsMany": "{} 会话", + "tautulli.Stream": "流", + "tautulli.Terminate": "终止", + "tautulli.TerminationAttachMessage": "您可以选择在下方附加终止消息。", + "tautulli.TerminationConfirmMessage": "您要终止此会话吗?", + "tautulli.TerminationMessage": "终止消息", + "tautulli.TerminatedSession": "终止的会话", + "tautulli.TerminateSession": "终止会话", + "tautulli.Throttled": "节流", + "tautulli.Title": "标题", + "tautulli.Transcode": "转码", + "tautulli.Transcodes": "转码", + "tautulli.User": "用户", + "tautulli.Users": "使用者", + "tautulli.Video": "视频", + "tautulli.ViewWebGUI": "网页图形用户界面", + "tautulli.Year": "年", + "tautulli.Subtitle": "副标题", + "tautulli.DeletingImageCache": "正在删除图像缓存…", + "tautulli.DeletingTemporarySessions": "正在删除临时会话…", + "tautulli.NoActiveStreams": "没有活动流", + "tautulli.Season": "季 {}", + "tautulli.TerminateSessionFailed": "终止会话失败", + "overseerr.NoRequests": "没有请求", + "overseerr.OneRequest": "1个请求", + "overseerr.SomeRequests": "{} 请求", + "overseerr.Requests": "请求", + "overseerr.NoRequestsFound": "未找到请求", + "overseerr.NoUsersFound": "未找到相应的用户", + "overseerr.UnknownUser": "未知用户", + "overseerr.Users": "用户" +} \ No newline at end of file diff --git a/lib/core.dart b/lib/core.dart index 02da46c2..ee7a2dc9 100644 --- a/lib/core.dart +++ b/lib/core.dart @@ -1,5 +1,6 @@ // Packages export 'package:easy_localization/easy_localization.dart'; +export 'package:expandable/expandable.dart'; export 'package:flash/flash.dart'; export 'package:fluro/fluro.dart'; export 'package:hive/hive.dart'; diff --git a/lib/core/extensions/iap_product_details.dart b/lib/core/extensions/iap_product_details.dart index 1b21e53f..009a0a09 100644 --- a/lib/core/extensions/iap_product_details.dart +++ b/lib/core/extensions/iap_product_details.dart @@ -6,15 +6,15 @@ extension ProductDetailsExtension on ProductDetails { IconData get lunaIcon { switch (this.id) { case LunaInAppPurchases.DONATION_01: - return Icons.local_drink; + return Icons.local_drink_rounded; case LunaInAppPurchases.DONATION_03: - return Icons.local_cafe; + return Icons.local_cafe_rounded; case LunaInAppPurchases.DONATION_05: - return Icons.local_bar; + return Icons.local_bar_rounded; case LunaInAppPurchases.DONATION_10: - return Icons.fastfood; + return Icons.fastfood_rounded; default: - return Icons.attach_money; + return Icons.attach_money_rounded; } } diff --git a/lib/core/ui/button.dart b/lib/core/ui/button.dart index 59289c30..a981ae97 100644 --- a/lib/core/ui/button.dart +++ b/lib/core/ui/button.dart @@ -96,7 +96,7 @@ class LunaButton extends Card { ); case LunaLoadingState.ERROR: return LunaButton.icon( - icon: Icons.error, + icon: Icons.error_rounded, iconSize: iconSize, color: color, backgroundColor: backgroundColor, diff --git a/lib/core/ui/dialog.dart b/lib/core/ui/dialog.dart index cfe8dec4..79fb7367 100644 --- a/lib/core/ui/dialog.dart +++ b/lib/core/ui/dialog.dart @@ -205,7 +205,7 @@ abstract class LunaDialog { mainAxisAlignment: MainAxisAlignment.center, children: [ Icon( - icon ?? Icons.error_outline, + icon ?? Icons.error_outline_rounded, color: iconColor ?? LunaColours.accent, ), ], diff --git a/lib/core/ui/drawer/drawer_header.dart b/lib/core/ui/drawer/drawer_header.dart index 16de0b12..dcf212be 100644 --- a/lib/core/ui/drawer/drawer_header.dart +++ b/lib/core/ui/drawer/drawer_header.dart @@ -25,7 +25,7 @@ class LunaDrawerHeader extends UserAccountsDrawerHeader { text: LunaDatabaseValue.ENABLED_PROFILE.data, ), const Icon( - Icons.arrow_drop_down, + Icons.arrow_drop_down_rounded, color: Colors.white70, size: LunaUI.FONT_SIZE_HEADER, ), diff --git a/lib/core/ui/icons/icon_button.dart b/lib/core/ui/icons/icon_button.dart index f239c476..9742c07a 100644 --- a/lib/core/ui/icons/icon_button.dart +++ b/lib/core/ui/icons/icon_button.dart @@ -73,7 +73,7 @@ class LunaIconButton extends StatelessWidget { Widget _icon() { if (loadingState == LunaLoadingState.ERROR) { return Icon( - Icons.error, + Icons.error_rounded, color: color, ); } else if (icon != null) { diff --git a/lib/core/ui/input_bar.dart b/lib/core/ui/input_bar.dart index 7238eecd..64ab4bde 100644 --- a/lib/core/ui/input_bar.dart +++ b/lib/core/ui/input_bar.dart @@ -37,7 +37,7 @@ class LunaTextInputBar extends StatefulWidget { this.action = TextInputAction.search, this.keyboardType = TextInputType.text, this.labelText, - this.labelIcon = Icons.search, + this.labelIcon = Icons.search_rounded, this.margin = LunaUI.MARGIN_CARD, this.autofocus = false, this.obscureText = false, @@ -98,7 +98,7 @@ class _State extends State { suffixIcon: AnimatedOpacity( child: InkWell( child: const Icon( - Icons.close, + Icons.close_rounded, color: LunaColours.accent, size: 24.0, ), diff --git a/lib/core/ui/list_tile/list_tile.dart b/lib/core/ui/list_tile/list_tile.dart index 7a867018..d398e6d0 100644 --- a/lib/core/ui/list_tile/list_tile.dart +++ b/lib/core/ui/list_tile/list_tile.dart @@ -20,19 +20,40 @@ class LunaListTile extends Card { key: key, child: Container( child: InkWell( - child: ListTile( - title: title, - subtitle: subtitle, - trailing: trailing, - leading: leading, - mouseCursor: onTap != null || onLongPress != null - ? SystemMouseCursors.click - : null, - contentPadding: contentPadding - ? customContentPadding ?? - const EdgeInsets.symmetric( - vertical: 6.0, horizontal: 12.0) - : null, + child: Row( + children: [ + Expanded( + child: ListTile( + title: title, + subtitle: subtitle, + // trailing: trailing, + leading: leading, + mouseCursor: onTap != null || onLongPress != null + ? SystemMouseCursors.click + : null, + contentPadding: contentPadding + ? customContentPadding?.copyWith( + right: trailing != null ? 0 : null, + ) ?? + LunaUI.MARGIN_CARD.copyWith( + right: trailing != null ? 0 : null, + ) + : LunaUI.MARGIN_CARD.copyWith( + top: 0, + bottom: 0, + right: trailing != null ? 0 : null, + ), + ), + ), + if (trailing != null) + Padding( + padding: EdgeInsets.only(right: LunaUI.MARGIN_CARD.right), + child: SizedBox( + width: 48.0, + child: trailing, + ), + ), + ], ), borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS), mouseCursor: SystemMouseCursors.click, diff --git a/lib/core/ui/list_view/paged_list_view.dart b/lib/core/ui/list_view/paged_list_view.dart index c0d06410..741ef6c2 100644 --- a/lib/core/ui/list_view/paged_list_view.dart +++ b/lib/core/ui/list_view/paged_list_view.dart @@ -69,11 +69,11 @@ class _State extends State> { padding: const EdgeInsets.only(bottom: 0.0), ), newPageErrorIndicatorBuilder: (context) => LunaIconButton( - icon: Icons.error, + icon: Icons.error_rounded, color: LunaColours.red, ), noMoreItemsIndicatorBuilder: (context) => LunaIconButton( - icon: Icons.check, + icon: Icons.check_rounded, color: LunaColours.accent, ), noItemsFoundIndicatorBuilder: (context) => LunaMessage( diff --git a/lib/core/ui/snackbar/snackbar.dart b/lib/core/ui/snackbar/snackbar.dart index e05e33c1..7b6f5dc2 100644 --- a/lib/core/ui/snackbar/snackbar.dart +++ b/lib/core/ui/snackbar/snackbar.dart @@ -25,13 +25,13 @@ extension LunaSnackbarTypeExtension on LunaSnackbarType { IconData get icon { switch (this) { case LunaSnackbarType.SUCCESS: - return Icons.check_circle_outline; + return Icons.check_circle_outline_rounded; case LunaSnackbarType.ERROR: - return Icons.error_outline; + return Icons.error_outline_rounded; case LunaSnackbarType.INFO: - return Icons.info_outline; + return Icons.info_outline_rounded; default: - return Icons.help_outline; + return Icons.help_outline_rounded; } } } @@ -50,8 +50,7 @@ Future showLunaSnackBar({ }) async => showFlash( context: LunaState.navigatorKey.currentContext, - duration: - duration ?? Duration(seconds: showButton ? 4 : 2), + duration: duration ?? Duration(seconds: showButton ? 4 : 2), builder: (context, controller) => Flash( backgroundColor: Theme.of(context).primaryColor, controller: controller, diff --git a/lib/core/widgets/expandable_list_tile.dart b/lib/core/widgets/expandable_list_tile.dart index 4849d5e0..2b058c9e 100644 --- a/lib/core/widgets/expandable_list_tile.dart +++ b/lib/core/widgets/expandable_list_tile.dart @@ -1,12 +1,9 @@ -import 'package:expandable/expandable.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; class LunaExpandableListTile extends StatefulWidget { final String title; - final TextSpan collapsedSubtitle1; - final TextSpan collapsedSubtitle2; - final TextSpan collapsedSubtitle3; + final List collapsedSubtitles; final Widget collapsedTrailing; final Widget collapsedLeading; final Color backgroundColor; @@ -24,9 +21,7 @@ class LunaExpandableListTile extends StatefulWidget { LunaExpandableListTile({ Key key, @required this.title, - @required this.collapsedSubtitle1, - this.collapsedSubtitle2, - this.collapsedSubtitle3, + @required this.collapsedSubtitles, this.collapsedTrailing, this.collapsedLeading, this.onLongPress, @@ -37,8 +32,7 @@ class LunaExpandableListTile extends StatefulWidget { this.backgroundColor, this.initialExpanded = false, }) : super(key: key) { - assert(title != null); - assert(collapsedSubtitle1 != null); + assert(collapsedSubtitles != null); if (expandedCustomWidget == null) { assert(expandedTableContent != null); } @@ -74,31 +68,37 @@ class _State extends State { ); } + List _parseSubtitles() { + if (widget.collapsedSubtitles.isEmpty) return []; + List _result = []; + for (int i = 0; i < widget.collapsedSubtitles.length; i++) { + _result.add(widget.collapsedSubtitles[i]); + if (i != widget.collapsedSubtitles.length - 1) { + _result.add(const TextSpan(text: '\n')); + } + } + return _result; + } + Widget collapsed() { return LunaListTile( context: context, - title: LunaText.title(text: widget.title), + title: LunaText.title(text: widget.title ?? LunaUI.TEXT_EMDASH), subtitle: RichText( text: TextSpan( style: const TextStyle( fontSize: LunaUI.FONT_SIZE_SUBTITLE, color: Colors.white70, ), - children: [ - widget.collapsedSubtitle1, - if (widget.collapsedSubtitle2 != null) const TextSpan(text: '\n'), - if (widget.collapsedSubtitle2 != null) widget.collapsedSubtitle2, - if (widget.collapsedSubtitle3 != null) const TextSpan(text: '\n'), - if (widget.collapsedSubtitle3 != null) widget.collapsedSubtitle3, - ], + children: _parseSubtitles(), ), overflow: TextOverflow.fade, softWrap: false, - maxLines: 3, + maxLines: widget.collapsedSubtitles.length, ), onTap: controller.toggle, onLongPress: widget.onLongPress, - contentPadding: widget.collapsedSubtitle2 != null, + contentPadding: widget.collapsedSubtitles.length > 1, trailing: widget.collapsedTrailing, leading: widget.collapsedLeading, color: widget.backgroundColor, @@ -115,7 +115,7 @@ class _State extends State { children: [ Padding( child: LunaText.title( - text: widget.title, + text: widget.title ?? LunaUI.TEXT_EMDASH, softWrap: true, maxLines: 8, ), @@ -139,8 +139,8 @@ class _State extends State { ...widget.expandedTableContent .map((content) => Padding( child: content, - padding: - const EdgeInsets.symmetric(horizontal: 12.0), + padding: const EdgeInsets.symmetric( + horizontal: 12.0), )) .toList(), if (widget.expandedTableButtons != null) @@ -163,7 +163,8 @@ class _State extends State { }), ], ), - padding: const EdgeInsets.symmetric(horizontal: 6.0), + padding: + const EdgeInsets.symmetric(horizontal: 6.0), ), ], ), diff --git a/lib/modules/dashboard/core/adapters/calendar_starting_size.dart b/lib/modules/dashboard/core/adapters/calendar_starting_size.dart index a89c212c..c1db379a 100644 --- a/lib/modules/dashboard/core/adapters/calendar_starting_size.dart +++ b/lib/modules/dashboard/core/adapters/calendar_starting_size.dart @@ -54,11 +54,11 @@ extension CalendarStartingSizeExtension on CalendarStartingSize { IconData get icon { switch (this) { case CalendarStartingSize.ONE_WEEK: - return Icons.photo_size_select_small; + return Icons.photo_size_select_small_rounded; case CalendarStartingSize.TWO_WEEKS: - return Icons.photo_size_select_large; + return Icons.photo_size_select_large_rounded; case CalendarStartingSize.ONE_MONTH: - return Icons.photo_size_select_actual; + return Icons.photo_size_select_actual_rounded; } throw Exception('Invalid CalendarStartingSize'); } diff --git a/lib/modules/dashboard/core/adapters/calendar_starting_type.dart b/lib/modules/dashboard/core/adapters/calendar_starting_type.dart index b1e0ac72..4da98a62 100644 --- a/lib/modules/dashboard/core/adapters/calendar_starting_type.dart +++ b/lib/modules/dashboard/core/adapters/calendar_starting_type.dart @@ -37,7 +37,7 @@ extension CalendarStartingTypeExtension on CalendarStartingType { case CalendarStartingType.SCHEDULE: return LunaIcons.calendar; case CalendarStartingType.CALENDAR: - return Icons.calendar_view_day; + return Icons.calendar_view_day_rounded; } throw Exception('Invalid CalendarStartingType'); } diff --git a/lib/modules/dashboard/core/api/data/lidarr.dart b/lib/modules/dashboard/core/api/data/lidarr.dart index 99b6087d..ca3493d4 100644 --- a/lib/modules/dashboard/core/api/data/lidarr.dart +++ b/lib/modules/dashboard/core/api/data/lidarr.dart @@ -70,7 +70,7 @@ class CalendarLidarrData extends CalendarData { @override Widget trailing(BuildContext context) => LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => trailingOnPress(context), onLongPress: () async => trailingOnLongPress(context), ); diff --git a/lib/modules/dashboard/core/api/data/radarr.dart b/lib/modules/dashboard/core/api/data/radarr.dart index 6607f1b9..8eeb17d2 100644 --- a/lib/modules/dashboard/core/api/data/radarr.dart +++ b/lib/modules/dashboard/core/api/data/radarr.dart @@ -71,7 +71,7 @@ class CalendarRadarrData extends CalendarData { @override Widget trailing(BuildContext context) { return LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => trailingOnPress(context), onLongPress: () async => trailingOnLongPress(context), ); diff --git a/lib/modules/lidarr/core/dialogs.dart b/lib/modules/lidarr/core/dialogs.dart index 59d5e094..bf75798e 100644 --- a/lib/modules/lidarr/core/dialogs.dart +++ b/lib/modules/lidarr/core/dialogs.dart @@ -22,7 +22,7 @@ class LidarrDialogs { content: List.generate( qualities.length, (index) => LunaDialog.tile( - icon: Icons.portrait, + icon: Icons.portrait_rounded, iconColor: LunaColours().byListIndex(index), text: qualities[index].name, onTap: () => _setValues(true, qualities[index]), @@ -50,7 +50,7 @@ class LidarrDialogs { content: List.generate( metadatas.length, (index) => LunaDialog.tile( - icon: Icons.portrait, + icon: Icons.portrait_rounded, iconColor: LunaColours().byListIndex(index), text: metadatas[index].name, onTap: () => _setValues(true, metadatas[index]), @@ -151,9 +151,9 @@ class LidarrDialogs { static Future> editArtist( BuildContext context, LidarrCatalogueData entry) async { List> _options = [ - ['Edit Artist', Icons.edit, 'edit_artist'], - ['Refresh Artist', Icons.refresh, 'refresh_artist'], - ['Remove Artist', Icons.delete, 'remove_artist'], + ['Edit Artist', Icons.edit_rounded, 'edit_artist'], + ['Refresh Artist', Icons.refresh_rounded, 'refresh_artist'], + ['Remove Artist', Icons.delete_rounded, 'remove_artist'], ]; bool _flag = false; String _value = ''; @@ -205,7 +205,7 @@ class LidarrDialogs { text: folders[index].freeSpace.lunaBytesToString()), ], ), - icon: Icons.folder, + icon: Icons.folder_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, folders[index]), ), @@ -217,11 +217,11 @@ class LidarrDialogs { static Future> globalSettings(BuildContext context) async { List> _options = [ - ['View Web GUI', Icons.language, 'web_gui'], - ['Update Library', Icons.autorenew, 'update_library'], - ['Run RSS Sync', Icons.rss_feed, 'rss_sync'], - ['Search All Missing', Icons.search, 'missing_search'], - ['Backup Database', Icons.save, 'backup'], + ['View Web GUI', Icons.language_rounded, 'web_gui'], + ['Update Library', Icons.autorenew_rounded, 'update_library'], + ['Run RSS Sync', Icons.rss_feed_rounded, 'rss_sync'], + ['Search All Missing', Icons.search_rounded, 'missing_search'], + ['Backup Database', Icons.save_rounded, 'backup'], ]; bool _flag = false; String _value = ''; diff --git a/lib/modules/lidarr/routes/add_details.dart b/lib/modules/lidarr/routes/add_details.dart index cf4a8d7c..054f07e6 100644 --- a/lib/modules/lidarr/routes/add_details.dart +++ b/lib/modules/lidarr/routes/add_details.dart @@ -121,7 +121,7 @@ class _State extends State with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.link, + icon: Icons.link_rounded, onPressed: () async { if (_arguments.data.discogsLink == null || _arguments.data.discogsLink == '') diff --git a/lib/modules/lidarr/routes/details_album.dart b/lib/modules/lidarr/routes/details_album.dart index 74e7324e..5b86b25e 100644 --- a/lib/modules/lidarr/routes/details_album.dart +++ b/lib/modules/lidarr/routes/details_album.dart @@ -64,7 +64,7 @@ class _State extends State with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => _automaticSearch(), onLongPress: () async => _manualSearch(), ), diff --git a/lib/modules/lidarr/routes/lidarr.dart b/lib/modules/lidarr/routes/lidarr.dart index e526aff2..3c66e898 100644 --- a/lib/modules/lidarr/routes/lidarr.dart +++ b/lib/modules/lidarr/routes/lidarr.dart @@ -91,11 +91,11 @@ class _State extends State { if (_api.enabled) actions = [ LunaIconButton( - icon: Icons.add, + icon: Icons.add_rounded, onPressed: () async => _enterAddArtist(), ), LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async => _handlePopup(), ), ]; diff --git a/lib/modules/lidarr/widgets/catalogue_hide_button.dart b/lib/modules/lidarr/widgets/catalogue_hide_button.dart index 0d40b8f6..c2eb1f7a 100644 --- a/lib/modules/lidarr/widgets/catalogue_hide_button.dart +++ b/lib/modules/lidarr/widgets/catalogue_hide_button.dart @@ -22,8 +22,8 @@ class _State extends State { builder: (context, model, widget) => InkWell( child: LunaIconButton( icon: model.hideUnmonitoredArtists - ? Icons.visibility_off - : Icons.visibility, + ? Icons.visibility_off_rounded + : Icons.visibility_rounded, ), onTap: () => model.hideUnmonitoredArtists = !model.hideUnmonitoredArtists, diff --git a/lib/modules/lidarr/widgets/catalogue_sorting_button.dart b/lib/modules/lidarr/widgets/catalogue_sorting_button.dart index fc216478..1f4e8cff 100644 --- a/lib/modules/lidarr/widgets/catalogue_sorting_button.dart +++ b/lib/modules/lidarr/widgets/catalogue_sorting_button.dart @@ -24,7 +24,7 @@ class _State extends State { builder: (context, model, _) => LunaPopupMenuButton( tooltip: 'Sort Catalogue', - icon: Icons.sort, + icon: Icons.sort_rounded, onSelected: (result) { if (model.sortCatalogueType == result) { model.sortCatalogueAscending = !model.sortCatalogueAscending; @@ -52,8 +52,8 @@ class _State extends State { LidarrCatalogueSorting.values[index]) Icon( model.sortCatalogueAscending - ? Icons.arrow_upward - : Icons.arrow_downward, + ? Icons.arrow_upward_rounded + : Icons.arrow_downward_rounded, size: LunaUI.FONT_SIZE_SUBTITLE + 2.0, color: LunaColours.accent, ), diff --git a/lib/modules/lidarr/widgets/catalogue_tile.dart b/lib/modules/lidarr/widgets/catalogue_tile.dart index 514927a0..33783869 100644 --- a/lib/modules/lidarr/widgets/catalogue_tile.dart +++ b/lib/modules/lidarr/widgets/catalogue_tile.dart @@ -37,7 +37,9 @@ class _State extends State { ), ), trailing: LunaIconButton( - icon: widget.data.monitored ? Icons.turned_in : Icons.turned_in_not, + icon: widget.data.monitored + ? Icons.turned_in_rounded + : Icons.turned_in_not_rounded, color: widget.data.monitored ? Colors.white : Colors.white30, onPressed: _toggleMonitoredStatus, ), diff --git a/lib/modules/lidarr/widgets/details_album_tile.dart b/lib/modules/lidarr/widgets/details_album_tile.dart index 32cb26aa..52bf91de 100644 --- a/lib/modules/lidarr/widgets/details_album_tile.dart +++ b/lib/modules/lidarr/widgets/details_album_tile.dart @@ -77,8 +77,8 @@ class _State extends State { Padding( child: LunaIconButton( icon: widget.data.monitored - ? Icons.turned_in - : Icons.turned_in_not, + ? Icons.turned_in_rounded + : Icons.turned_in_not_rounded, color: widget.data.monitored ? Colors.white : Colors.white30, onPressed: _toggleMonitoredStatus, ), diff --git a/lib/modules/lidarr/widgets/details_edit_button.dart b/lib/modules/lidarr/widgets/details_edit_button.dart index aec6d04a..a400e815 100644 --- a/lib/modules/lidarr/widgets/details_edit_button.dart +++ b/lib/modules/lidarr/widgets/details_edit_button.dart @@ -18,7 +18,7 @@ class _State extends State { @override Widget build(BuildContext context) => Consumer( builder: (context, model, widget) => LunaIconButton( - icon: Icons.edit, + icon: Icons.edit_rounded, onPressed: () async => _enterEditArtist(context), ), ); diff --git a/lib/modules/lidarr/widgets/details_hide_button.dart b/lib/modules/lidarr/widgets/details_hide_button.dart index 3bdf9550..e6f560b1 100644 --- a/lib/modules/lidarr/widgets/details_hide_button.dart +++ b/lib/modules/lidarr/widgets/details_hide_button.dart @@ -11,8 +11,8 @@ class LidarrDetailsHideButton extends StatelessWidget { Widget build(BuildContext context) => Consumer( builder: (context, model, widget) => LunaIconButton( icon: model.hideUnmonitoredAlbums - ? Icons.visibility_off - : Icons.visibility, + ? Icons.visibility_off_rounded + : Icons.visibility_rounded, onPressed: () => model.hideUnmonitoredAlbums = !model.hideUnmonitoredAlbums, ), diff --git a/lib/modules/lidarr/widgets/details_settings_button.dart b/lib/modules/lidarr/widgets/details_settings_button.dart index c661680a..95d0242b 100644 --- a/lib/modules/lidarr/widgets/details_settings_button.dart +++ b/lib/modules/lidarr/widgets/details_settings_button.dart @@ -20,7 +20,7 @@ class _State extends State { @override Widget build(BuildContext context) => Consumer( builder: (context, model, widget) => LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async => _handlePopup(context), ), ); diff --git a/lib/modules/lidarr/widgets/missing_tile.dart b/lib/modules/lidarr/widgets/missing_tile.dart index 7127b52e..2dec9635 100644 --- a/lib/modules/lidarr/widgets/missing_tile.dart +++ b/lib/modules/lidarr/widgets/missing_tile.dart @@ -50,7 +50,7 @@ class _State extends State { maxLines: 2, ), trailing: LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => _search(), onLongPress: () async => _interactiveSearch(), ), diff --git a/lib/modules/lidarr/widgets/releases_hide_button.dart b/lib/modules/lidarr/widgets/releases_hide_button.dart index f6ff2618..ee33ca82 100644 --- a/lib/modules/lidarr/widgets/releases_hide_button.dart +++ b/lib/modules/lidarr/widgets/releases_hide_button.dart @@ -21,16 +21,16 @@ class _State extends State { child: Consumer( builder: (context, model, widget) => LunaIconButton( icon: model.hideRejectedReleases - ? Icons.visibility_off - : Icons.visibility, + ? Icons.visibility_off_rounded + : Icons.visibility_rounded, onPressed: () => model.hideRejectedReleases = !model.hideRejectedReleases, ), ), height: LunaTextInputBar.appBarInnerHeight, width: LunaTextInputBar.appBarInnerHeight, - margin: - LunaTextInputBar.appBarMargin.subtract(const EdgeInsets.only(left: 12.0)), + margin: LunaTextInputBar.appBarMargin + .subtract(const EdgeInsets.only(left: 12.0)), color: Theme.of(context).canvasColor, ); } diff --git a/lib/modules/lidarr/widgets/releases_sorting_button.dart b/lib/modules/lidarr/widgets/releases_sorting_button.dart index 926d6d9d..ef937055 100644 --- a/lib/modules/lidarr/widgets/releases_sorting_button.dart +++ b/lib/modules/lidarr/widgets/releases_sorting_button.dart @@ -24,7 +24,7 @@ class _State extends State { builder: (context, model, _) => LunaPopupMenuButton( tooltip: 'Sort Releases', - icon: Icons.sort, + icon: Icons.sort_rounded, onSelected: (result) { if (model.sortReleasesType == result) { model.sortReleasesAscending = !model.sortReleasesAscending; @@ -52,8 +52,8 @@ class _State extends State { LidarrReleasesSorting.values[index]) Icon( model.sortReleasesAscending - ? Icons.arrow_upward - : Icons.arrow_downward, + ? Icons.arrow_upward_rounded + : Icons.arrow_downward_rounded, size: LunaUI.FONT_SIZE_SUBTITLE + 2.0, color: LunaColours.accent, ), @@ -63,8 +63,8 @@ class _State extends State { ), ), ), - margin: - LunaTextInputBar.appBarMargin.subtract(const EdgeInsets.only(left: 12.0)), + margin: LunaTextInputBar.appBarMargin + .subtract(const EdgeInsets.only(left: 12.0)), color: Theme.of(context).canvasColor, ); } diff --git a/lib/modules/lidarr/widgets/search_result_tile.dart b/lib/modules/lidarr/widgets/search_result_tile.dart index 1e5acece..97bb7f21 100644 --- a/lib/modules/lidarr/widgets/search_result_tile.dart +++ b/lib/modules/lidarr/widgets/search_result_tile.dart @@ -22,8 +22,10 @@ class _State extends State { Widget build(BuildContext context) { return LunaExpandableListTile( title: widget.release.title, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], collapsedTrailing: _trailing(), expandedHighlightedNodes: _highlightedNodes(), expandedTableContent: _tableContent(), @@ -71,8 +73,9 @@ class _State extends State { Widget _trailing() { return LunaIconButton( - icon: - widget.release.approved ? Icons.file_download : Icons.report_outlined, + icon: widget.release.approved + ? Icons.file_download_rounded + : Icons.report_outlined, color: widget.release.approved ? Colors.white : LunaColours.red, onPressed: () async => widget.release.approved ? _startDownload() : _showWarnings(), diff --git a/lib/modules/nzbget/core/api/data/sort.dart b/lib/modules/nzbget/core/api/data/sort.dart index 41e61ad4..1dcd1faa 100644 --- a/lib/modules/nzbget/core/api/data/sort.dart +++ b/lib/modules/nzbget/core/api/data/sort.dart @@ -72,21 +72,21 @@ extension NZBGetSortExtension on NZBGetSort { switch (this) { case NZBGetSort.name_asc: case NZBGetSort.name_desc: - return Icons.text_rotate_vertical; + return Icons.text_rotate_vertical_rounded; case NZBGetSort.priority_asc: case NZBGetSort.priority_desc: - return Icons.low_priority; + return Icons.low_priority_rounded; case NZBGetSort.category_asc: case NZBGetSort.category_desc: - return Icons.category; + return Icons.category_rounded; case NZBGetSort.size_asc: case NZBGetSort.size_desc: - return Icons.sd_card; + return Icons.sd_card_rounded; case NZBGetSort.left_asc: case NZBGetSort.left_desc: - return Icons.storage; + return Icons.storage_rounded; default: - return Icons.question_answer; + return Icons.question_answer_rounded; } } } diff --git a/lib/modules/nzbget/core/dialogs.dart b/lib/modules/nzbget/core/dialogs.dart index 7fff1b89..4bf7d761 100644 --- a/lib/modules/nzbget/core/dialogs.dart +++ b/lib/modules/nzbget/core/dialogs.dart @@ -7,10 +7,10 @@ class NZBGetDialogs { static Future> globalSettings(BuildContext context) async { List> _options = [ - ['View Web GUI', Icons.language, 'web_gui'], - ['Add NZB', Icons.add, 'add_nzb'], - ['Sort Queue', Icons.sort, 'sort'], - ['Status & Statistics', Icons.info_outline, 'server_details'], + ['View Web GUI', Icons.language_rounded, 'web_gui'], + ['Add NZB', Icons.add_rounded, 'add_nzb'], + ['Sort Queue', Icons.sort_rounded, 'sort'], + ['Status & Statistics', Icons.info_outline_rounded, 'server_details'], ]; bool _flag = false; String _value = ''; @@ -42,13 +42,13 @@ class NZBGetDialogs { BuildContext context, String title, bool isPaused) async { List> _options = [ isPaused - ? ['Resume Job', Icons.play_arrow, 'status'] - : ['Pause Job', Icons.pause, 'status'], - ['Change Category', Icons.category, 'category'], - ['Change Priority', Icons.low_priority, 'priority'], - ['Set Password', Icons.vpn_key, 'password'], - ['Rename Job', Icons.text_format, 'rename'], - ['Delete Job', Icons.delete, 'delete'], + ? ['Resume Job', Icons.play_arrow_rounded, 'status'] + : ['Pause Job', Icons.pause_rounded, 'status'], + ['Change Category', Icons.category_rounded, 'category'], + ['Change Priority', Icons.low_priority_rounded, 'priority'], + ['Set Password', Icons.vpn_key_rounded, 'password'], + ['Rename Job', Icons.text_format_rounded, 'rename'], + ['Delete Job', Icons.delete_rounded, 'delete'], ]; bool _flag = false; String _value = ''; @@ -159,7 +159,7 @@ class NZBGetDialogs { NZBGetPriority.values.length, (index) => LunaDialog.tile( text: NZBGetPriority.values[index].name, - icon: Icons.low_priority, + icon: Icons.low_priority_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, NZBGetPriority.values[index]), ), @@ -189,7 +189,7 @@ class NZBGetDialogs { text: categories[index].name.isEmpty ? 'No Category' : categories[index].name, - icon: Icons.category, + icon: Icons.category_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, categories[index]), ), @@ -300,8 +300,8 @@ class NZBGetDialogs { static Future> addNZB(BuildContext context) async { List> _options = [ - ['Add by URL', Icons.link, 'link'], - ['Add by File', Icons.sd_card, 'file'], + ['Add by URL', Icons.link_rounded, 'link'], + ['Add by File', Icons.sd_card_rounded, 'file'], ]; bool _flag = false; String _type = ''; @@ -373,14 +373,14 @@ class NZBGetDialogs { static Future> speedLimit( BuildContext context, String currentSpeed) async { List> _options = [ - ['Unlimited', Icons.timeline, 0], - ['125 MB/s', Icons.timeline, 128000], - ['100 MB/s', Icons.timeline, 102400], - ['75 MB/s', Icons.timeline, 76800], - ['50 MB/s', Icons.timeline, 51200], - ['25 MB/s', Icons.timeline, 25600], - ['10 MB/s', Icons.timeline, 10240], - ['Custom...', Icons.timeline, -1], + ['Unlimited', Icons.timeline_rounded, 0], + ['125 MB/s', Icons.timeline_rounded, 128000], + ['100 MB/s', Icons.timeline_rounded, 102400], + ['75 MB/s', Icons.timeline_rounded, 76800], + ['50 MB/s', Icons.timeline_rounded, 51200], + ['25 MB/s', Icons.timeline_rounded, 25600], + ['10 MB/s', Icons.timeline_rounded, 10240], + ['Custom...', Icons.timeline_rounded, -1], ]; bool _flag = false; int _limit = 0; @@ -458,9 +458,9 @@ class NZBGetDialogs { static Future> historySettings( BuildContext context, String title) async { List> _options = [ - ['Retry Job', Icons.autorenew, 'retry'], - ['Hide History', Icons.visibility_off, 'hide'], - ['Delete History', Icons.delete, 'delete'], + ['Retry Job', Icons.autorenew_rounded, 'retry'], + ['Hide History', Icons.visibility_off_rounded, 'hide'], + ['Delete History', Icons.delete_rounded, 'delete'], ]; bool _flag = false; String _value = ''; @@ -490,13 +490,13 @@ class NZBGetDialogs { static Future> pauseFor(BuildContext context) async { List> _options = [ - ['5 Minutes', Icons.access_time, 5], - ['15 Minutes', Icons.access_time, 15], - ['30 Minutes', Icons.access_time, 30], - ['1 Hour', Icons.access_time, 60], - ['3 Hours', Icons.access_time, 180], - ['6 Hours', Icons.access_time, 360], - ['Custom...', Icons.access_time, -1], + ['5 Minutes', Icons.access_time_rounded, 5], + ['15 Minutes', Icons.access_time_rounded, 15], + ['30 Minutes', Icons.access_time_rounded, 30], + ['1 Hour', Icons.access_time_rounded, 60], + ['3 Hours', Icons.access_time_rounded, 180], + ['6 Hours', Icons.access_time_rounded, 360], + ['Custom...', Icons.access_time_rounded, -1], ]; bool _flag = false; int _duration = 0; diff --git a/lib/modules/nzbget/routes/nzbget.dart b/lib/modules/nzbget/routes/nzbget.dart index 01590376..92005cfe 100644 --- a/lib/modules/nzbget/routes/nzbget.dart +++ b/lib/modules/nzbget/routes/nzbget.dart @@ -73,7 +73,7 @@ class _State extends State { error ? Container() : const NZBGetAppBarStats(), ), LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async => _handlePopup(), ), ]; diff --git a/lib/modules/nzbget/widgets/history_hide_button.dart b/lib/modules/nzbget/widgets/history_hide_button.dart index 988749e0..d78d7257 100644 --- a/lib/modules/nzbget/widgets/history_hide_button.dart +++ b/lib/modules/nzbget/widgets/history_hide_button.dart @@ -21,8 +21,8 @@ class _State extends State { child: Consumer( builder: (context, model, widget) => LunaIconButton( icon: model.historyHideFailed - ? Icons.visibility_off - : Icons.visibility, + ? Icons.visibility_off_rounded + : Icons.visibility_rounded, onPressed: () => model.historyHideFailed = !model.historyHideFailed, ), ), diff --git a/lib/modules/nzbget/widgets/history_tile.dart b/lib/modules/nzbget/widgets/history_tile.dart index 2096231c..9b53dec2 100644 --- a/lib/modules/nzbget/widgets/history_tile.dart +++ b/lib/modules/nzbget/widgets/history_tile.dart @@ -21,8 +21,10 @@ class _State extends State { Widget build(BuildContext context) { return LunaExpandableListTile( title: widget.data.name, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedHighlightedNodes: _expandedHighlightedNodes(), expandedTableContent: _expandedTableContent(), expandedTableButtons: _expandedTableButtons(), diff --git a/lib/modules/radarr/core/dialogs.dart b/lib/modules/radarr/core/dialogs.dart index 8dc67432..59218165 100644 --- a/lib/modules/radarr/core/dialogs.dart +++ b/lib/modules/radarr/core/dialogs.dart @@ -143,7 +143,7 @@ class RadarrDialogs { titles.length, (index) => LunaDialog.tile( text: titles[index], - icon: Icons.sort, + icon: Icons.sort_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, index), ), @@ -293,7 +293,7 @@ class RadarrDialogs { RadarrAvailability.values.length, (index) => LunaDialog.tile( text: RadarrAvailability.values[index].readable, - icon: Icons.folder, + icon: Icons.folder_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, RadarrAvailability.values[index]), ), @@ -600,7 +600,7 @@ class RadarrDialogs { text: folders[index].freeSpace.lunaBytesToString()) ], ), - icon: Icons.folder, + icon: Icons.folder_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, folders[index]), ), diff --git a/lib/modules/radarr/core/extensions/radarr_event_type.dart b/lib/modules/radarr/core/extensions/radarr_event_type.dart index 3c1376d4..5a498d53 100644 --- a/lib/modules/radarr/core/extensions/radarr_event_type.dart +++ b/lib/modules/radarr/core/extensions/radarr_event_type.dart @@ -28,21 +28,21 @@ extension LunaRadarrEventType on RadarrEventType { IconData get lunaIcon { switch (this) { case RadarrEventType.GRABBED: - return Icons.cloud_download; + return Icons.cloud_download_rounded; case RadarrEventType.DOWNLOAD_FAILED: - return Icons.cloud_download; + return Icons.cloud_download_rounded; case RadarrEventType.DOWNLOAD_FOLDER_IMPORTED: return Icons.download_rounded; case RadarrEventType.MOVIE_FOLDER_IMPORTED: return Icons.download_rounded; case RadarrEventType.MOVIE_FILE_DELETED: - return Icons.delete; + return Icons.delete_rounded; case RadarrEventType.DOWNLOAD_IGNORED: - return Icons.cancel; + return Icons.cancel_rounded; case RadarrEventType.MOVIE_FILE_RENAMED: - return Icons.drive_file_rename_outline; + return Icons.drive_file_rename_outline_rounded; default: - return Icons.help; + return Icons.help_rounded; } } diff --git a/lib/modules/radarr/core/types/settings_global.dart b/lib/modules/radarr/core/types/settings_global.dart index ebe21d16..2a59f143 100644 --- a/lib/modules/radarr/core/types/settings_global.dart +++ b/lib/modules/radarr/core/types/settings_global.dart @@ -14,15 +14,15 @@ extension RadarrGlobalSettingsTypeExtension on RadarrGlobalSettingsType { IconData get icon { switch (this) { case RadarrGlobalSettingsType.WEB_GUI: - return Icons.language; + return Icons.language_rounded; case RadarrGlobalSettingsType.UPDATE_LIBRARY: - return Icons.autorenew; + return Icons.autorenew_rounded; case RadarrGlobalSettingsType.RUN_RSS_SYNC: - return Icons.rss_feed; + return Icons.rss_feed_rounded; case RadarrGlobalSettingsType.SEARCH_ALL_MISSING: - return Icons.search; + return Icons.search_rounded; case RadarrGlobalSettingsType.BACKUP_DATABASE: - return Icons.save; + return Icons.save_rounded; } throw Exception('Invalid RadarrGlobalSettingsType'); } diff --git a/lib/modules/radarr/core/types/settings_movie.dart b/lib/modules/radarr/core/types/settings_movie.dart index 185b26fd..d95e19f8 100644 --- a/lib/modules/radarr/core/types/settings_movie.dart +++ b/lib/modules/radarr/core/types/settings_movie.dart @@ -13,13 +13,15 @@ extension RadarrMovieSettingsTypeExtension on RadarrMovieSettingsType { IconData icon(RadarrMovie movie) { switch (this) { case RadarrMovieSettingsType.MONITORED: - return movie.monitored ? Icons.turned_in_not : Icons.turned_in; + return movie.monitored + ? Icons.turned_in_not_rounded + : Icons.turned_in_rounded; case RadarrMovieSettingsType.EDIT: - return Icons.edit; + return Icons.edit_rounded; case RadarrMovieSettingsType.REFRESH: - return Icons.refresh; + return Icons.refresh_rounded; case RadarrMovieSettingsType.DELETE: - return Icons.delete; + return Icons.delete_rounded; } throw Exception('Invalid RadarrMovieSettingsType'); } diff --git a/lib/modules/radarr/routes/add_movie/widgets/navigation_bar.dart b/lib/modules/radarr/routes/add_movie/widgets/navigation_bar.dart index d08bf58b..c3d3f007 100644 --- a/lib/modules/radarr/routes/add_movie/widgets/navigation_bar.dart +++ b/lib/modules/radarr/routes/add_movie/widgets/navigation_bar.dart @@ -7,8 +7,8 @@ class RadarrAddMovieNavigationBar extends StatelessWidget { List.generate(icons.length, (_) => ScrollController()); static const List icons = [ - Icons.search, - Icons.whatshot, + Icons.search_rounded, + Icons.whatshot_rounded, ]; static List get titles => [ diff --git a/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart b/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart index 1b23f395..88ba3c3f 100644 --- a/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart +++ b/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart @@ -113,11 +113,20 @@ class _State extends State { return Row( children: [ _buildReleaseIcon( - Icons.videocam, LunaColours.orange, widget.movie.lunaIsInCinemas), + Icons.videocam_rounded, + LunaColours.orange, + widget.movie.lunaIsInCinemas, + ), _buildReleaseIcon( - Icons.album, LunaColours.blue, widget.movie.lunaIsReleased), + Icons.album_rounded, + LunaColours.blue, + widget.movie.lunaIsReleased, + ), _buildReleaseIcon( - Icons.check_circle, LunaColours.accent, widget.movie.hasFile), + Icons.check_circle_rounded, + LunaColours.accent, + widget.movie.hasFile, + ), Padding( child: widget.movie.hasFile ? widget.movie.lunaHasFileTextObject(widget.movie.monitored) diff --git a/lib/modules/radarr/routes/catalogue/widgets/search_bar_sort_button.dart b/lib/modules/radarr/routes/catalogue/widgets/search_bar_sort_button.dart index 83376a88..f20fb222 100644 --- a/lib/modules/radarr/routes/catalogue/widgets/search_bar_sort_button.dart +++ b/lib/modules/radarr/routes/catalogue/widgets/search_bar_sort_button.dart @@ -23,7 +23,7 @@ class _State extends State { builder: (context, state, _) => LunaPopupMenuButton( tooltip: 'radarr.SortCatalogue'.tr(), - icon: Icons.sort, + icon: Icons.sort_rounded, onSelected: (result) { if (state.moviesSortType == result) { state.moviesSortAscending = !state.moviesSortAscending; @@ -54,8 +54,8 @@ class _State extends State { if (state.moviesSortType == RadarrMoviesSorting.values[index]) Icon( state.moviesSortAscending - ? Icons.arrow_upward - : Icons.arrow_downward, + ? Icons.arrow_upward_rounded + : Icons.arrow_downward_rounded, size: LunaUI.FONT_SIZE_SUBTITLE + 2.0, color: LunaColours.accent, ), diff --git a/lib/modules/radarr/routes/history/widgets/history_tile.dart b/lib/modules/radarr/routes/history/widgets/history_tile.dart index 7cc2ec7d..c74c9dc1 100644 --- a/lib/modules/radarr/routes/history/widgets/history_tile.dart +++ b/lib/modules/radarr/routes/history/widgets/history_tile.dart @@ -19,19 +19,21 @@ class RadarrHistoryTile extends StatelessWidget { Widget build(BuildContext context) { return LunaExpandableListTile( title: movieHistory ? history?.sourceTitle : title, - collapsedSubtitle1: TextSpan( - text: [ - history?.date?.lunaAge ?? LunaUI.TEXT_EMDASH, - history?.date?.lunaDateTimeReadable() ?? LunaUI.TEXT_EMDASH, - ].join(LunaUI.TEXT_BULLET.lunaPad()), - ), - collapsedSubtitle2: TextSpan( - text: history?.eventType?.lunaReadable(history) ?? LunaUI.TEXT_EMDASH, - style: TextStyle( - color: history?.eventType?.lunaColour ?? LunaColours.blueGrey, - fontWeight: LunaUI.FONT_WEIGHT_BOLD, + collapsedSubtitles: [ + TextSpan( + text: [ + history?.date?.lunaAge ?? LunaUI.TEXT_EMDASH, + history?.date?.lunaDateTimeReadable() ?? LunaUI.TEXT_EMDASH, + ].join(LunaUI.TEXT_BULLET.lunaPad()), ), - ), + TextSpan( + text: history?.eventType?.lunaReadable(history) ?? LunaUI.TEXT_EMDASH, + style: TextStyle( + color: history?.eventType?.lunaColour ?? LunaColours.blueGrey, + fontWeight: LunaUI.FONT_WEIGHT_BOLD, + ), + ), + ], expandedHighlightedNodes: [ LunaHighlightedNode( text: history.eventType?.readable, diff --git a/lib/modules/radarr/routes/manual_import_details/widgets/import_tile.dart b/lib/modules/radarr/routes/manual_import_details/widgets/import_tile.dart index f15d2501..8e3bc53e 100644 --- a/lib/modules/radarr/routes/manual_import_details/widgets/import_tile.dart +++ b/lib/modules/radarr/routes/manual_import_details/widgets/import_tile.dart @@ -21,8 +21,10 @@ class RadarrManualImportDetailsTile extends StatelessWidget { .manualImport .relativePath, collapsedTrailing: _trailing(context), - collapsedSubtitle1: _subtitle1(context), - collapsedSubtitle2: _subtitle2(context), + collapsedSubtitles: [ + _subtitle1(context), + _subtitle2(context), + ], expandedTableButtons: _buttons(context), expandedTableContent: _table(context), backgroundColor: context diff --git a/lib/modules/radarr/routes/missing/widgets/missing_tile.dart b/lib/modules/radarr/routes/missing/widgets/missing_tile.dart index ba784ee9..b4f15c60 100644 --- a/lib/modules/radarr/routes/missing/widgets/missing_tile.dart +++ b/lib/modules/radarr/routes/missing/widgets/missing_tile.dart @@ -78,7 +78,7 @@ class _State extends State { LunaIconButton _trailing() { return LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => RadarrAPIHelper().automaticSearch( context: context, movieId: widget.movie.id, diff --git a/lib/modules/radarr/routes/movie_details/route.dart b/lib/modules/radarr/routes/movie_details/route.dart index aa3950d3..4440ae4c 100644 --- a/lib/modules/radarr/routes/movie_details/route.dart +++ b/lib/modules/radarr/routes/movie_details/route.dart @@ -120,7 +120,7 @@ class _State extends State<_Widget> with LunaLoadCallbackMixin { ? null : [ LunaIconButton( - icon: Icons.edit, + icon: Icons.edit_rounded, onPressed: () async => RadarrMoviesEditRouter() .navigateTo(context, movieId: widget.movieId), ), diff --git a/lib/modules/radarr/routes/movie_details/widgets/appbar_settings_action.dart b/lib/modules/radarr/routes/movie_details/widgets/appbar_settings_action.dart index f7b56bfb..385e3686 100644 --- a/lib/modules/radarr/routes/movie_details/widgets/appbar_settings_action.dart +++ b/lib/modules/radarr/routes/movie_details/widgets/appbar_settings_action.dart @@ -24,7 +24,7 @@ class RadarrAppBarMovieSettingsAction extends StatelessWidget { ); if (movie != null) return LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async { Tuple2 values = await RadarrDialogs().movieSettings(context, movie); diff --git a/lib/modules/radarr/routes/movie_details/widgets/files_file_block.dart b/lib/modules/radarr/routes/movie_details/widgets/files_file_block.dart index eeb88000..e632fce2 100644 --- a/lib/modules/radarr/routes/movie_details/widgets/files_file_block.dart +++ b/lib/modules/radarr/routes/movie_details/widgets/files_file_block.dart @@ -22,26 +22,41 @@ class _State extends State { return LunaTableCard( content: [ LunaTableContent( - title: 'relative path', body: widget.movieFile?.lunaRelativePath), + title: 'relative path', + body: widget.movieFile.lunaRelativePath, + ), LunaTableContent( - title: 'video', - body: widget.movieFile.mediaInfo.videoCodec ?? LunaUI.TEXT_EMDASH), + title: 'video', + body: widget.movieFile.mediaInfo?.lunaVideoCodec, + ), LunaTableContent( title: 'audio', body: [ - widget.movieFile.mediaInfo.audioCodec ?? LunaUI.TEXT_EMDASH, - if (widget.movieFile.mediaInfo.audioChannels != null) - widget.movieFile.mediaInfo.audioChannels.toString(), - ].join(LunaUI.TEXT_EMDASH.lunaPad()), + widget.movieFile?.mediaInfo?.lunaAudioCodec, + if (widget.movieFile?.mediaInfo?.audioChannels != null) + widget.movieFile?.mediaInfo?.audioChannels.toString(), + ].join(LunaUI.TEXT_BULLET.lunaPad()), ), - LunaTableContent(title: 'size', body: widget.movieFile?.lunaSize), LunaTableContent( - title: 'languages', body: widget.movieFile?.lunaLanguage), - LunaTableContent(title: 'quality', body: widget.movieFile?.lunaQuality), + title: 'size', + body: widget.movieFile?.lunaSize, + ), LunaTableContent( - title: 'formats', body: widget.movieFile?.lunaCustomFormats), + title: 'languages', + body: widget.movieFile?.lunaLanguage, + ), LunaTableContent( - title: 'added on', body: widget.movieFile?.lunaDateAdded), + title: 'quality', + body: widget.movieFile?.lunaQuality, + ), + LunaTableContent( + title: 'formats', + body: widget.movieFile?.lunaCustomFormats, + ), + LunaTableContent( + title: 'added on', + body: widget.movieFile?.lunaDateAdded, + ), ], buttons: [ if (widget.movieFile?.mediaInfo != null) @@ -53,7 +68,7 @@ class _State extends State { LunaButton( type: LunaButtonType.TEXT, text: 'Delete', - icon: Icons.delete, + icon: Icons.delete_rounded, onTap: () async => _deleteFile(), color: LunaColours.red, loadingState: _deleteFileState, @@ -83,53 +98,67 @@ class _State extends State { LunaTableCard( content: [ LunaTableContent( - title: 'bit depth', - body: widget.movieFile.mediaInfo.lunaVideoBitDepth), + title: 'bit depth', + body: widget.movieFile?.mediaInfo?.lunaVideoBitDepth, + ), LunaTableContent( - title: 'bitrate', - body: widget.movieFile.mediaInfo.lunaVideoBitrate), + title: 'bitrate', + body: widget.movieFile?.mediaInfo?.lunaVideoBitrate, + ), LunaTableContent( - title: 'codec', - body: widget.movieFile.mediaInfo.lunaVideoCodec), + title: 'codec', + body: widget.movieFile?.mediaInfo?.lunaVideoCodec, + ), LunaTableContent( - title: 'fps', body: widget.movieFile.mediaInfo.lunaVideoFps), + title: 'fps', + body: widget.movieFile?.mediaInfo?.lunaVideoFps, + ), LunaTableContent( - title: 'resolution', - body: widget.movieFile.mediaInfo.lunaVideoResolution), + title: 'resolution', + body: widget.movieFile?.mediaInfo?.lunaVideoResolution, + ), ], ), const LunaHeader(text: 'Audio'), LunaTableCard( content: [ LunaTableContent( - title: 'bitrate', - body: widget.movieFile.mediaInfo.lunaAudioBitrate), + title: 'bitrate', + body: widget.movieFile?.mediaInfo?.lunaAudioBitrate, + ), LunaTableContent( - title: 'channels', - body: widget.movieFile.mediaInfo.lunaAudioChannels), + title: 'channels', + body: widget.movieFile?.mediaInfo?.lunaAudioChannels, + ), LunaTableContent( - title: 'codec', - body: widget.movieFile.mediaInfo.lunaAudioCodec), + title: 'codec', + body: widget.movieFile?.mediaInfo?.lunaAudioCodec, + ), LunaTableContent( - title: 'features', - body: widget.movieFile.mediaInfo.lunaAudioAdditionalFeatures), + title: 'features', + body: widget.movieFile?.mediaInfo?.lunaAudioAdditionalFeatures, + ), LunaTableContent( - title: 'languages', - body: widget.movieFile.mediaInfo.lunaAudioLanguages), + title: 'languages', + body: widget.movieFile?.mediaInfo?.lunaAudioLanguages, + ), LunaTableContent( - title: 'streams', - body: widget.movieFile.mediaInfo.lunaAudioStreamCount), + title: 'streams', + body: widget.movieFile?.mediaInfo?.lunaAudioStreamCount, + ), ], ), const LunaHeader(text: 'Other'), LunaTableCard( content: [ LunaTableContent( - title: 'runtime', - body: widget.movieFile.mediaInfo.lunaRunTime), + title: 'runtime', + body: widget.movieFile?.mediaInfo?.lunaRunTime, + ), LunaTableContent( - title: 'subtitles', - body: widget.movieFile.mediaInfo.lunaSubtitles), + title: 'subtitles', + body: widget.movieFile?.mediaInfo?.lunaSubtitles, + ), ], ), ], diff --git a/lib/modules/radarr/routes/queue/widgets/queue_tile.dart b/lib/modules/radarr/routes/queue/widgets/queue_tile.dart index b1f232f0..6d1ab6b8 100644 --- a/lib/modules/radarr/routes/queue/widgets/queue_tile.dart +++ b/lib/modules/radarr/routes/queue/widgets/queue_tile.dart @@ -25,8 +25,10 @@ class RadarrQueueTile extends StatelessWidget { ); return LunaExpandableListTile( title: record.title, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedHighlightedNodes: _highlightedNodes(), expandedTableContent: _tableContent(movie), expandedTableButtons: _tableButtons(context), diff --git a/lib/modules/radarr/routes/radarr/widgets/appbar_add_movie_action.dart b/lib/modules/radarr/routes/radarr/widgets/appbar_add_movie_action.dart index fd375b24..c2df89e1 100644 --- a/lib/modules/radarr/routes/radarr/widgets/appbar_add_movie_action.dart +++ b/lib/modules/radarr/routes/radarr/widgets/appbar_add_movie_action.dart @@ -10,7 +10,7 @@ class RadarrAppBarAddMoviesAction extends StatelessWidget { @override Widget build(BuildContext context) { return LunaIconButton( - icon: Icons.add, + icon: Icons.add_rounded, onPressed: () async => RadarrAddMovieRouter().navigateTo( context, query: '', diff --git a/lib/modules/radarr/routes/radarr/widgets/appbar_global_settings_action.dart b/lib/modules/radarr/routes/radarr/widgets/appbar_global_settings_action.dart index 4c10d703..33d71a71 100644 --- a/lib/modules/radarr/routes/radarr/widgets/appbar_global_settings_action.dart +++ b/lib/modules/radarr/routes/radarr/widgets/appbar_global_settings_action.dart @@ -10,7 +10,7 @@ class RadarrAppBarGlobalSettingsAction extends StatelessWidget { @override Widget build(BuildContext context) { return LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async { Tuple2 values = await RadarrDialogs().globalSettings(context); diff --git a/lib/modules/radarr/routes/radarr/widgets/navigation_bar.dart b/lib/modules/radarr/routes/radarr/widgets/navigation_bar.dart index 1b43325c..228dc2e1 100644 --- a/lib/modules/radarr/routes/radarr/widgets/navigation_bar.dart +++ b/lib/modules/radarr/routes/radarr/widgets/navigation_bar.dart @@ -12,7 +12,7 @@ class RadarrNavigationBar extends StatelessWidget { LunaIcons.movies, LunaIcons.upcoming, LunaIcons.calendar_missing, - Icons.more_horiz, + Icons.more_horiz_rounded, ]; static List get titles => [ diff --git a/lib/modules/radarr/routes/releases/widgets/release_tile.dart b/lib/modules/radarr/routes/releases/widgets/release_tile.dart index 847f9b15..9503569a 100644 --- a/lib/modules/radarr/routes/releases/widgets/release_tile.dart +++ b/lib/modules/radarr/routes/releases/widgets/release_tile.dart @@ -21,8 +21,10 @@ class _State extends State { Widget build(BuildContext context) { return LunaExpandableListTile( title: widget.release.title, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], collapsedTrailing: _trailing(), expandedHighlightedNodes: _highlightedNodes(), expandedTableContent: _tableContent(), diff --git a/lib/modules/radarr/routes/releases/widgets/search_bar_sort_button.dart b/lib/modules/radarr/routes/releases/widgets/search_bar_sort_button.dart index 72cd0aa5..60233714 100644 --- a/lib/modules/radarr/routes/releases/widgets/search_bar_sort_button.dart +++ b/lib/modules/radarr/routes/releases/widgets/search_bar_sort_button.dart @@ -23,7 +23,7 @@ class _State extends State { builder: (context, state, _) => LunaPopupMenuButton( tooltip: 'Sort Releases', - icon: Icons.sort, + icon: Icons.sort_rounded, onSelected: (result) { if (state.sortType == result) { state.sortAscending = !state.sortAscending; @@ -54,8 +54,8 @@ class _State extends State { if (state.sortType == RadarrReleasesSorting.values[index]) Icon( state.sortAscending - ? Icons.arrow_upward - : Icons.arrow_downward, + ? Icons.arrow_upward_rounded + : Icons.arrow_downward_rounded, size: LunaUI.FONT_SIZE_SUBTITLE + 2.0, color: LunaColours.accent, ), diff --git a/lib/modules/radarr/routes/system_status/widgets/health_tile.dart b/lib/modules/radarr/routes/system_status/widgets/health_tile.dart index 79e4afd5..9cec7f20 100644 --- a/lib/modules/radarr/routes/system_status/widgets/health_tile.dart +++ b/lib/modules/radarr/routes/system_status/widgets/health_tile.dart @@ -14,8 +14,10 @@ class RadarrHealthCheckTile extends StatelessWidget { Widget build(BuildContext context) { return LunaExpandableListTile( title: healthCheck.message, - collapsedSubtitle1: subtitle1(), - collapsedSubtitle2: subtitle2(), + collapsedSubtitles: [ + subtitle1(), + subtitle2(), + ], expandedTableContent: expandedTable(), expandedHighlightedNodes: highlightedNodes(), onLongPress: healthCheck.wikiUrl.lunaOpenGenericLink, diff --git a/lib/modules/radarr/routes/tags/widgets/appbar_action_add_tag.dart b/lib/modules/radarr/routes/tags/widgets/appbar_action_add_tag.dart index 955935a5..eb0d717e 100644 --- a/lib/modules/radarr/routes/tags/widgets/appbar_action_add_tag.dart +++ b/lib/modules/radarr/routes/tags/widgets/appbar_action_add_tag.dart @@ -19,7 +19,7 @@ class RadarrTagsAppBarActionAddTag extends StatelessWidget { onPressed: () async => _onPressed(context), ); return LunaIconButton( - icon: Icons.add, + icon: Icons.add_rounded, onPressed: () async => _onPressed(context), ); } diff --git a/lib/modules/radarr/routes/tags/widgets/tag_tile.dart b/lib/modules/radarr/routes/tags/widgets/tag_tile.dart index c819e802..d8506a3c 100644 --- a/lib/modules/radarr/routes/tags/widgets/tag_tile.dart +++ b/lib/modules/radarr/routes/tags/widgets/tag_tile.dart @@ -53,7 +53,7 @@ class _State extends State with LunaLoadCallbackMixin { // Default to true, to not try to delete a tag that actually does have movies attached if (movieList?.isNotEmpty ?? true) return null; return LunaIconButton( - icon: Icons.delete, + icon: Icons.delete_rounded, color: LunaColours.red, onPressed: _delete, ); diff --git a/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart b/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart index 9300a507..8bbc11fc 100644 --- a/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart +++ b/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart @@ -112,7 +112,7 @@ class _State extends State { LunaIconButton _trailing() { return LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => RadarrAPIHelper().automaticSearch( context: context, movieId: widget.movie.id, diff --git a/lib/modules/sabnzbd/core/dialogs.dart b/lib/modules/sabnzbd/core/dialogs.dart index 63680ad3..89360339 100644 --- a/lib/modules/sabnzbd/core/dialogs.dart +++ b/lib/modules/sabnzbd/core/dialogs.dart @@ -7,12 +7,12 @@ class SABnzbdDialogs { static Future> globalSettings(BuildContext context) async { List> _options = [ - ['View Web GUI', Icons.language, 'web_gui'], - ['Add NZB', Icons.add, 'add_nzb'], - ['Sort Queue', Icons.sort, 'sort'], - ['Clear History', Icons.clear_all, 'clear_history'], - ['On Complete Action', Icons.settings_power, 'complete_action'], - ['Status & Statistics', Icons.info_outline, 'server_details'], + ['View Web GUI', Icons.language_rounded, 'web_gui'], + ['Add NZB', Icons.add_rounded, 'add_nzb'], + ['Sort Queue', Icons.sort_rounded, 'sort'], + ['Clear History', Icons.clear_all_rounded, 'clear_history'], + ['On Complete Action', Icons.settings_power_rounded, 'complete_action'], + ['Status & Statistics', Icons.info_outline_rounded, 'server_details'], ]; bool _flag = false; String _value = ''; @@ -44,13 +44,13 @@ class SABnzbdDialogs { BuildContext context, String title, bool isPaused) async { List> _options = [ isPaused - ? ['Resume Job', Icons.play_arrow, 'status'] - : ['Pause Job', Icons.pause, 'status'], - ['Change Category', Icons.category, 'category'], - ['Change Priority', Icons.low_priority, 'priority'], - ['Set Password', Icons.vpn_key, 'password'], - ['Rename Job', Icons.text_format, 'rename'], - ['Delete Job', Icons.delete, 'delete'], + ? ['Resume Job', Icons.play_arrow_rounded, 'status'] + : ['Pause Job', Icons.pause_rounded, 'status'], + ['Change Category', Icons.category_rounded, 'category'], + ['Change Priority', Icons.low_priority_rounded, 'priority'], + ['Set Password', Icons.vpn_key_rounded, 'password'], + ['Rename Job', Icons.text_format_rounded, 'rename'], + ['Delete Job', Icons.delete_rounded, 'delete'], ]; bool _flag = false; String _value = ''; @@ -81,9 +81,9 @@ class SABnzbdDialogs { static Future> historySettings( BuildContext context, String title, bool failed) async { List> _options = [ - if (failed) ['Retry Job', Icons.autorenew, 'retry'], - if (failed) ['Set Password', Icons.vpn_key, 'password'], - ['Delete History', Icons.delete, 'delete'], + if (failed) ['Retry Job', Icons.autorenew_rounded, 'retry'], + if (failed) ['Set Password', Icons.vpn_key_rounded, 'password'], + ['Delete History', Icons.delete_rounded, 'delete'], ]; bool _flag = false; String _value = ''; @@ -131,7 +131,7 @@ class SABnzbdDialogs { categories.length, (index) => LunaDialog.tile( text: categories[index].category, - icon: Icons.category, + icon: Icons.category_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, categories[index].category), ), @@ -143,12 +143,12 @@ class SABnzbdDialogs { static Future> sortQueue(BuildContext context) async { List> _options = [ - ['Age (Ascending)', Icons.access_time, 'avg_age', 'asc'], - ['Age (Descending)', Icons.access_time, 'avg_age', 'desc'], - ['Name (Ascending)', Icons.text_rotate_vertical, 'name', 'asc'], - ['Name (Descending)', Icons.text_rotate_vertical, 'name', 'desc'], - ['Size (Ascending)', Icons.sd_card, 'size', 'asc'], - ['Size (Descending)', Icons.sd_card, 'size', 'desc'], + ['Age (Ascending)', Icons.access_time_rounded, 'avg_age', 'asc'], + ['Age (Descending)', Icons.access_time_rounded, 'avg_age', 'desc'], + ['Name (Ascending)', Icons.text_rotate_vertical_rounded, 'name', 'asc'], + ['Name (Descending)', Icons.text_rotate_vertical_rounded, 'name', 'desc'], + ['Size (Ascending)', Icons.sd_card_rounded, 'size', 'asc'], + ['Size (Descending)', Icons.sd_card_rounded, 'size', 'desc'], ]; bool _flag = false; String _sort = ''; @@ -182,8 +182,8 @@ class SABnzbdDialogs { static Future> addNZB(BuildContext context) async { List> _options = [ - ['Add by URL', Icons.link, 'link'], - ['Add by File', Icons.sd_card, 'file'], + ['Add by URL', Icons.link_rounded, 'link'], + ['Add by File', Icons.sd_card_rounded, 'file'], ]; bool _flag = false; String _value = ''; @@ -332,12 +332,12 @@ class SABnzbdDialogs { static Future> speedLimit( BuildContext context, int currentSpeed) async { List> _options = [ - ['20%', Icons.timeline, 20], - ['40%', Icons.timeline, 40], - ['60%', Icons.timeline, 60], - ['80%', Icons.timeline, 80], - ['100%', Icons.timeline, 100], - ['Custom...', Icons.timeline, -1], + ['20%', Icons.timeline_rounded, 20], + ['40%', Icons.timeline_rounded, 40], + ['60%', Icons.timeline_rounded, 60], + ['80%', Icons.timeline_rounded, 80], + ['100%', Icons.timeline_rounded, 100], + ['Custom...', Icons.timeline_rounded, -1], ]; bool _flag = false; int _limit = 0; @@ -366,13 +366,13 @@ class SABnzbdDialogs { static Future> pauseFor(BuildContext context) async { List> _options = [ - ['5 Minutes', Icons.access_time, 5], - ['15 Minutes', Icons.access_time, 15], - ['30 Minutes', Icons.access_time, 30], - ['1 Hour', Icons.access_time, 60], - ['3 Hours', Icons.access_time, 180], - ['6 Hours', Icons.access_time, 360], - ['Custom...', Icons.access_time, -1], + ['5 Minutes', Icons.access_time_rounded, 5], + ['15 Minutes', Icons.access_time_rounded, 15], + ['30 Minutes', Icons.access_time_rounded, 30], + ['1 Hour', Icons.access_time_rounded, 60], + ['3 Hours', Icons.access_time_rounded, 180], + ['6 Hours', Icons.access_time_rounded, 360], + ['Custom...', Icons.access_time_rounded, -1], ]; bool _flag = false; int _duration = 0; @@ -454,12 +454,12 @@ class SABnzbdDialogs { static Future> changePriority(BuildContext context) async { List> _options = [ - ['Category Default', Icons.low_priority, -100], - ['Force', Icons.low_priority, 2], - ['High', Icons.low_priority, 1], - ['Normal', Icons.low_priority, 0], - ['Low', Icons.low_priority, -1], - ['Stop', Icons.low_priority, -4], + ['Category Default', Icons.low_priority_rounded, -100], + ['Force', Icons.low_priority_rounded, 2], + ['High', Icons.low_priority_rounded, 1], + ['Normal', Icons.low_priority_rounded, 0], + ['Low', Icons.low_priority_rounded, -1], + ['Stop', Icons.low_priority_rounded, -4], ]; bool _flag = false; int _priority = 0; @@ -492,11 +492,11 @@ class SABnzbdDialogs { static Future> changeOnCompleteAction( BuildContext context) async { List> _options = [ - ['Shutdown SABnzbd', Icons.settings_power, 'shutdown_program'], - ['Shutdown Machine', Icons.settings_power, 'shutdown_pc'], - ['Hibernate Machine', Icons.settings_power, 'hibernate_pc'], - ['Standby Machine', Icons.settings_power, 'standby_pc'], - ['Nothing', Icons.settings_power, 'none'], + ['Shutdown SABnzbd', Icons.settings_power_rounded, 'shutdown_program'], + ['Shutdown Machine', Icons.settings_power_rounded, 'shutdown_pc'], + ['Hibernate Machine', Icons.settings_power_rounded, 'hibernate_pc'], + ['Standby Machine', Icons.settings_power_rounded, 'standby_pc'], + ['Nothing', Icons.settings_power_rounded, 'none'], ]; bool _flag = false; String _action = ''; @@ -528,10 +528,10 @@ class SABnzbdDialogs { static Future> clearAllHistory(BuildContext context) async { List> _options = [ - ['Clear All', Icons.clear_all, 'all', false], - ['Clear Completed', Icons.clear_all, 'completed', false], - ['Clear Failed', Icons.clear_all, 'failed', false], - ['Clear & Delete Failed', Icons.clear_all, 'failed', true], + ['Clear All', Icons.clear_all_rounded, 'all', false], + ['Clear Completed', Icons.clear_all_rounded, 'completed', false], + ['Clear Failed', Icons.clear_all_rounded, 'failed', false], + ['Clear & Delete Failed', Icons.clear_all_rounded, 'failed', true], ]; bool _flag = false; bool _delete = false; diff --git a/lib/modules/sabnzbd/routes/sabnzbd.dart b/lib/modules/sabnzbd/routes/sabnzbd.dart index 353dac9c..1179195a 100644 --- a/lib/modules/sabnzbd/routes/sabnzbd.dart +++ b/lib/modules/sabnzbd/routes/sabnzbd.dart @@ -73,7 +73,7 @@ class _State extends State { error ? Container() : const SABnzbdAppBarStats(), ), LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async => _handlePopup(), ), ]; diff --git a/lib/modules/sabnzbd/widgets/history_hide_button.dart b/lib/modules/sabnzbd/widgets/history_hide_button.dart index 10744f79..03b91fe9 100644 --- a/lib/modules/sabnzbd/widgets/history_hide_button.dart +++ b/lib/modules/sabnzbd/widgets/history_hide_button.dart @@ -21,8 +21,8 @@ class _State extends State { child: Consumer( builder: (context, model, widget) => LunaIconButton( icon: model.historyHideFailed - ? Icons.visibility_off - : Icons.visibility, + ? Icons.visibility_off_rounded + : Icons.visibility_rounded, onPressed: () => model.historyHideFailed = !model.historyHideFailed, ), ), diff --git a/lib/modules/sabnzbd/widgets/history_tile.dart b/lib/modules/sabnzbd/widgets/history_tile.dart index 30fb8d2e..5af5bffd 100644 --- a/lib/modules/sabnzbd/widgets/history_tile.dart +++ b/lib/modules/sabnzbd/widgets/history_tile.dart @@ -21,8 +21,10 @@ class _State extends State { Widget build(BuildContext context) { return LunaExpandableListTile( title: widget.data.name, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedTableContent: _expandedTableContent(), expandedHighlightedNodes: _expandedHighlightedNodes(), expandedTableButtons: _expandedButtons(), @@ -72,7 +74,7 @@ class _State extends State { return [ LunaButton.text( text: 'Stages', - icon: Icons.subject, + icon: Icons.subject_rounded, onTap: () async => _enterStages(), ), LunaButton.text( diff --git a/lib/modules/search/core/dialogs.dart b/lib/modules/search/core/dialogs.dart index cde7ae7a..9237349d 100644 --- a/lib/modules/search/core/dialogs.dart +++ b/lib/modules/search/core/dialogs.dart @@ -37,7 +37,7 @@ class SearchDialogs { ), ), const Icon( - Icons.arrow_drop_down, + Icons.arrow_drop_down_rounded, color: LunaColours.accent, ), ], diff --git a/lib/modules/search/core/models/category.dart b/lib/modules/search/core/models/category.dart index f273fdc6..374ec364 100644 --- a/lib/modules/search/core/models/category.dart +++ b/lib/modules/search/core/models/category.dart @@ -23,14 +23,14 @@ class NewznabCategoryData { }.toString(); IconData get icon { - if (id >= 1000 && id <= 1999) return Icons.games; - if (id >= 2000 && id <= 2999) return Icons.movie; - if (id >= 3000 && id <= 3999) return Icons.library_music; - if (id >= 4000 && id <= 4999) return Icons.computer; - if (id >= 5000 && id <= 5999) return Icons.live_tv; - if (id >= 6000 && id <= 6999) return Icons.lock; - if (id >= 7000 && id <= 7999) return Icons.book; - return Icons.category; + if (id >= 1000 && id <= 1999) return Icons.games_rounded; + if (id >= 2000 && id <= 2999) return Icons.movie_rounded; + if (id >= 3000 && id <= 3999) return Icons.library_music_rounded; + if (id >= 4000 && id <= 4999) return Icons.computer_rounded; + if (id >= 5000 && id <= 5999) return Icons.live_tv_rounded; + if (id >= 6000 && id <= 6999) return Icons.lock_rounded; + if (id >= 7000 && id <= 7999) return Icons.book_rounded; + return Icons.category_rounded; } String get subcategoriesTitleList { diff --git a/lib/modules/search/routes/categories/route.dart b/lib/modules/search/routes/categories/route.dart index 5dcf848e..7888f085 100644 --- a/lib/modules/search/routes/categories/route.dart +++ b/lib/modules/search/routes/categories/route.dart @@ -47,7 +47,7 @@ class _State extends State<_Widget> scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: _enterSearch, ), ], diff --git a/lib/modules/search/routes/results/route.dart b/lib/modules/search/routes/results/route.dart index a886346e..7bd2a6a4 100644 --- a/lib/modules/search/routes/results/route.dart +++ b/lib/modules/search/routes/results/route.dart @@ -78,7 +78,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: title, actions: [ LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async => SearchSearchRouter().navigateTo(context), ), ], diff --git a/lib/modules/search/routes/results/widgets/result_tile.dart b/lib/modules/search/routes/results/widgets/result_tile.dart index 156cc3c2..3478e778 100644 --- a/lib/modules/search/routes/results/widgets/result_tile.dart +++ b/lib/modules/search/routes/results/widgets/result_tile.dart @@ -14,8 +14,10 @@ class SearchResultTile extends StatelessWidget { Widget build(BuildContext context) { return LunaExpandableListTile( title: data.title, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedTableContent: _tableContent(), collapsedTrailing: _trailing(context), expandedTableButtons: _tableButtons(context), diff --git a/lib/modules/search/routes/subcategories/route.dart b/lib/modules/search/routes/subcategories/route.dart index 9dea6d75..0f4914a8 100644 --- a/lib/modules/search/routes/subcategories/route.dart +++ b/lib/modules/search/routes/subcategories/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: () async { context.read().activeSubcategory = null; SearchSearchRouter().navigateTo(context); diff --git a/lib/modules/settings/core/dialogs.dart b/lib/modules/settings/core/dialogs.dart index ef417b5c..7518e955 100644 --- a/lib/modules/settings/core/dialogs.dart +++ b/lib/modules/settings/core/dialogs.dart @@ -51,7 +51,7 @@ class SettingsDialogs { ? List.generate( backups.length, (index) => LunaDialog.tile( - icon: Icons.file_copy, + icon: Icons.file_copy_rounded, iconColor: LunaColours().byListIndex(index), text: backups[index].title.toString(), onTap: () => _setValues(true, backups[index]), @@ -521,7 +521,7 @@ class SettingsDialogs { content: List.generate( profiles.length, (index) => LunaDialog.tile( - icon: Icons.settings, + icon: Icons.settings_rounded, iconColor: LunaColours().byListIndex(index), text: profiles[index], onTap: () => _setValues(true, profiles[index]), @@ -599,7 +599,7 @@ class SettingsDialogs { content: List.generate( profiles.length, (index) => LunaDialog.tile( - icon: Icons.settings, + icon: Icons.settings_rounded, iconColor: LunaColours().byListIndex(index), text: profiles[index], onTap: () => _setValues(true, profiles[index]), @@ -629,7 +629,7 @@ class SettingsDialogs { content: List.generate( profiles.length, (index) => LunaDialog.tile( - icon: Icons.settings, + icon: Icons.settings_rounded, iconColor: LunaColours().byListIndex(index), text: profiles[index], onTap: () => _setValues(true, profiles[index]), @@ -774,7 +774,7 @@ class SettingsDialogs { case CalendarStartingType.SCHEDULE: return CalendarStartingType.CALENDAR.icon; default: - return Icons.help; + return Icons.help_rounded; } } diff --git a/lib/modules/settings/core/pages/headers.dart b/lib/modules/settings/core/pages/headers.dart index 1ca34823..aa5e6b86 100644 --- a/lib/modules/settings/core/pages/headers.dart +++ b/lib/modules/settings/core/pages/headers.dart @@ -37,7 +37,7 @@ class _State extends State with LunaScrollControllerMixin { actions: [ LunaButton.text( text: 'settings.AddHeader'.tr(), - icon: Icons.add, + icon: Icons.add_rounded, onTap: () async { await HeaderUtility().addHeader(context, headers: _headers()); _resetState(); @@ -83,7 +83,7 @@ class _State extends State with LunaScrollControllerMixin { title: LunaText.title(text: key), subtitle: LunaText.subtitle(text: value), trailing: LunaIconButton( - icon: Icons.delete, + icon: Icons.delete_rounded, color: LunaColours.red, onPressed: () async { await HeaderUtility() diff --git a/lib/modules/settings/core/types/header.dart b/lib/modules/settings/core/types/header.dart index 6ba662d6..d05f8d19 100644 --- a/lib/modules/settings/core/types/header.dart +++ b/lib/modules/settings/core/types/header.dart @@ -20,9 +20,9 @@ extension HeaderTypeExtension on HeaderType { IconData get icon { switch (this) { case HeaderType.GENERIC: - return Icons.device_hub; + return Icons.device_hub_rounded; case HeaderType.AUTHORIZATION: - return Icons.verified_user; + return Icons.verified_user_rounded; } throw Exception('Invalid HeaderType'); } diff --git a/lib/modules/settings/routes/account/pages/password_reset.dart b/lib/modules/settings/routes/account/pages/password_reset.dart index fa60e325..c95cda58 100644 --- a/lib/modules/settings/routes/account/pages/password_reset.dart +++ b/lib/modules/settings/routes/account/pages/password_reset.dart @@ -66,7 +66,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { controller: _emailController, isFormField: true, margin: const EdgeInsets.all(12.0), - labelIcon: Icons.person, + labelIcon: Icons.person_rounded, labelText: 'settings.Email'.tr(), action: TextInputAction.next, keyboardType: TextInputType.emailAddress, diff --git a/lib/modules/settings/routes/account/pages/signed_in.dart b/lib/modules/settings/routes/account/pages/signed_in.dart index 2d490d08..47e7b108 100644 --- a/lib/modules/settings/routes/account/pages/signed_in.dart +++ b/lib/modules/settings/routes/account/pages/signed_in.dart @@ -31,7 +31,7 @@ class _State extends State { actions: [ LunaButton.text( text: 'settings.SignOut'.tr(), - icon: Icons.logout, + icon: Icons.logout_rounded, color: LunaColours.red, onTap: () async { bool result = diff --git a/lib/modules/settings/routes/account/pages/signed_out.dart b/lib/modules/settings/routes/account/pages/signed_out.dart index fb586694..3c476483 100644 --- a/lib/modules/settings/routes/account/pages/signed_out.dart +++ b/lib/modules/settings/routes/account/pages/signed_out.dart @@ -35,7 +35,7 @@ class _State extends State { LunaButton( type: LunaButtonType.TEXT, text: 'settings.Register'.tr(), - icon: Icons.app_registration, + icon: Icons.app_registration_rounded, onTap: _register, loadingState: _state, ), @@ -72,18 +72,21 @@ class _State extends State { controller: _emailController, isFormField: true, margin: const EdgeInsets.all(12.0), - labelIcon: Icons.person, + labelIcon: Icons.person_rounded, labelText: 'settings.Email'.tr(), action: TextInputAction.next, keyboardType: TextInputType.emailAddress, - autofillHints: const [AutofillHints.username, AutofillHints.email], + autofillHints: const [ + AutofillHints.username, + AutofillHints.email + ], ), LunaTextInputBar( controller: _passwordController, isFormField: true, - margin: - const EdgeInsets.only(bottom: 12.0, left: 12.0, right: 12.0), - labelIcon: Icons.vpn_key, + margin: const EdgeInsets.only( + bottom: 12.0, left: 12.0, right: 12.0), + labelIcon: Icons.vpn_key_rounded, labelText: 'settings.Password'.tr(), obscureText: true, keyboardType: TextInputType.text, diff --git a/lib/modules/settings/routes/account/route.dart b/lib/modules/settings/routes/account/route.dart index 1bb7cfff..828f783f 100644 --- a/lib/modules/settings/routes/account/route.dart +++ b/lib/modules/settings/routes/account/route.dart @@ -37,7 +37,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => SettingsDialogs().accountHelpMessage(context), ), ], diff --git a/lib/modules/settings/routes/configuration/route.dart b/lib/modules/settings/routes/configuration/route.dart index 50e7fec6..87f16b6e 100644 --- a/lib/modules/settings/routes/configuration/route.dart +++ b/lib/modules/settings/routes/configuration/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.switch_account, + icon: Icons.switch_account_rounded, onPressed: () async { Tuple2 results = await SettingsDialogs().enabledProfile( @@ -110,7 +110,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { subtitle: LunaText.subtitle( text: 'settings.QuickActionsDescription'.tr(), ), - trailing: LunaIconButton(icon: Icons.rounded_corner), + trailing: LunaIconButton(icon: Icons.rounded_corner_rounded), onTap: () async => SettingsConfigurationQuickActionsRouter().navigateTo(context), ), diff --git a/lib/modules/settings/routes/configuration_externalmodules/route.dart b/lib/modules/settings/routes/configuration_externalmodules/route.dart index 8ba73195..dc1795c5 100644 --- a/lib/modules/settings/routes/configuration_externalmodules/route.dart +++ b/lib/modules/settings/routes/configuration_externalmodules/route.dart @@ -39,7 +39,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: LunaModule.EXTERNAL_MODULES.name, actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async { SettingsDialogs() .moduleInformation(context, LunaModule.EXTERNAL_MODULES); diff --git a/lib/modules/settings/routes/configuration_lidarr/route.dart b/lib/modules/settings/routes/configuration_lidarr/route.dart index 7ace020f..56ce2c15 100644 --- a/lib/modules/settings/routes/configuration_lidarr/route.dart +++ b/lib/modules/settings/routes/configuration_lidarr/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: 'Lidarr', actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async { SettingsDialogs().moduleInformation(context, LunaModule.LIDARR); }, diff --git a/lib/modules/settings/routes/configuration_localization/route.dart b/lib/modules/settings/routes/configuration_localization/route.dart index 38582169..07c73b82 100644 --- a/lib/modules/settings/routes/configuration_localization/route.dart +++ b/lib/modules/settings/routes/configuration_localization/route.dart @@ -57,7 +57,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { text: LunaLanguage.ENGLISH.fromLocale(context.locale)?.name ?? LunaUI.TEXT_EMDASH, ), - trailing: LunaIconButton(icon: Icons.language), + trailing: LunaIconButton(icon: Icons.language_rounded), onTap: () async { Tuple2 result = await SettingsDialogs().changeLanguage(context); diff --git a/lib/modules/settings/routes/configuration_nzbget/route.dart b/lib/modules/settings/routes/configuration_nzbget/route.dart index d67286a9..06084505 100644 --- a/lib/modules/settings/routes/configuration_nzbget/route.dart +++ b/lib/modules/settings/routes/configuration_nzbget/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => SettingsDialogs().moduleInformation( context, LunaModule.NZBGET, diff --git a/lib/modules/settings/routes/configuration_overseerr/route.dart b/lib/modules/settings/routes/configuration_overseerr/route.dart index 147ead65..f7831a27 100644 --- a/lib/modules/settings/routes/configuration_overseerr/route.dart +++ b/lib/modules/settings/routes/configuration_overseerr/route.dart @@ -39,7 +39,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async { SettingsDialogs().moduleInformation(context, LunaModule.OVERSEERR); }, diff --git a/lib/modules/settings/routes/configuration_quickactions/route.dart b/lib/modules/settings/routes/configuration_quickactions/route.dart index 8c8509aa..38e36506 100644 --- a/lib/modules/settings/routes/configuration_quickactions/route.dart +++ b/lib/modules/settings/routes/configuration_quickactions/route.dart @@ -39,7 +39,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: 'Quick Actions', actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => LunaDialogs().textPreview( context, 'Quick Actions', diff --git a/lib/modules/settings/routes/configuration_radarr/route.dart b/lib/modules/settings/routes/configuration_radarr/route.dart index f7a809cd..390850b5 100644 --- a/lib/modules/settings/routes/configuration_radarr/route.dart +++ b/lib/modules/settings/routes/configuration_radarr/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => SettingsDialogs().moduleInformation(context, LunaModule.RADARR), ), diff --git a/lib/modules/settings/routes/configuration_sabnzbd/route.dart b/lib/modules/settings/routes/configuration_sabnzbd/route.dart index 0f77d247..007272d6 100644 --- a/lib/modules/settings/routes/configuration_sabnzbd/route.dart +++ b/lib/modules/settings/routes/configuration_sabnzbd/route.dart @@ -39,7 +39,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async { SettingsDialogs().moduleInformation(context, LunaModule.SABNZBD); }, diff --git a/lib/modules/settings/routes/configuration_search/pages/add_indexer_headers.dart b/lib/modules/settings/routes/configuration_search/pages/add_indexer_headers.dart index 3c5a4fed..d04f22c7 100644 --- a/lib/modules/settings/routes/configuration_search/pages/add_indexer_headers.dart +++ b/lib/modules/settings/routes/configuration_search/pages/add_indexer_headers.dart @@ -107,7 +107,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: LunaText.title(text: key.toString()), subtitle: LunaText.subtitle(text: value.toString()), trailing: LunaIconButton( - icon: Icons.delete, + icon: Icons.delete_rounded, color: LunaColours.red, onPressed: () async { await HeaderUtility().deleteHeader(context, diff --git a/lib/modules/settings/routes/configuration_search/pages/edit_indexer_headers.dart b/lib/modules/settings/routes/configuration_search/pages/edit_indexer_headers.dart index 43baeedf..57f067d1 100644 --- a/lib/modules/settings/routes/configuration_search/pages/edit_indexer_headers.dart +++ b/lib/modules/settings/routes/configuration_search/pages/edit_indexer_headers.dart @@ -123,7 +123,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: LunaText.title(text: key.toString()), subtitle: LunaText.subtitle(text: value.toString()), trailing: LunaIconButton( - icon: Icons.delete, + icon: Icons.delete_rounded, color: LunaColours.red, onPressed: () async => HeaderUtility().deleteHeader(context, headers: _indexer.headers, key: key, indexer: _indexer), diff --git a/lib/modules/settings/routes/configuration_search/route.dart b/lib/modules/settings/routes/configuration_search/route.dart index 6641db21..c6bb2639 100644 --- a/lib/modules/settings/routes/configuration_search/route.dart +++ b/lib/modules/settings/routes/configuration_search/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => SettingsDialogs().moduleInformation(context, LunaModule.SEARCH), ), diff --git a/lib/modules/settings/routes/configuration_sonarr/route.dart b/lib/modules/settings/routes/configuration_sonarr/route.dart index 6f3de8e4..e4254adb 100644 --- a/lib/modules/settings/routes/configuration_sonarr/route.dart +++ b/lib/modules/settings/routes/configuration_sonarr/route.dart @@ -37,7 +37,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => SettingsDialogs().moduleInformation(context, LunaModule.SONARR), ), diff --git a/lib/modules/settings/routes/configuration_tautulli/route.dart b/lib/modules/settings/routes/configuration_tautulli/route.dart index ee30864b..6502808f 100644 --- a/lib/modules/settings/routes/configuration_tautulli/route.dart +++ b/lib/modules/settings/routes/configuration_tautulli/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => SettingsDialogs().moduleInformation(context, LunaModule.TAUTULLI), ), @@ -112,7 +112,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { subtitle: LunaText.subtitle( text: terminationMessage.isEmpty ? 'Not Set' : terminationMessage), - trailing: LunaIconButton(icon: Icons.videocam_off), + trailing: LunaIconButton(icon: Icons.videocam_off_rounded), onTap: () async { Tuple2 result = await TautulliDialogs.setTerminationMessage(context); @@ -137,7 +137,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Activity Refresh Rate'), subtitle: LunaText.subtitle(text: refreshRate), - trailing: LunaIconButton(icon: Icons.refresh), + trailing: LunaIconButton(icon: Icons.refresh_rounded), onTap: () async { List _values = await TautulliDialogs.setRefreshRate(context); if (_values[0]) TautulliDatabaseValue.REFRESH_RATE.put(_values[1]); diff --git a/lib/modules/settings/routes/configuration_wakeonlan/route.dart b/lib/modules/settings/routes/configuration_wakeonlan/route.dart index fe57b02a..6bf81383 100644 --- a/lib/modules/settings/routes/configuration_wakeonlan/route.dart +++ b/lib/modules/settings/routes/configuration_wakeonlan/route.dart @@ -38,7 +38,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { title: 'Wake on LAN', actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async { SettingsDialogs().moduleInformation( context, diff --git a/lib/modules/settings/routes/profiles.dart b/lib/modules/settings/routes/profiles.dart index c223b2ff..d55c9aa7 100644 --- a/lib/modules/settings/routes/profiles.dart +++ b/lib/modules/settings/routes/profiles.dart @@ -36,7 +36,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { scrollControllers: [scrollController], actions: [ LunaIconButton( - icon: Icons.help_outline, + icon: Icons.help_outline_rounded, onPressed: () async => LunaDialogs().textPreview( context, 'Profiles', @@ -60,21 +60,21 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Add'), subtitle: LunaText.subtitle(text: 'Add a New Profile'), - trailing: LunaIconButton(icon: Icons.add), + trailing: LunaIconButton(icon: Icons.add_rounded), onTap: () async => LunaProfile().addProfile(), ), LunaListTile( context: context, title: LunaText.title(text: 'Rename'), subtitle: LunaText.subtitle(text: 'Rename an Existing Profile'), - trailing: LunaIconButton(icon: Icons.text_format), + trailing: LunaIconButton(icon: Icons.text_format_rounded), onTap: () async => LunaProfile().renameProfile(), ), LunaListTile( context: context, title: LunaText.title(text: 'Delete'), subtitle: LunaText.subtitle(text: 'Delete an Existing Profile'), - trailing: LunaIconButton(icon: Icons.delete), + trailing: LunaIconButton(icon: Icons.delete_rounded), onTap: () async => LunaProfile().deleteProfile(), ), ], @@ -89,7 +89,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { builder: (context, _, __) => LunaText.subtitle(text: LunaDatabaseValue.ENABLED_PROFILE.data), ), - trailing: LunaIconButton(icon: Icons.switch_account), + trailing: LunaIconButton(icon: Icons.switch_account_rounded), onTap: () async { Tuple2 results = await SettingsDialogs().enabledProfile( LunaState.navigatorKey.currentContext, diff --git a/lib/modules/settings/routes/resources/route.dart b/lib/modules/settings/routes/resources/route.dart index 3f6e0261..45222299 100644 --- a/lib/modules/settings/routes/resources/route.dart +++ b/lib/modules/settings/routes/resources/route.dart @@ -60,7 +60,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Feedback Board'), subtitle: LunaText.subtitle(text: 'Request New Features'), - trailing: LunaIconButton(icon: Icons.speaker_notes), + trailing: LunaIconButton(icon: Icons.speaker_notes_rounded), onTap: LunaLinks.FEEDBACK_BOARD.launch, ), LunaListTile( @@ -82,7 +82,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'TestFlight'), subtitle: LunaText.subtitle(text: 'Join the TestFlight Beta'), - trailing: LunaIconButton(icon: Icons.developer_board), + trailing: LunaIconButton(icon: Icons.developer_board_rounded), onTap: LunaLinks.TESTFLIGHT.launch), LunaListTile( context: context, @@ -95,7 +95,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Weblate'), subtitle: LunaText.subtitle(text: 'Help Localize LunaSea'), - trailing: LunaIconButton(icon: Icons.translate), + trailing: LunaIconButton(icon: Icons.translate_rounded), onTap: LunaLinks.WEBLATE.launch, ), LunaListTile( diff --git a/lib/modules/settings/routes/settings/route.dart b/lib/modules/settings/routes/settings/route.dart index 12c77774..15f364a9 100644 --- a/lib/modules/settings/routes/settings/route.dart +++ b/lib/modules/settings/routes/settings/route.dart @@ -87,7 +87,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { subtitle: LunaText.subtitle( text: 'settings.ProfilesDescription'.tr(), ), - trailing: LunaIconButton(icon: Icons.switch_account), + trailing: LunaIconButton(icon: Icons.switch_account_rounded), onTap: () async => SettingsProfilesRouter().navigateTo(context), ), const LunaDivider(), diff --git a/lib/modules/settings/routes/system/route.dart b/lib/modules/settings/routes/system/route.dart index 0a18a98e..6c84e52b 100644 --- a/lib/modules/settings/routes/system/route.dart +++ b/lib/modules/settings/routes/system/route.dart @@ -72,7 +72,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Version: $version'), subtitle: LunaText.subtitle(text: 'View Recent Changes'), - trailing: LunaIconButton(icon: Icons.system_update), + trailing: LunaIconButton(icon: Icons.system_update_rounded), onTap: () async => LunaChangelog().showChangelog( snapshot.data?.version, snapshot.data?.buildNumber), ); @@ -84,7 +84,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Logs'), subtitle: LunaText.subtitle(text: 'View, Export, and Clear Logs'), - trailing: LunaIconButton(icon: Icons.developer_mode), + trailing: LunaIconButton(icon: Icons.developer_mode_rounded), onTap: () async => SettingsSystemLogsRouter().navigateTo(context), ); } @@ -156,7 +156,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'Clear Configuration'), subtitle: LunaText.subtitle(text: 'Clean Slate'), - trailing: LunaIconButton(icon: Icons.delete_sweep), + trailing: LunaIconButton(icon: Icons.delete_sweep_rounded), onTap: () async { bool result = await SettingsDialogs().clearConfiguration(context); if (result) { diff --git a/lib/modules/settings/routes/system_logs/route.dart b/lib/modules/settings/routes/system_logs/route.dart index 52fa6d05..1dce4b02 100644 --- a/lib/modules/settings/routes/system_logs/route.dart +++ b/lib/modules/settings/routes/system_logs/route.dart @@ -55,7 +55,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { context: context, title: LunaText.title(text: 'All Logs'), subtitle: LunaText.subtitle(text: 'View Logs of All Types'), - trailing: LunaIconButton(icon: Icons.developer_mode), + trailing: LunaIconButton(icon: Icons.developer_mode_rounded), onTap: () async => _viewLogs('all'), ), ...List.generate( @@ -82,7 +82,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { Widget _clearLogs() { return LunaButton.text( text: 'Clear', - icon: Icons.delete, + icon: Icons.delete_rounded, color: LunaColours.red, onTap: () async { bool result = await SettingsDialogs().clearLogs(context); @@ -101,7 +101,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { return Builder( builder: (context) => LunaButton.text( text: 'Export', - icon: Icons.file_download, + icon: Icons.file_download_rounded, onTap: () async { showLunaInfoSnackBar( title: 'Exporting Logs', diff --git a/lib/modules/settings/routes/system_logs/widgets/log_tile.dart b/lib/modules/settings/routes/system_logs/widgets/log_tile.dart index 0698eac3..2c5a0008 100644 --- a/lib/modules/settings/routes/system_logs/widgets/log_tile.dart +++ b/lib/modules/settings/routes/system_logs/widgets/log_tile.dart @@ -15,14 +15,16 @@ class SettingsSystemLogTile extends StatelessWidget { .lunaDateTimeReadable(); return LunaExpandableListTile( title: log.message, - collapsedSubtitle1: TextSpan(text: dateTime), - collapsedSubtitle2: TextSpan( - text: log.type.name.toUpperCase(), - style: TextStyle( - color: log.type.color, - fontWeight: LunaUI.FONT_WEIGHT_BOLD, + collapsedSubtitles: [ + TextSpan(text: dateTime), + TextSpan( + text: log.type.name.toUpperCase(), + style: TextStyle( + color: log.type.color, + fontWeight: LunaUI.FONT_WEIGHT_BOLD, + ), ), - ), + ], expandedHighlightedNodes: [ LunaHighlightedNode( text: log.type.name.toUpperCase(), diff --git a/lib/modules/sonarr/core/api_controller.dart b/lib/modules/sonarr/core/api_controller.dart index 205cf02d..5a414316 100644 --- a/lib/modules/sonarr/core/api_controller.dart +++ b/lib/modules/sonarr/core/api_controller.dart @@ -574,10 +574,11 @@ class SonarrAPIController { error, stack, ); - showLunaErrorSnackBar( - title: 'sonarr.FailedToRemoveSeries'.tr(), - error: error, - ); + if (showSnackbar) + showLunaErrorSnackBar( + title: 'sonarr.FailedToRemoveSeries'.tr(), + error: error, + ); return false; }); } @@ -640,4 +641,39 @@ class SonarrAPIController { } return null; } + + Future removeFromQueue({ + @required BuildContext context, + @required SonarrQueueRecord queueRecord, + bool showSnackbar = true, + }) async { + if (context.read().enabled) { + return context + .read() + .api + .queue + .delete(id: queueRecord.id) + .then((_) { + if (showSnackbar) + showLunaSuccessSnackBar( + title: 'sonarr.RemovedFromQueue'.tr(), + message: queueRecord.title, + ); + return true; + }).catchError((error, stack) { + LunaLogger().error( + 'Failed to remove queue record: ${queueRecord.id}', + error, + stack, + ); + if (showSnackbar) + showLunaErrorSnackBar( + title: 'sonarr.FailedToRemoveFromQueue'.tr(), + error: error, + ); + return false; + }); + } + return false; + } } diff --git a/lib/modules/sonarr/core/database.dart b/lib/modules/sonarr/core/database.dart index bcf40e0a..fd51df87 100644 --- a/lib/modules/sonarr/core/database.dart +++ b/lib/modules/sonarr/core/database.dart @@ -64,6 +64,8 @@ class SonarrDatabase extends LunaModuleDatabase { case SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_MISSING: case SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_CUTOFF_UNMET: case SonarrDatabaseValue.ADD_SERIES_DEFAULT_MONITOR_TYPE: + case SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST: + case SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT: data[value.key] = value.data; break; } @@ -111,6 +113,8 @@ class SonarrDatabase extends LunaModuleDatabase { case SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_MISSING: case SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_CUTOFF_UNMET: case SonarrDatabaseValue.ADD_SERIES_DEFAULT_MONITOR_TYPE: + case SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST: + case SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT: value.put(config[key]); break; } @@ -168,6 +172,10 @@ class SonarrDatabase extends LunaModuleDatabase { return SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_MISSING; case 'SONARR_ADD_SERIES_SEARCH_FOR_CUTOFF_UNMET': return SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_CUTOFF_UNMET; + case 'SONARR_QUEUE_REMOVE_DOWNLOAD_CLIENT': + return SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT; + case 'SONARR_QUEUE_ADD_BLOCKLIST': + return SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST; default: return null; } @@ -198,6 +206,8 @@ enum SonarrDatabaseValue { REMOVE_SERIES_EXCLUSION_LIST, UPCOMING_FUTURE_DAYS, QUEUE_REFRESH_RATE, + QUEUE_REMOVE_DOWNLOAD_CLIENT, + QUEUE_ADD_BLOCKLIST, CONTENT_PAGE_SIZE, } @@ -252,6 +262,10 @@ extension SonarrDatabaseValueExtension on SonarrDatabaseValue { return 'SONARR_ADD_SERIES_SEARCH_FOR_MISSING'; case SonarrDatabaseValue.DEFAULT_FILTERING_RELEASES: return 'SONARR_DEFAULT_FILTERING_RELEASES'; + case SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT: + return 'SONARR_QUEUE_REMOVE_DOWNLOAD_CLIENT'; + case SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST: + return 'SONARR_QUEUE_ADD_BLOCKLIST'; } throw Exception('key not found'); } @@ -268,7 +282,7 @@ extension SonarrDatabaseValueExtension on SonarrDatabaseValue { case SonarrDatabaseValue.UPCOMING_FUTURE_DAYS: return _box.get(this.key, defaultValue: 7); case SonarrDatabaseValue.QUEUE_REFRESH_RATE: - return _box.get(this.key, defaultValue: 60); + return _box.get(this.key, defaultValue: 15); case SonarrDatabaseValue.CONTENT_PAGE_SIZE: return _box.get(this.key, defaultValue: 25); case SonarrDatabaseValue.ADD_SERIES_DEFAULT_MONITORED: @@ -313,6 +327,10 @@ extension SonarrDatabaseValueExtension on SonarrDatabaseValue { return _box.get(this.key, defaultValue: false); case SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_MISSING: return _box.get(this.key, defaultValue: false); + case SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT: + return _box.get(this.key, defaultValue: false); + case SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST: + return _box.get(this.key, defaultValue: false); } throw Exception('data not found'); } @@ -392,6 +410,12 @@ extension SonarrDatabaseValueExtension on SonarrDatabaseValue { case SonarrDatabaseValue.ADD_SERIES_SEARCH_FOR_MISSING: if (value is bool) box.put(this.key, value); return; + case SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT: + if (value is bool) box.put(this.key, value); + return; + case SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST: + if (value is bool) box.put(this.key, value); + return; } LunaLogger().warning( 'SonarrDatabaseValueExtension', diff --git a/lib/modules/sonarr/core/dialogs.dart b/lib/modules/sonarr/core/dialogs.dart index 9f62a442..06cda579 100644 --- a/lib/modules/sonarr/core/dialogs.dart +++ b/lib/modules/sonarr/core/dialogs.dart @@ -350,7 +350,7 @@ class SonarrDialogs { titles.length, (index) => LunaDialog.tile( text: titles[index], - icon: Icons.sort, + icon: Icons.sort_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, index), ), @@ -435,7 +435,7 @@ class SonarrDialogs { profiles.length, (index) => LunaDialog.tile( text: profiles[index].name, - icon: Icons.portrait, + icon: Icons.portrait_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, profiles[index]), ), @@ -463,7 +463,7 @@ class SonarrDialogs { profiles.length, (index) => LunaDialog.tile( text: profiles[index].name, - icon: Icons.portrait, + icon: Icons.portrait_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, profiles[index]), ), @@ -497,7 +497,7 @@ class SonarrDialogs { text: folders[index].freeSpace.lunaBytesToString()) ], ), - icon: Icons.folder, + icon: Icons.folder_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, folders[index]), ), @@ -525,7 +525,7 @@ class SonarrDialogs { SonarrSeriesMonitorType.values.length, (index) => LunaDialog.tile( text: SonarrSeriesMonitorType.values[index].lunaName, - icon: Icons.view_list, + icon: Icons.view_list_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, SonarrSeriesMonitorType.values[index]), ), @@ -554,7 +554,7 @@ class SonarrDialogs { (index) => LunaDialog.tile( text: SonarrSeriesType.values[index].value.lunaCapitalizeFirstLetters(), - icon: Icons.folder_open, + icon: Icons.folder_open_rounded, iconColor: LunaColours().byListIndex(index), onTap: () => _setValues(true, SonarrSeriesType.values[index]), ), @@ -696,4 +696,129 @@ class SonarrDialogs { ); return _flag; } + + Future removeFromQueue(BuildContext context) async { + bool _flag = false; + + void _setValues(bool flag) { + _flag = flag; + Navigator.of(context, rootNavigator: true).pop(); + } + + await LunaDialog.dialog( + context: context, + title: 'sonarr.RemoveFromQueue'.tr(), + buttons: [ + LunaDialog.button( + text: 'lunasea.Remove'.tr(), + textColor: LunaColours.red, + onPressed: () => _setValues(true), + ), + ], + content: [ + SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT.listen( + builder: (context, value, _) => LunaDialog.checkbox( + title: 'sonarr.RemoveFromDownloadClient'.tr(), + value: SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT.data, + onChanged: (value) => + SonarrDatabaseValue.QUEUE_REMOVE_DOWNLOAD_CLIENT.put(value), + ), + ), + SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST.listen( + builder: (context, value, _) => LunaDialog.checkbox( + title: 'sonarr.AddReleaseToBlocklist'.tr(), + value: SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST.data, + onChanged: (value) => + SonarrDatabaseValue.QUEUE_ADD_BLOCKLIST.put(value), + ), + ), + ], + contentPadding: LunaDialog.listDialogContentPadding(), + ); + return _flag; + } + + Future showQueueStatusMessages( + BuildContext context, + List messages, + ) async { + if (messages.isEmpty) { + return LunaDialogs().textPreview( + context, + 'sonarr.Messages'.tr(), + 'sonarr.NoMessagesFound'.tr(), + ); + } + await LunaDialog.dialog( + context: context, + title: 'sonarr.Messages'.tr(), + cancelButtonText: 'lunasea.Close'.tr(), + contentPadding: LunaDialog.listDialogContentPadding(), + content: List.generate( + messages.length, + (index) => Padding( + padding: LunaDialog.tileContentPadding(), + child: Column( + children: [ + Row( + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + const Padding( + padding: EdgeInsets.only(right: 32.0), + child: Icon( + Icons.warning_amber_rounded, + color: LunaColours.orange, + size: 24.0, + ), + ), + Expanded( + child: Text( + messages[index].title, + style: const TextStyle( + fontSize: LunaDialog.BODY_SIZE, + color: LunaColours.orange, + fontWeight: LunaUI.FONT_WEIGHT_BOLD, + ), + ), + ), + ], + ), + Padding( + padding: const EdgeInsets.symmetric( + vertical: LunaUI.DEFAULT_MARGIN_SIZE / 3, + ), + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (messages[index].messages.isNotEmpty) + Row( + children: [ + Expanded( + child: Padding( + padding: const EdgeInsets.only( + left: 56.0, // 32.0 + iconSize + ), + child: LunaDialog.richText( + children: [ + TextSpan( + text: messages[index] + .messages + .map((s) => '${LunaUI.TEXT_BULLET} $s') + .join('\n'), + ), + ], + ), + ), + ), + ], + ), + ], + ), + ), + ], + ), + ), + ), + ); + } } diff --git a/lib/modules/sonarr/core/extensions.dart b/lib/modules/sonarr/core/extensions.dart index 4718c2d0..7df84eac 100644 --- a/lib/modules/sonarr/core/extensions.dart +++ b/lib/modules/sonarr/core/extensions.dart @@ -3,7 +3,9 @@ export 'extensions/sonarr_episode_file_media_info.dart'; export 'extensions/sonarr_episode.dart'; export 'extensions/sonarr_event_type.dart'; export 'extensions/sonarr_history.dart'; +export 'extensions/sonarr_protocol.dart'; export 'extensions/sonarr_queue_record.dart'; +export 'extensions/sonarr_queue_status.dart'; export 'extensions/sonarr_series_monitor_type.dart'; export 'extensions/sonarr_release.dart'; export 'extensions/sonarr_series.dart'; diff --git a/lib/modules/sonarr/core/extensions/sonarr_episode.dart b/lib/modules/sonarr/core/extensions/sonarr_episode.dart index 9acc33aa..6fa9531b 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_episode.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_episode.dart @@ -15,7 +15,18 @@ extension SonarrEpisodeExtension on SonarrEpisode { return DateFormat.yMMMMd().format(this.airDateUtc.toLocal()); } - String lunaDownloadedQuality(SonarrEpisodeFile file) { + String lunaDownloadedQuality( + SonarrEpisodeFile file, + SonarrQueueRecord queueRecord, + ) { + if (queueRecord != null) { + return [ + queueRecord.lunaPercentage(), + LunaUI.TEXT_EMDASH, + queueRecord.lunaStatusParameters().item1, + ].join(' '); + } + if (!this.hasFile) { if (_hasAired()) return 'sonarr.Unaired'.tr(); return 'sonarr.Missing'.tr(); @@ -26,7 +37,14 @@ extension SonarrEpisodeExtension on SonarrEpisode { return '$quality ${LunaUI.TEXT_EMDASH} $size'; } - Color lunaDownloadedQualityColor(SonarrEpisodeFile file) { + Color lunaDownloadedQualityColor( + SonarrEpisodeFile file, + SonarrQueueRecord queueRecord, + ) { + if (queueRecord != null) { + return queueRecord.lunaStatusParameters(canBeWhite: false).item3; + } + if (!this.hasFile) { if (_hasAired()) return LunaColours.blue; return LunaColours.red; diff --git a/lib/modules/sonarr/core/extensions/sonarr_event_type.dart b/lib/modules/sonarr/core/extensions/sonarr_event_type.dart index fe426bb4..4a156f90 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_event_type.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_event_type.dart @@ -27,21 +27,21 @@ extension SonarrEventTypeLunaExtension on SonarrEventType { IconData lunaIcon() { switch (this) { case SonarrEventType.EPISODE_FILE_RENAMED: - return Icons.drive_file_rename_outline; + return Icons.drive_file_rename_outline_rounded; case SonarrEventType.EPISODE_FILE_DELETED: - return Icons.delete; + return Icons.delete_rounded; case SonarrEventType.DOWNLOAD_FOLDER_IMPORTED: return Icons.download_rounded; case SonarrEventType.DOWNLOAD_FAILED: - return Icons.cloud_download; + return Icons.cloud_download_rounded; case SonarrEventType.DOWNLOAD_IGNORED: - return Icons.cancel; + return Icons.cancel_rounded; case SonarrEventType.GRABBED: - return Icons.cloud_download; + return Icons.cloud_download_rounded; case SonarrEventType.SERIES_FOLDER_IMPORTED: return Icons.download_rounded; default: - return Icons.help; + return Icons.help_rounded; } } diff --git a/lib/modules/sonarr/core/extensions/sonarr_history.dart b/lib/modules/sonarr/core/extensions/sonarr_history.dart index 47e478bb..df9e1c92 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_history.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_history.dart @@ -26,8 +26,13 @@ extension SonarrHistoryRecordLunaExtension on SonarrHistoryRecord { } String lunaPreferredWordScore() { - if (lunaHasPreferredWordScore()) - return '+${this.data['preferredWordScore']}'; + if (lunaHasPreferredWordScore()) { + int _preferredScore = int.tryParse(this.data['preferredWordScore']); + if (_preferredScore != null) { + String _prefix = _preferredScore > 0 ? '+' : ''; + return '$_prefix${this.data['preferredWordScore']}'; + } + } return LunaUI.TEXT_EMDASH; } } diff --git a/lib/modules/sonarr/core/extensions/sonarr_protocol.dart b/lib/modules/sonarr/core/extensions/sonarr_protocol.dart new file mode 100644 index 00000000..1864200a --- /dev/null +++ b/lib/modules/sonarr/core/extensions/sonarr_protocol.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +extension LunaSonarrProtocolExtension on SonarrProtocol { + Color lunaProtocolColor({ + SonarrRelease release, + }) { + if (this == SonarrProtocol.USENET) return LunaColours.accent; + if (release == null) return LunaColours.blue; + + int seeders = release.seeders ?? 0; + if (seeders > 10) return LunaColours.blue; + if (seeders > 0) return LunaColours.orange; + return LunaColours.red; + } + + String lunaReadable() { + switch (this) { + case SonarrProtocol.USENET: + return 'sonarr.Usenet'.tr(); + case SonarrProtocol.TORRENT: + return 'sonarr.Torrent'.tr(); + } + throw Exception('Invalid SonarrProtocol'); + } +} diff --git a/lib/modules/sonarr/core/extensions/sonarr_queue_record.dart b/lib/modules/sonarr/core/extensions/sonarr_queue_record.dart index 726ba7a0..2a958a22 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_queue_record.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_queue_record.dart @@ -3,52 +3,108 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; extension SonarrQueueRecordExtension on SonarrQueueRecord { - String get lunaStatusText { - switch (this?.status?.toLowerCase() ?? '') { - case 'delay': - return 'Pending'; - case 'downloading': - return 'Downloading'; - case 'completed': - return 'Completed'; - case 'failed': - return 'Failed'; - case 'paused': - return 'Paused'; - } - return this?.status ?? 'Unknown'; - } + Tuple3 lunaStatusParameters({ + bool canBeWhite = true, + }) { + SonarrQueueStatus _status = this.status; + SonarrTrackedDownloadStatus _tStatus = this.trackedDownloadStatus; + SonarrTrackedDownloadState _tState = this.trackedDownloadState; - IconData get lunaStatusIcon { - switch (this?.status?.toLowerCase() ?? '') { - case 'delay': - return Icons.schedule; - case 'paused': - return Icons.pause; - case 'completed': - return Icons.file_download; - case 'downloading': - case 'failed': - return Icons.cloud_download; - } - return Icons.help; - } + String _title = 'sonarr.Downloading'.tr(); + IconData _icon = Icons.cloud_download_rounded; + Color _color = canBeWhite ? Colors.white : LunaColours.blueGrey; - Color get lunaStatusColor { - if (this?.status?.toLowerCase() == 'completed') - switch (this?.trackedDownloadStatus?.toLowerCase()) { - case 'warning': - return LunaColours.orange; - case 'ok': - return LunaColours.purple; + // Paused + if (_status == SonarrQueueStatus.PAUSED) { + _icon = Icons.pause_rounded; + _title = 'sonarr.Paused'.tr(); + } + + // Queued + if (_status == SonarrQueueStatus.QUEUED) { + _icon = Icons.cloud_rounded; + _title = 'sonarr.Queued'.tr(); + } + + // Complete + if (_status == SonarrQueueStatus.COMPLETED) { + _title = 'sonarr.Downloaded'.tr(); + _icon = Icons.file_download_rounded; + + if (_tState == SonarrTrackedDownloadState.IMPORT_PENDING) { + _title = 'sonarr.DownloadedWaitingToImport'.tr(); + _color = LunaColours.purple; } - if (this?.status?.toLowerCase() == 'failed') return LunaColours.red; - return Colors.white; + if (_tState == SonarrTrackedDownloadState.IMPORTING) { + _title = 'sonarr.DownloadedImporting'.tr(); + _color = LunaColours.purple; + } + if (_tState == SonarrTrackedDownloadState.FAILED_PENDING) { + _title = 'sonarr.DownloadedWaitingToProcess'.tr(); + _color = LunaColours.red; + } + } + + if (_tStatus == SonarrTrackedDownloadStatus.WARNING) { + _color = LunaColours.orange; + } + + // Delay + if (_status == SonarrQueueStatus.DELAY) { + _title = 'sonarr.Pending'.tr(); + _icon = Icons.schedule_rounded; + } + + // Download Client Unavailable + if (_status == SonarrQueueStatus.DOWNLOAD_CLIENT_UNAVAILABLE) { + _title = 'sonarr.PendingWithMessage'.tr( + args: ['sonarr.DownloadClientUnavailable'.tr()], + ); + _icon = Icons.schedule_rounded; + _color = LunaColours.orange; + } + + // Failed + if (_status == SonarrQueueStatus.FAILED) { + _title = 'sonarr.DownloadFailed'.tr(); + _icon = Icons.cloud_download_rounded; + _color = LunaColours.red; + } + + // Warning + if (_status == SonarrQueueStatus.WARNING) { + _title = 'sonarr.DownloadWarningWithMessage'.tr(args: [ + 'sonarr.CheckDownloadClient'.tr(), + ]); + _icon = Icons.cloud_download_rounded; + _color = LunaColours.orange; + } + + // Error + if (_tStatus == SonarrTrackedDownloadStatus.ERROR) { + if (_status == SonarrQueueStatus.COMPLETED) { + _title = 'sonarr.ImportFailed'.tr(); + _icon = Icons.file_download_rounded; + _color = LunaColours.red; + } else { + _title = 'sonarr.DownloadFailed'.tr(); + _icon = Icons.cloud_download_rounded; + _color = LunaColours.red; + } + } + + return Tuple3(_title, _icon, _color); } - int get lunaPercentageComplete { - if (this.sizeLeft == null || this.size == null || this.size == 0) return 0; - double sizeFetched = this.size - this.sizeLeft; - return ((sizeFetched / this.size) * 100).round(); + String lunaPercentage() { + if (this.sizeleft == null || this.size == null || this.size == 0) + return '0%'; + double sizeFetched = this.size - this.sizeleft; + int percentage = ((sizeFetched / this.size) * 100).round(); + return '$percentage%'; + } + + String lunaTimeLeft() { + return this.timeleft ?? LunaUI.TEXT_EMDASH; } } diff --git a/lib/modules/sonarr/core/extensions/sonarr_queue_status.dart b/lib/modules/sonarr/core/extensions/sonarr_queue_status.dart new file mode 100644 index 00000000..b96c4038 --- /dev/null +++ b/lib/modules/sonarr/core/extensions/sonarr_queue_status.dart @@ -0,0 +1,26 @@ +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +extension LunaSonarrQueueStatusExtension on SonarrQueueStatus { + String lunaStatus() { + switch (this) { + case SonarrQueueStatus.DOWNLOADING: + return 'sonarr.Downloading'.tr(); + case SonarrQueueStatus.PAUSED: + return 'sonarr.Paused'.tr(); + case SonarrQueueStatus.QUEUED: + return 'sonarr.Queued'.tr(); + case SonarrQueueStatus.COMPLETED: + return 'sonarr.Downloaded'.tr(); + case SonarrQueueStatus.DELAY: + return 'sonarr.Pending'.tr(); + case SonarrQueueStatus.DOWNLOAD_CLIENT_UNAVAILABLE: + return 'sonarr.DownloadClientUnavailable'.tr(); + case SonarrQueueStatus.FAILED: + return 'sonarr.DownloadFailed'.tr(); + case SonarrQueueStatus.WARNING: + return 'sonarr.DownloadWarning'.tr(); + } + throw Exception('Invalid SonarrQueueStatus'); + } +} diff --git a/lib/modules/sonarr/core/extensions/sonarr_release.dart b/lib/modules/sonarr/core/extensions/sonarr_release.dart index 549d8ca3..1b45f169 100644 --- a/lib/modules/sonarr/core/extensions/sonarr_release.dart +++ b/lib/modules/sonarr/core/extensions/sonarr_release.dart @@ -16,19 +16,11 @@ extension SonarrReleaseExtension on SonarrRelease { String get lunaProtocol { if (this.protocol != null) return this.protocol == SonarrProtocol.TORRENT - ? '${this.protocol.readable} (${this?.seeders ?? 0}/${this?.leechers ?? 0})' - : this.protocol.readable; + ? '${this.protocol.lunaReadable()} (${this?.seeders ?? 0}/${this?.leechers ?? 0})' + : this.protocol.lunaReadable(); return LunaUI.TEXT_EMDASH; } - Color get lunaProtocolColor { - if (this.protocol == SonarrProtocol.USENET) return LunaColours.accent; - int seeders = this.seeders ?? 0; - if (seeders > 10) return LunaColours.blue; - if (seeders > 0) return LunaColours.orange; - return LunaColours.red; - } - String get lunaIndexer { if (this.indexer != null && this.indexer.isNotEmpty) return this.indexer; return LunaUI.TEXT_EMDASH; @@ -57,8 +49,10 @@ extension SonarrReleaseExtension on SonarrRelease { } String lunaPreferredWordScore({bool nullOnEmpty = false}) { - if ((this.preferredWordScore ?? 0) != 0) - return '+${this.preferredWordScore}'; + if ((this.preferredWordScore ?? 0) != 0) { + String _prefix = this.preferredWordScore > 0 ? '+' : ''; + return '$_prefix${this.preferredWordScore}'; + } if (nullOnEmpty) return null; return LunaUI.TEXT_EMDASH; } diff --git a/lib/modules/sonarr/core/state.dart b/lib/modules/sonarr/core/state.dart index 668b3a86..fad96802 100644 --- a/lib/modules/sonarr/core/state.dart +++ b/lib/modules/sonarr/core/state.dart @@ -14,25 +14,22 @@ class SonarrState extends LunaModuleState { @override void reset() { - // Reset stored data _series = null; _upcoming = null; _missing = null; - _rootFolders = null; _qualityProfiles = null; _languageProfiles = null; _tags = null; - // Reinitialize resetProfile(); if (_enabled) { fetchAllSeries(); fetchUpcoming(); fetchMissing(); + fetchRootFolders(); fetchQualityProfiles(); fetchLanguageProfiles(); - fetchRootFolders(); fetchTags(); } notifyListeners(); @@ -81,9 +78,9 @@ class SonarrState extends LunaModuleState { } } - ////////////// - /// SERIES /// - ////////////// + ///////////////// + /// CATALOGUE /// + ///////////////// String _seriesSearchQuery = ''; String get seriesSearchQuery => _seriesSearchQuery; @@ -120,6 +117,10 @@ class SonarrState extends LunaModuleState { notifyListeners(); } + ////////////// + /// SERIES /// + ////////////// + Future> _series; Future> get series => _series; void fetchAllSeries() { @@ -202,7 +203,7 @@ class SonarrState extends LunaModuleState { } //////////////// - /// METADATA /// + /// PROFILES /// //////////////// Future> _qualityProfiles; @@ -231,13 +232,21 @@ class SonarrState extends LunaModuleState { notifyListeners(); } + //////////////////// + /// ROOT FOLDERS /// + //////////////////// + Future> _rootFolders; Future> get rootFolders => _rootFolders; void fetchRootFolders() { - if (_api != null) _rootFolders = _api.rootFolder.getRootFolders(); + if (_api != null) _rootFolders = _api.rootFolder.get(); notifyListeners(); } + //////////// + /// TAGS /// + //////////// + Future> _tags; Future> get tags => _tags; set tags(Future> tags) { @@ -247,7 +256,7 @@ class SonarrState extends LunaModuleState { } void fetchTags() { - if (_api != null) _tags = _api.tag.getAllTags(); + if (_api != null) _tags = _api.tag.getAll(); notifyListeners(); } diff --git a/lib/modules/sonarr/core/types/settings_episode.dart b/lib/modules/sonarr/core/types/settings_episode.dart index 9d760cdc..bc50ce55 100644 --- a/lib/modules/sonarr/core/types/settings_episode.dart +++ b/lib/modules/sonarr/core/types/settings_episode.dart @@ -13,13 +13,15 @@ extension SonarrEpisodeSettingsTypeExtension on SonarrEpisodeSettingsType { IconData icon(SonarrEpisode episode) { switch (this) { case SonarrEpisodeSettingsType.MONITORED: - return episode.monitored ? Icons.turned_in_not : Icons.turned_in; + return episode.monitored + ? Icons.turned_in_not_rounded + : Icons.turned_in_rounded; case SonarrEpisodeSettingsType.AUTOMATIC_SEARCH: - return Icons.search; + return Icons.search_rounded; case SonarrEpisodeSettingsType.INTERACTIVE_SEARCH: - return Icons.youtube_searched_for; + return Icons.youtube_searched_for_rounded; case SonarrEpisodeSettingsType.DELETE_FILE: - return Icons.delete; + return Icons.delete_rounded; } throw Exception('Invalid SonarrEpisodeSettingsType'); } diff --git a/lib/modules/sonarr/core/types/settings_global.dart b/lib/modules/sonarr/core/types/settings_global.dart index 982cfc24..50c9a52d 100644 --- a/lib/modules/sonarr/core/types/settings_global.dart +++ b/lib/modules/sonarr/core/types/settings_global.dart @@ -14,15 +14,15 @@ extension SonarrGlobalSettingsTypeExtension on SonarrGlobalSettingsType { IconData get icon { switch (this) { case SonarrGlobalSettingsType.WEB_GUI: - return Icons.language; + return Icons.language_rounded; case SonarrGlobalSettingsType.UPDATE_LIBRARY: - return Icons.autorenew; + return Icons.autorenew_rounded; case SonarrGlobalSettingsType.RUN_RSS_SYNC: - return Icons.rss_feed; + return Icons.rss_feed_rounded; case SonarrGlobalSettingsType.SEARCH_ALL_MISSING: - return Icons.search; + return Icons.search_rounded; case SonarrGlobalSettingsType.BACKUP_DATABASE: - return Icons.save; + return Icons.save_rounded; } throw Exception('Invalid SonarrGlobalSettingsType'); } diff --git a/lib/modules/sonarr/core/types/settings_season.dart b/lib/modules/sonarr/core/types/settings_season.dart index 969fb0c8..61489377 100644 --- a/lib/modules/sonarr/core/types/settings_season.dart +++ b/lib/modules/sonarr/core/types/settings_season.dart @@ -11,9 +11,9 @@ extension SonarrSeasonSettingsTypeExtension on SonarrSeasonSettingsType { IconData get icon { switch (this) { case SonarrSeasonSettingsType.AUTOMATIC_SEARCH: - return Icons.search; + return Icons.search_rounded; case SonarrSeasonSettingsType.INTERACTIVE_SEARCH: - return Icons.youtube_searched_for; + return Icons.youtube_searched_for_rounded; } throw Exception('Invalid SonarrSeasonSettingsType'); } diff --git a/lib/modules/sonarr/core/types/settings_series.dart b/lib/modules/sonarr/core/types/settings_series.dart index a6d3a0e2..a8f7e1ab 100644 --- a/lib/modules/sonarr/core/types/settings_series.dart +++ b/lib/modules/sonarr/core/types/settings_series.dart @@ -13,13 +13,15 @@ extension SonarrSeriesSettingsTypeExtension on SonarrSeriesSettingsType { IconData icon(SonarrSeries series) { switch (this) { case SonarrSeriesSettingsType.MONITORED: - return series.monitored ? Icons.turned_in_not : Icons.turned_in; + return series.monitored + ? Icons.turned_in_not_rounded + : Icons.turned_in_rounded; case SonarrSeriesSettingsType.EDIT: - return Icons.edit; + return Icons.edit_rounded; case SonarrSeriesSettingsType.REFRESH: - return Icons.refresh; + return Icons.refresh_rounded; case SonarrSeriesSettingsType.DELETE: - return Icons.delete; + return Icons.delete_rounded; } throw Exception('Invalid SonarrSeriesSettingsType'); } diff --git a/lib/modules/sonarr/core/types/sorting_releases.dart b/lib/modules/sonarr/core/types/sorting_releases.dart index 3b2dd048..71879624 100644 --- a/lib/modules/sonarr/core/types/sorting_releases.dart +++ b/lib/modules/sonarr/core/types/sorting_releases.dart @@ -17,6 +17,8 @@ enum SonarrReleasesSorting { TYPE, @HiveField(5) WEIGHT, + @HiveField(6) + WORD_SCORE, } extension SonarrReleasesSortingExtension on SonarrReleasesSorting { @@ -34,6 +36,8 @@ extension SonarrReleasesSortingExtension on SonarrReleasesSorting { return 'type'; case SonarrReleasesSorting.SIZE: return 'size'; + case SonarrReleasesSorting.WORD_SCORE: + return 'word_score'; default: return null; } @@ -53,6 +57,8 @@ extension SonarrReleasesSortingExtension on SonarrReleasesSorting { return 'Type'; case SonarrReleasesSorting.SIZE: return 'Size'; + case SonarrReleasesSorting.WORD_SCORE: + return 'sonarr.WordScore'.tr(); default: return null; } @@ -72,6 +78,8 @@ extension SonarrReleasesSortingExtension on SonarrReleasesSorting { return SonarrReleasesSorting.TYPE; case 'weight': return SonarrReleasesSorting.WEIGHT; + case 'word_score': + return SonarrReleasesSorting.WORD_SCORE; default: return null; } @@ -100,6 +108,8 @@ class _Sorter { return _type(releases, ascending); case SonarrReleasesSorting.SIZE: return _size(releases, ascending); + case SonarrReleasesSorting.WORD_SCORE: + return _wordScore(releases, ascending); } throw Exception('sorting type not found'); } @@ -169,4 +179,13 @@ class _Sorter { : releases.sort((a, b) => (b.size ?? -1).compareTo((a.size ?? -1))); return releases; } + + List _wordScore(List releases, bool ascending) { + ascending + ? releases.sort((a, b) => + (b.preferredWordScore ?? 0).compareTo((a.preferredWordScore ?? 0))) + : releases.sort((a, b) => + (a.preferredWordScore ?? 0).compareTo((b.preferredWordScore ?? 0))); + return releases; + } } diff --git a/lib/modules/sonarr/core/types/sorting_releases.g.dart b/lib/modules/sonarr/core/types/sorting_releases.g.dart index ec9e0c8e..761fe53f 100644 --- a/lib/modules/sonarr/core/types/sorting_releases.g.dart +++ b/lib/modules/sonarr/core/types/sorting_releases.g.dart @@ -25,6 +25,8 @@ class SonarrReleasesSortingAdapter extends TypeAdapter { return SonarrReleasesSorting.TYPE; case 5: return SonarrReleasesSorting.WEIGHT; + case 6: + return SonarrReleasesSorting.WORD_SCORE; default: return SonarrReleasesSorting.AGE; } @@ -51,6 +53,9 @@ class SonarrReleasesSortingAdapter extends TypeAdapter { case SonarrReleasesSorting.WEIGHT: writer.writeByte(5); break; + case SonarrReleasesSorting.WORD_SCORE: + writer.writeByte(6); + break; } } diff --git a/lib/modules/sonarr/routes/add_series/state.dart b/lib/modules/sonarr/routes/add_series/state.dart index e7b5671d..5d32bebf 100644 --- a/lib/modules/sonarr/routes/add_series/state.dart +++ b/lib/modules/sonarr/routes/add_series/state.dart @@ -30,8 +30,7 @@ class SonarrAddSeriesState extends ChangeNotifier { Future> get exclusions => _exclusions; void fetchExclusions(BuildContext context) { if ((context.read().enabled ?? false)) { - _exclusions = - context.read().api.importList.getExclusionList(); + _exclusions = context.read().api.importList.get(); } notifyListeners(); } diff --git a/lib/modules/sonarr/routes/catalogue/widgets/search_bar_sort_button.dart b/lib/modules/sonarr/routes/catalogue/widgets/search_bar_sort_button.dart index 2c4f79d9..4f8d9398 100644 --- a/lib/modules/sonarr/routes/catalogue/widgets/search_bar_sort_button.dart +++ b/lib/modules/sonarr/routes/catalogue/widgets/search_bar_sort_button.dart @@ -22,7 +22,7 @@ class _State extends State { builder: (context, state, _) => LunaPopupMenuButton( tooltip: 'sonarr.SortCatalogue'.tr(), - icon: Icons.sort, + icon: Icons.sort_rounded, onSelected: (result) { if (state.seriesSortType == result) { state.seriesSortAscending = !state.seriesSortAscending; @@ -54,8 +54,8 @@ class _State extends State { SonarrSeriesSorting.values[index]) Icon( state.seriesSortAscending - ? Icons.arrow_upward - : Icons.arrow_downward, + ? Icons.arrow_upward_rounded + : Icons.arrow_downward_rounded, size: LunaUI.FONT_SIZE_SUBTITLE + 2.0, color: LunaColours.accent, ), diff --git a/lib/modules/sonarr/routes/history/widgets/history_tile.dart b/lib/modules/sonarr/routes/history/widgets/history_tile.dart index db5160ba..9cf7885e 100644 --- a/lib/modules/sonarr/routes/history/widgets/history_tile.dart +++ b/lib/modules/sonarr/routes/history/widgets/history_tile.dart @@ -49,9 +49,11 @@ class SonarrHistoryTile extends StatelessWidget { title: type != SonarrHistoryTileType.ALL ? history.sourceTitle : series?.title ?? LunaUI.TEXT_EMDASH, - collapsedSubtitle1: _isThreeLine ? _subtitle1() : _subtitle2(), - collapsedSubtitle2: _isThreeLine ? _subtitle2() : _subtitle3(), - collapsedSubtitle3: _isThreeLine ? _subtitle3() : null, + collapsedSubtitles: [ + if (_isThreeLine) _subtitle1(), + _subtitle2(), + _subtitle3(), + ], expandedHighlightedNodes: [ LunaHighlightedNode( text: history.eventType?.readable ?? LunaUI.TEXT_EMDASH, diff --git a/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart b/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart index 7872ffbf..638e7e95 100644 --- a/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart +++ b/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart @@ -41,7 +41,7 @@ class _State extends State { Widget _trailing() { return LunaIconButton( - icon: Icons.search, + icon: Icons.search_rounded, onPressed: _trailingOnTap, onLongPress: _trailingOnLongPress, ); diff --git a/lib/modules/sonarr/routes/more/route.dart b/lib/modules/sonarr/routes/more/route.dart index a2cdaa15..c10622a1 100644 --- a/lib/modules/sonarr/routes/more/route.dart +++ b/lib/modules/sonarr/routes/more/route.dart @@ -66,8 +66,7 @@ class _State extends State with AutomaticKeepAliveClientMixin { icon: Icons.queue_rounded, color: LunaColours().byListIndex(2), ), - onTap: () async => _showComingSoonMessage(), - // onTap: () async => SonarrQueueRouter().navigateTo(context), + onTap: () async => SonarrQueueRouter().navigateTo(context), ), LunaListTile( context: context, diff --git a/lib/modules/sonarr/routes/queue.dart b/lib/modules/sonarr/routes/queue.dart index 29f788da..d0ee7f76 100644 --- a/lib/modules/sonarr/routes/queue.dart +++ b/lib/modules/sonarr/routes/queue.dart @@ -1,2 +1,3 @@ export 'queue/route.dart'; +export 'queue/state.dart'; export 'queue/widgets.dart'; diff --git a/lib/modules/sonarr/routes/queue/route.dart b/lib/modules/sonarr/routes/queue/route.dart index 018a94f5..9ab6406e 100644 --- a/lib/modules/sonarr/routes/queue/route.dart +++ b/lib/modules/sonarr/routes/queue/route.dart @@ -20,20 +20,81 @@ class _Widget extends StatefulWidget { } class _State extends State<_Widget> with LunaScrollControllerMixin { - final GlobalKey _scaffoldKey = GlobalKey(); + final _scaffoldKey = GlobalKey(); + final _refreshKey = GlobalKey(); @override Widget build(BuildContext context) { - return LunaScaffold( - scaffoldKey: _scaffoldKey, - appBar: _appBar(), + return ChangeNotifierProvider( + create: (context) => SonarrQueueState(context), + builder: (context, _) => LunaScaffold( + scaffoldKey: _scaffoldKey, + appBar: _appBar(), + body: _body(context), + ), ); } + Future _onRefresh(BuildContext context) async { + await context.read().fetchQueue( + context, + hardCheck: true, + ); + await context.read().queue; + } + Widget _appBar() { return LunaAppBar( title: 'sonarr.Queue'.tr(), scrollControllers: [scrollController], ); } + + Widget _body(BuildContext context) { + return LunaRefreshIndicator( + key: _refreshKey, + context: context, + onRefresh: () async => _onRefresh(context), + child: FutureBuilder( + future: context.watch().queue, + builder: (context, AsyncSnapshot snapshot) { + if (snapshot.hasError) { + if (snapshot.connectionState != ConnectionState.waiting) { + LunaLogger().error( + 'Unable to fetch Sonarr queue', + snapshot.error, + snapshot.stackTrace, + ); + } + return LunaMessage.error( + onTap: _refreshKey.currentState.show, + ); + } + if (snapshot.hasData) { + return _list(snapshot.data); + } + return const LunaLoader(); + }, + ), + ); + } + + Widget _list(SonarrQueue queue) { + if (queue.records.isEmpty) { + return LunaMessage( + text: 'sonarr.EmptyQueue'.tr(), + buttonText: 'lunasea.Refresh'.tr(), + onTap: _refreshKey.currentState.show, + ); + } + return LunaListViewBuilder( + controller: scrollController, + itemCount: queue.records.length, + itemBuilder: (context, index) => SonarrQueueTile( + key: ObjectKey(queue.records[index].id), + queueRecord: queue.records[index], + type: SonarrQueueTileType.ALL, + ), + ); + } } diff --git a/lib/modules/sonarr/routes/queue/state.dart b/lib/modules/sonarr/routes/queue/state.dart new file mode 100644 index 00000000..b695300e --- /dev/null +++ b/lib/modules/sonarr/routes/queue/state.dart @@ -0,0 +1,55 @@ +import 'dart:async'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +class SonarrQueueState extends ChangeNotifier { + SonarrQueueState(BuildContext context) { + fetchQueue(context); + } + + Timer _timer; + void cancelTimer() => _timer?.cancel(); + void createTimer(BuildContext context) { + _timer = Timer.periodic( + Duration(seconds: SonarrDatabaseValue.QUEUE_REFRESH_RATE.data), + (_) => fetchQueue(context), + ); + } + + Future _queue; + Future get queue => _queue; + set queue(Future queue) { + assert(queue != null); + this.queue = queue; + notifyListeners(); + } + + Future fetchQueue( + BuildContext context, { + bool hardCheck = false, + }) async { + cancelTimer(); + if (context.read().enabled) { + if (hardCheck) { + // "Hard" check by telling Sonarr to refresh the monitored downloads + // Give it 500 ms to internally check and then continue to fetch queue + await context + .read() + .api + .command + .refreshMonitoredDownloads() + .then( + (_) => Future.delayed(const Duration(milliseconds: 500), () {}), + ); + } + _queue = context.read().api.queue.get( + includeEpisode: true, + includeSeries: true, + pageSize: 100, + ); + createTimer(context); + } + notifyListeners(); + } +} diff --git a/lib/modules/sonarr/routes/queue/widgets.dart b/lib/modules/sonarr/routes/queue/widgets.dart index e69de29b..f6ee9af5 100644 --- a/lib/modules/sonarr/routes/queue/widgets.dart +++ b/lib/modules/sonarr/routes/queue/widgets.dart @@ -0,0 +1 @@ +export 'widgets/queue_tile.dart'; diff --git a/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart b/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart new file mode 100644 index 00000000..10468f4f --- /dev/null +++ b/lib/modules/sonarr/routes/queue/widgets/queue_tile.dart @@ -0,0 +1,237 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +enum SonarrQueueTileType { + ALL, + EPISODE, +} + +class SonarrQueueTile extends StatefulWidget { + final SonarrQueueRecord queueRecord; + final SonarrQueueTileType type; + + const SonarrQueueTile({ + Key key, + @required this.queueRecord, + @required this.type, + }) : super(key: key); + + @override + State createState() => _State(); +} + +class _State extends State { + @override + Widget build(BuildContext context) { + return LunaExpandableListTile( + title: widget.queueRecord.title, + collapsedSubtitles: [ + if (widget.type == SonarrQueueTileType.ALL) _subtitle1(), + if (widget.type == SonarrQueueTileType.ALL) _subtitle2(), + _subtitle3(), + _subtitle4(), + ], + expandedTableContent: _expandedTableContent(), + expandedHighlightedNodes: _expandedHighlightedNodes(), + expandedTableButtons: _tableButtons(), + collapsedTrailing: _collapsedTrailing(), + onLongPress: _onLongPress, + ); + } + + Future _onLongPress() async { + switch (widget.type) { + case SonarrQueueTileType.ALL: + SonarrSeriesDetailsRouter().navigateTo( + context, + seriesId: widget.queueRecord.seriesId, + ); + break; + case SonarrQueueTileType.EPISODE: + SonarrQueueRouter().navigateTo(context); + break; + } + } + + Widget _collapsedTrailing() { + Tuple3 _status = + widget.queueRecord.lunaStatusParameters(); + return LunaIconButton( + icon: _status.item2, + color: _status.item3, + ); + } + + TextSpan _subtitle1() { + return TextSpan( + text: widget.queueRecord.series.title ?? LunaUI.TEXT_EMDASH, + ); + } + + TextSpan _subtitle2() { + return TextSpan( + children: [ + TextSpan( + text: widget.queueRecord.episode?.lunaSeasonEpisode() ?? + LunaUI.TEXT_EMDASH), + const TextSpan(text: ': '), + TextSpan( + text: widget.queueRecord.episode.title ?? LunaUI.TEXT_EMDASH, + style: const TextStyle(fontStyle: FontStyle.italic)), + ], + ); + } + + TextSpan _subtitle3() { + return TextSpan( + children: [ + TextSpan( + text: widget.queueRecord.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, + ), + TextSpan(text: LunaUI.TEXT_BULLET.lunaPad()), + TextSpan( + text: widget.queueRecord.language?.name ?? LunaUI.TEXT_EMDASH, + ), + TextSpan(text: LunaUI.TEXT_BULLET.lunaPad()), + TextSpan( + text: widget.queueRecord.lunaTimeLeft() ?? LunaUI.TEXT_EMDASH, + ), + ], + ); + } + + TextSpan _subtitle4() { + Tuple3 _params = + widget.queueRecord.lunaStatusParameters(canBeWhite: false); + return TextSpan( + style: TextStyle( + color: _params.item3, + fontWeight: LunaUI.FONT_WEIGHT_BOLD, + ), + children: [ + TextSpan(text: widget.queueRecord.lunaPercentage()), + TextSpan(text: LunaUI.TEXT_EMDASH.lunaPad()), + TextSpan(text: _params.item1), + ], + ); + } + + List _expandedHighlightedNodes() { + Tuple3 _status = + widget.queueRecord.lunaStatusParameters(canBeWhite: false); + return [ + LunaHighlightedNode( + text: widget.queueRecord.protocol.lunaReadable(), + backgroundColor: widget.queueRecord.protocol.lunaProtocolColor(), + ), + LunaHighlightedNode( + text: widget.queueRecord.lunaPercentage(), + backgroundColor: _status.item3, + ), + LunaHighlightedNode( + text: widget.queueRecord.status.lunaStatus(), + backgroundColor: _status.item3, + ), + ]; + } + + List _expandedTableContent() { + return [ + if (widget.queueRecord.series != null) + LunaTableContent( + title: 'sonarr.Series'.tr(), + body: widget.queueRecord.series.title, + ), + if (widget.queueRecord.episode != null) + LunaTableContent( + title: 'sonarr.Episode'.tr(), + body: widget.queueRecord.episode.lunaSeasonEpisode(), + ), + if (widget.queueRecord.episode != null) + LunaTableContent( + title: 'sonarr.Title'.tr(), + body: widget.queueRecord.episode.title, + ), + const LunaTableContent(title: '', body: ''), + LunaTableContent( + title: 'sonarr.Quality'.tr(), + body: widget.queueRecord.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, + ), + LunaTableContent( + title: 'sonarr.Language'.tr(), + body: widget.queueRecord.language?.name ?? LunaUI.TEXT_EMDASH, + ), + LunaTableContent( + title: 'sonarr.Client'.tr(), + body: widget.queueRecord.downloadClient ?? LunaUI.TEXT_EMDASH, + ), + LunaTableContent( + title: 'sonarr.Size'.tr(), + body: widget.queueRecord.size?.floor()?.lunaBytesToString() ?? + LunaUI.TEXT_EMDASH, + ), + LunaTableContent( + title: 'sonarr.TimeLeft'.tr(), + body: widget.queueRecord.lunaTimeLeft(), + ), + ]; + } + + List _tableButtons() { + return [ + if ((widget.queueRecord?.statusMessages ?? []).isNotEmpty) + LunaButton.text( + icon: Icons.messenger_outline_rounded, + color: LunaColours.orange, + text: 'sonarr.Messages'.tr(), + onTap: () async { + SonarrDialogs().showQueueStatusMessages( + context, + widget.queueRecord.statusMessages, + ); + }, + ), + // if (widget.queueRecord.status == SonarrQueueStatus.COMPLETED && + // widget.queueRecord?.trackedDownloadStatus == + // SonarrTrackedDownloadStatus.WARNING) + // LunaButton.text( + // icon: Icons.download_done_rounded, + // text: 'sonarr.Import'.tr(), + // onTap: () async {}, + // ), + LunaButton.text( + icon: Icons.delete_rounded, + color: LunaColours.red, + text: 'lunasea.Remove'.tr(), + onTap: () async { + bool result = await SonarrDialogs().removeFromQueue(context); + if (result) { + SonarrAPIController() + .removeFromQueue( + context: context, + queueRecord: widget.queueRecord, + ) + .then((_) { + switch (widget.type) { + case SonarrQueueTileType.ALL: + context.read().fetchQueue( + context, + hardCheck: true, + ); + break; + case SonarrQueueTileType.EPISODE: + context.read().fetchState( + context, + shouldFetchEpisodes: false, + shouldFetchFiles: false, + ); + break; + } + }); + } + }, + ), + ]; + } +} diff --git a/lib/modules/sonarr/routes/releases/widgets/release_tile.dart b/lib/modules/sonarr/routes/releases/widgets/release_tile.dart index fa683fd2..d4a206d3 100644 --- a/lib/modules/sonarr/routes/releases/widgets/release_tile.dart +++ b/lib/modules/sonarr/routes/releases/widgets/release_tile.dart @@ -21,8 +21,10 @@ class _State extends State { Widget build(BuildContext context) { return LunaExpandableListTile( title: widget.release.title, - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], collapsedTrailing: _trailing(), expandedHighlightedNodes: _highlightedNodes(), expandedTableContent: _tableContent(), @@ -47,7 +49,9 @@ class _State extends State { TextSpan( text: widget.release.lunaProtocol, style: TextStyle( - color: widget.release.lunaProtocolColor, + color: widget.release.protocol.lunaProtocolColor( + release: widget.release, + ), fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), ), @@ -86,8 +90,10 @@ class _State extends State { List _highlightedNodes() { return [ LunaHighlightedNode( - text: widget.release.protocol.readable, - backgroundColor: widget.release.lunaProtocolColor, + text: widget.release.protocol.lunaReadable(), + backgroundColor: widget.release.protocol.lunaProtocolColor( + release: widget.release, + ), ), if (widget.release.lunaPreferredWordScore(nullOnEmpty: true) != null) LunaHighlightedNode( diff --git a/lib/modules/sonarr/routes/releases/widgets/search_bar_sort_button.dart b/lib/modules/sonarr/routes/releases/widgets/search_bar_sort_button.dart index c3034909..c4db9efa 100644 --- a/lib/modules/sonarr/routes/releases/widgets/search_bar_sort_button.dart +++ b/lib/modules/sonarr/routes/releases/widgets/search_bar_sort_button.dart @@ -23,7 +23,7 @@ class _State extends State { builder: (context, state, _) => LunaPopupMenuButton( tooltip: 'sonarr.SortReleases'.tr(), - icon: Icons.sort, + icon: Icons.sort_rounded, onSelected: (result) { if (state.sortType == result) { state.sortAscending = !state.sortAscending; @@ -54,8 +54,8 @@ class _State extends State { if (state.sortType == SonarrReleasesSorting.values[index]) Icon( state.sortAscending - ? Icons.arrow_upward - : Icons.arrow_downward, + ? Icons.arrow_upward_rounded + : Icons.arrow_downward_rounded, size: LunaUI.FONT_SIZE_SUBTITLE + 2.0, color: LunaColours.accent, ), diff --git a/lib/modules/sonarr/routes/season_details/route.dart b/lib/modules/sonarr/routes/season_details/route.dart index b269f451..2fbfa20a 100644 --- a/lib/modules/sonarr/routes/season_details/route.dart +++ b/lib/modules/sonarr/routes/season_details/route.dart @@ -7,11 +7,11 @@ class SonarrSeasonDetailsRouter extends SonarrPageRouter { : super('/sonarr/series/details/:seriesid/season/:seasonnumber'); @override - _Widget widget({ + _SonarrSeasonDetails widget({ @required int seriesId, @required int seasonNumber, }) { - return _Widget( + return _SonarrSeasonDetails( seriesId: seriesId, seasonNumber: seasonNumber, ); @@ -47,15 +47,16 @@ class SonarrSeasonDetailsRouter extends SonarrPageRouter { int seasonNumber = (params['seasonnumber']?.isNotEmpty ?? false) ? (int.tryParse(params['seasonnumber'][0]) ?? -1) : -1; - return _Widget(seriesId: seriesId, seasonNumber: seasonNumber); + return _SonarrSeasonDetails( + seriesId: seriesId, seasonNumber: seasonNumber); }); } -class _Widget extends StatefulWidget { +class _SonarrSeasonDetails extends StatefulWidget { final int seriesId; final int seasonNumber; - const _Widget({ + const _SonarrSeasonDetails({ Key key, @required this.seriesId, @required this.seasonNumber, @@ -65,7 +66,8 @@ class _Widget extends StatefulWidget { State createState() => _State(); } -class _State extends State<_Widget> with LunaScrollControllerMixin { +class _State extends State<_SonarrSeasonDetails> + with LunaScrollControllerMixin { final GlobalKey _scaffoldKey = GlobalKey(); PageController _pageController; diff --git a/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart b/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart index aed5ee6e..f654b462 100644 --- a/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart +++ b/lib/modules/sonarr/routes/season_details/sheets/episode_details.dart @@ -3,26 +3,30 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { - final BuildContext context; - final SonarrEpisode episode; - final SonarrEpisodeFile episodeFile; - final SonarrQueueRecord queueRecord; + BuildContext context; + SonarrEpisode episode; + SonarrEpisodeFile episodeFile; + List queueRecords; SonarrEpisodeDetailsSheet({ @required this.context, @required this.episode, - this.episodeFile, - this.queueRecord, + @required this.episodeFile, + @required this.queueRecords, }) { _intializeSheet(); } Future _intializeSheet() async { - context - .read() - .fetchEpisodeHistory(context, episode.id); - context.read().episodeSearchState = - LunaLoadingState.INACTIVE; + SonarrSeasonDetailsState _state = context.read(); + _state.currentEpisodeId = episode.id; + _state.episodeSearchState = LunaLoadingState.INACTIVE; + _state.fetchState( + context, + shouldFetchEpisodes: false, + shouldFetchFiles: false, + shouldFetchHistory: false, + ); } Widget _highlightedNodes(BuildContext context) { @@ -51,24 +55,13 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { backgroundColor: LunaColours.blueGrey, text: episodeFile.size?.lunaBytesToString() ?? LunaUI.TEXT_EMDASH, ), - if (queueRecord != null) - LunaHighlightedNode( - text: [ - queueRecord?.quality?.quality?.name ?? LunaUI.TEXT_EMDASH, - LunaUI.TEXT_EMDASH, - '${queueRecord.lunaPercentageComplete}%', - ].join(' '), - backgroundColor: LunaColours.purple, - ), - if (queueRecord == null && - !episode.hasFile && + if (!episode.hasFile && (episode?.airDateUtc?.toLocal()?.isAfter(DateTime.now()) ?? true)) LunaHighlightedNode( backgroundColor: LunaColours.blue, text: 'sonarr.Unaired'.tr(), ), - if (queueRecord == null && - !episode.hasFile && + if (!episode.hasFile && (episode?.airDateUtc?.toLocal()?.isBefore(DateTime.now()) ?? true)) LunaHighlightedNode( backgroundColor: LunaColours.red, @@ -104,6 +97,8 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { 'sonarr.EpisodeNumber'.tr( args: [episode?.episodeNumber.toString()], ), + if (episode?.absoluteEpisodeNumber != null) + ' (${episode.absoluteEpisodeNumber})', ].join(), ), _highlightedNodes(context), @@ -139,7 +134,7 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { episodeFile?.mediaInfo?.audioCodec ?? LunaUI.TEXT_EMDASH, if (episodeFile?.mediaInfo?.audioChannels != null) episodeFile?.mediaInfo?.audioChannels?.toString(), - ].join(LunaUI.TEXT_EMDASH.lunaPad()), + ].join(LunaUI.TEXT_BULLET.lunaPad()), ), LunaTableContent( title: 'sonarr.Size'.tr(), @@ -163,7 +158,7 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { LunaButton( type: LunaButtonType.TEXT, text: 'lunasea.Delete'.tr(), - icon: Icons.delete, + icon: Icons.delete_rounded, onTap: () async { bool result = await SonarrDialogs().deleteEpisode(context); if (result) { @@ -190,6 +185,18 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { ]; } + List _queue(BuildContext context) { + if (queueRecords?.isNotEmpty ?? false) { + return queueRecords + .map((r) => SonarrQueueTile( + queueRecord: r, + type: SonarrQueueTileType.EPISODE, + )) + .toList(); + } + return []; + } + List _history(BuildContext context) { return [ FutureBuilder( @@ -245,7 +252,7 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { ]; } - LunaBottomActionBar _actionBar(BuildContext context) { + Widget _actionBar(BuildContext context) { return LunaBottomActionBar( actions: [ LunaButton( @@ -260,20 +267,25 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { LunaLoadingState.ACTIVE; SonarrAPIController() .episodeSearch(context: context, episode: episode) - .whenComplete( - () => context - .read() - .episodeSearchState = LunaLoadingState.INACTIVE, - ); + .whenComplete(() => context + .read() + .episodeSearchState = LunaLoadingState.INACTIVE); }, ), LunaButton.text( text: 'sonarr.Interactive'.tr(), icon: Icons.person_rounded, - onTap: () async => SonarrReleasesRouter().navigateTo( - context, - episodeId: episode.id, - ), + onTap: () async { + await SonarrReleasesRouter().navigateTo( + context, + episodeId: episode.id, + ); + context.read().fetchState( + context, + shouldFetchEpisodes: false, + shouldFetchFiles: false, + ); + }, ), ], ); @@ -281,15 +293,41 @@ class SonarrEpisodeDetailsSheet extends LunaBottomModalSheet { @override Widget builder(BuildContext context) { - return ChangeNotifierProvider.value( - value: this.context.read(), - builder: (context, _) => LunaListViewModal( - children: [ - ..._episodeDetails(context), - ..._files(context), - ..._history(context), - ], - actionBar: _actionBar(context), + return ChangeNotifierProvider.value( + value: this.context.watch(), + builder: (context, _) => Consumer( + builder: (context, state, _) => FutureBuilder( + future: Future.wait([ + state.episodes, + state.files, + state.queue, + state.getEpisodeHistory(episode.id), + ]), + builder: (BuildContext context, AsyncSnapshot snapshot) { + if (snapshot.hasData) { + SonarrEpisode _e = + (snapshot.data[0] as Map)[episode.id]; + episode = _e; + SonarrEpisodeFile _ef = (snapshot.data[1] + as Map)[episode.episodeFileId]; + episodeFile = _ef; + List _qr = + (snapshot.data[2] as List) + .where((q) => q.episodeId == episode.id) + .toList(); + queueRecords = _qr; + } + return LunaListViewModal( + children: [ + ..._episodeDetails(context), + ..._queue(context), + ..._files(context), + ..._history(context), + ], + actionBar: _actionBar(context), + ); + }, + ), ), ); } diff --git a/lib/modules/sonarr/routes/season_details/state.dart b/lib/modules/sonarr/routes/season_details/state.dart index e6bea234..0167ea22 100644 --- a/lib/modules/sonarr/routes/season_details/state.dart +++ b/lib/modules/sonarr/routes/season_details/state.dart @@ -1,3 +1,4 @@ +import 'dart:async'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; @@ -5,15 +6,38 @@ import 'package:lunasea/modules/sonarr.dart'; class SonarrSeasonDetailsState extends ChangeNotifier { final int seriesId; final int seasonNumber; + int _currentQueueItems = 0; + int currentEpisodeId; SonarrSeasonDetailsState({ @required BuildContext context, @required this.seriesId, @required this.seasonNumber, }) { - fetchEpisodes(context); - fetchFiles(context); - fetchHistory(context); + fetchState(context, queueHardCheck: false); + } + + Future fetchState( + BuildContext context, { + bool shouldFetchEpisodes = true, + bool shouldFetchFiles = true, + bool shouldFetchHistory = true, + bool shouldFetchQueue = true, + bool queueHardCheck = true, + bool shouldFetchMostRecentEpisodeHistory = true, + }) async { + if (shouldFetchEpisodes) fetchEpisodes(context); + if (shouldFetchFiles) fetchFiles(context); + if (shouldFetchHistory) fetchHistory(context); + if (shouldFetchQueue) fetchQueue(context, hardCheck: queueHardCheck); + if (shouldFetchMostRecentEpisodeHistory) + fetchEpisodeHistory(context, currentEpisodeId); + } + + @override + void dispose() { + _queueTimer?.cancel(); + super.dispose(); } LunaLoadingState _episodeSearchState = LunaLoadingState.INACTIVE; @@ -110,4 +134,62 @@ class SonarrSeasonDetailsState extends ChangeNotifier { } notifyListeners(); } + + Timer _queueTimer; + void cancelQueueTimer() => _queueTimer?.cancel(); + void createQueueTimer(BuildContext context) { + _queueTimer = Timer.periodic( + Duration(seconds: SonarrDatabaseValue.QUEUE_REFRESH_RATE.data), + (_) => fetchQueue(context), + ); + } + + Future> _queue; + Future> get queue => _queue; + set queue(Future> queue) { + assert(queue != null); + _queue = queue; + notifyListeners(); + } + + Future fetchQueue( + BuildContext context, { + bool hardCheck = false, + }) async { + cancelQueueTimer(); + if (context.read().enabled) { + // "Hard" check by telling Sonarr to refresh the monitored downloads + // Give it 500 ms to internally check and then continue to fetch queue + if (hardCheck) { + await context + .read() + .api + .command + .refreshMonitoredDownloads() + .then( + (_) => Future.delayed(const Duration(milliseconds: 500), () {}), + ); + } + _queue = context + .read() + .api + .queue + .getDetails( + seriesId: seriesId, + includeEpisode: true, + ) + .then((queue) { + if (_currentQueueItems != queue.length) { + fetchState( + context, + shouldFetchQueue: false, + ); + } + _currentQueueItems = queue.length; + return queue; + }); + createQueueTimer(context); + } + notifyListeners(); + } } diff --git a/lib/modules/sonarr/routes/season_details/widgets/episode_tile.dart b/lib/modules/sonarr/routes/season_details/widgets/episode_tile.dart index 08f3026c..25e7de93 100644 --- a/lib/modules/sonarr/routes/season_details/widgets/episode_tile.dart +++ b/lib/modules/sonarr/routes/season_details/widgets/episode_tile.dart @@ -5,11 +5,13 @@ import 'package:lunasea/modules/sonarr.dart'; class SonarrEpisodeTile extends StatefulWidget { final SonarrEpisode episode; final SonarrEpisodeFile episodeFile; + final List queueRecords; const SonarrEpisodeTile({ Key key, @required this.episode, this.episodeFile, + this.queueRecords, }) : super(key: key); @override @@ -41,6 +43,7 @@ class _State extends State { context: context, episode: widget.episode, episodeFile: widget.episodeFile, + queueRecords: widget.queueRecords, ).showModal(context: context); } @@ -67,19 +70,36 @@ class _State extends State { TextSpan(text: widget.episode.lunaAirDate()), const TextSpan(text: '\n'), TextSpan( - text: widget.episode.lunaDownloadedQuality(widget.episodeFile), + text: widget.episode.lunaDownloadedQuality( + widget.episodeFile, + widget.queueRecords?.isNotEmpty ?? false + ? widget.queueRecords.first + : null, + ), style: TextStyle( color: widget.episode.monitored - ? widget.episode - .lunaDownloadedQualityColor(widget.episodeFile) + ? widget.episode.lunaDownloadedQualityColor( + widget.episodeFile, + widget.queueRecords?.isNotEmpty ?? false + ? widget.queueRecords.first + : null, + ) : widget.episode - .lunaDownloadedQualityColor(widget.episodeFile) + .lunaDownloadedQualityColor( + widget.episodeFile, + widget.queueRecords?.isNotEmpty ?? false + ? widget.queueRecords.first + : null, + ) .withOpacity(0.30), fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), ), ], ), + maxLines: 2, + softWrap: false, + overflow: TextOverflow.fade, ); } diff --git a/lib/modules/sonarr/routes/season_details/widgets/page_episodes.dart b/lib/modules/sonarr/routes/season_details/widgets/page_episodes.dart index 5e0127cd..2ed2c3d1 100644 --- a/lib/modules/sonarr/routes/season_details/widgets/page_episodes.dart +++ b/lib/modules/sonarr/routes/season_details/widgets/page_episodes.dart @@ -30,14 +30,25 @@ class _State extends State } Future _refresh() async { - context.read().fetchEpisodes(context); - context.read().fetchFiles(context); + await context.read().fetchState( + context, + shouldFetchHistory: false, + shouldFetchMostRecentEpisodeHistory: false, + ); await Future.wait([ context.read().episodes, context.read().files, + context.read().queue, ]); } + List _findQueueRecords( + List records, + int episodeId, + ) { + return records.where((q) => q.episodeId == episodeId).toList(); + } + Widget _body() { return LunaRefreshIndicator( key: _refreshKey, @@ -48,19 +59,18 @@ class _State extends State future: Future.wait([ state.episodes, state.files, + state.queue, ]), builder: ( context, snapshot, ) { if (snapshot.hasError) { - if (snapshot.connectionState != ConnectionState.waiting) { - LunaLogger().error( - 'Unable to fetch Sonarr episode files', - snapshot.error, - snapshot.stackTrace, - ); - } + LunaLogger().error( + 'Unable to fetch Sonarr episode files', + snapshot.error, + snapshot.stackTrace, + ); return LunaMessage.error( onTap: _refreshKey.currentState.show, ); @@ -69,6 +79,7 @@ class _State extends State return _list( episodes: snapshot.data[0], episodeFiles: snapshot.data[1], + queue: snapshot.data[2], ); return const LunaLoader(); }, @@ -80,6 +91,7 @@ class _State extends State Widget _list({ @required Map episodes, @required Map episodeFiles, + @required List queue, }) { if (episodes?.isEmpty ?? true) { return LunaMessage( @@ -92,6 +104,7 @@ class _State extends State List _widgets = _buildSeasonWidgets( episodes: episodes, episodeFiles: episodeFiles, + queue: queue, ); return LunaListViewBuilder( @@ -104,6 +117,7 @@ class _State extends State List _buildSeasonWidgets({ @required Map episodes, @required Map episodeFiles, + @required List queue, }) { List _episodes = episodes.values.toList() ..sort((a, b) { @@ -121,6 +135,7 @@ class _State extends State episodeFile: episode.hasFile && episodeFiles != null ? episodeFiles[episode.episodeFileId] : null, + queueRecords: _findQueueRecords(queue, episode.id), )) .toList(); } @@ -136,6 +151,7 @@ class _State extends State episodeFile: episode.hasFile && episodeFiles != null ? episodeFiles[episode.episodeFileId] : null, + queueRecords: _findQueueRecords(queue, episode.id), )); }); }); diff --git a/lib/modules/sonarr/routes/series_details/route.dart b/lib/modules/sonarr/routes/series_details/route.dart index bd462acc..125485c5 100644 --- a/lib/modules/sonarr/routes/series_details/route.dart +++ b/lib/modules/sonarr/routes/series_details/route.dart @@ -6,10 +6,10 @@ class SonarrSeriesDetailsRouter extends SonarrPageRouter { SonarrSeriesDetailsRouter() : super('/sonarr/series/:seriesid'); @override - _Widget widget({ + _SonarrSeriesDetails widget({ @required int seriesId, }) { - return _Widget(seriesId: seriesId); + return _SonarrSeriesDetails(seriesId: seriesId); } @override @@ -38,16 +38,16 @@ class SonarrSeriesDetailsRouter extends SonarrPageRouter { int seriesId = (params['seriesid']?.isNotEmpty ?? false) ? (int.tryParse(params['seriesid'][0]) ?? -1) : -1; - return _Widget(seriesId: seriesId); + return _SonarrSeriesDetails(seriesId: seriesId); }, ); } } -class _Widget extends StatefulWidget { +class _SonarrSeriesDetails extends StatefulWidget { final int seriesId; - const _Widget({ + const _SonarrSeriesDetails({ Key key, @required this.seriesId, }) : super(key: key); @@ -56,7 +56,7 @@ class _Widget extends StatefulWidget { State createState() => _State(); } -class _State extends State<_Widget> with LunaLoadCallbackMixin { +class _State extends State<_SonarrSeriesDetails> with LunaLoadCallbackMixin { final GlobalKey _scaffoldKey = GlobalKey(); SonarrSeries series; PageController _pageController; @@ -131,7 +131,7 @@ class _State extends State<_Widget> with LunaLoadCallbackMixin { ? null : [ LunaIconButton( - icon: Icons.edit, + icon: Icons.edit_rounded, onPressed: () async => SonarrEditSeriesRouter().navigateTo( context, seriesId: widget.seriesId, diff --git a/lib/modules/sonarr/routes/series_details/widgets/appbar_settings_action.dart b/lib/modules/sonarr/routes/series_details/widgets/appbar_settings_action.dart index bba78b54..49e6a012 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/appbar_settings_action.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/appbar_settings_action.dart @@ -21,7 +21,7 @@ class SonarrAppBarSeriesSettingsAction extends StatelessWidget { SonarrSeries series = snapshot.data[seriesId]; if (series != null) return LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async { Tuple2 values = await SonarrDialogs().seriesSettings(context, series); diff --git a/lib/modules/sonarr/routes/series_details/widgets/page_seasons.dart b/lib/modules/sonarr/routes/series_details/widgets/page_seasons.dart index 57237199..5af34d30 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/page_seasons.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/page_seasons.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrSeriesDetailsSeasonsPage extends StatelessWidget { +class SonarrSeriesDetailsSeasonsPage extends StatefulWidget { final SonarrSeries series; const SonarrSeriesDetailsSeasonsPage({ @@ -10,23 +10,53 @@ class SonarrSeriesDetailsSeasonsPage extends StatelessWidget { @required this.series, }) : super(key: key); + @override + State createState() => _State(); +} + +class _State extends State { + final _scaffoldKey = GlobalKey(); + final _refreshKey = GlobalKey(); + @override Widget build(BuildContext context) { - if (series?.seasons?.isEmpty ?? true) { - return LunaMessage(text: 'sonarr.NoSeasonsFound'.tr()); + return LunaScaffold( + scaffoldKey: _scaffoldKey, + body: _body(), + ); + } + + Widget _body() { + return LunaRefreshIndicator( + key: _refreshKey, + context: context, + onRefresh: () async => context.read().fetchSeries( + widget.series.id, + ), + child: _list(), + ); + } + + Widget _list() { + if (widget.series?.seasons?.isEmpty ?? true) { + return LunaMessage( + text: 'sonarr.NoSeasonsFound'.tr(), + buttonText: 'lunasea.Refresh'.tr(), + onTap: _refreshKey.currentState.show, + ); } - List _seasons = series.seasons; + List _seasons = widget.series.seasons; _seasons.sort((a, b) => a.seasonNumber.compareTo(b.seasonNumber)); return LunaListView( controller: SonarrSeriesDetailsNavigationBar.scrollControllers[1], children: [ if (_seasons.length > 1) - SonarrSeriesDetailsSeasonAllTile(series: series), + SonarrSeriesDetailsSeasonAllTile(series: widget.series), ...List.generate( _seasons.length, (index) => SonarrSeriesDetailsSeasonTile( - seriesId: series.id, - season: series.seasons[_seasons.length - 1 - index], + seriesId: widget.series.id, + season: widget.series.seasons[_seasons.length - 1 - index], ), ), ], diff --git a/lib/modules/sonarr/routes/series_details/widgets/season_all_tile.dart b/lib/modules/sonarr/routes/series_details/widgets/season_all_tile.dart index 63cf4230..a1379070 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/season_all_tile.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/season_all_tile.dart @@ -62,7 +62,7 @@ class SonarrSeriesDetailsSeasonAllTile extends StatelessWidget { ), text: [ '${series.lunaPercentageComplete}%', - LunaUI.TEXT_EMDASH.lunaPad(), + LunaUI.TEXT_BULLET, '${series.statistics?.episodeFileCount ?? 0}/${series.statistics?.episodeCount ?? 0}', 'Episodes Available', ].join(' '), diff --git a/lib/modules/sonarr/routes/series_details/widgets/season_tile.dart b/lib/modules/sonarr/routes/series_details/widgets/season_tile.dart index b1f0289d..4ff3b1ee 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/season_tile.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/season_tile.dart @@ -85,7 +85,7 @@ class _State extends State { ), text: [ '${widget.season.lunaPercentageComplete}%', - LunaUI.TEXT_EMDASH.lunaPad(), + LunaUI.TEXT_BULLET, '${widget?.season?.statistics?.episodeFileCount ?? 0}/${widget?.season?.statistics?.episodeCount ?? 0}', 'sonarr.EpisodesAvailable'.tr(), ].join(' '), @@ -98,7 +98,9 @@ class _State extends State { } return LunaIconButton( - icon: widget.season.monitored ? Icons.turned_in : Icons.turned_in_not, + icon: widget.season.monitored + ? Icons.turned_in_rounded + : Icons.turned_in_not_rounded, color: widget.season.monitored ? Colors.white : Colors.white30, loadingState: _loadingState, onPressed: () async { diff --git a/lib/modules/sonarr/routes/sonarr/widgets/appbar_add_series_action.dart b/lib/modules/sonarr/routes/sonarr/widgets/appbar_add_series_action.dart index 39374172..a7702455 100644 --- a/lib/modules/sonarr/routes/sonarr/widgets/appbar_add_series_action.dart +++ b/lib/modules/sonarr/routes/sonarr/widgets/appbar_add_series_action.dart @@ -10,7 +10,7 @@ class SonarrAppBarAddSeriesAction extends StatelessWidget { @override Widget build(BuildContext context) { return LunaIconButton( - icon: Icons.add, + icon: Icons.add_rounded, onPressed: () async => SonarrAddSeriesRouter().navigateTo( context, query: '', diff --git a/lib/modules/sonarr/routes/sonarr/widgets/appbar_global_settings_action.dart b/lib/modules/sonarr/routes/sonarr/widgets/appbar_global_settings_action.dart index 5b6f0f12..fe1c8764 100644 --- a/lib/modules/sonarr/routes/sonarr/widgets/appbar_global_settings_action.dart +++ b/lib/modules/sonarr/routes/sonarr/widgets/appbar_global_settings_action.dart @@ -10,7 +10,7 @@ class SonarrAppBarGlobalSettingsAction extends StatelessWidget { @override Widget build(BuildContext context) { return LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async { Tuple2 values = await SonarrDialogs().globalSettings(context); diff --git a/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart b/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart index 440a5147..20bdd319 100644 --- a/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart +++ b/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart @@ -12,7 +12,7 @@ class SonarrNavigationBar extends StatelessWidget { LunaIcons.television, LunaIcons.upcoming, LunaIcons.calendar_missing, - Icons.more_horiz, + Icons.more_horiz_rounded, ]; static List get titles => [ diff --git a/lib/modules/sonarr/routes/tags/widgets/appbar_action_add_tag.dart b/lib/modules/sonarr/routes/tags/widgets/appbar_action_add_tag.dart index c7fc0de8..4fda8bd5 100644 --- a/lib/modules/sonarr/routes/tags/widgets/appbar_action_add_tag.dart +++ b/lib/modules/sonarr/routes/tags/widgets/appbar_action_add_tag.dart @@ -19,7 +19,7 @@ class SonarrTagsAppBarActionAddTag extends StatelessWidget { onPressed: () async => _onPressed(context), ); return LunaIconButton( - icon: Icons.add, + icon: Icons.add_rounded, onPressed: () async => _onPressed(context), ); } diff --git a/lib/modules/sonarr/routes/tags/widgets/tag_tile.dart b/lib/modules/sonarr/routes/tags/widgets/tag_tile.dart index 7365992b..aac4b7b4 100644 --- a/lib/modules/sonarr/routes/tags/widgets/tag_tile.dart +++ b/lib/modules/sonarr/routes/tags/widgets/tag_tile.dart @@ -46,7 +46,7 @@ class _State extends State with LunaLoadCallbackMixin { trailing: (seriesList?.isNotEmpty ?? true) ? null : LunaIconButton( - icon: Icons.delete, + icon: Icons.delete_rounded, color: LunaColours.red, onPressed: _handleDelete, ), @@ -71,17 +71,13 @@ class _State extends State with LunaLoadCallbackMixin { Future _handleDelete() async { if (seriesList?.isNotEmpty ?? true) { showLunaErrorSnackBar( - title: 'Cannot Delete Tag', - message: 'The tag must not be attached to any series'); + title: 'Cannot Delete Tag', + message: 'The tag must not be attached to any series', + ); } else { bool result = await SonarrDialogs().deleteTag(context); if (result) - context - .read() - .api - .tag - .deleteTag(id: widget.tag.id) - .then((_) { + context.read().api.tag.delete(id: widget.tag.id).then((_) { showLunaSuccessSnackBar( title: 'Deleted Tag', message: widget.tag.label, diff --git a/lib/modules/tautulli/core/extensions/tautulli_history_record.dart b/lib/modules/tautulli/core/extensions/tautulli_history_record.dart index 701a5d3b..e7f4327d 100644 --- a/lib/modules/tautulli/core/extensions/tautulli_history_record.dart +++ b/lib/modules/tautulli/core/extensions/tautulli_history_record.dart @@ -23,12 +23,12 @@ extension TautulliHistoryRecordExtension on TautulliHistoryRecord { IconData get lsWatchStatusIcon { switch (this.watchedStatus) { case TautulliWatchedStatus.PARTIALLY_WATCHED: - return Icons.radio_button_checked; + return Icons.radio_button_checked_rounded; case TautulliWatchedStatus.WATCHED: - return Icons.check_circle; + return Icons.check_circle_rounded; case TautulliWatchedStatus.UNWATCHED: default: - return Icons.radio_button_unchecked; + return Icons.radio_button_unchecked_rounded; } } diff --git a/lib/modules/tautulli/core/extensions/tautulli_session.dart b/lib/modules/tautulli/core/extensions/tautulli_session.dart index faeae8da..a302436a 100644 --- a/lib/modules/tautulli/core/extensions/tautulli_session.dart +++ b/lib/modules/tautulli/core/extensions/tautulli_session.dart @@ -87,9 +87,10 @@ extension TautulliSessionExtension on TautulliSession { String get lunaDuration { double _percent = (this.progressPercent ?? 0) / 100; String _progress = Duration( - seconds: ((this.streamDuration ?? const Duration(seconds: 0)).inSeconds * - _percent) - .floor()) + seconds: + ((this.streamDuration ?? const Duration(seconds: 0)).inSeconds * + _percent) + .floor()) .lunaTimestamp; String _total = this.streamDuration.lunaTimestamp; return '$_progress/$_total (${this.progressPercent}%)'; @@ -187,12 +188,12 @@ extension TautulliSessionExtension on TautulliSession { IconData get lunaSessionStateIcon { switch (this.state) { case TautulliSessionState.PAUSED: - return Icons.pause; + return Icons.pause_rounded; case TautulliSessionState.PLAYING: - return Icons.play_arrow; + return Icons.play_arrow_rounded; case TautulliSessionState.BUFFERING: default: - return Icons.compare_arrows; + return Icons.compare_arrows_rounded; } } diff --git a/lib/modules/tautulli/core/graphs/graph.dart b/lib/modules/tautulli/core/graphs/graph.dart index 8a441da3..80b46290 100644 --- a/lib/modules/tautulli/core/graphs/graph.dart +++ b/lib/modules/tautulli/core/graphs/graph.dart @@ -107,7 +107,7 @@ class TautulliGraphHelper { height: GRAPH_HEIGHT + LEGEND_HEIGHT, alignment: Alignment.center, child: LunaIconButton( - icon: Icons.error, + icon: Icons.error_rounded, iconSize: 60.0, color: Colors.white12, ), diff --git a/lib/modules/tautulli/core/types/settings_global.dart b/lib/modules/tautulli/core/types/settings_global.dart index 4cdf9471..6ab313ee 100644 --- a/lib/modules/tautulli/core/types/settings_global.dart +++ b/lib/modules/tautulli/core/types/settings_global.dart @@ -15,17 +15,17 @@ extension TautulliGlobalSettingsTypeExtension on TautulliGlobalSettingsType { IconData get icon { switch (this) { case TautulliGlobalSettingsType.WEB_GUI: - return Icons.language; + return Icons.language_rounded; case TautulliGlobalSettingsType.BACKUP_CONFIG: - return Icons.note; + return Icons.note_rounded; case TautulliGlobalSettingsType.BACKUP_DB: - return Icons.save; + return Icons.save_rounded; case TautulliGlobalSettingsType.DELETE_CACHE: - return Icons.cached; + return Icons.cached_rounded; case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: - return Icons.image; + return Icons.image_rounded; case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: - return Icons.delete_sweep; + return Icons.delete_sweep_rounded; } throw Exception('Invalid TautulliGlobalSettingsType'); } diff --git a/lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart b/lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart index fcd9644c..59ee3ec7 100644 --- a/lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart +++ b/lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart @@ -23,7 +23,7 @@ class TautulliActivityDetailsMetadataAction extends StatelessWidget { orElse: () => null); if (session != null) return LunaIconButton( - icon: Icons.info_outline, + icon: Icons.info_outline_rounded, onPressed: () async => _onPressed(context, session), ); } diff --git a/lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart b/lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart index d50aa5b7..c808f9df 100644 --- a/lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart +++ b/lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart @@ -23,7 +23,7 @@ class TautulliActivityDetailsUserAction extends StatelessWidget { orElse: () => null); if (session != null) return LunaIconButton( - icon: Icons.person, + icon: Icons.person_rounded, onPressed: () async => _onPressed(context, session.userId), ); } diff --git a/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart index aa11214d..88b7334c 100644 --- a/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart @@ -8,7 +8,7 @@ class TautulliGraphsNavigationBar extends StatelessWidget { static const List icons = [ LunaIcons.history, - Icons.videocam, + Icons.videocam_rounded, ]; static const List titles = [ diff --git a/lib/modules/tautulli/routes/graphs/widgets/type_button.dart b/lib/modules/tautulli/routes/graphs/widgets/type_button.dart index 7bd5cfff..27e760d9 100644 --- a/lib/modules/tautulli/routes/graphs/widgets/type_button.dart +++ b/lib/modules/tautulli/routes/graphs/widgets/type_button.dart @@ -13,7 +13,7 @@ class TautulliGraphsTypeButton extends StatelessWidget { selector: (_, state) => state.graphYAxis, builder: (context, type, _) => LunaPopupMenuButton( tooltip: 'Graph Type', - icon: Icons.merge_type, + icon: Icons.merge_type_rounded, onSelected: (value) { context.read().graphYAxis = value; context.read().resetAllPlayPeriodGraphs(); diff --git a/lib/modules/tautulli/routes/history_details/widgets/metadata.dart b/lib/modules/tautulli/routes/history_details/widgets/metadata.dart index 460efe5e..ddd657e1 100644 --- a/lib/modules/tautulli/routes/history_details/widgets/metadata.dart +++ b/lib/modules/tautulli/routes/history_details/widgets/metadata.dart @@ -28,7 +28,7 @@ class TautulliHistoryDetailsMetadata extends StatelessWidget { }, orElse: () => null); if (_record != null) return LunaIconButton( - icon: Icons.info_outline, + icon: Icons.info_outline_rounded, onPressed: () async => _onPressed(context, _record), ); } diff --git a/lib/modules/tautulli/routes/history_details/widgets/user.dart b/lib/modules/tautulli/routes/history_details/widgets/user.dart index d365c3ed..07075a3c 100644 --- a/lib/modules/tautulli/routes/history_details/widgets/user.dart +++ b/lib/modules/tautulli/routes/history_details/widgets/user.dart @@ -28,7 +28,7 @@ class TautulliHistoryDetailsUser extends StatelessWidget { }, orElse: () => null); if (_record != null) return LunaIconButton( - icon: Icons.person, + icon: Icons.person_rounded, onPressed: () async => _onPressed(context, _record.userId), ); } diff --git a/lib/modules/tautulli/routes/libraries_details/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/libraries_details/widgets/navigation_bar.dart index b971cd3d..dcbe2413 100644 --- a/lib/modules/tautulli/routes/libraries_details/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/libraries_details/widgets/navigation_bar.dart @@ -7,8 +7,8 @@ class TautulliLibrariesDetailsNavigationBar extends StatelessWidget { List.generate(icons.length, (_) => ScrollController()); static const List icons = [ - Icons.info_outline, - Icons.people, + Icons.info_outline_rounded, + Icons.people_rounded, ]; static const List titles = [ diff --git a/lib/modules/tautulli/routes/logs_logins/widgets/log_tile.dart b/lib/modules/tautulli/routes/logs_logins/widgets/log_tile.dart index b2710cfb..00c9e1a9 100644 --- a/lib/modules/tautulli/routes/logs_logins/widgets/log_tile.dart +++ b/lib/modules/tautulli/routes/logs_logins/widgets/log_tile.dart @@ -55,7 +55,8 @@ class TautulliLogsLoginsLogTile extends StatelessWidget { return Column( children: [ LunaIconButton( - icon: login.success ? Icons.check_circle : Icons.cancel, + icon: + login.success ? Icons.check_circle_rounded : Icons.cancel_rounded, color: login.success ? Colors.white : LunaColours.red, ), ], diff --git a/lib/modules/tautulli/routes/logs_newsletters/widgets/log_tile.dart b/lib/modules/tautulli/routes/logs_newsletters/widgets/log_tile.dart index 19656351..9f4c26dc 100644 --- a/lib/modules/tautulli/routes/logs_newsletters/widgets/log_tile.dart +++ b/lib/modules/tautulli/routes/logs_newsletters/widgets/log_tile.dart @@ -52,7 +52,9 @@ class TautulliLogsNewsletterLogTile extends StatelessWidget { Widget _trailing() => Column( children: [ LunaIconButton( - icon: newsletter.success ? Icons.check_circle : Icons.cancel, + icon: newsletter.success + ? Icons.check_circle_rounded + : Icons.cancel_rounded, color: newsletter.success ? Colors.white : LunaColours.red, ), ], diff --git a/lib/modules/tautulli/routes/logs_notifications/widgets/log_tile.dart b/lib/modules/tautulli/routes/logs_notifications/widgets/log_tile.dart index 5d519074..f982118b 100644 --- a/lib/modules/tautulli/routes/logs_notifications/widgets/log_tile.dart +++ b/lib/modules/tautulli/routes/logs_notifications/widgets/log_tile.dart @@ -52,7 +52,9 @@ class TautulliLogsNotificationLogTile extends StatelessWidget { Widget _trailing() => Column( children: [ LunaIconButton( - icon: notification.success ? Icons.check_circle : Icons.cancel, + icon: notification.success + ? Icons.check_circle_rounded + : Icons.cancel_rounded, color: notification.success ? Colors.white : LunaColours.red, ), ], diff --git a/lib/modules/tautulli/routes/logs_plex_media_scanner/widgets/log_tile.dart b/lib/modules/tautulli/routes/logs_plex_media_scanner/widgets/log_tile.dart index 52643913..26aadf75 100644 --- a/lib/modules/tautulli/routes/logs_plex_media_scanner/widgets/log_tile.dart +++ b/lib/modules/tautulli/routes/logs_plex_media_scanner/widgets/log_tile.dart @@ -14,8 +14,10 @@ class TautulliLogsPlexMediaScannerLogTile extends StatelessWidget { Widget build(BuildContext context) { return LunaExpandableListTile( title: log.message.trim(), - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedTableContent: _tableContent(), ); } diff --git a/lib/modules/tautulli/routes/logs_plex_media_server/widgets/log_tile.dart b/lib/modules/tautulli/routes/logs_plex_media_server/widgets/log_tile.dart index 6524aedd..d694745e 100644 --- a/lib/modules/tautulli/routes/logs_plex_media_server/widgets/log_tile.dart +++ b/lib/modules/tautulli/routes/logs_plex_media_server/widgets/log_tile.dart @@ -14,8 +14,10 @@ class TautulliLogsPlexMediaServerLogTile extends StatelessWidget { Widget build(BuildContext context) { return LunaExpandableListTile( title: log.message.trim(), - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedTableContent: _tableContent(), ); } diff --git a/lib/modules/tautulli/routes/logs_tautulli/widgets/log_tile.dart b/lib/modules/tautulli/routes/logs_tautulli/widgets/log_tile.dart index e39f9211..55dd6451 100644 --- a/lib/modules/tautulli/routes/logs_tautulli/widgets/log_tile.dart +++ b/lib/modules/tautulli/routes/logs_tautulli/widgets/log_tile.dart @@ -14,8 +14,10 @@ class TautulliLogsTautulliLogTile extends StatelessWidget { Widget build(BuildContext context) { return LunaExpandableListTile( title: log.message.trim(), - collapsedSubtitle1: _subtitle1(), - collapsedSubtitle2: _subtitle2(), + collapsedSubtitles: [ + _subtitle1(), + _subtitle2(), + ], expandedTableContent: _tableContent(), ); } diff --git a/lib/modules/tautulli/routes/media_details/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/media_details/widgets/navigation_bar.dart index 1aaf1d91..272e6fa2 100644 --- a/lib/modules/tautulli/routes/media_details/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/media_details/widgets/navigation_bar.dart @@ -7,7 +7,7 @@ class TautulliMediaDetailsNavigationBar extends StatelessWidget { List.generate(icons.length, (_) => ScrollController()); static const List icons = [ - Icons.info_outline, + Icons.info_outline_rounded, LunaIcons.history, ]; diff --git a/lib/modules/tautulli/routes/statistics/widgets/time_range_button.dart b/lib/modules/tautulli/routes/statistics/widgets/time_range_button.dart index 28a2cf8f..a7bd889a 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/time_range_button.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/time_range_button.dart @@ -14,7 +14,7 @@ class TautulliStatisticsTimeRangeButton extends StatelessWidget { builder: (context, range, _) => LunaPopupMenuButton( tooltip: 'Time Range', - icon: Icons.access_time, + icon: Icons.access_time_rounded, onSelected: (value) { context.read().statisticsTimeRange = value; context.read().resetStatistics(); diff --git a/lib/modules/tautulli/routes/statistics/widgets/type_button.dart b/lib/modules/tautulli/routes/statistics/widgets/type_button.dart index c1da0c79..6b831a36 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/type_button.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/type_button.dart @@ -13,7 +13,7 @@ class TautulliStatisticsTypeButton extends StatelessWidget { selector: (_, state) => state.statisticsType, builder: (context, type, _) => LunaPopupMenuButton( tooltip: 'Statistics Type', - icon: Icons.merge_type, + icon: Icons.merge_type_rounded, onSelected: (value) { context.read().statisticsType = value; context.read().resetStatistics(); diff --git a/lib/modules/tautulli/routes/tautulli/widgets/appbar_global_settings_action.dart b/lib/modules/tautulli/routes/tautulli/widgets/appbar_global_settings_action.dart index 288caaaf..4e9f96ac 100644 --- a/lib/modules/tautulli/routes/tautulli/widgets/appbar_global_settings_action.dart +++ b/lib/modules/tautulli/routes/tautulli/widgets/appbar_global_settings_action.dart @@ -10,7 +10,7 @@ class TautulliAppBarGlobalSettingsAction extends StatelessWidget { @override Widget build(BuildContext context) { return LunaIconButton( - icon: Icons.more_vert, + icon: Icons.more_vert_rounded, onPressed: () async { Tuple2 values = await TautulliDialogs().globalSettings(context); diff --git a/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart index 774fcbf1..8c368b16 100644 --- a/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart @@ -11,7 +11,7 @@ class TautulliNavigationBar extends StatefulWidget { LunaIcons.monitoring, LunaIcons.user, LunaIcons.history, - Icons.more_horiz, + Icons.more_horiz_rounded, ]; static List get titles => [ diff --git a/lib/modules/tautulli/routes/users/widgets/user_tile.dart b/lib/modules/tautulli/routes/users/widgets/user_tile.dart index d7335738..8997f5e0 100644 --- a/lib/modules/tautulli/routes/users/widgets/user_tile.dart +++ b/lib/modules/tautulli/routes/users/widgets/user_tile.dart @@ -73,7 +73,7 @@ class TautulliUserTile extends StatelessWidget { children: [ const Padding( child: Icon( - Icons.visibility, + Icons.visibility_rounded, size: LunaUI.FONT_SIZE_SUBTITLE, ), padding: EdgeInsets.only(right: 6.0), @@ -91,7 +91,7 @@ class TautulliUserTile extends StatelessWidget { children: [ const Padding( child: Icon( - Icons.play_arrow, + Icons.play_arrow_rounded, size: LunaUI.FONT_SIZE_SUBTITLE, ), padding: EdgeInsets.only(right: 6.0), diff --git a/lib/modules/tautulli/routes/users_details/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/users_details/widgets/navigation_bar.dart index bb0aae8b..cf9d13f2 100644 --- a/lib/modules/tautulli/routes/users_details/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/users_details/widgets/navigation_bar.dart @@ -9,8 +9,8 @@ class TautulliUserDetailsNavigationBar extends StatelessWidget { static const List icons = [ LunaIcons.user, LunaIcons.history, - Icons.sync, - Icons.computer, + Icons.sync_rounded, + Icons.computer_rounded, ]; static const List titles = [ diff --git a/localization/sonarr/en.json b/localization/sonarr/en.json index 1bcd8f05..777e085a 100644 --- a/localization/sonarr/en.json +++ b/localization/sonarr/en.json @@ -2,6 +2,7 @@ "sonarr.AddedOn": "Added On", "sonarr.AddedSeries": "Added Series", "sonarr.AddedTag": "Added Tag", + "sonarr.AddReleaseToBlocklist": "Add Release to Blocklist", "sonarr.AddSeries": "Add Series", "sonarr.AddToExclusionList": "Add to Exclusion List", "sonarr.Age": "Age", @@ -17,6 +18,7 @@ "sonarr.Bitrate": "Bitrate", "sonarr.BitDepth": "Bit Depth", "sonarr.Channels": "Channels", + "sonarr.CheckDownloadClient": "Check download client for more details", "sonarr.Codec": "Codec", "sonarr.Client": "Client", "sonarr.Continuing": "Continuing", @@ -30,11 +32,21 @@ "sonarr.Destination": "Destination", "sonarr.DestinationRelative": "Destination Relative", "sonarr.Download": "Download", + "sonarr.Downloaded": "Downloaded", + "sonarr.DownloadedImporting": "Downloaded: Importing", + "sonarr.DownloadedWaitingToImport": "Downloaded: Waiting to Import", + "sonarr.DownloadedWaitingToProcess": "Downloaded: Waiting to Process", + "sonarr.Downloading": "Downloading", + "sonarr.DownloadingWithMessage": "Downloading: {}", "sonarr.DownloadingRelease": "Downloading Release…", + "sonarr.DownloadClientUnavailable": "Download Client is navailable", "sonarr.DownloadFailed": "Download Failed", "sonarr.DownloadID": "Download ID", "sonarr.DownloadIgnored": "Download Ignored", + "sonarr.DownloadWarning": "Download Warning", + "sonarr.DownloadWarningWithMessage": "Download Warning: {}", "sonarr.EditSeries": "Edit Series", + "sonarr.EmptyQueue": "Empty Queue", "sonarr.Ended": "Ended", "sonarr.Episode": "Episode", "sonarr.Episodes": "Episodes", @@ -52,6 +64,7 @@ "sonarr.FailedToMonitorSeason": "Failed to Monitor Season", "sonarr.FailedToMonitorSeries": "Failed to Monitor Series", "sonarr.FailedToRefresh": "Failed to Refresh", + "sonarr.FailedToRemoveFromQueue": "Failed to Remove From Queue", "sonarr.FailedToRemoveSeries": "Failed to Remove Series", "sonarr.FailedToRunRSSSync": "Failed to Run RSS Sync", "sonarr.FailedToSeasonSearch": "Failed to Season Search", @@ -61,12 +74,15 @@ "sonarr.FailedToUnmonitorSeries": "Failed to Unmonitor Series", "sonarr.FailedToUpdateLibrary": "Failed to Update Library", "sonarr.FailedToUpdateSeries": "Failed to Update Series", + "sonarr.Files": "Files", "sonarr.FilterCatalogue": "Filter Catalogue", "sonarr.FilterReleases": "Filter Releases", "sonarr.FPS": "FPS", "sonarr.GrabbedFrom": "Grabbed from {}", "sonarr.History": "History", "sonarr.HistoryDescription": "View Recent Activity", + "sonarr.Import": "Import", + "sonarr.ImportFailed": "Imported Failed", "sonarr.ImportedTo": "Imported To", "sonarr.Indexer": "Indexer", "sonarr.InfoURL": "Info URL", @@ -81,6 +97,7 @@ "sonarr.ManySeasons": "{} Seasons", "sonarr.MediaInfo": "Media Info", "sonarr.Message": "Message", + "sonarr.Messages": "Messages", "sonarr.Missing": "Missing", "sonarr.MissingEpisodes": "Missing Episodes", "sonarr.MissingEpisodesHint1": "Are you sure you want to search for all missing episodes?", @@ -95,6 +112,7 @@ "sonarr.NoEpisodesFound": "No Episodes Found", "sonarr.NoHistoryFound": "No History Found", "sonarr.NoLongerMonitoring": "No Longer Monitoring", + "sonarr.NoMessagesFound": "No Messages Found", "sonarr.NoReleasesFound": "No Releases Found", "sonarr.NoResultsFound": "No Results Found", "sonarr.NoSeasonsFound": "No Seasons Found", @@ -105,10 +123,14 @@ "sonarr.Other": "Other", "sonarr.Overview": "Overview", "sonarr.Path": "Path", + "sonarr.Paused": "Paused", + "sonarr.Pending": "Pending", + "sonarr.PendingWithMessage": "Pending: {}", "sonarr.PublishedDate": "Published Date", "sonarr.Quality": "Quality", "sonarr.QualityProfile": "Quality Profile", "sonarr.Queue": "Queue", + "sonarr.Queued": "Queued", "sonarr.QueueDescription": "View Active & Queued Content", "sonarr.Reason": "Reason", "sonarr.RefreshSeries": "Refresh Series", @@ -116,6 +138,9 @@ "sonarr.RelativePath": "Relative Path", "sonarr.Releases": "Releases", "sonarr.ReleaseGroup": "Release Group", + "sonarr.RemoveFromQueue": "Remove From Queue", + "sonarr.RemovedFromQueue": "Removed From Queue", + "sonarr.RemoveFromDownloadClient": "Remove From Download Client", "sonarr.RemoveSeries": "Remove Series", "sonarr.RemovedSeries": "Removed Series", "sonarr.RemovedSeriesWithFiles": "Removed Series (With Files)", @@ -163,6 +188,9 @@ "sonarr.SystemStatusDescription": "System Status & Disk Space", "sonarr.Tags": "Tags", "sonarr.TagsDescription": "Manage Your Tags", + "sonarr.TimeLeft": "Time Left", + "sonarr.Title": "Title", + "sonarr.Torrent": "Torrent", "sonarr.Unaired": "Unaired", "sonarr.Unmonitored": "Unmonitored", "sonarr.UnmonitorSeries": "Unmonitor Series", @@ -173,6 +201,7 @@ "sonarr.UpdatingLibrary": "Updating Library", "sonarr.UpdatingLibraryDescription": "Updating library in the background", "sonarr.UpdatedSeries": "Updated Series", + "sonarr.Usenet": "Usenet", "sonarr.UseSeasonFolders": "Use Season Folders", "sonarr.UseSeasonFoldersDescription": "Sort episodes into season folders", "sonarr.Video": "Video", diff --git a/packages/sonarr/example/main.dart b/packages/sonarr/example/main.dart index e8738df0..f1223d1a 100644 --- a/packages/sonarr/example/main.dart +++ b/packages/sonarr/example/main.dart @@ -8,5 +8,5 @@ void main() async { String key = ''; Sonarr api = Sonarr(host: host, apiKey: key); // Run your commands - api.series.get(seriesId: 1).then((data) => print(data)); + api.queue.get().then((data) => print(data)); } diff --git a/packages/sonarr/lib/commands.dart b/packages/sonarr/lib/commands.dart deleted file mode 100644 index 3dc76287..00000000 --- a/packages/sonarr/lib/commands.dart +++ /dev/null @@ -1,93 +0,0 @@ -/// Library containing all logic and accessors to make calls to Sonarr's API. -library sonarr_commands; - -import 'package:dio/dio.dart'; -import 'package:intl/intl.dart'; -import 'package:sonarr/types.dart'; -import 'models.dart'; - -// Calendar -part 'src/commands/calendar.dart'; -part 'src/commands/calendar/get_calendar.dart'; - -// Command -part 'src/commands/command.dart'; -part 'src/commands/command/backup.dart'; -part 'src/commands/command/episode_search.dart'; -part 'src/commands/command/missing_episode_search.dart'; -part 'src/commands/command/queue.dart'; -part 'src/commands/command/refresh_monitored_downloads.dart'; -part 'src/commands/command/refresh_series.dart'; -part 'src/commands/command/rescan_series.dart'; -part 'src/commands/command/rss_sync.dart'; -part 'src/commands/command/season_search.dart'; - -// Episode File -part 'src/commands/episode_file.dart'; -part 'src/commands/episode_file/delete_episode_file.dart'; -part 'src/commands/episode_file/get_episode_file.dart'; -part 'src/commands/episode_file/get_series_episode_files.dart'; - -// Episode -part 'src/commands/episode.dart'; -part 'src/commands/episode/get_episode.dart'; -part 'src/commands/episode/get_episodes.dart'; -part 'src/commands/episode/set_monitored.dart'; -part 'src/commands/episode/update_episode.dart'; - -// History -part 'src/commands/history.dart'; -part 'src/commands/history/get_history.dart'; -part 'src/commands/history/get_history_by_series.dart'; - -// Import List -part 'src/commands/import_list.dart'; -part 'src/commands/import_list/get_exclusion_list.dart'; - -// Profile -part 'src/commands/profile.dart'; -part 'src/commands/profile/get_language_profiles.dart'; -part 'src/commands/profile/get_quality_profiles.dart'; - -// Queue -part 'src/commands/queue.dart'; -part 'src/commands/queue/delete_queue.dart'; -part 'src/commands/queue/get_queue.dart'; - -// Releases -part 'src/commands/release.dart'; -part 'src/commands/release/add_release.dart'; -part 'src/commands/release/get_release.dart'; -part 'src/commands/release/get_season_release.dart'; - -// Root Folder -part 'src/commands/root_folder.dart'; -part 'src/commands/root_folder/get_root_folders.dart'; - -// Series -part 'src/commands/series.dart'; -part 'src/commands/series/add_series.dart'; -part 'src/commands/series/delete_series.dart'; -part 'src/commands/series/get_all_series.dart'; -part 'src/commands/series/get_series.dart'; -part 'src/commands/series/update_series.dart'; - -// Series Lookup -part 'src/commands/series_lookup.dart'; -part 'src/commands/series_lookup/lookup.dart'; - -// System -part 'src/commands/system.dart'; -part 'src/commands/system/get_status.dart'; - -// Tags -part 'src/commands/tag.dart'; -part 'src/commands/tag/add_tag.dart'; -part 'src/commands/tag/delete_tag.dart'; -part 'src/commands/tag/get_all_tags.dart'; -part 'src/commands/tag/get_tag.dart'; -part 'src/commands/tag/update_tag.dart'; - -// Wanted/Missing -part 'src/commands/wanted.dart'; -part 'src/commands/wanted/get_missing.dart'; diff --git a/packages/sonarr/lib/controllers.dart b/packages/sonarr/lib/controllers.dart new file mode 100644 index 00000000..d5a71630 --- /dev/null +++ b/packages/sonarr/lib/controllers.dart @@ -0,0 +1,94 @@ +/// Library containing all logic and accessors to make calls to Sonarr's API. +library sonarr_commands; + +import 'package:dio/dio.dart'; +import 'package:intl/intl.dart'; +import 'package:sonarr/types.dart'; +import 'models.dart'; + +// Calendar +part 'src/controllers/calendar.dart'; +part 'src/controllers/calendar/get_calendar.dart'; + +// Command +part 'src/controllers/command.dart'; +part 'src/controllers/command/backup.dart'; +part 'src/controllers/command/episode_search.dart'; +part 'src/controllers/command/missing_episode_search.dart'; +part 'src/controllers/command/queue.dart'; +part 'src/controllers/command/refresh_monitored_downloads.dart'; +part 'src/controllers/command/refresh_series.dart'; +part 'src/controllers/command/rescan_series.dart'; +part 'src/controllers/command/rss_sync.dart'; +part 'src/controllers/command/season_search.dart'; + +// Episode File +part 'src/controllers/episode_file.dart'; +part 'src/controllers/episode_file/delete_episode_file.dart'; +part 'src/controllers/episode_file/get_episode_file.dart'; +part 'src/controllers/episode_file/get_series_episode_files.dart'; + +// Episode +part 'src/controllers/episode.dart'; +part 'src/controllers/episode/get_episode.dart'; +part 'src/controllers/episode/get_episodes.dart'; +part 'src/controllers/episode/set_monitored.dart'; +part 'src/controllers/episode/update_episode.dart'; + +// History +part 'src/controllers/history.dart'; +part 'src/controllers/history/get_history.dart'; +part 'src/controllers/history/get_history_by_series.dart'; + +// Import List +part 'src/controllers/import_list.dart'; +part 'src/controllers/import_list/get_exclusion_list.dart'; + +// Profile +part 'src/controllers/profile.dart'; +part 'src/controllers/profile/get_language_profiles.dart'; +part 'src/controllers/profile/get_quality_profiles.dart'; + +// Queue +part 'src/controllers/queue.dart'; +part 'src/controllers/queue/delete_queue.dart'; +part 'src/controllers/queue/get_queue.dart'; +part 'src/controllers/queue/get_queue_details.dart'; + +// Releases +part 'src/controllers/release.dart'; +part 'src/controllers/release/add_release.dart'; +part 'src/controllers/release/get_release.dart'; +part 'src/controllers/release/get_season_release.dart'; + +// Root Folder +part 'src/controllers/root_folder.dart'; +part 'src/controllers/root_folder/get_root_folders.dart'; + +// Series +part 'src/controllers/series.dart'; +part 'src/controllers/series/add_series.dart'; +part 'src/controllers/series/delete_series.dart'; +part 'src/controllers/series/get_all_series.dart'; +part 'src/controllers/series/get_series.dart'; +part 'src/controllers/series/update_series.dart'; + +// Series Lookup +part 'src/controllers/series_lookup.dart'; +part 'src/controllers/series_lookup/lookup.dart'; + +// System +part 'src/controllers/system.dart'; +part 'src/controllers/system/get_status.dart'; + +// Tags +part 'src/controllers/tag.dart'; +part 'src/controllers/tag/add_tag.dart'; +part 'src/controllers/tag/delete_tag.dart'; +part 'src/controllers/tag/get_all_tags.dart'; +part 'src/controllers/tag/get_tag.dart'; +part 'src/controllers/tag/update_tag.dart'; + +// Wanted/Missing +part 'src/controllers/wanted.dart'; +part 'src/controllers/wanted/get_missing.dart'; diff --git a/packages/sonarr/lib/models.dart b/packages/sonarr/lib/models.dart index 9a8c23a7..8a4a9bec 100644 --- a/packages/sonarr/lib/models.dart +++ b/packages/sonarr/lib/models.dart @@ -37,6 +37,7 @@ export 'src/models/profile/quality_profile_item.dart'; export 'src/models/profile/quality_profile.dart'; /// Queue +export 'src/models/queue/queue.dart'; export 'src/models/queue/queue_record.dart'; export 'src/models/queue/queue_status_message.dart'; diff --git a/packages/sonarr/lib/sonarr.dart b/packages/sonarr/lib/sonarr.dart index 957430b1..3cff9173 100644 --- a/packages/sonarr/lib/sonarr.dart +++ b/packages/sonarr/lib/sonarr.dart @@ -1,8 +1,8 @@ library sonarr; import 'package:dio/dio.dart'; -import 'commands.dart'; -export 'commands.dart'; +import 'controllers.dart'; +export 'controllers.dart'; export 'models.dart'; export 'types.dart'; export 'utilities.dart'; @@ -47,21 +47,21 @@ class Sonarr { ); return Sonarr._internal( httpClient: _dio, - calendar: SonarrCommandHandler_Calendar(_dio), - command: SonarrCommandHandler_Command(_dio), - episode: SonarrCommandHandler_Episode(_dio), - episodeFile: SonarrCommandHandler_EpisodeFile(_dio), - history: SonarrCommandHandler_History(_dio), - importList: SonarrCommandHandler_ImportList(_dio), - profile: SonarrCommandHandler_Profile(_dio), - queue: SonarrCommandHandler_Queue(_dio), - release: SonarrCommandHandler_Release(_dio), - rootFolder: SonarrCommandHandler_RootFolder(_dio), - series: SonarrCommandHandler_Series(_dio), - seriesLookup: SonarrCommandHandler_SeriesLookup(_dio), - system: SonarrCommandHandler_System(_dio), - tag: SonarrCommandHandler_Tag(_dio), - wanted: SonarrCommandHandler_Wanted(_dio), + calendar: SonarrController_Calendar(_dio), + command: SonarrController_Command(_dio), + episode: SonarrController_Episode(_dio), + episodeFile: SonarrController_EpisodeFile(_dio), + history: SonarrController_History(_dio), + importList: SonarrController_ImportList(_dio), + profile: SonarrController_Profile(_dio), + queue: SonarrController_Queue(_dio), + release: SonarrController_Release(_dio), + rootFolder: SonarrController_RootFolder(_dio), + series: SonarrController_Series(_dio), + seriesLookup: SonarrController_SeriesLookup(_dio), + system: SonarrController_System(_dio), + tag: SonarrController_Tag(_dio), + wanted: SonarrController_Wanted(_dio), ); } @@ -70,39 +70,39 @@ class Sonarr { }) { return Sonarr._internal( httpClient: client, - calendar: SonarrCommandHandler_Calendar(client), - command: SonarrCommandHandler_Command(client), - episode: SonarrCommandHandler_Episode(client), - episodeFile: SonarrCommandHandler_EpisodeFile(client), - history: SonarrCommandHandler_History(client), - importList: SonarrCommandHandler_ImportList(client), - profile: SonarrCommandHandler_Profile(client), - queue: SonarrCommandHandler_Queue(client), - release: SonarrCommandHandler_Release(client), - rootFolder: SonarrCommandHandler_RootFolder(client), - series: SonarrCommandHandler_Series(client), - seriesLookup: SonarrCommandHandler_SeriesLookup(client), - system: SonarrCommandHandler_System(client), - tag: SonarrCommandHandler_Tag(client), - wanted: SonarrCommandHandler_Wanted(client), + calendar: SonarrController_Calendar(client), + command: SonarrController_Command(client), + episode: SonarrController_Episode(client), + episodeFile: SonarrController_EpisodeFile(client), + history: SonarrController_History(client), + importList: SonarrController_ImportList(client), + profile: SonarrController_Profile(client), + queue: SonarrController_Queue(client), + release: SonarrController_Release(client), + rootFolder: SonarrController_RootFolder(client), + series: SonarrController_Series(client), + seriesLookup: SonarrController_SeriesLookup(client), + system: SonarrController_System(client), + tag: SonarrController_Tag(client), + wanted: SonarrController_Wanted(client), ); } final Dio httpClient; - final SonarrCommandHandler_Calendar calendar; - final SonarrCommandHandler_Command command; - final SonarrCommandHandler_Episode episode; - final SonarrCommandHandler_EpisodeFile episodeFile; - final SonarrCommandHandler_History history; - final SonarrCommandHandler_ImportList importList; - final SonarrCommandHandler_Profile profile; - final SonarrCommandHandler_Queue queue; - final SonarrCommandHandler_Release release; - final SonarrCommandHandler_RootFolder rootFolder; - final SonarrCommandHandler_Series series; - final SonarrCommandHandler_SeriesLookup seriesLookup; - final SonarrCommandHandler_System system; - final SonarrCommandHandler_Tag tag; - final SonarrCommandHandler_Wanted wanted; + final SonarrController_Calendar calendar; + final SonarrController_Command command; + final SonarrController_Episode episode; + final SonarrController_EpisodeFile episodeFile; + final SonarrController_History history; + final SonarrController_ImportList importList; + final SonarrController_Profile profile; + final SonarrController_Queue queue; + final SonarrController_Release release; + final SonarrController_RootFolder rootFolder; + final SonarrController_Series series; + final SonarrController_SeriesLookup seriesLookup; + final SonarrController_System system; + final SonarrController_Tag tag; + final SonarrController_Wanted wanted; } diff --git a/packages/sonarr/lib/src/commands/command.dart b/packages/sonarr/lib/src/commands/command.dart deleted file mode 100644 index 7cc9e970..00000000 --- a/packages/sonarr/lib/src/commands/command.dart +++ /dev/null @@ -1,82 +0,0 @@ -part of sonarr_commands; - -/// Facilitates, encapsulates, and manages individual calls related to commands within Sonarr. -/// -/// [SonarrCommandHandler_Command] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Command { - final Dio _client; - - /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Command(this._client); - - /// Handler for [command (Backup)](https://github.com/Sonarr/Sonarr/wiki/Command#backup). - /// - /// Instruct Sonarr to perform a backup of its database and config file (nzbdrone.db and config.xml). - Future backup() async => _commandBackup(_client); - - /// Handler for [command (EpisodeSearch)](https://github.com/Sonarr/Sonarr/wiki/Command#episodesearch). - /// - /// Search for one or more episodes. - /// - /// Required Parameters: - /// - `episodeIds`: List of episode identifiers to search for - Future episodeSearch({ - required List episodeIds, - }) async => _commandEpisodeSearch(_client, episodeIds: episodeIds); - - /// Handler for [command](https://github.com/Sonarr/Sonarr/wiki/Command#get). - /// - /// Queries the status of a previously started command, or all currently started commands. - Future> queue() async => _commandCommandQueue(_client); - - /// Handler for [command (MissingEpisodeSearch)](https://github.com/Sonarr/Sonarr/wiki/Command#missingepisodesearch). - /// - /// Instruct Sonarr to perform a backlog search of missing episodes (Similar functionality to Sickbeard). - Future missingEpisodeSearch() async => _commandMissingEpisodeSearch(_client); - - /// Handler for [command (RefreshMonitoredDownloads)](https://github.com/Sonarr/Sonarr/wiki/Command). - /// - /// Refresh the actively monitored downloads in the queue. - Future refreshMonitoredDownloads({ - int? seriesId, - }) async => _commandRefreshMonitoredDownloads(_client); - - /// Handler for [command (RefreshSeries)](https://github.com/Sonarr/Sonarr/wiki/Command#refreshseries). - /// - /// Refresh series information from trakt and rescan disk. - /// If no `seriesId` is supplied, all series are refreshed. - /// - /// Optional Parameters: - /// - `seriesId`: Series ID for the series to refresh - Future refreshSeries({ - int? seriesId, - }) async => _commandRefreshSeries(_client, seriesId: seriesId); - - /// Handler for [command (RescanSeries)](https://github.com/Sonarr/Sonarr/wiki/Command#rescanseries). - /// - /// Refresh rescan disk for a single series. - /// If no `seriesId` is supplied, all series are rescanned. - /// - /// Optional Parameters: - /// - `seriesId`: Series ID for the series to refresh - Future rescanSeries({ - int? seriesId, - }) async => _commandRescanSeries(_client, seriesId: seriesId); - - /// Handler for [command (RssSync)](https://github.com/Sonarr/Sonarr/wiki/Command#rsssync). - /// - /// Instruct Sonarr to perform an RSS sync with all enabled indexers. - Future rssSync() async => _commandRSSSync(_client); - - /// Handler for [command (EpisodeSearch)](https://github.com/Sonarr/Sonarr/wiki/Command#episodesearch). - /// - /// Search for all episodes of a particular season. - /// - /// Required Parameters: - /// - `seriesId`: Series identifier - /// - `seasonNumber`: Season number to search for - Future seasonSearch({ - required int seriesId, - required int seasonNumber, - }) async => _commandSeasonSearch(_client, seriesId: seriesId, seasonNumber: seasonNumber); -} diff --git a/packages/sonarr/lib/src/commands/queue.dart b/packages/sonarr/lib/src/commands/queue.dart deleted file mode 100644 index 9f047eb4..00000000 --- a/packages/sonarr/lib/src/commands/queue.dart +++ /dev/null @@ -1,24 +0,0 @@ -part of sonarr_commands; - -/// Facilitates, encapsulates, and manages individual calls related to queue within Sonarr. -/// -/// [SonarrCommandHandler_Queue] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Queue { - final Dio _client; - - /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Queue(this._client); - - /// Handler for [queue](https://github.com/Sonarr/Sonarr/wiki/Queue#get). - /// - /// Gets currently downloading (queue) information. - Future> getQueue() async => _commandGetQueue(_client); - - /// Handler for [queue](https://github.com/Sonarr/Sonarr/wiki/Queue#delete). - /// - /// Deletes an item from the queue and download client.. - Future deleteQueue({ - required int id, - bool? blacklist, - }) async => _commandDeleteQueue(_client, id: id, blacklist: blacklist); -} diff --git a/packages/sonarr/lib/src/commands/queue/delete_queue.dart b/packages/sonarr/lib/src/commands/queue/delete_queue.dart deleted file mode 100644 index 5d5ec384..00000000 --- a/packages/sonarr/lib/src/commands/queue/delete_queue.dart +++ /dev/null @@ -1,10 +0,0 @@ -part of sonarr_commands; - -Future _commandDeleteQueue(Dio client, { - required int id, - bool? blacklist, -}) async { - await client.delete('queue/$id', queryParameters: { - if(blacklist != null) 'blacklist': blacklist, - }); -} diff --git a/packages/sonarr/lib/src/commands/queue/get_queue.dart b/packages/sonarr/lib/src/commands/queue/get_queue.dart deleted file mode 100644 index 8ef6637f..00000000 --- a/packages/sonarr/lib/src/commands/queue/get_queue.dart +++ /dev/null @@ -1,6 +0,0 @@ -part of sonarr_commands; - -Future> _commandGetQueue(Dio client) async { - Response response = await client.get('queue'); - return (response.data as List).map((record) => SonarrQueueRecord.fromJson(record)).toList(); -} diff --git a/packages/sonarr/lib/src/commands/root_folder.dart b/packages/sonarr/lib/src/commands/root_folder.dart deleted file mode 100644 index 6e53e934..00000000 --- a/packages/sonarr/lib/src/commands/root_folder.dart +++ /dev/null @@ -1,16 +0,0 @@ -part of sonarr_commands; - -/// Facilitates, encapsulates, and manages individual calls related to root folders within Sonarr. -/// -/// [SonarrCommandHandler_RootFolder] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_RootFolder { - final Dio _client; - - /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_RootFolder(this._client); - - /// Handler for [rootfolder](https://github.com/Sonarr/Sonarr/wiki/Rootfolder#get). - /// - /// Returns a list of root folders. - Future> getRootFolders() async => _commandGetRootFolders(_client); -} diff --git a/packages/sonarr/lib/src/commands/system.dart b/packages/sonarr/lib/src/commands/system.dart deleted file mode 100644 index dabbd4ea..00000000 --- a/packages/sonarr/lib/src/commands/system.dart +++ /dev/null @@ -1,16 +0,0 @@ -part of sonarr_commands; - -/// Facilitates, encapsulates, and manages individual calls related to system within Sonarr. -/// -/// [SonarrCommandHandler_System] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_System { - final Dio _client; - - /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_System(this._client); - - /// Handler for [system/status](https://github.com/Sonarr/Sonarr/wiki/System-Status#get). - /// - /// Returns system status information. - Future getStatus() async => _commandGetStatus(_client); -} diff --git a/packages/sonarr/lib/src/commands/tag.dart b/packages/sonarr/lib/src/commands/tag.dart deleted file mode 100644 index 2863ff4e..00000000 --- a/packages/sonarr/lib/src/commands/tag.dart +++ /dev/null @@ -1,56 +0,0 @@ -part of sonarr_commands; - -/// Facilitates, encapsulates, and manages individual calls related to tags within Sonarr. -/// -/// [SonarrCommandHandler_Tag] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Tag { - final Dio _client; - - /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Tag(this._client); - - /// Handler for [tag](https://github.com/Sonarr/Sonarr/wiki/Tag#post). - /// - /// Adds a new tag. - /// - /// Required Parameters: - /// - `label`: Tag label - Future create({ - required String label, - }) async => _commandAddTag(_client, label: label); - - /// Handler for [tag/{id}](https://github.com/Sonarr/Sonarr/wiki/Tag#deleteid). - /// - /// Delete the tag with the given ID. - /// - /// Required Parameters: - /// - `id`: Tag identifier - Future deleteTag({ - required int id, - }) async => _commandDeleteTag(_client, id: id); - - /// Handler for [tag/{id}](https://github.com/Sonarr/Sonarr/wiki/Tag#getid). - /// - /// Returns the tag with the matching ID. - /// - /// Required Parameters: - /// - `id`: Tag identifier - Future getTag({ - required int id, - }) async => _commandGetTag(_client, id: id); - - /// Handler for [tag](https://github.com/Sonarr/Sonarr/wiki/Tag#get). - /// - /// Returns a list of all tags. - Future> getAllTags() async => _commandGetAllTags(_client); - - /// Handler for [tag](https://github.com/Sonarr/Sonarr/wiki/Tag#put). - /// - /// Update an existing tag. - /// - /// Required Parameters: - /// - `tag`: A modified [SonarrTag] object - Future updateTag({ - required SonarrTag tag, - }) async => _commandUpdateTag(_client, tag: tag); -} diff --git a/packages/sonarr/lib/src/commands/calendar.dart b/packages/sonarr/lib/src/controllers/calendar.dart similarity index 83% rename from packages/sonarr/lib/src/commands/calendar.dart rename to packages/sonarr/lib/src/controllers/calendar.dart index 4d705ef7..6bb179e2 100644 --- a/packages/sonarr/lib/src/commands/calendar.dart +++ b/packages/sonarr/lib/src/controllers/calendar.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to calendar within Sonarr. /// -/// [SonarrCommandHandler_Calendar] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Calendar { +/// [SonarrController_Calendar] internally handles routing the HTTP client to the API calls. +class SonarrController_Calendar { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Calendar(this._client); + SonarrController_Calendar(this._client); /// Handler for [calendar](https://github.com/Sonarr/Sonarr/wiki/Calendar#get). /// diff --git a/packages/sonarr/lib/src/commands/calendar/get_calendar.dart b/packages/sonarr/lib/src/controllers/calendar/get_calendar.dart similarity index 100% rename from packages/sonarr/lib/src/commands/calendar/get_calendar.dart rename to packages/sonarr/lib/src/controllers/calendar/get_calendar.dart diff --git a/packages/sonarr/lib/src/controllers/command.dart b/packages/sonarr/lib/src/controllers/command.dart new file mode 100644 index 00000000..ab5efdd6 --- /dev/null +++ b/packages/sonarr/lib/src/controllers/command.dart @@ -0,0 +1,87 @@ +part of sonarr_commands; + +/// Facilitates, encapsulates, and manages individual calls related to commands within Sonarr. +/// +/// [SonarrController_Command] internally handles routing the HTTP client to the API calls. +class SonarrController_Command { + final Dio _client; + + /// Create a series command handler using an initialized [Dio] client. + SonarrController_Command(this._client); + + /// Handler for [command (Backup)](https://github.com/Sonarr/Sonarr/wiki/Command#backup). + /// + /// Instruct Sonarr to perform a backup of its database and config file (nzbdrone.db and config.xml). + Future backup() async => _commandBackup(_client); + + /// Handler for [command (EpisodeSearch)](https://github.com/Sonarr/Sonarr/wiki/Command#episodesearch). + /// + /// Search for one or more episodes. + /// + /// Required Parameters: + /// - `episodeIds`: List of episode identifiers to search for + Future episodeSearch({ + required List episodeIds, + }) async => + _commandEpisodeSearch(_client, episodeIds: episodeIds); + + /// Handler for [command](https://github.com/Sonarr/Sonarr/wiki/Command#get). + /// + /// Queries the status of a previously started command, or all currently started commands. + Future> queue() async => _commandCommandQueue(_client); + + /// Handler for [command (MissingEpisodeSearch)](https://github.com/Sonarr/Sonarr/wiki/Command#missingepisodesearch). + /// + /// Instruct Sonarr to perform a backlog search of missing episodes (Similar functionality to Sickbeard). + Future missingEpisodeSearch() async => + _commandMissingEpisodeSearch(_client); + + /// Handler for [command (RefreshMonitoredDownloads)](https://github.com/Sonarr/Sonarr/wiki/Command). + /// + /// Refresh the actively monitored downloads in the queue. + Future refreshMonitoredDownloads() async => + _commandRefreshMonitoredDownloads(_client); + + /// Handler for [command (RefreshSeries)](https://github.com/Sonarr/Sonarr/wiki/Command#refreshseries). + /// + /// Refresh series information from trakt and rescan disk. + /// If no `seriesId` is supplied, all series are refreshed. + /// + /// Optional Parameters: + /// - `seriesId`: Series ID for the series to refresh + Future refreshSeries({ + int? seriesId, + }) async => + _commandRefreshSeries(_client, seriesId: seriesId); + + /// Handler for [command (RescanSeries)](https://github.com/Sonarr/Sonarr/wiki/Command#rescanseries). + /// + /// Refresh rescan disk for a single series. + /// If no `seriesId` is supplied, all series are rescanned. + /// + /// Optional Parameters: + /// - `seriesId`: Series ID for the series to refresh + Future rescanSeries({ + int? seriesId, + }) async => + _commandRescanSeries(_client, seriesId: seriesId); + + /// Handler for [command (RssSync)](https://github.com/Sonarr/Sonarr/wiki/Command#rsssync). + /// + /// Instruct Sonarr to perform an RSS sync with all enabled indexers. + Future rssSync() async => _commandRSSSync(_client); + + /// Handler for [command (EpisodeSearch)](https://github.com/Sonarr/Sonarr/wiki/Command#episodesearch). + /// + /// Search for all episodes of a particular season. + /// + /// Required Parameters: + /// - `seriesId`: Series identifier + /// - `seasonNumber`: Season number to search for + Future seasonSearch({ + required int seriesId, + required int seasonNumber, + }) async => + _commandSeasonSearch(_client, + seriesId: seriesId, seasonNumber: seasonNumber); +} diff --git a/packages/sonarr/lib/src/commands/command/backup.dart b/packages/sonarr/lib/src/controllers/command/backup.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/backup.dart rename to packages/sonarr/lib/src/controllers/command/backup.dart diff --git a/packages/sonarr/lib/src/commands/command/episode_search.dart b/packages/sonarr/lib/src/controllers/command/episode_search.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/episode_search.dart rename to packages/sonarr/lib/src/controllers/command/episode_search.dart diff --git a/packages/sonarr/lib/src/commands/command/missing_episode_search.dart b/packages/sonarr/lib/src/controllers/command/missing_episode_search.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/missing_episode_search.dart rename to packages/sonarr/lib/src/controllers/command/missing_episode_search.dart diff --git a/packages/sonarr/lib/src/commands/command/queue.dart b/packages/sonarr/lib/src/controllers/command/queue.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/queue.dart rename to packages/sonarr/lib/src/controllers/command/queue.dart diff --git a/packages/sonarr/lib/src/commands/command/refresh_monitored_downloads.dart b/packages/sonarr/lib/src/controllers/command/refresh_monitored_downloads.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/refresh_monitored_downloads.dart rename to packages/sonarr/lib/src/controllers/command/refresh_monitored_downloads.dart diff --git a/packages/sonarr/lib/src/commands/command/refresh_series.dart b/packages/sonarr/lib/src/controllers/command/refresh_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/refresh_series.dart rename to packages/sonarr/lib/src/controllers/command/refresh_series.dart diff --git a/packages/sonarr/lib/src/commands/command/rescan_series.dart b/packages/sonarr/lib/src/controllers/command/rescan_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/rescan_series.dart rename to packages/sonarr/lib/src/controllers/command/rescan_series.dart diff --git a/packages/sonarr/lib/src/commands/command/rss_sync.dart b/packages/sonarr/lib/src/controllers/command/rss_sync.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/rss_sync.dart rename to packages/sonarr/lib/src/controllers/command/rss_sync.dart diff --git a/packages/sonarr/lib/src/commands/command/season_search.dart b/packages/sonarr/lib/src/controllers/command/season_search.dart similarity index 100% rename from packages/sonarr/lib/src/commands/command/season_search.dart rename to packages/sonarr/lib/src/controllers/command/season_search.dart diff --git a/packages/sonarr/lib/src/commands/episode.dart b/packages/sonarr/lib/src/controllers/episode.dart similarity index 90% rename from packages/sonarr/lib/src/commands/episode.dart rename to packages/sonarr/lib/src/controllers/episode.dart index ca9544da..d8aba1f6 100644 --- a/packages/sonarr/lib/src/commands/episode.dart +++ b/packages/sonarr/lib/src/controllers/episode.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to episodes within Sonarr. /// -/// [SonarrCommandHandler_Episode] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Episode { +/// [SonarrController_Episode] internally handles routing the HTTP client to the API calls. +class SonarrController_Episode { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Episode(this._client); + SonarrController_Episode(this._client); /// Handler for [episode](https://github.com/Sonarr/Sonarr/wiki/Episode#get). /// diff --git a/packages/sonarr/lib/src/commands/episode/get_episode.dart b/packages/sonarr/lib/src/controllers/episode/get_episode.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode/get_episode.dart rename to packages/sonarr/lib/src/controllers/episode/get_episode.dart diff --git a/packages/sonarr/lib/src/commands/episode/get_episodes.dart b/packages/sonarr/lib/src/controllers/episode/get_episodes.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode/get_episodes.dart rename to packages/sonarr/lib/src/controllers/episode/get_episodes.dart diff --git a/packages/sonarr/lib/src/commands/episode/set_monitored.dart b/packages/sonarr/lib/src/controllers/episode/set_monitored.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode/set_monitored.dart rename to packages/sonarr/lib/src/controllers/episode/set_monitored.dart diff --git a/packages/sonarr/lib/src/commands/episode/update_episode.dart b/packages/sonarr/lib/src/controllers/episode/update_episode.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode/update_episode.dart rename to packages/sonarr/lib/src/controllers/episode/update_episode.dart diff --git a/packages/sonarr/lib/src/commands/episode_file.dart b/packages/sonarr/lib/src/controllers/episode_file.dart similarity index 88% rename from packages/sonarr/lib/src/commands/episode_file.dart rename to packages/sonarr/lib/src/controllers/episode_file.dart index 9fdb2bf7..d3a17972 100644 --- a/packages/sonarr/lib/src/commands/episode_file.dart +++ b/packages/sonarr/lib/src/controllers/episode_file.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to episode files within Sonarr. /// -/// [SonarrCommandHandler_EpisodeFile] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_EpisodeFile { +/// [SonarrController_EpisodeFile] internally handles routing the HTTP client to the API calls. +class SonarrController_EpisodeFile { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_EpisodeFile(this._client); + SonarrController_EpisodeFile(this._client); /// Handler for [episodefile/{id}](https://github.com/Sonarr/Sonarr/wiki/EpisodeFile#delete). /// diff --git a/packages/sonarr/lib/src/commands/episode_file/delete_episode_file.dart b/packages/sonarr/lib/src/controllers/episode_file/delete_episode_file.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode_file/delete_episode_file.dart rename to packages/sonarr/lib/src/controllers/episode_file/delete_episode_file.dart diff --git a/packages/sonarr/lib/src/commands/episode_file/get_episode_file.dart b/packages/sonarr/lib/src/controllers/episode_file/get_episode_file.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode_file/get_episode_file.dart rename to packages/sonarr/lib/src/controllers/episode_file/get_episode_file.dart diff --git a/packages/sonarr/lib/src/commands/episode_file/get_series_episode_files.dart b/packages/sonarr/lib/src/controllers/episode_file/get_series_episode_files.dart similarity index 100% rename from packages/sonarr/lib/src/commands/episode_file/get_series_episode_files.dart rename to packages/sonarr/lib/src/controllers/episode_file/get_series_episode_files.dart diff --git a/packages/sonarr/lib/src/commands/history.dart b/packages/sonarr/lib/src/controllers/history.dart similarity index 90% rename from packages/sonarr/lib/src/commands/history.dart rename to packages/sonarr/lib/src/controllers/history.dart index 557add01..b11a12e0 100644 --- a/packages/sonarr/lib/src/commands/history.dart +++ b/packages/sonarr/lib/src/controllers/history.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to history within Sonarr. /// -/// [SonarrCommandHandler_History] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_History { +/// [SonarrController_History] internally handles routing the HTTP client to the API calls. +class SonarrController_History { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_History(this._client); + SonarrController_History(this._client); /// Handler for [history](https://github.com/Sonarr/Sonarr/wiki/History#get). /// diff --git a/packages/sonarr/lib/src/commands/history/get_history.dart b/packages/sonarr/lib/src/controllers/history/get_history.dart similarity index 100% rename from packages/sonarr/lib/src/commands/history/get_history.dart rename to packages/sonarr/lib/src/controllers/history/get_history.dart diff --git a/packages/sonarr/lib/src/commands/history/get_history_by_series.dart b/packages/sonarr/lib/src/controllers/history/get_history_by_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/history/get_history_by_series.dart rename to packages/sonarr/lib/src/controllers/history/get_history_by_series.dart diff --git a/packages/sonarr/lib/src/commands/import_list.dart b/packages/sonarr/lib/src/controllers/import_list.dart similarity index 52% rename from packages/sonarr/lib/src/commands/import_list.dart rename to packages/sonarr/lib/src/controllers/import_list.dart index ac29ddf7..24bc234e 100644 --- a/packages/sonarr/lib/src/commands/import_list.dart +++ b/packages/sonarr/lib/src/controllers/import_list.dart @@ -2,13 +2,13 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to import lists within Sonarr. /// -/// [SonarrCommandHandler_ImportList] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_ImportList { +/// [SonarrController_ImportList] internally handles routing the HTTP client to the API calls. +class SonarrController_ImportList { final Dio _client; /// Create an import list command handler using an initialized [Dio] client. - SonarrCommandHandler_ImportList(this._client); + SonarrController_ImportList(this._client); - Future> getExclusionList() async => + Future> get() async => _commandGetExclusionList(_client); } diff --git a/packages/sonarr/lib/src/commands/import_list/get_exclusion_list.dart b/packages/sonarr/lib/src/controllers/import_list/get_exclusion_list.dart similarity index 100% rename from packages/sonarr/lib/src/commands/import_list/get_exclusion_list.dart rename to packages/sonarr/lib/src/controllers/import_list/get_exclusion_list.dart diff --git a/packages/sonarr/lib/src/commands/profile.dart b/packages/sonarr/lib/src/controllers/profile.dart similarity index 80% rename from packages/sonarr/lib/src/commands/profile.dart rename to packages/sonarr/lib/src/controllers/profile.dart index 14b1402b..ee93870e 100644 --- a/packages/sonarr/lib/src/commands/profile.dart +++ b/packages/sonarr/lib/src/controllers/profile.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to profiles within Sonarr. /// -/// [SonarrCommandHandler_Profile] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Profile { +/// [SonarrController_Profile] internally handles routing the HTTP client to the API calls. +class SonarrController_Profile { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Profile(this._client); + SonarrController_Profile(this._client); /// Handler for [profile](https://github.com/Sonarr/Sonarr/wiki/Profile#get). /// diff --git a/packages/sonarr/lib/src/commands/profile/get_language_profiles.dart b/packages/sonarr/lib/src/controllers/profile/get_language_profiles.dart similarity index 100% rename from packages/sonarr/lib/src/commands/profile/get_language_profiles.dart rename to packages/sonarr/lib/src/controllers/profile/get_language_profiles.dart diff --git a/packages/sonarr/lib/src/commands/profile/get_quality_profiles.dart b/packages/sonarr/lib/src/controllers/profile/get_quality_profiles.dart similarity index 100% rename from packages/sonarr/lib/src/commands/profile/get_quality_profiles.dart rename to packages/sonarr/lib/src/controllers/profile/get_quality_profiles.dart diff --git a/packages/sonarr/lib/src/controllers/queue.dart b/packages/sonarr/lib/src/controllers/queue.dart new file mode 100644 index 00000000..07c06cda --- /dev/null +++ b/packages/sonarr/lib/src/controllers/queue.dart @@ -0,0 +1,66 @@ +part of sonarr_commands; + +/// Facilitates, encapsulates, and manages individual calls related to queue within Sonarr. +/// +/// [SonarrController_Queue] internally handles routing the HTTP client to the API calls. +class SonarrController_Queue { + final Dio _client; + + /// Create a series command handler using an initialized [Dio] client. + SonarrController_Queue(this._client); + + /// Handler for [queue](https://github.com/Sonarr/Sonarr/wiki/Queue#get). + /// + /// Gets currently downloading (queue) information. + Future get({ + bool? includeUnknownSeriesItems, + bool? includeSeries, + bool? includeEpisode, + SonarrSortDirection? sortDirection, + SonarrQueueSortKey? sortKey, + int? page, + int? pageSize, + }) async => + _commandGetQueue( + _client, + includeUnknownSeriesItems: includeUnknownSeriesItems, + includeEpisode: includeEpisode, + includeSeries: includeSeries, + sortDirection: sortDirection, + sortKey: sortKey, + page: page, + pageSize: pageSize, + ); + + /// Handler for [queue/details](https://github.com/Sonarr/Sonarr/wiki/Queue#get). + /// + /// Gets currently downloading (queue) information. + Future> getDetails({ + int? seriesId, + List? episodeIds, + bool? includeSeries, + bool? includeEpisode, + }) async => + _commandGetQueueDetails( + _client, + seriesId: seriesId, + episodeIds: episodeIds, + includeSeries: includeSeries, + includeEpisode: includeEpisode, + ); + + /// Handler for [queue](https://github.com/Sonarr/Sonarr/wiki/Queue#delete). + /// + /// Deletes an item from the queue and download client.. + Future delete({ + required int id, + bool? removeFromClient, + bool? blocklist, + }) async => + _commandDeleteQueue( + _client, + id: id, + blocklist: blocklist, + removeFromClient: removeFromClient, + ); +} diff --git a/packages/sonarr/lib/src/controllers/queue/delete_queue.dart b/packages/sonarr/lib/src/controllers/queue/delete_queue.dart new file mode 100644 index 00000000..e28eceed --- /dev/null +++ b/packages/sonarr/lib/src/controllers/queue/delete_queue.dart @@ -0,0 +1,13 @@ +part of sonarr_commands; + +Future _commandDeleteQueue( + Dio client, { + required int id, + bool? removeFromClient, + bool? blocklist, +}) async { + await client.delete('queue/$id', queryParameters: { + if (removeFromClient != null) 'removeFromClient': removeFromClient, + if (blocklist != null) 'blocklist': blocklist, + }); +} diff --git a/packages/sonarr/lib/src/controllers/queue/get_queue.dart b/packages/sonarr/lib/src/controllers/queue/get_queue.dart new file mode 100644 index 00000000..b4270167 --- /dev/null +++ b/packages/sonarr/lib/src/controllers/queue/get_queue.dart @@ -0,0 +1,24 @@ +part of sonarr_commands; + +Future _commandGetQueue( + Dio client, { + bool? includeUnknownSeriesItems, + bool? includeSeries, + bool? includeEpisode, + SonarrSortDirection? sortDirection, + SonarrQueueSortKey? sortKey, + int? page, + int? pageSize, +}) async { + Response response = await client.get('queue', queryParameters: { + if (includeUnknownSeriesItems != null) + 'includeUnknownSeriesItems': includeUnknownSeriesItems, + if (includeSeries != null) 'includeSeries': includeSeries, + if (includeEpisode != null) 'includeEpisode': includeEpisode, + if (sortDirection != null) 'sortDirection': sortDirection.value, + if (sortKey != null) 'sortKey': sortKey.value, + if (page != null) 'page': pageSize, + if (pageSize != null) 'pageSize': pageSize, + }); + return SonarrQueue.fromJson(response.data); +} diff --git a/packages/sonarr/lib/src/controllers/queue/get_queue_details.dart b/packages/sonarr/lib/src/controllers/queue/get_queue_details.dart new file mode 100644 index 00000000..68e386c1 --- /dev/null +++ b/packages/sonarr/lib/src/controllers/queue/get_queue_details.dart @@ -0,0 +1,19 @@ +part of sonarr_commands; + +Future> _commandGetQueueDetails( + Dio client, { + int? seriesId, + List? episodeIds, + bool? includeSeries, + bool? includeEpisode, +}) async { + Response response = await client.get('queue/details', queryParameters: { + if (episodeIds != null) 'episodeIds': episodeIds, + if (seriesId != null) 'seriesId': seriesId, + if (includeSeries != null) 'includeSeries': includeSeries, + if (includeEpisode != null) 'includeEpisode': includeEpisode, + }); + return (response.data as List) + .map((series) => SonarrQueueRecord.fromJson(series)) + .toList(); +} diff --git a/packages/sonarr/lib/src/commands/release.dart b/packages/sonarr/lib/src/controllers/release.dart similarity index 88% rename from packages/sonarr/lib/src/commands/release.dart rename to packages/sonarr/lib/src/controllers/release.dart index ed4f6c7c..b8804b44 100644 --- a/packages/sonarr/lib/src/commands/release.dart +++ b/packages/sonarr/lib/src/controllers/release.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to releases within Sonarr. /// -/// [SonarrCommandHandler_Release] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Release { +/// [SonarrController_Release] internally handles routing the HTTP client to the API calls. +class SonarrController_Release { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Release(this._client); + SonarrController_Release(this._client); /// Handler for [release](https://github.com/Sonarr/Sonarr/wiki/Release#get). /// diff --git a/packages/sonarr/lib/src/commands/release/add_release.dart b/packages/sonarr/lib/src/controllers/release/add_release.dart similarity index 100% rename from packages/sonarr/lib/src/commands/release/add_release.dart rename to packages/sonarr/lib/src/controllers/release/add_release.dart diff --git a/packages/sonarr/lib/src/commands/release/get_release.dart b/packages/sonarr/lib/src/controllers/release/get_release.dart similarity index 100% rename from packages/sonarr/lib/src/commands/release/get_release.dart rename to packages/sonarr/lib/src/controllers/release/get_release.dart diff --git a/packages/sonarr/lib/src/commands/release/get_season_release.dart b/packages/sonarr/lib/src/controllers/release/get_season_release.dart similarity index 100% rename from packages/sonarr/lib/src/commands/release/get_season_release.dart rename to packages/sonarr/lib/src/controllers/release/get_season_release.dart diff --git a/packages/sonarr/lib/src/controllers/root_folder.dart b/packages/sonarr/lib/src/controllers/root_folder.dart new file mode 100644 index 00000000..335503f9 --- /dev/null +++ b/packages/sonarr/lib/src/controllers/root_folder.dart @@ -0,0 +1,16 @@ +part of sonarr_commands; + +/// Facilitates, encapsulates, and manages individual calls related to root folders within Sonarr. +/// +/// [SonarrController_RootFolder] internally handles routing the HTTP client to the API calls. +class SonarrController_RootFolder { + final Dio _client; + + /// Create a series command handler using an initialized [Dio] client. + SonarrController_RootFolder(this._client); + + /// Handler for [rootfolder](https://github.com/Sonarr/Sonarr/wiki/Rootfolder#get). + /// + /// Returns a list of root folders. + Future> get() async => _commandGetRootFolders(_client); +} diff --git a/packages/sonarr/lib/src/commands/root_folder/get_root_folders.dart b/packages/sonarr/lib/src/controllers/root_folder/get_root_folders.dart similarity index 100% rename from packages/sonarr/lib/src/commands/root_folder/get_root_folders.dart rename to packages/sonarr/lib/src/controllers/root_folder/get_root_folders.dart diff --git a/packages/sonarr/lib/src/commands/series.dart b/packages/sonarr/lib/src/controllers/series.dart similarity index 93% rename from packages/sonarr/lib/src/commands/series.dart rename to packages/sonarr/lib/src/controllers/series.dart index 83930e30..54d88f6c 100644 --- a/packages/sonarr/lib/src/commands/series.dart +++ b/packages/sonarr/lib/src/controllers/series.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to series within Sonarr. /// -/// [SonarrCommandHandler_Series] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Series { +/// [SonarrController_Series] internally handles routing the HTTP client to the API calls. +class SonarrController_Series { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Series(this._client); + SonarrController_Series(this._client); /// Handler for [series](https://github.com/Sonarr/Sonarr/wiki/Series#post). /// diff --git a/packages/sonarr/lib/src/commands/series/add_series.dart b/packages/sonarr/lib/src/controllers/series/add_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/series/add_series.dart rename to packages/sonarr/lib/src/controllers/series/add_series.dart diff --git a/packages/sonarr/lib/src/commands/series/delete_series.dart b/packages/sonarr/lib/src/controllers/series/delete_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/series/delete_series.dart rename to packages/sonarr/lib/src/controllers/series/delete_series.dart diff --git a/packages/sonarr/lib/src/commands/series/get_all_series.dart b/packages/sonarr/lib/src/controllers/series/get_all_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/series/get_all_series.dart rename to packages/sonarr/lib/src/controllers/series/get_all_series.dart diff --git a/packages/sonarr/lib/src/commands/series/get_series.dart b/packages/sonarr/lib/src/controllers/series/get_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/series/get_series.dart rename to packages/sonarr/lib/src/controllers/series/get_series.dart diff --git a/packages/sonarr/lib/src/commands/series/update_series.dart b/packages/sonarr/lib/src/controllers/series/update_series.dart similarity index 100% rename from packages/sonarr/lib/src/commands/series/update_series.dart rename to packages/sonarr/lib/src/controllers/series/update_series.dart diff --git a/packages/sonarr/lib/src/commands/series_lookup.dart b/packages/sonarr/lib/src/controllers/series_lookup.dart similarity index 76% rename from packages/sonarr/lib/src/commands/series_lookup.dart rename to packages/sonarr/lib/src/controllers/series_lookup.dart index 3365fd3b..6b710e47 100644 --- a/packages/sonarr/lib/src/commands/series_lookup.dart +++ b/packages/sonarr/lib/src/controllers/series_lookup.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to series lookup within Sonarr. /// -/// [SonarrCommandHandler_SeriesLookup] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_SeriesLookup { +/// [SonarrController_SeriesLookup] internally handles routing the HTTP client to the API calls. +class SonarrController_SeriesLookup { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_SeriesLookup(this._client); + SonarrController_SeriesLookup(this._client); /// Handler for [series/lookup](https://github.com/Sonarr/Sonarr/wiki/Series-Lookup#get). /// diff --git a/packages/sonarr/lib/src/commands/series_lookup/lookup.dart b/packages/sonarr/lib/src/controllers/series_lookup/lookup.dart similarity index 100% rename from packages/sonarr/lib/src/commands/series_lookup/lookup.dart rename to packages/sonarr/lib/src/controllers/series_lookup/lookup.dart diff --git a/packages/sonarr/lib/src/controllers/system.dart b/packages/sonarr/lib/src/controllers/system.dart new file mode 100644 index 00000000..ddac22f0 --- /dev/null +++ b/packages/sonarr/lib/src/controllers/system.dart @@ -0,0 +1,16 @@ +part of sonarr_commands; + +/// Facilitates, encapsulates, and manages individual calls related to system within Sonarr. +/// +/// [SonarrController_System] internally handles routing the HTTP client to the API calls. +class SonarrController_System { + final Dio _client; + + /// Create a series command handler using an initialized [Dio] client. + SonarrController_System(this._client); + + /// Handler for [system/status](https://github.com/Sonarr/Sonarr/wiki/System-Status#get). + /// + /// Returns system status information. + Future getStatus() async => _commandGetStatus(_client); +} diff --git a/packages/sonarr/lib/src/commands/system/get_status.dart b/packages/sonarr/lib/src/controllers/system/get_status.dart similarity index 100% rename from packages/sonarr/lib/src/commands/system/get_status.dart rename to packages/sonarr/lib/src/controllers/system/get_status.dart diff --git a/packages/sonarr/lib/src/controllers/tag.dart b/packages/sonarr/lib/src/controllers/tag.dart new file mode 100644 index 00000000..d3ab4af3 --- /dev/null +++ b/packages/sonarr/lib/src/controllers/tag.dart @@ -0,0 +1,48 @@ +part of sonarr_commands; + +/// Facilitates, encapsulates, and manages individual calls related to tags within Sonarr. +/// +/// [SonarrController_Tag] internally handles routing the HTTP client to the API calls. +class SonarrController_Tag { + final Dio _client; + + /// Create a series command handler using an initialized [Dio] client. + SonarrController_Tag(this._client); + + /// Handler for [tag](https://github.com/Sonarr/Sonarr/wiki/Tag#post). + /// + /// Adds a new tag. + Future create({ + required String label, + }) async => + _commandAddTag(_client, label: label); + + /// Handler for [tag/{id}](https://github.com/Sonarr/Sonarr/wiki/Tag#deleteid). + /// + /// Delete the tag with the given ID. + Future delete({ + required int id, + }) async => + _commandDeleteTag(_client, id: id); + + /// Handler for [tag/{id}](https://github.com/Sonarr/Sonarr/wiki/Tag#getid). + /// + /// Returns the tag with the matching ID. + Future get({ + required int id, + }) async => + _commandGetTag(_client, id: id); + + /// Handler for [tag](https://github.com/Sonarr/Sonarr/wiki/Tag#get). + /// + /// Returns a list of all tags. + Future> getAll() async => _commandGetAllTags(_client); + + /// Handler for [tag](https://github.com/Sonarr/Sonarr/wiki/Tag#put). + /// + /// Update an existing tag. + Future update({ + required SonarrTag tag, + }) async => + _commandUpdateTag(_client, tag: tag); +} diff --git a/packages/sonarr/lib/src/commands/tag/add_tag.dart b/packages/sonarr/lib/src/controllers/tag/add_tag.dart similarity index 100% rename from packages/sonarr/lib/src/commands/tag/add_tag.dart rename to packages/sonarr/lib/src/controllers/tag/add_tag.dart diff --git a/packages/sonarr/lib/src/commands/tag/delete_tag.dart b/packages/sonarr/lib/src/controllers/tag/delete_tag.dart similarity index 100% rename from packages/sonarr/lib/src/commands/tag/delete_tag.dart rename to packages/sonarr/lib/src/controllers/tag/delete_tag.dart diff --git a/packages/sonarr/lib/src/commands/tag/get_all_tags.dart b/packages/sonarr/lib/src/controllers/tag/get_all_tags.dart similarity index 100% rename from packages/sonarr/lib/src/commands/tag/get_all_tags.dart rename to packages/sonarr/lib/src/controllers/tag/get_all_tags.dart diff --git a/packages/sonarr/lib/src/commands/tag/get_tag.dart b/packages/sonarr/lib/src/controllers/tag/get_tag.dart similarity index 100% rename from packages/sonarr/lib/src/commands/tag/get_tag.dart rename to packages/sonarr/lib/src/controllers/tag/get_tag.dart diff --git a/packages/sonarr/lib/src/commands/tag/update_tag.dart b/packages/sonarr/lib/src/controllers/tag/update_tag.dart similarity index 100% rename from packages/sonarr/lib/src/commands/tag/update_tag.dart rename to packages/sonarr/lib/src/controllers/tag/update_tag.dart diff --git a/packages/sonarr/lib/src/commands/wanted.dart b/packages/sonarr/lib/src/controllers/wanted.dart similarity index 85% rename from packages/sonarr/lib/src/commands/wanted.dart rename to packages/sonarr/lib/src/controllers/wanted.dart index 17890bac..f6fa0a8a 100644 --- a/packages/sonarr/lib/src/commands/wanted.dart +++ b/packages/sonarr/lib/src/controllers/wanted.dart @@ -2,12 +2,12 @@ part of sonarr_commands; /// Facilitates, encapsulates, and manages individual calls related to wanted/missing episodes within Sonarr. /// -/// [SonarrCommandHandler_Wanted] internally handles routing the HTTP client to the API calls. -class SonarrCommandHandler_Wanted { +/// [SonarrController_Wanted] internally handles routing the HTTP client to the API calls. +class SonarrController_Wanted { final Dio _client; /// Create a series command handler using an initialized [Dio] client. - SonarrCommandHandler_Wanted(this._client); + SonarrController_Wanted(this._client); /// Handler for [wanted/missing](https://github.com/Sonarr/Sonarr/wiki/Wanted-Missing#get). /// diff --git a/packages/sonarr/lib/src/commands/wanted/get_missing.dart b/packages/sonarr/lib/src/controllers/wanted/get_missing.dart similarity index 100% rename from packages/sonarr/lib/src/commands/wanted/get_missing.dart rename to packages/sonarr/lib/src/controllers/wanted/get_missing.dart diff --git a/packages/sonarr/lib/src/models/queue/queue.dart b/packages/sonarr/lib/src/models/queue/queue.dart new file mode 100644 index 00000000..e930fc4f --- /dev/null +++ b/packages/sonarr/lib/src/models/queue/queue.dart @@ -0,0 +1,43 @@ +import 'dart:convert'; +import 'package:json_annotation/json_annotation.dart'; +import 'package:sonarr/models.dart'; + +part 'queue.g.dart'; + +@JsonSerializable(explicitToJson: true, includeIfNull: false) +class SonarrQueue { + @JsonKey(name: 'page') + int? page; + + @JsonKey(name: 'pageSize') + int? pageSize; + + @JsonKey(name: 'sortKey') + String? sortKey; + + @JsonKey(name: 'sortDirection') + String? sortDirection; + + @JsonKey(name: 'totalRecords') + int? totalRecords; + + @JsonKey(name: 'records') + List? records; + + SonarrQueue({ + this.page, + this.pageSize, + this.sortKey, + this.sortDirection, + this.totalRecords, + this.records, + }); + + @override + String toString() => json.encode(this.toJson()); + + factory SonarrQueue.fromJson(Map json) => + _$SonarrQueueFromJson(json); + + Map toJson() => _$SonarrQueueToJson(this); +} diff --git a/packages/sonarr/lib/src/models/queue/queue.g.dart b/packages/sonarr/lib/src/models/queue/queue.g.dart new file mode 100644 index 00000000..b6ef395e --- /dev/null +++ b/packages/sonarr/lib/src/models/queue/queue.g.dart @@ -0,0 +1,36 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'queue.dart'; + +// ************************************************************************** +// JsonSerializableGenerator +// ************************************************************************** + +SonarrQueue _$SonarrQueueFromJson(Map json) => SonarrQueue( + page: json['page'] as int?, + pageSize: json['pageSize'] as int?, + sortKey: json['sortKey'] as String?, + sortDirection: json['sortDirection'] as String?, + totalRecords: json['totalRecords'] as int?, + records: (json['records'] as List?) + ?.map((e) => SonarrQueueRecord.fromJson(e as Map)) + .toList(), + ); + +Map _$SonarrQueueToJson(SonarrQueue instance) { + final val = {}; + + void writeNotNull(String key, dynamic value) { + if (value != null) { + val[key] = value; + } + } + + writeNotNull('page', instance.page); + writeNotNull('pageSize', instance.pageSize); + writeNotNull('sortKey', instance.sortKey); + writeNotNull('sortDirection', instance.sortDirection); + writeNotNull('totalRecords', instance.totalRecords); + writeNotNull('records', instance.records?.map((e) => e.toJson()).toList()); + return val; +} diff --git a/packages/sonarr/lib/src/models/queue/queue_record.dart b/packages/sonarr/lib/src/models/queue/queue_record.dart index ec196d1e..a1ca0489 100644 --- a/packages/sonarr/lib/src/models/queue/queue_record.dart +++ b/packages/sonarr/lib/src/models/queue/queue_record.dart @@ -1,90 +1,129 @@ import 'dart:convert'; import 'package:json_annotation/json_annotation.dart'; import 'package:sonarr/models.dart'; +import 'package:sonarr/types.dart'; import 'package:sonarr/utilities.dart'; part 'queue_record.g.dart'; -/// Model for the from Sonarr. @JsonSerializable(explicitToJson: true, includeIfNull: false) class SonarrQueueRecord { - /// [SonarrSeries] object containing series information + @JsonKey(name: 'seriesId') + int? seriesId; + + @JsonKey(name: 'episodeId') + int? episodeId; + @JsonKey(name: 'series') SonarrSeries? series; - /// [SonarrEpisode] object containing episode information @JsonKey(name: 'episode') SonarrEpisode? episode; - /// [SonarrEpisodeFileQuality] object containing quality information + @JsonKey(name: 'language') + SonarrEpisodeFileLanguage? language; + @JsonKey(name: 'quality') SonarrEpisodeFileQuality? quality; - /// Size of the queued item @JsonKey(name: 'size') double? size; - /// Title of the queued item @JsonKey(name: 'title') String? title; - /// Size of the download remaining @JsonKey(name: 'sizeleft') - double? sizeLeft; + double? sizeleft; - /// Estimated remaining time left @JsonKey(name: 'timeleft') - String? timeLeft; + String? timeleft; - /// Estimated time of completion @JsonKey( - name: 'estimatedCompletionTime', - toJson: SonarrUtilities.dateTimeToJson, - fromJson: SonarrUtilities.dateTimeFromJson) + name: 'estimatedCompletionTime', + toJson: SonarrUtilities.dateTimeToJson, + fromJson: SonarrUtilities.dateTimeFromJson, + ) DateTime? estimatedCompletionTime; - /// Status of the queued item (Delay, Completed, etc.) - @JsonKey(name: 'status') - String? status; + @JsonKey( + name: 'status', + toJson: SonarrUtilities.queueStatusToJson, + fromJson: SonarrUtilities.queueStatusFromJson, + ) + SonarrQueueStatus? status; - /// Status of the download - @JsonKey(name: 'trackedDownloadStatus') - String? trackedDownloadStatus; + @JsonKey( + name: 'trackedDownloadStatus', + toJson: SonarrUtilities.queueTrackedDownloadStatusToJson, + fromJson: SonarrUtilities.queueTrackedDownloadStatusFromJson, + ) + SonarrTrackedDownloadStatus? trackedDownloadStatus; + + @JsonKey( + name: 'trackedDownloadState', + toJson: SonarrUtilities.queueTrackedDownloadStateToJson, + fromJson: SonarrUtilities.queueTrackedDownloadStateFromJson, + ) + SonarrTrackedDownloadState? trackedDownloadState; @JsonKey(name: 'statusMessages') List? statusMessages; - /// Protocol being used (torrent, usenet) - @JsonKey(name: 'protocol') - String? protocol; + @JsonKey(name: 'errorMessage') + String? errorMessage; + + @JsonKey(name: 'downloadId') + String? downloadId; + + @JsonKey( + name: 'protocol', + toJson: SonarrUtilities.protocolToJson, + fromJson: SonarrUtilities.protocolFromJson, + ) + SonarrProtocol? protocol; + + @JsonKey(name: 'downloadClient') + String? downloadClient; + + @JsonKey(name: 'indexer') + String? indexer; + + @JsonKey(name: 'outputPath') + String? outputPath; - /// Queue item identifier @JsonKey(name: 'id') int? id; SonarrQueueRecord({ + this.seriesId, + this.episodeId, this.series, this.episode, + this.language, this.quality, this.size, this.title, - this.sizeLeft, - this.timeLeft, + this.sizeleft, + this.timeleft, this.estimatedCompletionTime, this.status, this.trackedDownloadStatus, + this.trackedDownloadState, this.statusMessages, + this.errorMessage, + this.downloadId, + this.protocol, + this.downloadClient, + this.indexer, + this.outputPath, this.id, }); - /// Returns a JSON-encoded string version of this object. @override String toString() => json.encode(this.toJson()); - /// Deserialize a JSON map to a [SonarrQueueRecord] object. factory SonarrQueueRecord.fromJson(Map json) => _$SonarrQueueRecordFromJson(json); - /// Serialize a [SonarrQueueRecord] object to a JSON map. Map toJson() => _$SonarrQueueRecordToJson(this); } diff --git a/packages/sonarr/lib/src/models/queue/queue_record.g.dart b/packages/sonarr/lib/src/models/queue/queue_record.g.dart index 721fcafc..4200ccd9 100644 --- a/packages/sonarr/lib/src/models/queue/queue_record.g.dart +++ b/packages/sonarr/lib/src/models/queue/queue_record.g.dart @@ -8,30 +8,45 @@ part of 'queue_record.dart'; SonarrQueueRecord _$SonarrQueueRecordFromJson(Map json) => SonarrQueueRecord( + seriesId: json['seriesId'] as int?, + episodeId: json['episodeId'] as int?, series: json['series'] == null ? null : SonarrSeries.fromJson(json['series'] as Map), episode: json['episode'] == null ? null : SonarrEpisode.fromJson(json['episode'] as Map), + language: json['language'] == null + ? null + : SonarrEpisodeFileLanguage.fromJson( + json['language'] as Map), quality: json['quality'] == null ? null : SonarrEpisodeFileQuality.fromJson( json['quality'] as Map), size: (json['size'] as num?)?.toDouble(), title: json['title'] as String?, - sizeLeft: (json['sizeleft'] as num?)?.toDouble(), - timeLeft: json['timeleft'] as String?, + sizeleft: (json['sizeleft'] as num?)?.toDouble(), + timeleft: json['timeleft'] as String?, estimatedCompletionTime: SonarrUtilities.dateTimeFromJson( json['estimatedCompletionTime'] as String?), - status: json['status'] as String?, - trackedDownloadStatus: json['trackedDownloadStatus'] as String?, + status: SonarrUtilities.queueStatusFromJson(json['status'] as String?), + trackedDownloadStatus: SonarrUtilities.queueTrackedDownloadStatusFromJson( + json['trackedDownloadStatus'] as String?), + trackedDownloadState: SonarrUtilities.queueTrackedDownloadStateFromJson( + json['trackedDownloadState'] as String?), statusMessages: (json['statusMessages'] as List?) ?.map((e) => SonarrQueueStatusMessage.fromJson(e as Map)) .toList(), + errorMessage: json['errorMessage'] as String?, + downloadId: json['downloadId'] as String?, + protocol: SonarrUtilities.protocolFromJson(json['protocol'] as String?), + downloadClient: json['downloadClient'] as String?, + indexer: json['indexer'] as String?, + outputPath: json['outputPath'] as String?, id: json['id'] as int?, - )..protocol = json['protocol'] as String?; + ); Map _$SonarrQueueRecordToJson(SonarrQueueRecord instance) { final val = {}; @@ -42,20 +57,35 @@ Map _$SonarrQueueRecordToJson(SonarrQueueRecord instance) { } } + writeNotNull('seriesId', instance.seriesId); + writeNotNull('episodeId', instance.episodeId); writeNotNull('series', instance.series?.toJson()); writeNotNull('episode', instance.episode?.toJson()); + writeNotNull('language', instance.language?.toJson()); writeNotNull('quality', instance.quality?.toJson()); writeNotNull('size', instance.size); writeNotNull('title', instance.title); - writeNotNull('sizeleft', instance.sizeLeft); - writeNotNull('timeleft', instance.timeLeft); + writeNotNull('sizeleft', instance.sizeleft); + writeNotNull('timeleft', instance.timeleft); writeNotNull('estimatedCompletionTime', SonarrUtilities.dateTimeToJson(instance.estimatedCompletionTime)); - writeNotNull('status', instance.status); - writeNotNull('trackedDownloadStatus', instance.trackedDownloadStatus); + writeNotNull('status', SonarrUtilities.queueStatusToJson(instance.status)); + writeNotNull( + 'trackedDownloadStatus', + SonarrUtilities.queueTrackedDownloadStatusToJson( + instance.trackedDownloadStatus)); + writeNotNull( + 'trackedDownloadState', + SonarrUtilities.queueTrackedDownloadStateToJson( + instance.trackedDownloadState)); writeNotNull('statusMessages', instance.statusMessages?.map((e) => e.toJson()).toList()); - writeNotNull('protocol', instance.protocol); + writeNotNull('errorMessage', instance.errorMessage); + writeNotNull('downloadId', instance.downloadId); + writeNotNull('protocol', SonarrUtilities.protocolToJson(instance.protocol)); + writeNotNull('downloadClient', instance.downloadClient); + writeNotNull('indexer', instance.indexer); + writeNotNull('outputPath', instance.outputPath); writeNotNull('id', instance.id); return val; } diff --git a/packages/sonarr/lib/src/types/queue_sort_key.dart b/packages/sonarr/lib/src/types/queue_sort_key.dart new file mode 100644 index 00000000..1663a346 --- /dev/null +++ b/packages/sonarr/lib/src/types/queue_sort_key.dart @@ -0,0 +1,81 @@ +part of sonarr_types; + +enum SonarrQueueSortKey { + EPISODE, + TIME_LEFT, + ESTIMATED_COMPLETION_TIME, + PROTOCOL, + INDEXER, + DOWNLOAD_CLIENT, + LANGUAGE, + QUALITY, + STATUS, + SERIES_SORT_TITLE, + TITLE, + EPISODE_AIRDATE_UTC, + EPISODE_TITLE, +} + +extension SonarrQueueSortKeyExtension on SonarrQueueSortKey { + SonarrQueueSortKey? from(String? type) { + switch (type) { + case 'episode': + return SonarrQueueSortKey.EPISODE; + case 'timeleft': + return SonarrQueueSortKey.TIME_LEFT; + case 'estimatedCompletionTime': + return SonarrQueueSortKey.ESTIMATED_COMPLETION_TIME; + case 'protocol': + return SonarrQueueSortKey.PROTOCOL; + case 'indexer': + return SonarrQueueSortKey.INDEXER; + case 'downloadClient': + return SonarrQueueSortKey.DOWNLOAD_CLIENT; + case 'language': + return SonarrQueueSortKey.LANGUAGE; + case 'quality': + return SonarrQueueSortKey.QUALITY; + case 'status': + return SonarrQueueSortKey.STATUS; + case 'series.sortTitle': + return SonarrQueueSortKey.SERIES_SORT_TITLE; + case 'title': + return SonarrQueueSortKey.TITLE; + case 'episode.airDateUtc': + return SonarrQueueSortKey.EPISODE_AIRDATE_UTC; + case 'episode.title': + return SonarrQueueSortKey.EPISODE_TITLE; + } + } + + String? get value { + switch (this) { + case SonarrQueueSortKey.EPISODE: + return 'episode'; + case SonarrQueueSortKey.TIME_LEFT: + return 'timeleft'; + case SonarrQueueSortKey.ESTIMATED_COMPLETION_TIME: + return 'estimatedCompletionTime'; + case SonarrQueueSortKey.PROTOCOL: + return 'protocol'; + case SonarrQueueSortKey.INDEXER: + return 'indexer'; + case SonarrQueueSortKey.DOWNLOAD_CLIENT: + return 'downloadClient'; + case SonarrQueueSortKey.LANGUAGE: + return 'language'; + case SonarrQueueSortKey.QUALITY: + return 'quality'; + case SonarrQueueSortKey.STATUS: + return 'status'; + case SonarrQueueSortKey.SERIES_SORT_TITLE: + return 'series.sortTitle'; + case SonarrQueueSortKey.TITLE: + return 'title'; + case SonarrQueueSortKey.EPISODE_AIRDATE_UTC: + return 'episode.airDateUtc'; + case SonarrQueueSortKey.EPISODE_TITLE: + return 'episode.title'; + } + } +} diff --git a/packages/sonarr/lib/src/types/queue_status_type.dart b/packages/sonarr/lib/src/types/queue_status_type.dart new file mode 100644 index 00000000..c0d589bf --- /dev/null +++ b/packages/sonarr/lib/src/types/queue_status_type.dart @@ -0,0 +1,60 @@ +part of sonarr_types; + +enum SonarrQueueStatus { + DOWNLOADING, + PAUSED, + QUEUED, + COMPLETED, + DELAY, + DOWNLOAD_CLIENT_UNAVAILABLE, + FAILED, + WARNING, +} + +extension SonarrQueueStatusExtension on SonarrQueueStatus { + SonarrQueueStatus? from(String? type) { + switch (type) { + case 'downloading': + return SonarrQueueStatus.DOWNLOADING; + case 'paused': + return SonarrQueueStatus.PAUSED; + case 'queued': + return SonarrQueueStatus.QUEUED; + case 'completed': + return SonarrQueueStatus.COMPLETED; + case 'delay': + return SonarrQueueStatus.DELAY; + case 'downloadClientUnavailable': + return SonarrQueueStatus.DOWNLOAD_CLIENT_UNAVAILABLE; + case 'failed': + return SonarrQueueStatus.FAILED; + case 'warning': + return SonarrQueueStatus.WARNING; + default: + return null; + } + } + + String? get value { + switch (this) { + case SonarrQueueStatus.DOWNLOADING: + return 'downloading'; + case SonarrQueueStatus.PAUSED: + return 'paused'; + case SonarrQueueStatus.QUEUED: + return 'queued'; + case SonarrQueueStatus.COMPLETED: + return 'completed'; + case SonarrQueueStatus.DELAY: + return 'delay'; + case SonarrQueueStatus.DOWNLOAD_CLIENT_UNAVAILABLE: + return 'downloadClientUnavailable'; + case SonarrQueueStatus.FAILED: + return 'failed'; + case SonarrQueueStatus.WARNING: + return 'warning'; + default: + return null; + } + } +} diff --git a/packages/sonarr/lib/src/types/queue_tracked_download_state_type.dart b/packages/sonarr/lib/src/types/queue_tracked_download_state_type.dart new file mode 100644 index 00000000..96ce3899 --- /dev/null +++ b/packages/sonarr/lib/src/types/queue_tracked_download_state_type.dart @@ -0,0 +1,40 @@ +part of sonarr_types; + +enum SonarrTrackedDownloadState { + DOWNLOADING, + IMPORT_PENDING, + IMPORTING, + FAILED_PENDING, +} + +extension SonarrTrackedDownloadStateExtension on SonarrTrackedDownloadState { + SonarrTrackedDownloadState? from(String? type) { + switch (type) { + case 'downloading': + return SonarrTrackedDownloadState.DOWNLOADING; + case 'importPending': + return SonarrTrackedDownloadState.IMPORT_PENDING; + case 'importing': + return SonarrTrackedDownloadState.IMPORTING; + case 'failedPending': + return SonarrTrackedDownloadState.FAILED_PENDING; + default: + return null; + } + } + + String? get value { + switch (this) { + case SonarrTrackedDownloadState.DOWNLOADING: + return 'downloading'; + case SonarrTrackedDownloadState.IMPORT_PENDING: + return 'importPending'; + case SonarrTrackedDownloadState.IMPORTING: + return 'importing'; + case SonarrTrackedDownloadState.FAILED_PENDING: + return 'failedPending'; + default: + return null; + } + } +} diff --git a/packages/sonarr/lib/src/types/queue_tracked_download_status_type.dart b/packages/sonarr/lib/src/types/queue_tracked_download_status_type.dart new file mode 100644 index 00000000..5f7e3814 --- /dev/null +++ b/packages/sonarr/lib/src/types/queue_tracked_download_status_type.dart @@ -0,0 +1,35 @@ +part of sonarr_types; + +enum SonarrTrackedDownloadStatus { + OK, + WARNING, + ERROR, +} + +extension SonarrTrackedDownloadStatusExtension on SonarrTrackedDownloadStatus { + SonarrTrackedDownloadStatus? from(String? type) { + switch (type) { + case 'ok': + return SonarrTrackedDownloadStatus.OK; + case 'warning': + return SonarrTrackedDownloadStatus.WARNING; + case 'error': + return SonarrTrackedDownloadStatus.ERROR; + default: + return null; + } + } + + String? get value { + switch (this) { + case SonarrTrackedDownloadStatus.OK: + return 'ok'; + case SonarrTrackedDownloadStatus.WARNING: + return 'warning'; + case SonarrTrackedDownloadStatus.ERROR: + return 'error'; + default: + return null; + } + } +} diff --git a/packages/sonarr/lib/types.dart b/packages/sonarr/lib/types.dart index ace666af..851a98b2 100644 --- a/packages/sonarr/lib/types.dart +++ b/packages/sonarr/lib/types.dart @@ -4,6 +4,10 @@ library sonarr_types; part 'src/types/event_type.dart'; part 'src/types/history_sort_key.dart'; part 'src/types/protocol_type.dart'; +part 'src/types/queue_sort_key.dart'; +part 'src/types/queue_status_type.dart'; +part 'src/types/queue_tracked_download_state_type.dart'; +part 'src/types/queue_tracked_download_status_type.dart'; part 'src/types/series_monitor_type.dart'; part 'src/types/series_type.dart'; part 'src/types/sort_dir.dart'; diff --git a/packages/sonarr/lib/utilities.dart b/packages/sonarr/lib/utilities.dart index 82e485bc..a65af59d 100644 --- a/packages/sonarr/lib/utilities.dart +++ b/packages/sonarr/lib/utilities.dart @@ -47,6 +47,23 @@ class SonarrUtilities { static SonarrProtocol? protocolFromJson(String? protocol) => SonarrProtocol.USENET.from(protocol); - static String? protocolToJson(SonarrProtocol? protocol) => protocol?.value; + + static SonarrQueueStatus? queueStatusFromJson(String? status) => + SonarrQueueStatus.DOWNLOADING.from(status); + static String? queueStatusToJson(SonarrQueueStatus? status) => status?.value; + + static SonarrTrackedDownloadState? queueTrackedDownloadStateFromJson( + String? state) => + SonarrTrackedDownloadState.DOWNLOADING.from(state); + static String? queueTrackedDownloadStateToJson( + SonarrTrackedDownloadState? state) => + state?.value; + + static SonarrTrackedDownloadStatus? queueTrackedDownloadStatusFromJson( + String? status) => + SonarrTrackedDownloadStatus.OK.from(status); + static String? queueTrackedDownloadStatusToJson( + SonarrTrackedDownloadStatus? status) => + status?.value; } diff --git a/packages/tautulli/lib/src/models/system/pms_update.dart b/packages/tautulli/lib/src/models/system/pms_update.dart index e3252917..cf9219e2 100644 --- a/packages/tautulli/lib/src/models/system/pms_update.dart +++ b/packages/tautulli/lib/src/models/system/pms_update.dart @@ -4,81 +4,107 @@ import 'package:tautulli/utilities.dart'; part 'pms_update.g.dart'; -/// Model to store update information for Plex Media Server. @JsonSerializable(explicitToJson: true) class TautulliPMSUpdate { - /// Is there an update available? - @JsonKey(name: 'update_available', fromJson: TautulliUtilities.ensureBooleanFromJson) - final bool? updateAvailable; + @JsonKey( + name: 'update_available', + fromJson: TautulliUtilities.ensureBooleanFromJson, + ) + final bool? updateAvailable; - /// Machine's platform. - @JsonKey(name: 'platform', fromJson: TautulliUtilities.ensureStringFromJson) - final String? platform; + @JsonKey( + name: 'platform', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? platform; - /// The release date of the update. - @JsonKey(name: 'release_date', fromJson: TautulliUtilities.millisecondsDateTimeFromJson) - final DateTime? releaseDate; + @JsonKey( + name: 'release_date', + fromJson: TautulliUtilities.millisecondsDateTimeFromJson, + ) + final DateTime? releaseDate; - /// Full version code of the release. - @JsonKey(name: 'version', fromJson: TautulliUtilities.ensureStringFromJson) - final String? version; + @JsonKey( + name: 'version', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? version; - /// List of requirements. - @JsonKey(name: 'requirements', fromJson: TautulliUtilities.ensureStringFromJson) - final String? requirements; + @JsonKey( + name: 'requirements', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? requirements; - /// Any extra information. - @JsonKey(name: 'extra_info', fromJson: TautulliUtilities.ensureStringFromJson) - final String? extraInfo; + @JsonKey( + name: 'extra_info', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? extraInfo; - /// List of changes that includes new/added content. - @JsonKey(name: 'changelog_added', toJson: _releaseNotesToJson, fromJson: _releaseNotesFromJson) - final List? changelogAdded; + @JsonKey( + name: 'changelog_added', + toJson: _releaseNotesToJson, + fromJson: _releaseNotesFromJson, + ) + final List? changelogAdded; - /// List of changes that includes fixed bugs. - @JsonKey(name: 'changelog_fixed', toJson: _releaseNotesToJson, fromJson: _releaseNotesFromJson) - final List? changelogFixed; + @JsonKey( + name: 'changelog_fixed', + toJson: _releaseNotesToJson, + fromJson: _releaseNotesFromJson, + ) + final List? changelogFixed; - /// Label for the release. - @JsonKey(name: 'label', fromJson: TautulliUtilities.ensureStringFromJson) - final String? label; + @JsonKey( + name: 'label', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? label; - /// Distribution for the release. - @JsonKey(name: 'distro', fromJson: TautulliUtilities.ensureStringFromJson) - final String? distro; + @JsonKey( + name: 'distro', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? distro; - /// Build information for the distribution release. - @JsonKey(name: 'distro_build', fromJson: TautulliUtilities.ensureStringFromJson) - final String? distroBuild; + @JsonKey( + name: 'distro_build', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? distroBuild; - /// URL to download this release. - @JsonKey(name: 'download_url', fromJson: TautulliUtilities.ensureStringFromJson) - final String? downloadUrl; + @JsonKey( + name: 'download_url', + fromJson: TautulliUtilities.ensureStringFromJson, + ) + final String? downloadUrl; - TautulliPMSUpdate({ - this.updateAvailable, - this.platform, - this.releaseDate, - this.version, - this.requirements, - this.extraInfo, - this.changelogAdded, - this.changelogFixed, - this.label, - this.distro, - this.distroBuild, - this.downloadUrl, - }); + TautulliPMSUpdate({ + this.updateAvailable, + this.platform, + this.releaseDate, + this.version, + this.requirements, + this.extraInfo, + this.changelogAdded, + this.changelogFixed, + this.label, + this.distro, + this.distroBuild, + this.downloadUrl, + }); - /// Returns a JSON-encoded string version of this object. - @override - String toString() => json.encode(this.toJson()); + @override + String toString() => json.encode(this.toJson()); - /// Deserialize a JSON map to a [TautulliPMSUpdate] object. - factory TautulliPMSUpdate.fromJson(Map json) => _$TautulliPMSUpdateFromJson(json); - /// Serialize a [TautulliPMSUpdate] object to a JSON map. - Map toJson() => _$TautulliPMSUpdateToJson(this); + factory TautulliPMSUpdate.fromJson(Map json) => + _$TautulliPMSUpdateFromJson(json); - static List _releaseNotesFromJson(String notes) => notes.split("\n"); - static String? _releaseNotesToJson(List? notes) => notes?.join("\n"); + Map toJson() => _$TautulliPMSUpdateToJson(this); + + static List? _releaseNotesFromJson(String? notes) => + notes?.split("\n") ?? []; + static String? _releaseNotesToJson(List? notes) => + notes?.join("\n") ?? ''; } diff --git a/packages/tautulli/pubspec.yaml b/packages/tautulli/pubspec.yaml index b3aee07d..4a6c8e02 100644 --- a/packages/tautulli/pubspec.yaml +++ b/packages/tautulli/pubspec.yaml @@ -14,4 +14,4 @@ dev_dependencies: json_serializable: ^4.1.0 test: ^1.16.8 scripts: - build: pub run build_runner build --delete-conflicting-outputs + build: dart run build_runner build --delete-conflicting-outputs diff --git a/pubspec.yaml b/pubspec.yaml index dc7eb6cf..31086226 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,6 +1,6 @@ name: lunasea description: Self-Hosted Controller -version: 6.0.0+60000001 +version: 6.0.0+60000002 publish_to: 'none' environment: sdk: ">=2.7.0 <3.0.0"