diff --git a/.all-contributorsrc b/.all-contributorsrc index ecb2e0c0..fa93d456 100644 --- a/.all-contributorsrc +++ b/.all-contributorsrc @@ -61,6 +61,15 @@ "contributions": [ "translation" ] + }, + { + "login": "iFelix18", + "name": "Davide", + "avatar_url": "https://avatars.githubusercontent.com/u/19800006?v=4", + "profile": "https://github.com/iFelix18", + "contributions": [ + "translation" + ] } ], "contributorsPerLine": 7, diff --git a/CHANGELOG.md b/CHANGELOG.md index 61356df5..74bd826c 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,42 @@ # LunaSea Changelog +## v5.0.0 (50000013) + +#### NEW +- `[-Arr/Releases]` Match torrent seeder colours to the web GUI +- `[Firebase/Analytics]` Added analytics for breadcrumb tracking in crashes +- `[Logger]` Utilize a new, custom built on-device logging system +- `[Logger]` Compact/delete old log entries once the log count passes 100 +- `[Logger]` Exported logs are now in JSON format +- `[Routing]` Protect all module routes by showing a "Not Enabled" screen when the module is not enabled +- `[Settings/System]` Added toggle to disable Firebase Analytics +- `[Tautulli/Activity]` Show custom season titles from Plex's new TV agent + +#### TWEAKS +- `[Radarr/Files]` Add languages to file block +- `[Radarr/Files]` Small changes to table titles +- `[System/Logs]` Reimplemented logger view +- `[System/Logs]` Removed viewing the stack trace within the application (still viewable within the exported logs) +- `[System/Logs]` Added the exception to the expanded table instead of a separate dialog popup +- `[Tautulli/Activity]` Minor UI tweaks including showing the full season title and italicizing the episode title +- `[UI/Navbar]` Jump instead of animate to page when tapping a navbar item + +#### FIXES +- `[Firebase/Crashes]` Do not log DioError/networking exceptions +- `[Flutter]` Updated packages +- `[Flutter]` Upgrade all Comet.Tools packages to null-safety/NNBD +- `[Radarr/Releases]` Negative format scores were not being shown +- `[Share]` The sharesheet could break after the first time it was opened +- `[Strings]` Safe-guard many substring operations +- `[Tautulli/Activity]` Play/paused/buffering icon was not properly left aligned to the text +- `[Tautulli/Users]` User images would not be fetched on newer versions of Tautulli +- `[UI/UX]` Modal scroll controller was not being attached to the ListView in a bottom modal sheet +- `[UI/UX]` Do not log errors when network images fail to load +- `[UI/UX]` Prevent attempting to load background images that are passed an empty URL +- `[URLs]` Safe-guard launching specific invalid URLs + +--- + ## v5.0.0 (50000012) #### NEW diff --git a/README.md b/README.md index 9936603d..dce941fb 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# LunaSea  LunaSea +# LunaSea  LunaSea [![App Store](https://img.shields.io/badge/%20Download-ios-red?style=for-the-badge&logo=app-store&color=%232196F3&logoColor=white)](https://www.lunasea.app/appstore) [![Play Store](https://img.shields.io/badge/%20Download-android-red?style=for-the-badge&logo=google-play&color=%234CAF50&logoColor=white)](https://www.lunasea.app/playstore) @@ -60,7 +60,7 @@ Thank you to all tools and services for offering free subscriptions for open-sou ## Contributors -[![All Contributors](https://img.shields.io/badge/all_contributors-6-orange.svg?style=flat)](#contributors-) +[![All Contributors](https://img.shields.io/badge/all_contributors-7-orange.svg?style=flat-square)](#contributors-) Thank you to everyone who has helped contribute to LunaSea, from development to localization efforts! @@ -76,6 +76,7 @@ Thank you to everyone who has helped contribute to LunaSea, from development to
Allan Nordhøy

🌍
cpt-kuesel

🌍
KovalevArtem

🌍 +
Davide

🌍 diff --git a/assets/changelog.json b/assets/changelog.json index 6cf55a61..512ba84a 100644 --- a/assets/changelog.json +++ b/assets/changelog.json @@ -1,38 +1,129 @@ { - "motd": "This build now includes support for infinite scrolling in the indexer search! Each page will return 50 results, and will load the next page of results as you near the bottom of the list. Please note that each new page load is an additional API hit, so please consider that when using indexers with limited API calls.\n\nBecause of the added support for infinite scrolling, there is no longer the option to sort or filter the fetched results, as these are not directly supported within the newznab specification. Client-sided sorting and filtering are not compatible with the concept of infinite scroll, so now releases will be shown in the indexer's returned positioning.", + "motd": "This build introduces a revamped logging system. While most changes are not user-facing, the logs are now much more versatile and carry more information within the stack traces, which will allow for easier and better debugging of errors.\n\nThis build also introduces Firebase Analytics, which is being used with Firebase Crashlytics to give breadcrumb tracking for crashes. Breadcrumbs let me know how you got to the point of a crash, and do not contain any identifying information. Just as you can disable Firebase Crashlytics, a new option has been added to completely disable Firebase Analytics.\n\nIf you have previously disabled Firebase Crashlytics, you may need to disable Firebase Crashlytics in the settings again.", "new": [ { - "module": "Radarr/\nFiles", + "module": "-Arr/\nReleases", "changes": [ - "Add video and audio codec to the media file card" + "Match torrent seeder colours to the web GUI" ] }, { - "module": "Search", + "module": "Firebase/\nAnalytics", "changes": [ - "Now supports infinite scrolling for loading additional pages of results", - "Much faster parsing of XML responses", - "Fully adapted for localization" + "Added analytics for breadcrumb tracking in crashes" + ] + }, + { + "module": "Logger", + "changes": [ + "Utilize a new, custom built on-device logging system", + "Compact/delete old log entries once the log count passes 100", + "Exported logs are now in JSON format" + ] + }, + { + "module": "Routing", + "changes": [ + "Protect all module routes by showing a \"Not Enabled\" screen when the module is not enabled" + ] + }, + { + "module": "Settings/\nSystem", + "changes": [ + "Added toggle to disable Firebase Analytics" + ] + }, + { + "module": "Tautulli/\nActivity", + "changes": [ + "Show custom season titles from Plex's new TV agent" ] } ], "tweaks": [ { - "module": "Search", + "module": "Radarr/\nFiles", "changes": [ - "Now returns 50 results per infinite scrolling page", - "Removed support for sorting the catalogue and instead show the results in the order the indexer returns the data", - "Removed support for filtering releases by a search query", - "Minor tweaks to the icons on the indexer, category, and subcategory tiles" + "Add languages to file block", + "Small changes to table titles" + ] + }, + { + "module": "System/\nLogs", + "changes": [ + "Reimplemented logger view", + "Removed viewing the stack trace within the application (still viewable within the exported logs)", + "Added the exception to the expanded table instead of a separate dialog popup" + ] + }, + { + "module": "Tautulli/\nActivity", + "changes": [ + "Minor UI tweaks including showing the full season title and italicizing the episode title" + ] + }, + { + "module": "UI/\nNavbar", + "changes": [ + "Jump instead of animate to page when tapping a navbar item" ] } ], "fixes": [ { - "module": "Search", + "module": "Firebase/\nCrashes", "changes": [ - "Search would only return 10 results", - "Age of the release could show as \"Unknown Age\" in some cases" + "Do not log DioError/networking exceptions" + ] + }, + { + "module": "Flutter", + "changes": [ + "Updated packages", + "Upgrade all Comet.Tools packages to null-safety/NNBD" + ] + }, + { + "module": "Radarr/\nReleases", + "changes": [ + "Negative format scores were not being shown" + ] + }, + { + "module": "Share", + "changes": [ + "The sharesheet could break after the first time it was opened" + ] + }, + { + "module": "Strings", + "changes": [ + "Safe-guard many substring operations" + ] + }, + { + "module": "Tautulli/\nActivity", + "changes": [ + "Play/paused/buffering icon was not properly left aligned to the text" + ] + }, + { + "module": "Tautulli/\nUsers", + "changes": [ + "User images would not be fetched on newer versions of Tautulli" + ] + }, + { + "module": "UI/UX", + "changes": [ + "Modal scroll controller was not being attached to the ListView in a bottom modal sheet", + "Do not log errors when network images fail to load" + ] + }, + { + "module": "URLs", + "changes": [ + "Safe-guard crashing related to launching specific invalid URLs" ] } ] diff --git a/assets/images/lidarr/noalbumart.png b/assets/images/blanks/audio.png similarity index 100% rename from assets/images/lidarr/noalbumart.png rename to assets/images/blanks/audio.png diff --git a/assets/images/tautulli/platform.png b/assets/images/blanks/platform.png similarity index 100% rename from assets/images/tautulli/platform.png rename to assets/images/blanks/platform.png diff --git a/assets/images/tautulli/streams.png b/assets/images/blanks/stream.png similarity index 100% rename from assets/images/tautulli/streams.png rename to assets/images/blanks/stream.png diff --git a/assets/images/lidarr/noartistposter.png b/assets/images/blanks/user.png similarity index 100% rename from assets/images/lidarr/noartistposter.png rename to assets/images/blanks/user.png diff --git a/assets/images/radarr/nomovieposter.png b/assets/images/blanks/video.png similarity index 100% rename from assets/images/radarr/nomovieposter.png rename to assets/images/blanks/video.png diff --git a/assets/branding/icon.png b/assets/images/branding/icon.png similarity index 100% rename from assets/branding/icon.png rename to assets/images/branding/icon.png diff --git a/assets/branding/icon_adaptive.png b/assets/images/branding/icon_adaptive.png similarity index 100% rename from assets/branding/icon_adaptive.png rename to assets/images/branding/icon_adaptive.png diff --git a/assets/branding/icon_drawer.png b/assets/images/branding/icon_drawer.png similarity index 100% rename from assets/branding/icon_drawer.png rename to assets/images/branding/icon_drawer.png diff --git a/assets/branding/splash.png b/assets/images/branding/splash.png similarity index 100% rename from assets/branding/splash.png rename to assets/images/branding/splash.png diff --git a/assets/images/colors/accent.png b/assets/images/colors/accent.png deleted file mode 100644 index 20783ca4..00000000 Binary files a/assets/images/colors/accent.png and /dev/null differ diff --git a/assets/images/colors/black.png b/assets/images/colors/black.png deleted file mode 100644 index 7c301776..00000000 Binary files a/assets/images/colors/black.png and /dev/null differ diff --git a/assets/images/colors/secondary.png b/assets/images/colors/secondary.png deleted file mode 100644 index 097d2d55..00000000 Binary files a/assets/images/colors/secondary.png and /dev/null differ diff --git a/assets/images/sonarr/noseriesposter.png b/assets/images/sonarr/noseriesposter.png deleted file mode 100644 index 6607ea21..00000000 Binary files a/assets/images/sonarr/noseriesposter.png and /dev/null differ diff --git a/assets/images/tautulli/nouserthumb.png b/assets/images/tautulli/nouserthumb.png deleted file mode 100644 index 9c9e33ac..00000000 Binary files a/assets/images/tautulli/nouserthumb.png and /dev/null differ diff --git a/assets/localization/de.json b/assets/localization/de.json index d4e6f7df..bf318c30 100644 --- a/assets/localization/de.json +++ b/assets/localization/de.json @@ -1,16 +1,17 @@ { "lunasea.AnErrorHasOccurred": "Ein Fehler ist aufgetreten", + "lunasea.Cancel": "Abbrechen", "lunasea.ChangeProfiles": "Profile wechseln", - "lunasea.CheckLogsMessage": "Überprüfe die Logs für mehr Details", + "lunasea.CheckLogsMessage": "Überprüfe die Protokolle für mehr Details", "lunasea.ComingSoon": "Bald verfügbar", - "lunasea.Dashboard": "Dashboard", + "lunasea.Dashboard": "Instrumentenanlage", "lunasea.GoBack": "Zurück", - "lunasea.ModuleIsNotEnabled": "{} Ist Nicht Aktiviert", + "lunasea.ModuleIsNotEnabled": "{} ist nicht aktiviert", "lunasea.Refresh": "Aktualisieren", - "lunasea.ReturnToDashboard": "Zurück zum Dashboard", - "lunasea.SearchTextBar": "Suche…", + "lunasea.ReturnToDashboard": "Zurück zur Instrumentenanlage", + "lunasea.SearchTextBar": "Suche …", "lunasea.Settings": "Einstellungen", - "lunasea.TryAgain": "Erneut Versuchen", + "lunasea.TryAgain": "Erneut versuchen", "lunasea.Unknown": "Unbekannt", "radarr.AddMovie": "Film hinzufügen", "radarr.AddMovieAndSearch": "Hinzufügen + Suchen", @@ -27,7 +28,7 @@ "radarr.DateAdded": "Hinzugefügt am", "radarr.Discover": "Entdecken", "radarr.DownloadFailed": "Herunterladen gescheitert", - "radarr.DownloadIgnored": "Download ignoriert", + "radarr.DownloadIgnored": "Herunterladen ignoriert", "radarr.EditMovie": "Film bearbeiten", "radarr.FilterCatalogue": "Katalog filtern", "radarr.GrabbedFrom": "Gegrabbed von {}", @@ -70,7 +71,7 @@ "radarr.SortCatalogue": "Katalog sortieren", "radarr.Studio": "Studio", "radarr.SystemStatus": "Systemstatus", - "radarr.SystemStatusDescription": "Systemstatus & Speicherplatz", + "radarr.SystemStatusDescription": "Systemstatus und Speicherplatz", "radarr.Tags": "Tags", "radarr.TagsDescription": "Verwalte deine Tags", "radarr.Type": "Typ", @@ -88,8 +89,8 @@ "search.FailedToDownloadNZB": "Herunterladen der NZB fehlgeschlagen", "search.DownloadToDevice": "Auf Gerät herunterladen", "search.DownloadingNZBToDevice": "Lädt NZB auf deinem Gerät herunter", - "search.Downloading": "Herunterladen…", - "search.Download": "Download", + "search.Downloading": "Herunterladen …", + "search.Download": "Herunterladen", "search.Comments": "Kommentare", "search.Categories": "Kategorien", "search.Category": "Kategorie", @@ -99,9 +100,77 @@ "search.Subcategories": "Unterkategorien", "search.Size": "Größe", "search.SentTo": "An {} gesendet", - "search.SentNZBData": "NZB Daten gesendet", + "search.SentNZBData": "NZB-Daten gesendet", "search.Search": "Suche", "search.Results": "Ergebnisse", "search.NoSubcategoriesFound": "Keine Unterkategorien gefunden", - "search.NoResultsFound": "Keine Ergebnisse gefunden" + "search.NoResultsFound": "Keine Ergebnisse gefunden", + "tautulli.TerminateSessionFailed": "Abbrechen der Sitzung fehlgeschlagen", + "tautulli.TerminateSession": "Sitzung abbrechen", + "tautulli.TerminatedSession": "Abgebrochene Sitzung", + "tautulli.TerminationConfirmMessage": "Möchtest du diese Sitzung abbrechen?", + "tautulli.Terminate": "Abbrechen", + "tautulli.Episode": "Folge {}", + "tautulli.Year": "Jahr", + "tautulli.ViewWebGUI": "Weboberfläche ansehen", + "tautulli.Video": "Video", + "tautulli.Users": "Benutzer", + "tautulli.User": "Benutzer", + "tautulli.Transcodes": "Transkodierungen", + "tautulli.Transcode": "Transkodieren", + "tautulli.Title": "Titel", + "tautulli.Throttled": "Throttled", + "tautulli.TerminationMessage": "Abbruch-Begründung", + "tautulli.TerminationAttachMessage": "Du kannst optional unten eine Abbruch-Begründung angeben.", + "tautulli.Subtitle": "Untertitel", + "tautulli.Stream": "Stream", + "tautulli.SessionsMany": "{} Sitzungen", + "tautulli.SessionsOne": "1 Sitzung", + "tautulli.Sessions": "Sitzungen", + "tautulli.SessionEnded": "Sitzung beendet", + "tautulli.Season": "Staffel {}", + "tautulli.Quality": "Qualität", + "tautulli.Product": "Produkt", + "tautulli.Player": "Player", + "tautulli.Platform": "Plattform", + "tautulli.NoActiveStreams": "Keine aktiven Streams", + "tautulli.None": "Nichts", + "tautulli.More": "Mehr", + "tautulli.Metadata": "Metadaten", + "tautulli.Location": "Ort", + "tautulli.Library": "Bibliothek", + "tautulli.History": "Verlauf", + "tautulli.ETA": "Restzeit", + "tautulli.Duration": "Dauer", + "tautulli.DirectStreams": "Direct Streams", + "tautulli.DirectStream": "Direct Stream", + "tautulli.DirectPlays": "Direct Plays", + "tautulli.DirectPlay": "Direct Play", + "tautulli.DeletingTemporarySessionsFailed": "Löschen der temporären Sitzungen fehlgeschlagen", + "tautulli.DeletingTemporarySessionsDescription": "Temporäre Sitzungen werden gelöscht", + "tautulli.DeletingTemporarySessions": "Lösche temporäre Sitzungen…", + "tautulli.DeletingImageCacheFailed": "Löschen des Bild-Zwischenspeicher fehlgeschlagen", + "tautulli.DeletingImageCacheDescription": "Tautulli Bild-Zwischenspeicher wird gelöscht", + "tautulli.DeletingImageCache": "Lösche Bild-Zwischenspeicher…", + "tautulli.DeletingCacheFailed": "Löschen des Zwischenspeichers fehlgeschlagen", + "tautulli.DeletingCacheDescription": "Tautulli Zwischenspeicher wird gelöscht", + "tautulli.DeletingCache": "Lösche Zwischenspeicher…", + "tautulli.DeleteTemporarySessions": "Lösche temporäre Sitzungen", + "tautulli.DeleteImageCache": "Bild-Zwischenspeicher löschen", + "tautulli.DeleteCache": "Zwischenspeicher löschen", + "tautulli.Copy": "Kopieren", + "tautulli.Container": "Container", + "tautulli.Burn": "Einbrennen", + "tautulli.Bandwidth": "Bandbreite", + "tautulli.BackupDatabase": "Datenbank sichern", + "tautulli.BackupConfiguration": "Konfiguration sichern", + "tautulli.BackingUpDatabaseFailed": "Sichern der Datenbank fehlgeschlagen", + "tautulli.BackingUpDatabaseDescription": "Deine Datenbank wird im Hintergrund gesichert", + "tautulli.BackingUpDatabase": "Datenbank wird gesichert…", + "tautulli.BackingUpConfigurationFailed": "Sichern der Konfiguration fehlgeschlagen", + "tautulli.BackingUpConfigurationDescription": "Deine Konfiguration wird im Hintergrund gesichert", + "tautulli.BackingUpConfiguration": "Konfiguration wird gesichert…", + "tautulli.Audio": "Audio", + "tautulli.ActivityDetails": "Aktivitätsdetails", + "tautulli.Activity": "Aktivität" } \ No newline at end of file diff --git a/assets/localization/en.json b/assets/localization/en.json index 63789b2b..88e2381c 100644 --- a/assets/localization/en.json +++ b/assets/localization/en.json @@ -1,5 +1,6 @@ { "lunasea.AnErrorHasOccurred": "An Error Has Occurred", + "lunasea.Cancel": "Cancel", "lunasea.ChangeProfiles": "Change Profiles", "lunasea.CheckLogsMessage": "Check the logs for more details", "lunasea.ComingSoon": "Coming Soon", @@ -103,5 +104,73 @@ "search.SentNZBData": "Sent NZB Data", "search.SentTo": "Sent to {}", "search.Size": "Size", - "search.Subcategories": "Subcategories" + "search.Subcategories": "Subcategories", + "tautulli.Activity": "Activity", + "tautulli.ActivityDetails": "Activity Details", + "tautulli.Audio": "Audio", + "tautulli.BackingUpConfiguration": "Backing Up Configuration…", + "tautulli.BackingUpConfigurationDescription": "Backing up your configuration in the background", + "tautulli.BackingUpConfigurationFailed": "Failed to Backup Configuration", + "tautulli.BackingUpDatabase": "Backing Up Database…", + "tautulli.BackingUpDatabaseDescription": "Backing up your database in the background", + "tautulli.BackingUpDatabaseFailed": "Failed to Backup Database", + "tautulli.BackupConfiguration": "Backup Configuration", + "tautulli.BackupDatabase": "Backup Database", + "tautulli.Bandwidth": "Bandwidth", + "tautulli.Burn": "Burn", + "tautulli.Container": "Container", + "tautulli.Copy": "Copy", + "tautulli.DeleteCache": "Delete Cache", + "tautulli.DeleteImageCache": "Delete Image Cache", + "tautulli.DeleteTemporarySessions": "Delete Temporary Sessions", + "tautulli.DeletingCache": "Deleting Cache…", + "tautulli.DeletingCacheDescription": "Tautulli cache is being deleted", + "tautulli.DeletingCacheFailed": "Failed to Delete Cache", + "tautulli.DeletingImageCache": "Deleting Image Cache…", + "tautulli.DeletingImageCacheDescription": "Tautulli image cache is being deleted", + "tautulli.DeletingImageCacheFailed": "Failed to Delete Image Cache", + "tautulli.DeletingTemporarySessions": "Deleting Temporary Sessions…", + "tautulli.DeletingTemporarySessionsDescription": "Temporary sessions are being deleted", + "tautulli.DeletingTemporarySessionsFailed": "Failed to Delete Temporary Sessions", + "tautulli.DirectPlay": "Direct Play", + "tautulli.DirectPlays": "Direct Plays", + "tautulli.DirectStream": "Direct Stream", + "tautulli.DirectStreams": "Direct Streams", + "tautulli.Duration": "Duration", + "tautulli.Episode": "Episode {}", + "tautulli.ETA": "ETA", + "tautulli.History": "History", + "tautulli.Library": "Library", + "tautulli.Location": "Location", + "tautulli.Metadata": "Metadata", + "tautulli.More": "More", + "tautulli.None": "None", + "tautulli.NoActiveStreams": "No Active Streams", + "tautulli.Platform": "Platform", + "tautulli.Player": "Player", + "tautulli.Product": "Product", + "tautulli.Quality": "Quality", + "tautulli.Season": "Season {}", + "tautulli.SessionEnded": "Session Ended", + "tautulli.Sessions": "Sessions", + "tautulli.SessionsOne": "1 Session", + "tautulli.SessionsMany": "{} Sessions", + "tautulli.Stream": "Stream", + "tautulli.Subtitle": "Subtitle", + "tautulli.Terminate": "Terminate", + "tautulli.TerminationAttachMessage": "You can optionally attach a termination message below.", + "tautulli.TerminationConfirmMessage": "Do you want to terminate this session?", + "tautulli.TerminationMessage": "Termination Message", + "tautulli.TerminatedSession": "Terminated Session", + "tautulli.TerminateSession": "Terminate Session", + "tautulli.TerminateSessionFailed": "Failed to Terminate Session", + "tautulli.Throttled": "Throttled", + "tautulli.Title": "Title", + "tautulli.Transcode": "Transcode", + "tautulli.Transcodes": "Transcodes", + "tautulli.User": "User", + "tautulli.Users": "Users", + "tautulli.Video": "Video", + "tautulli.ViewWebGUI": "View Web GUI", + "tautulli.Year": "Year" } \ No newline at end of file diff --git a/assets/localization/fr.json b/assets/localization/fr.json index 3c44a329..0d1fd530 100644 --- a/assets/localization/fr.json +++ b/assets/localization/fr.json @@ -1,7 +1,8 @@ { "lunasea.AnErrorHasOccurred": "Une erreur s'est produite", + "lunasea.Cancel": "Annuler", "lunasea.ChangeProfiles": "Changer de profil", - "lunasea.CheckLogsMessage": "Vérifier les logs pour plus de détails", + "lunasea.CheckLogsMessage": "Vérifier les journaux pour plus de détails", "lunasea.ComingSoon": "Prochainement", "lunasea.Dashboard": "Tableau de bord", "lunasea.GoBack": "Retour en arrière", @@ -26,8 +27,8 @@ "radarr.CutoffUnmet": "Qualité préférée non atteinte", "radarr.DateAdded": "Date ajoutée", "radarr.Discover": "Découvrir", - "radarr.DownloadFailed": "Echec du téléchargement", - "radarr.DownloadIgnored": "Télécharger Ignoré", + "radarr.DownloadFailed": "Échec du téléchargement", + "radarr.DownloadIgnored": "Téléchargement ignoré", "radarr.EditMovie": "Modifier le film", "radarr.FilterCatalogue": "Catalogue des filtres", "radarr.GrabbedFrom": "Récupéré depuis {}", @@ -51,7 +52,7 @@ "radarr.NoMoviesFound": "Aucun film trouvé", "radarr.NoResultsFound": "Aucun résultat", "radarr.NoSummaryIsAvailable": "Aucun résumé n'est disponible.", - "radarr.QualityProfile": "Profil de la qualité", + "radarr.QualityProfile": "Profil de qualité", "radarr.Queue": "File d'attente", "radarr.QueueDescription": "Voir le contenu actif et en attente", "radarr.RefreshMovie": "Rafraichir le film", @@ -71,8 +72,8 @@ "radarr.Studio": "Studio", "radarr.SystemStatus": "État du système", "radarr.SystemStatusDescription": "État du système et espace disque", - "radarr.Tags": "Tags", - "radarr.TagsDescription": "Gérer vos tags", + "radarr.Tags": "Étiquettes", + "radarr.TagsDescription": "Gérer vos étiquettes", "radarr.Type": "Type", "radarr.UnmonitorMovie": "Ne plus surveiller le film", "radarr.Unmonitored": "Non surveillé", @@ -82,5 +83,94 @@ "radarr.ViewWebGUI": "Voir l'interface web", "radarr.Wanted": "Recherché", "radarr.Weight": "Poids", - "radarr.Year": "Année" + "radarr.Year": "Année", + "search.Subcategories": "Sous-catégories", + "search.Size": "Taille", + "search.SentTo": "Envoyé à {}", + "search.SentNZBData": "Données NZB envoyées", + "search.Search": "Rechercher", + "search.Results": "Résultats", + "search.NoSubcategoriesFound": "Aucune sous-catégorie trouvée", + "search.NoResultsFound": "Aucun résultat", + "search.NoCategoriesFound": "Aucune catégorie trouvée", + "search.FailedToSend": "Erreur lors de l'envoi", + "search.FailedToDownloadNZB": "Erreur lors du téléchargement du NZB", + "search.DownloadToDevice": "Télécharger sur l'appareil", + "search.DownloadingNZBToDevice": "Télécharger le NZB sur votre appareil", + "search.Downloading": "Téléchargement en cours…", + "search.Download": "Télécharger", + "search.Comments": "Commentaires", + "search.Categories": "Catégories", + "search.Category": "Catégorie", + "search.Alphabetical": "Alphabétique", + "search.AllSubcategories": "Toutes les sous-catégories", + "search.Age": "Âge", + "tautulli.Burn": "Brûler", + "tautulli.Year": "Année", + "tautulli.ViewWebGUI": "Afficher l'interface Web", + "tautulli.Video": "Vidéo", + "tautulli.Users": "Utilisateurs", + "tautulli.User": "Utilisateur", + "tautulli.Transcodes": "Transcodes", + "tautulli.Transcode": "Transcode", + "tautulli.Title": "Titre", + "tautulli.Throttled": "Throttled", + "tautulli.TerminateSessionFailed": "Échec de la fin de la session", + "tautulli.TerminateSession": "Mettre fin à la session", + "tautulli.TerminatedSession": "Session terminée", + "tautulli.TerminationMessage": "Message de fin de session", + "tautulli.TerminationConfirmMessage": "Voulez-vous mettre fin à cette session ?", + "tautulli.TerminationAttachMessage": "Vous pouvez éventuellement joindre un message ci-dessous.", + "tautulli.Terminate": "Terminer", + "tautulli.Subtitle": "Sous-titre", + "tautulli.Stream": "Stream", + "tautulli.SessionsMany": "{} Sessions", + "tautulli.SessionsOne": "1 Session", + "tautulli.Sessions": "Sessions", + "tautulli.SessionEnded": "Session terminée", + "tautulli.Season": "Saison {}", + "tautulli.Quality": "Qualité", + "tautulli.Product": "Produit", + "tautulli.Player": "Player", + "tautulli.Platform": "Platforme", + "tautulli.NoActiveStreams": "Aucun stream en cours", + "tautulli.None": "Aucun", + "tautulli.More": "Plus", + "tautulli.Metadata": "Métadonnées", + "tautulli.Location": "Localisation", + "tautulli.Library": "Bibliothèque", + "tautulli.History": "Historique", + "tautulli.ETA": "Temps restant", + "tautulli.Episode": "Épisode {}", + "tautulli.Duration": "Durée", + "tautulli.DirectStreams": "Direct Streams", + "tautulli.DirectStream": "Direct Stream", + "tautulli.DirectPlays": "Lectures directe", + "tautulli.DirectPlay": "Lecture directe", + "tautulli.DeletingTemporarySessionsFailed": "Échec de la suppression des sessions temporaires", + "tautulli.DeletingTemporarySessionsDescription": "Les sessions temporaires ont été supprimés", + "tautulli.DeletingImageCacheDescription": "Le cache des images de Tautulli a été supprimé", + "tautulli.DeletingTemporarySessions": "Suppression des sessions temporaires…", + "tautulli.DeletingImageCacheFailed": "Échec de la suppression du cache d'image", + "tautulli.DeletingImageCache": "Suppression du cache des images…", + "tautulli.DeletingCacheFailed": "Échec de la suppression du cache", + "tautulli.DeletingCacheDescription": "Le cache de Tautulli est en cours de suppression", + "tautulli.DeletingCache": "Suppression du cache en cours…", + "tautulli.DeleteTemporarySessions": "Supprimer les sessions temporaires", + "tautulli.DeleteImageCache": "Supprimer le cache des images", + "tautulli.DeleteCache": "Supprimer le cache", + "tautulli.Copy": "Copier", + "tautulli.Container": "Container", + "tautulli.Bandwidth": "Bande passante", + "tautulli.BackupDatabase": "Sauvegarder la base de donnée", + "tautulli.BackupConfiguration": "Sauvegarder la configuration", + "tautulli.BackingUpDatabaseFailed": "Échec de la sauvegarde de la base de données", + "tautulli.BackingUpDatabaseDescription": "Sauvegarde de votre base de données en arrière-plan", + "tautulli.BackingUpDatabase": "Sauvegarde de la base de données…", + "tautulli.BackingUpConfigurationFailed": "Échec de la sauvegarde de la configuration", + "tautulli.BackingUpConfigurationDescription": "Sauvegarde de votre configuration en arrière-plan", + "tautulli.BackingUpConfiguration": "Sauvegarde de la configuration…", + "tautulli.Audio": "Audio", + "tautulli.ActivityDetails": "Détails de l'activité", + "tautulli.Activity": "Activité" } \ No newline at end of file diff --git a/assets/localization/it.json b/assets/localization/it.json new file mode 100644 index 00000000..32d0f937 --- /dev/null +++ b/assets/localization/it.json @@ -0,0 +1,107 @@ +{ + "lunasea.AnErrorHasOccurred": "C'è stato un errore", + "lunasea.ChangeProfiles": "Cambia profili", + "lunasea.CheckLogsMessage": "Controlla i registri per maggiori dettagli", + "lunasea.ComingSoon": "Prossimamente", + "lunasea.Dashboard": "Pannello di controllo", + "lunasea.GoBack": "Indietro", + "lunasea.ModuleIsNotEnabled": "{} non è abilitato", + "lunasea.Refresh": "Ricarica", + "lunasea.ReturnToDashboard": "Torna al pannello di controllo", + "lunasea.SearchTextBar": "Ricerca…", + "lunasea.Settings": "Impostazioni", + "lunasea.TryAgain": "Riprova", + "lunasea.Unknown": "Sconosciuto", + "radarr.AddMovie": "Aggiungi Film", + "radarr.AddMovieAndSearch": "Aggiungi + Cerca", + "radarr.Age": "Età", + "radarr.All": "Tutti", + "radarr.Alphabetical": "Alfabetico", + "radarr.Approved": "Approvato", + "radarr.AvailabilityUnknown": "Disponibilità Sconosciuta", + "radarr.AvailableIn": "Disponibile in {}", + "radarr.AvailableToday": "Disponibile Oggi", + "radarr.BackupDatabase": "Fai un backup della banca dati", + "radarr.CinemaDateUnknown": "Data Cinema Sconosciuta", + "radarr.CutoffUnmet": "Soglia Non Raggiunta", + "radarr.DateAdded": "Data Aggiunta", + "radarr.Discover": "Scopri", + "radarr.DownloadFailed": "Scaricamento fallito", + "radarr.DownloadIgnored": "Scaricamento ignorato", + "radarr.EditMovie": "Modifica il film", + "radarr.FilterCatalogue": "Filtra catalogo", + "radarr.GrabbedFrom": "Preso da {}", + "radarr.History": "Cronologia", + "radarr.HistoryDescription": "Visualizza l'attività recente", + "radarr.InCinemasIn": "Nei cinema in {}", + "radarr.InCinemasToday": "Nei cinema oggi", + "radarr.MinimumAvailability": "Disponibilità minima", + "radarr.Missing": "Mancante", + "radarr.MonitorMovie": "Monitora il film", + "radarr.Monitored": "Monitorato", + "radarr.MonitoredDescription": "Monitora per nuove versioni", + "radarr.More": "Di più", + "radarr.MovieFileDeleted": "File film eliminato", + "radarr.MovieFileRenamed": "File film rinominato", + "radarr.MovieImported": "Film importato ({})", + "radarr.MovieNotFound": "Film non trovato", + "radarr.MoviePath": "Percorso film", + "radarr.Movies": "Film", + "radarr.NoHistoryFound": "Nessuna cronologia trovata", + "radarr.NoMoviesFound": "Nessun film trovato", + "radarr.NoResultsFound": "Nessun risultato trovato", + "radarr.NoSummaryIsAvailable": "Nessun riepilogo disponibile.", + "radarr.QualityProfile": "Profilo qualità", + "radarr.Queue": "Coda", + "radarr.QueueDescription": "Visualizza il contenuto attivo e in coda", + "radarr.RefreshMovie": "Ricarica il film", + "radarr.Rejected": "Rifiutato", + "radarr.Released": "Rilasciato", + "radarr.ReleasedToday": "Rilasciato oggi", + "radarr.RemoveMovie": "Rimuovi il film", + "radarr.RootFolder": "Cartella root", + "radarr.RunRSSSync": "Esegui sincronizzazione RSS", + "radarr.Runtime": "Durata", + "radarr.Search": "Cerca", + "radarr.SearchAllMissing": "Cerca tutti mancanti", + "radarr.SearchFor": "Cerco {}", + "radarr.Seeders": "Seeder", + "radarr.Size": "Dimensioni", + "radarr.SortCatalogue": "Ordina catalogo", + "radarr.Studio": "Studio", + "radarr.SystemStatus": "Stato sistema", + "radarr.SystemStatusDescription": "Stato sistema e spazio su disco", + "radarr.Tags": "Etichette", + "radarr.TagsDescription": "Gestisci le tue etichette", + "radarr.Type": "Tipo", + "radarr.UnmonitorMovie": "Non monitorare il film", + "radarr.Unmonitored": "Non monitorato", + "radarr.Upcoming": "Imminente", + "radarr.UpdateLibrary": "Aggiorna la libreria", + "radarr.UpdateMovie": "Aggiorna il film", + "radarr.ViewWebGUI": "Visualizza Web GUI", + "radarr.Wanted": "Ricercato", + "radarr.Weight": "Peso", + "radarr.Year": "Anno", + "search.Subcategories": "Sottocategorie", + "search.Size": "Dimensioni", + "search.SentTo": "Invia a {}", + "search.SentNZBData": "Dati NZB inviati", + "search.Search": "Cerca", + "search.Results": "Risultati", + "search.NoSubcategoriesFound": "Nessuna sottocategoria trovata", + "search.NoResultsFound": "Nessun risultato trovato", + "search.NoCategoriesFound": "Nessuna categoria trovata", + "search.FailedToSend": "Invio non riuscito", + "search.FailedToDownloadNZB": "Impossibile scaricare NZB", + "search.DownloadToDevice": "Scarica sul dispositivo", + "search.DownloadingNZBToDevice": "Scaricamento di NZB sul tuo dispositivo", + "search.Downloading": "Scaricamento in corso…", + "search.Download": "Scarica", + "search.Comments": "Commenti", + "search.Categories": "Categorie", + "search.Category": "Categoria", + "search.Alphabetical": "Alfabetico", + "search.AllSubcategories": "Tutte Le Sottocategorie", + "search.Age": "Età" +} \ No newline at end of file diff --git a/assets/localization/sv.json b/assets/localization/sv.json index df021d78..79e95e15 100644 --- a/assets/localization/sv.json +++ b/assets/localization/sv.json @@ -1,37 +1,107 @@ { "lunasea.AnErrorHasOccurred": "Ett fel har inträffat", + "lunasea.ChangeProfiles": "Byta Profil", + "lunasea.CheckLogsMessage": "Kolla loggen för mera detaljer", + "lunasea.ComingSoon": "Kommer Snart", + "lunasea.Dashboard": "Instrumentbräda", + "lunasea.GoBack": "Tillbaka", + "lunasea.ModuleIsNotEnabled": "{} Är Inte Aktiverad", "lunasea.Refresh": "Uppdatera", + "lunasea.ReturnToDashboard": "Gå Tillbaka till Instrumentbrädan", "lunasea.SearchTextBar": "Sök…", "lunasea.Settings": "Inställningar", + "lunasea.TryAgain": "Försök Igen", + "lunasea.Unknown": "Okänd", "radarr.AddMovie": "Lägg till Film", "radarr.AddMovieAndSearch": "Lägg till + Sök", + "radarr.Age": "Ålder", + "radarr.All": "Alla", + "radarr.Alphabetical": "Alfabetiskt", + "radarr.Approved": "Godkänd", + "radarr.AvailabilityUnknown": "Tillgänglighet Okänd", + "radarr.AvailableIn": "Tillgänglig i {}", + "radarr.AvailableToday": "Tillgänglig Idag", + "radarr.BackupDatabase": "Säkerhetskopiera Databasen", + "radarr.CinemaDateUnknown": "Okänt Biograf Datum", + "radarr.CutoffUnmet": "Avgränsande ej tillgodosedd", + "radarr.DateAdded": "Datum tillagt", "radarr.Discover": "Utforska", + "radarr.DownloadFailed": "Nedladdning Misslyckades", + "radarr.DownloadIgnored": "Ignorerad Nedladdning", "radarr.EditMovie": "Redigera Film", "radarr.FilterCatalogue": "Filterkatalog", + "radarr.GrabbedFrom": "Hämtad från {}", "radarr.History": "Historik", "radarr.HistoryDescription": "Visa Senaste Aktivitet", + "radarr.InCinemasIn": "Visas på Biograf {}", + "radarr.InCinemasToday": "På Biograf Idag", "radarr.MinimumAvailability": "Minsta Tillgänglighet", "radarr.Missing": "Saknas", + "radarr.MonitorMovie": "Bevaka Film", "radarr.Monitored": "Bevakad", "radarr.MonitoredDescription": "Bevaka för nya utgåvor", "radarr.More": "Mer", + "radarr.MovieFileDeleted": "Filmfil Raderad", + "radarr.MovieFileRenamed": "Filmfil Omdöpt", + "radarr.MovieImported": "Film Importerad ({})", "radarr.MovieNotFound": "Film Hittades Inte", "radarr.MoviePath": "Film Sökväg", "radarr.Movies": "Filmer", + "radarr.NoHistoryFound": "Ingen Historik Hittad", "radarr.NoMoviesFound": "Inga Filmer Funna", "radarr.NoResultsFound": "Inga Resultat Funna", "radarr.NoSummaryIsAvailable": "Ingen sammanfattning finns tillgänglig.", "radarr.QualityProfile": "Kvalitetsprofil", "radarr.Queue": "Kö", "radarr.QueueDescription": "Visa Aktivt & Köat Innehåll", + "radarr.RefreshMovie": "Uppdatera Film", + "radarr.Rejected": "Avvisad", + "radarr.Released": "Släppt", + "radarr.ReleasedToday": "Släpptes Idag", + "radarr.RemoveMovie": "Ta Bort Film", "radarr.RootFolder": "Rotmapp", + "radarr.RunRSSSync": "Kör RSS Synkronisering", + "radarr.Runtime": "Speltid", "radarr.Search": "Sök", + "radarr.SearchAllMissing": "Sök Alla Saknade", "radarr.SearchFor": "Sök efter {}", + "radarr.Seeders": "Seedare", + "radarr.Size": "Storlek", "radarr.SortCatalogue": "Sortera Katalog", + "radarr.Studio": "Studio", "radarr.SystemStatus": "Systemstatus", "radarr.SystemStatusDescription": "Systemstatus & Disk Utrymme", "radarr.Tags": "Taggar", "radarr.TagsDescription": "Hantera Dina Taggar", + "radarr.Type": "Typ", + "radarr.UnmonitorMovie": "Obevaka Film", + "radarr.Unmonitored": "Obevakad", "radarr.Upcoming": "Kommande", - "radarr.UpdateMovie": "Uppdatera Film" + "radarr.UpdateLibrary": "Uppdatera Bibliotek", + "radarr.UpdateMovie": "Uppdatera Film", + "radarr.ViewWebGUI": "Visa Webb GUI", + "radarr.Wanted": "Önskad", + "radarr.Weight": "Vikt", + "radarr.Year": "År", + "search.Size": "Storlek", + "search.Search": "Sök", + "search.NoResultsFound": "Inga Resultat Funna", + "search.Alphabetical": "Alfabetiskt", + "search.Age": "Ålder", + "search.Subcategories": "Underkategorier", + "search.SentTo": "Skickat till {}", + "search.SentNZBData": "NZB Data Skickat", + "search.Results": "Resultat", + "search.NoSubcategoriesFound": "Inga Underkategorier Funna", + "search.NoCategoriesFound": "Inga Kategorier Funna", + "search.FailedToSend": "Misslyckades att Skicka", + "search.FailedToDownloadNZB": "Misslyckades med att Ladda ned NZB", + "search.DownloadToDevice": "Ladda ned till Enhet", + "search.DownloadingNZBToDevice": "Laddar ned NZB till din enhet", + "search.Downloading": "Laddar ned…", + "search.Download": "Ladda ned", + "search.Comments": "Kommentarer", + "search.Categories": "Kategorier", + "search.Category": "Kategori", + "search.AllSubcategories": "Alla Underkategorier" } \ No newline at end of file diff --git a/derry.yaml b/derry.yaml new file mode 100644 index 00000000..a19ad78a --- /dev/null +++ b/derry.yaml @@ -0,0 +1,12 @@ +generate: + runner: flutter packages pub run build_runner build --delete-conflicting-outputs + localization: dart ./scripts/generate/localization.dart +build: + android: + apk: ./scripts/build/apk.sh + aab: ./scripts/build/aab.sh + ios: + ipa: ./scripts/build/ipa.sh + archive: + - flutter clean + - flutter build ios diff --git a/ios/Podfile.lock b/ios/Podfile.lock index abf5b83a..f86ca006 100644 --- a/ios/Podfile.lock +++ b/ios/Podfile.lock @@ -1,5 +1,5 @@ PODS: - - cloud_firestore (1.0.0): + - cloud_firestore (1.0.1): - Firebase/Firestore (= 7.3.0) - firebase_core - Flutter @@ -40,9 +40,14 @@ PODS: - file_picker (0.0.1): - DKImagePickerController/PhotoGallery - Flutter + - Firebase/Analytics (7.3.0): + - Firebase/Core - Firebase/Auth (7.3.0): - Firebase/CoreOnly - FirebaseAuth (~> 7.3.0) + - Firebase/Core (7.3.0): + - Firebase/CoreOnly + - FirebaseAnalytics (= 7.3.0) - Firebase/CoreOnly (7.3.0): - FirebaseCore (= 7.3.0) - Firebase/Crashlytics (7.3.0): @@ -57,11 +62,15 @@ PODS: - Firebase/Storage (7.3.0): - Firebase/CoreOnly - FirebaseStorage (~> 7.3.0) - - firebase_auth (1.0.0): + - firebase_analytics (7.1.1): + - Firebase/Analytics (= 7.3.0) + - firebase_core + - Flutter + - firebase_auth (1.0.1): - Firebase/Auth (= 7.3.0) - firebase_core - Flutter - - firebase_core (1.0.0): + - firebase_core (1.0.1): - Firebase/CoreOnly (= 7.3.0) - Flutter - firebase_crashlytics (1.0.0): @@ -75,6 +84,15 @@ PODS: - Firebase/Storage (= 7.3.0) - firebase_core - Flutter + - FirebaseAnalytics (7.3.0): + - FirebaseCore (~> 7.0) + - FirebaseInstallations (~> 7.0) + - GoogleAppMeasurement (= 7.3.0) + - GoogleUtilities/AppDelegateSwizzler (~> 7.0) + - GoogleUtilities/MethodSwizzler (~> 7.0) + - GoogleUtilities/Network (~> 7.0) + - "GoogleUtilities/NSData+zlib (~> 7.0)" + - nanopb (~> 2.30906.0) - FirebaseAuth (7.3.0): - FirebaseCore (~> 7.0) - GoogleUtilities/AppDelegateSwizzler (~> 7.0) @@ -117,6 +135,12 @@ PODS: - FirebaseCore (~> 7.0) - GTMSessionFetcher/Core (~> 1.4) - Flutter (1.0.0) + - GoogleAppMeasurement (7.3.0): + - GoogleUtilities/AppDelegateSwizzler (~> 7.0) + - GoogleUtilities/MethodSwizzler (~> 7.0) + - GoogleUtilities/Network (~> 7.0) + - "GoogleUtilities/NSData+zlib (~> 7.0)" + - nanopb (~> 2.30906.0) - GoogleDataTransport (8.1.0): - nanopb (~> 2.30906.0) - GoogleUtilities/AppDelegateSwizzler (7.2.2): @@ -127,6 +151,8 @@ PODS: - PromisesObjC (~> 1.2) - GoogleUtilities/Logger (7.2.2): - GoogleUtilities/Environment + - GoogleUtilities/MethodSwizzler (7.2.2): + - GoogleUtilities/Logger - GoogleUtilities/Network (7.2.2): - GoogleUtilities/Logger - "GoogleUtilities/NSData+zlib" @@ -157,7 +183,7 @@ PODS: - SDWebImage (5.10.4): - SDWebImage/Core (= 5.10.4) - SDWebImage/Core (5.10.4) - - share_plus (0.0.1): + - share (0.0.1): - Flutter - shared_preferences (0.0.1): - Flutter @@ -170,6 +196,7 @@ DEPENDENCIES: - connectivity_plus (from `.symlinks/plugins/connectivity_plus/ios`) - file_picker (from `.symlinks/plugins/file_picker/ios`) - Firebase/Messaging + - firebase_analytics (from `.symlinks/plugins/firebase_analytics/ios`) - firebase_auth (from `.symlinks/plugins/firebase_auth/ios`) - firebase_core (from `.symlinks/plugins/firebase_core/ios`) - firebase_crashlytics (from `.symlinks/plugins/firebase_crashlytics/ios`) @@ -182,7 +209,7 @@ DEPENDENCIES: - package_info (from `.symlinks/plugins/package_info/ios`) - path_provider (from `.symlinks/plugins/path_provider/ios`) - quick_actions (from `.symlinks/plugins/quick_actions/ios`) - - share_plus (from `.symlinks/plugins/share_plus/ios`) + - share (from `.symlinks/plugins/share/ios`) - shared_preferences (from `.symlinks/plugins/shared_preferences/ios`) - url_launcher (from `.symlinks/plugins/url_launcher/ios`) @@ -191,6 +218,7 @@ SPEC REPOS: - DKImagePickerController - DKPhotoGallery - Firebase + - FirebaseAnalytics - FirebaseAuth - FirebaseCore - FirebaseCoreDiagnostics @@ -199,6 +227,7 @@ SPEC REPOS: - FirebaseInstanceID - FirebaseMessaging - FirebaseStorage + - GoogleAppMeasurement - GoogleDataTransport - GoogleUtilities - GTMSessionFetcher @@ -215,6 +244,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/connectivity_plus/ios" file_picker: :path: ".symlinks/plugins/file_picker/ios" + firebase_analytics: + :path: ".symlinks/plugins/firebase_analytics/ios" firebase_auth: :path: ".symlinks/plugins/firebase_auth/ios" firebase_core: @@ -240,8 +271,8 @@ EXTERNAL SOURCES: :path: ".symlinks/plugins/path_provider/ios" quick_actions: :path: ".symlinks/plugins/quick_actions/ios" - share_plus: - :path: ".symlinks/plugins/share_plus/ios" + share: + :path: ".symlinks/plugins/share/ios" shared_preferences: :path: ".symlinks/plugins/shared_preferences/ios" url_launcher: @@ -253,17 +284,19 @@ CHECKOUT OPTIONS: :tag: 7.3.0 SPEC CHECKSUMS: - cloud_firestore: efd6d2bafe5147690cff2ccfbde13752a56fa281 + cloud_firestore: 69d71054fcab9a1c0d4779362f85b94aec7ff7d7 connectivity_plus: f5e5e0b894ec1187bfab9816d6c2f034da8d46da DKImagePickerController: b5eb7f7a388e4643264105d648d01f727110fc3d DKPhotoGallery: fdfad5125a9fdda9cc57df834d49df790dbb4179 file_picker: 3e6c3790de664ccf9b882732d9db5eaf6b8d4eb1 Firebase: 26223c695fe322633274198cb19dca8cb7e54416 - firebase_auth: f07f3ee03813d95157ee08ce763c649c656174b5 - firebase_core: f47224dd6a9b928b4cf0128b0d004ec9e47d4bf2 + firebase_analytics: ee4abb07bfa857e7c95d97144efe9eb68be414cd + firebase_auth: 9f6491ea8e44570323361ae713a2ae3175b3f21a + firebase_core: d2e03528e2a600891f6f460b5e92932624480d1d firebase_crashlytics: a62319db93baf2bfeca8a2384af3f29e3d62b09c firebase_messaging: fc1811236795c2313b8339c35d31295b1cd8486f firebase_storage: a4b292db6551a64c3697c7e67cb1df524b494bb1 + FirebaseAnalytics: 2580c2d62535ae7b644143d48941fcc239ea897a FirebaseAuth: c224a0cf1afa0949bd5c7bfcf154b4f5ce8ddef2 FirebaseCore: 4d3c72622ce0e2106aaa07bb4b2935ba2c370972 FirebaseCoreDiagnostics: d50e11039e5984d92c8a512be2395f13df747350 @@ -274,6 +307,7 @@ SPEC CHECKSUMS: FirebaseMessaging: 68d1bcb14880189558a8ae57167abe0b7e417232 FirebaseStorage: 5002b1895bfe74a5ce92ad54f966e6162d0da2e5 Flutter: 434fef37c0980e73bb6479ef766c45957d4b510c + GoogleAppMeasurement: 8d3c0aeede16ab7764144b5a4ca8e1d4323841b7 GoogleDataTransport: 116c84c4bdeb76be2a7a46de51244368f9794eab GoogleUtilities: 31c5b01f978a70c6cff2afc6272b3f1921614b43 GTMSessionFetcher: b3503b20a988c4e20cc189aa798fd18220133f52 @@ -286,7 +320,7 @@ SPEC CHECKSUMS: quick_actions: 6cb2390c4dab0e737c94573c27e18d9666710720 Reachability: 33e18b67625424e47b6cde6d202dce689ad7af96 SDWebImage: c666b97e1fa9c64b4909816a903322018f0a9c84 - share_plus: 2e6276f752c279a84cd68a9fc27dfbbe2a74b072 + share: 0b2c3e82132f5888bccca3351c504d0003b3b410 shared_preferences: af6bfa751691cdc24be3045c43ec037377ada40d SwiftyGif: 5d4af95df24caf1c570dbbcb32a3b8a0763bc6d7 url_launcher: 6fef411d543ceb26efce54b05a0a40bfd74cbbef diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj index f825c68d..23694519 100644 --- a/ios/Runner.xcodeproj/project.pbxproj +++ b/ios/Runner.xcodeproj/project.pbxproj @@ -442,7 +442,7 @@ "${BUILT_PRODUCTS_DIR}/FirebaseStorage/FirebaseStorage.framework", "${BUILT_PRODUCTS_DIR}/GTMSessionFetcher/GTMSessionFetcher.framework", "${BUILT_PRODUCTS_DIR}/GoogleDataTransport/GoogleDataTransport.framework", - "${BUILT_PRODUCTS_DIR}/GoogleUtilities/GoogleUtilities.framework", + "${BUILT_PRODUCTS_DIR}/GoogleUtilities-00567490/GoogleUtilities.framework", "${BUILT_PRODUCTS_DIR}/PromisesObjC/FBLPromises.framework", "${BUILT_PRODUCTS_DIR}/Reachability/Reachability.framework", "${BUILT_PRODUCTS_DIR}/SDWebImage/SDWebImage.framework", @@ -455,7 +455,7 @@ "${BUILT_PRODUCTS_DIR}/package_info/package_info.framework", "${BUILT_PRODUCTS_DIR}/path_provider/path_provider.framework", "${BUILT_PRODUCTS_DIR}/quick_actions/quick_actions.framework", - "${BUILT_PRODUCTS_DIR}/share_plus/share_plus.framework", + "${BUILT_PRODUCTS_DIR}/share/share.framework", "${BUILT_PRODUCTS_DIR}/shared_preferences/shared_preferences.framework", "${BUILT_PRODUCTS_DIR}/url_launcher/url_launcher.framework", ); @@ -486,7 +486,7 @@ "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/package_info.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/path_provider.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/quick_actions.framework", - "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share_plus.framework", + "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/share.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/shared_preferences.framework", "${TARGET_BUILD_DIR}/${FRAMEWORKS_FOLDER_PATH}/url_launcher.framework", ); diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme index a28140cf..fb2dffc4 100644 --- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme +++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme @@ -27,8 +27,6 @@ selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB" selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB" shouldUseLaunchSchemeArgsEnv = "YES"> - - - - + + - - _openBoxes() async { - await Hive.openBox('lunasea'); await Hive.openBox('alerts'); await Hive.openBox('indexers'); + await Hive.openBox('logs'); + await Hive.openBox('lunasea'); await Hive.openBox('profiles'); } /// Set the default state for all hive boxes. - void setDefaults({ bool clearAlerts = false }) { + void setDefaults({ bool clearEverything = false }) { //Clear all the boxes - clearAllBoxes(clearAlerts: clearAlerts); + clearAllBoxes(clearEverything: clearEverything); //Set default profile & enabled profile profilesBox.put('default', ProfileHiveObject.empty()); lunaSeaBox.put(LunaDatabaseValue.ENABLED_PROFILE.key, 'default'); } //Get boxes - static Box get lunaSeaBox => Hive.box('lunasea'); static Box get alertsBox => Hive.box('alerts'); - static Box get profilesBox => Hive.box('profiles'); - static Box get indexersBox => Hive.box('indexers'); + static Box get indexersBox => Hive.box('indexers'); + static Box get logsBox => Hive.box('logs'); + static Box get lunaSeaBox => Hive.box('lunasea'); + static Box get profilesBox => Hive.box('profiles'); //Clear boxes + void clearAlertsBox() => alertsBox.deleteAll(alertsBox.keys); + void clearIndexersBox() => indexersBox.deleteAll(indexersBox.keys); + void clearLogsBox() => logsBox.deleteAll(logsBox.keys); void clearLunaSeaBox() => lunaSeaBox.deleteAll(lunaSeaBox.keys); void clearProfilesBox() => profilesBox.deleteAll(profilesBox.keys); - void clearIndexersBox() => indexersBox.deleteAll(indexersBox.keys); - void clearAlertsBox() => alertsBox.deleteAll(alertsBox.keys); - void clearAllBoxes({ bool clearAlerts = false }) { + + void clearAllBoxes({ bool clearEverything = false }) { clearLunaSeaBox(); clearProfilesBox(); clearIndexersBox(); - if(clearAlerts) clearAlertsBox(); + if(clearEverything) { + clearAlertsBox(); + clearLogsBox(); + } } //Profile values diff --git a/lib/core/database/luna_database.dart b/lib/core/database/luna_database.dart index a5048080..e79adc2f 100644 --- a/lib/core/database/luna_database.dart +++ b/lib/core/database/luna_database.dart @@ -4,6 +4,10 @@ import 'package:lunasea/core.dart'; class LunaDatabase extends LunaModuleDatabase { @override void registerAdapters() { + Hive.registerAdapter(IndexerHiveObjectAdapter()); + Hive.registerAdapter(ProfileHiveObjectAdapter()); + Hive.registerAdapter(LunaLogHiveObjectAdapter()); + Hive.registerAdapter(LunaLogTypeAdapter()); Hive.registerAdapter(LunaBrowserAdapter()); } @@ -16,7 +20,8 @@ class LunaDatabase extends LunaModuleDatabase { case LunaDatabaseValue.SELECTED_BROWSER: data[value.key] = (LunaDatabaseValue.SELECTED_BROWSER.data as LunaBrowser).key; break; // Primitive values case LunaDatabaseValue.ENABLED_PROFILE: - case LunaDatabaseValue.ENABLED_SENTRY: + case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS: + case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS: case LunaDatabaseValue.THEME_AMOLED: case LunaDatabaseValue.THEME_AMOLED_BORDER: case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY: @@ -43,7 +48,8 @@ class LunaDatabase extends LunaModuleDatabase { case LunaDatabaseValue.SELECTED_BROWSER: value.put(LunaBrowser.APPLE_SAFARI.fromKey(config[key])); break; // Primitive values case LunaDatabaseValue.ENABLED_PROFILE: - case LunaDatabaseValue.ENABLED_SENTRY: + case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS: + case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS: case LunaDatabaseValue.THEME_AMOLED: case LunaDatabaseValue.THEME_AMOLED_BORDER: case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY: @@ -63,7 +69,8 @@ class LunaDatabase extends LunaModuleDatabase { LunaDatabaseValue valueFromKey(String key) { switch(key) { case 'profile': return LunaDatabaseValue.ENABLED_PROFILE; - case 'LUNASEA_ENABLED_SENTRY': return LunaDatabaseValue.ENABLED_SENTRY; + case 'LUNASEA_ENABLE_FIREBASE_ANALYTICS': return LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS; + case 'LUNASEA_ENABLE_FIREBASE_CRASHLYTICS': return LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS; case 'LUNASEA_THEME_AMOLED': return LunaDatabaseValue.THEME_AMOLED; case 'LUNASEA_THEME_AMOLED_BORDER': return LunaDatabaseValue.THEME_AMOLED_BORDER; case 'LUNASEA_THEME_IMAGE_BACKGROUND_OPACITY': return LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY; @@ -84,7 +91,8 @@ class LunaDatabase extends LunaModuleDatabase { enum LunaDatabaseValue { ENABLED_PROFILE, - ENABLED_SENTRY, + ENABLE_FIREBASE_ANALYTICS, + ENABLE_FIREBASE_CRASHLYTICS, THEME_AMOLED, THEME_AMOLED_BORDER, THEME_IMAGE_BACKGROUND_OPACITY, @@ -104,7 +112,8 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue { String get key { switch(this) { case LunaDatabaseValue.ENABLED_PROFILE: return 'profile'; - case LunaDatabaseValue.ENABLED_SENTRY: return 'LUNASEA_ENABLED_SENTRY'; + case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS: return 'LUNASEA_ENABLE_FIREBASE_ANALYTICS'; + case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS: return 'LUNASEA_ENABLE_FIREBASE_CRASHLYTICS'; case LunaDatabaseValue.THEME_AMOLED: return 'LUNASEA_THEME_AMOLED'; case LunaDatabaseValue.THEME_AMOLED_BORDER: return 'LUNASEA_THEME_AMOLED_BORDER'; case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY: return 'LUNASEA_THEME_IMAGE_BACKGROUND_OPACITY'; @@ -130,7 +139,8 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue { case LunaDatabaseValue.THEME_AMOLED: return box.get(this.key, defaultValue: false); case LunaDatabaseValue.THEME_AMOLED_BORDER: return box.get(this.key, defaultValue: false); case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY: return box.get(this.key, defaultValue: 10); - case LunaDatabaseValue.ENABLED_SENTRY: return box.get(this.key, defaultValue: true); + case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS: return box.get(this.key, defaultValue: true); + case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS: return box.get(this.key, defaultValue: true); case LunaDatabaseValue.QUICK_ACTIONS_LIDARR: return box.get(this.key, defaultValue: false); case LunaDatabaseValue.QUICK_ACTIONS_RADARR: return box.get(this.key, defaultValue: false); case LunaDatabaseValue.QUICK_ACTIONS_SONARR: return box.get(this.key, defaultValue: false); @@ -148,7 +158,8 @@ extension LunaDatabaseValueExtension on LunaDatabaseValue { final box = Database.lunaSeaBox; switch(this) { case LunaDatabaseValue.ENABLED_PROFILE: if(value.runtimeType == String) box.put(this.key, value); return; - case LunaDatabaseValue.ENABLED_SENTRY: if(value.runtimeType == bool) box.put(this.key, value); return; + case LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS: if(value.runtimeType == bool) box.put(this.key, value); return; + case LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS: if(value.runtimeType == bool) box.put(this.key, value); return; case LunaDatabaseValue.THEME_AMOLED: if(value.runtimeType == bool) box.put(this.key, value); return; case LunaDatabaseValue.THEME_AMOLED_BORDER: if(value.runtimeType == bool) box.put(this.key, value); return; case LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY: if(value.runtimeType == int) box.put(this.key, value); return; diff --git a/lib/core/extensions.dart b/lib/core/extensions.dart index 25a5d62b..0b9f5ea8 100644 --- a/lib/core/extensions.dart +++ b/lib/core/extensions.dart @@ -1,7 +1,6 @@ export 'extensions/datetime.dart'; export 'extensions/double.dart'; export 'extensions/duration.dart'; -export 'extensions/flog_log_level.dart'; export 'extensions/iap_product_details.dart'; export 'extensions/int.dart'; export 'extensions/navigator_state.dart'; diff --git a/lib/core/extensions/flog_log_level.dart b/lib/core/extensions/flog_log_level.dart deleted file mode 100644 index d03868e7..00000000 --- a/lib/core/extensions/flog_log_level.dart +++ /dev/null @@ -1,18 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:f_logs/f_logs.dart'; - -extension FLogLogLevelExtension on LogLevel { - /// Return a readable string version of the log level. - String get lunaName => this.toString().substring(9); - - /// Return a [Color] corresponding to the log level. - Color get lunaColour { - switch(this) { - case LogLevel.WARNING: return LunaColours.orange; - case LogLevel.ERROR: return LunaColours.red; - case LogLevel.FATAL: return LunaColours.accent; - default: return LunaColours.blueGrey; - } - } -} \ No newline at end of file diff --git a/lib/core/extensions/page_controller.dart b/lib/core/extensions/page_controller.dart index 60b3e10d..e649b1f7 100644 --- a/lib/core/extensions/page_controller.dart +++ b/lib/core/extensions/page_controller.dart @@ -10,4 +10,9 @@ extension PageControllerExtension on PageController { curve: Curves.decelerate, ); } + + /// Jump a [PageView] to the given index. + Future lunaJumpToPage(int index) async { + if(this.hasClients) this.jumpToPage(index); + } } diff --git a/lib/core/extensions/string.dart b/lib/core/extensions/string.dart index 8fd9cb1f..892f41f5 100644 --- a/lib/core/extensions/string.dart +++ b/lib/core/extensions/string.dart @@ -8,7 +8,11 @@ extension StringExtension on String { String lunaCapitalizeFirstLetters({ Pattern pattern = ' ' }) { List split = this.split(pattern); for(var i=0; i { host: fields[1] as String, apiKey: fields[2] as String, headers: (fields[3] as Map)?.cast(), + icon: fields[4] as LunaIndexerIcon, ); } @override void write(BinaryWriter writer, IndexerHiveObject obj) { writer - ..writeByte(4) + ..writeByte(5) ..writeByte(0) ..write(obj.displayName) ..writeByte(1) @@ -35,7 +36,9 @@ class IndexerHiveObjectAdapter extends TypeAdapter { ..writeByte(2) ..write(obj.apiKey) ..writeByte(3) - ..write(obj.headers); + ..write(obj.headers) + ..writeByte(4) + ..write(obj.icon); } @override diff --git a/lib/core/models/hive_objects/profile.dart b/lib/core/models/configuration/profile.dart similarity index 100% rename from lib/core/models/hive_objects/profile.dart rename to lib/core/models/configuration/profile.dart diff --git a/lib/core/models/hive_objects/profile.g.dart b/lib/core/models/configuration/profile.g.dart similarity index 100% rename from lib/core/models/hive_objects/profile.g.dart rename to lib/core/models/configuration/profile.g.dart diff --git a/lib/core/models/hive_objects.dart b/lib/core/models/hive_objects.dart deleted file mode 100644 index 8e6ecf4d..00000000 --- a/lib/core/models/hive_objects.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'hive_objects/indexer.dart'; -export 'hive_objects/profile.dart'; diff --git a/lib/core/models/log.dart b/lib/core/models/log.dart new file mode 100644 index 00000000..9d09bf73 --- /dev/null +++ b/lib/core/models/log.dart @@ -0,0 +1,88 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:stack_trace/stack_trace.dart'; + +part 'log.g.dart'; + +/// Hive database object containing all information on a log +@HiveType(typeId: 23, adapterName: 'LunaLogHiveObjectAdapter') +class LunaLogHiveObject extends HiveObject { + LunaLogHiveObject({ + @required this.timestamp, + @required this.type, + this.className, + this.methodName, + @required this.message, + this.error, + this.stackTrace, + }); + + factory LunaLogHiveObject.withMessage({ + @required LunaLogType type, + @required String message, + String className, + String methodName, + }) { + assert(type != null); + int timestamp = DateTime.now().millisecondsSinceEpoch; + return LunaLogHiveObject( + timestamp: timestamp, + type: type, + message: message, + ); + } + + factory LunaLogHiveObject.withError({ + @required LunaLogType type, + @required String message, + @required dynamic error, + @required StackTrace stackTrace, + String className, + String methodName, + }) { + assert(type != null); + int timestamp = DateTime.now().millisecondsSinceEpoch; + Trace trace = stackTrace == null ? null : Trace.from(stackTrace); + String _className, _methodName; + if((trace?.frames?.length ?? 0) >= 1) { + _className = trace.frames[0]?.uri?.toString(); + _methodName = trace.frames[0]?.member?.toString(); + } + return LunaLogHiveObject( + timestamp: timestamp, + type: type, + className: className ?? _className, + methodName: methodName ?? _methodName, + message: message, + error: error?.toString(), + stackTrace: trace?.toString(), + ); + } + + Map toMap() { + return { + "timestamp": DateTime.fromMillisecondsSinceEpoch(timestamp).toIso8601String(), + "type": type.name, + if(className != null && className.isNotEmpty) "class_name": className, + if(methodName != null && methodName.isNotEmpty) "method_name": methodName, + "message": message, + if(error != null && (error?.isNotEmpty ?? false)) "error": error, + if(stackTrace != null && (stackTrace?.isNotEmpty ?? false)) "stack_trace": stackTrace?.trim()?.split('\n') ?? [], + }; + } + + @HiveField(0) + final int timestamp; + @HiveField(1) + final LunaLogType type; + @HiveField(2) + final String className; + @HiveField(3) + final String methodName; + @HiveField(4) + final String message; + @HiveField(5) + final String error; + @HiveField(6) + final String stackTrace; +} diff --git a/lib/core/models/log.g.dart b/lib/core/models/log.g.dart new file mode 100644 index 00000000..f652d560 --- /dev/null +++ b/lib/core/models/log.g.dart @@ -0,0 +1,59 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'log.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class LunaLogHiveObjectAdapter extends TypeAdapter { + @override + final int typeId = 23; + + @override + LunaLogHiveObject read(BinaryReader reader) { + final numOfFields = reader.readByte(); + final fields = { + for (int i = 0; i < numOfFields; i++) reader.readByte(): reader.read(), + }; + return LunaLogHiveObject( + timestamp: fields[0] as int, + type: fields[1] as LunaLogType, + className: fields[2] as String, + methodName: fields[3] as String, + message: fields[4] as String, + error: fields[5] as String, + stackTrace: fields[6] as String, + ); + } + + @override + void write(BinaryWriter writer, LunaLogHiveObject obj) { + writer + ..writeByte(7) + ..writeByte(0) + ..write(obj.timestamp) + ..writeByte(1) + ..write(obj.type) + ..writeByte(2) + ..write(obj.className) + ..writeByte(3) + ..write(obj.methodName) + ..writeByte(4) + ..write(obj.message) + ..writeByte(5) + ..write(obj.error) + ..writeByte(6) + ..write(obj.stackTrace); + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LunaLogHiveObjectAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/core/models/router/page_router.dart b/lib/core/models/router/page_router.dart index 57b957ff..e932a54d 100644 --- a/lib/core/models/router/page_router.dart +++ b/lib/core/models/router/page_router.dart @@ -19,14 +19,29 @@ abstract class LunaPageRouter { /// Define the route in the passed in router without any parameters required. /// - /// Already has a definition that: + /// Already defines: /// - Calls [FluroRouter.define] with the [fullRoute] /// - Creates a basic [Handler] /// - Sets the transition type to [LunaRouter.transitionType] - void noParameterRouteDefinition(FluroRouter router, Widget widget) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) => widget), - transitionType: LunaRouter.transitionType, + /// - Checks that the module is enabled, and if not returns a `[LunaNotEnabledRoute] instead of the intended route + void noParameterRouteDefinition( + FluroRouter router, + Widget widget, + { bool homeRoute = false } + ); + + /// Define the route in the passed in router with some parameters required. + /// + /// Already defines: + /// - Calls [FluroRouter.define] with the [fullRoute] + /// - Creates a basic [Handler] + /// - Sets the transition type to [LunaRouter.transitionType] + /// - Checks that the module is enabled, and if not returns a `[LunaNotEnabledRoute] instead of the intended route + /// - Parses and injects the required parameters into the route for the handler + void withParameterRouteDefinition( + FluroRouter router, + Widget Function(BuildContext, Map>) handlerFunc, + { bool homeRoute = false } ); LunaPageRouter(this.fullRoute); diff --git a/lib/core/models/types.dart b/lib/core/models/types.dart index d8a7c218..75200e7a 100644 --- a/lib/core/models/types.dart +++ b/lib/core/models/types.dart @@ -1,2 +1,4 @@ export 'types/browser.dart'; +export 'types/indexer_icon.dart'; export 'types/loading_state.dart'; +export 'types/log_type.dart'; diff --git a/lib/core/models/types/browser.dart b/lib/core/models/types/browser.dart index db2f340a..a764cffa 100644 --- a/lib/core/models/types/browser.dart +++ b/lib/core/models/types/browser.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; @@ -63,7 +65,7 @@ extension LunaBrowserExtension on LunaBrowser { } String formatted(String url) { - bool isHttps = url.substring(0, 8) == 'https://'; + bool isHttps = url.substring(0, min(8, url.length)) == 'https://'; switch(this) { case LunaBrowser.BRAVE_BROWSER: return 'brave://open-url?url=$url'; case LunaBrowser.GOOGLE_CHROME: return isHttps diff --git a/lib/core/models/types/browser.g.dart b/lib/core/models/types/browser.g.dart index 3adf715a..2539c471 100644 --- a/lib/core/models/types/browser.g.dart +++ b/lib/core/models/types/browser.g.dart @@ -24,7 +24,7 @@ class LunaBrowserAdapter extends TypeAdapter { case 4: return LunaBrowser.MOZILLA_FIREFOX; default: - return null; + return LunaBrowser.APPLE_SAFARI; } } diff --git a/lib/core/models/types/indexer_icon.dart b/lib/core/models/types/indexer_icon.dart new file mode 100644 index 00000000..48041ccf --- /dev/null +++ b/lib/core/models/types/indexer_icon.dart @@ -0,0 +1,76 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +part 'indexer_icon.g.dart'; + +@HiveType(typeId: 22, adapterName: 'LunaIndexerIconAdapter') +enum LunaIndexerIcon { + @HiveField(0) + GENERIC, + @HiveField(1) + DOGNZB, + @HiveField(2) + DRUNKENSLUG, + @HiveField(3) + NZBFINDER, + @HiveField(4) + NZBGEEK, + @HiveField(5) + NZBHYDRA, + @HiveField(6) + NZBSU, +} + +extension LunaIndexerIconExtension on LunaIndexerIcon { + LunaIndexerIcon fromKey(String key) { + switch(key) { + case 'generic': return LunaIndexerIcon.GENERIC; + case 'dognzb': return LunaIndexerIcon.DOGNZB; + case 'drunkenslug': return LunaIndexerIcon.DRUNKENSLUG; + case 'nzbfinder': return LunaIndexerIcon.NZBFINDER; + case 'nzbgeek': return LunaIndexerIcon.NZBGEEK; + case 'nzbhydra': return LunaIndexerIcon.NZBHYDRA; + case 'nzbsu': return LunaIndexerIcon.NZBSU; + default: return LunaIndexerIcon.GENERIC; + } + } + + String get key { + switch(this) { + case LunaIndexerIcon.GENERIC: return 'generic'; + case LunaIndexerIcon.DOGNZB: return 'dognzb'; + case LunaIndexerIcon.DRUNKENSLUG: return 'drunkenslug'; + case LunaIndexerIcon.NZBFINDER: return 'nzbfinder'; + case LunaIndexerIcon.NZBGEEK: return 'nzbgeek'; + case LunaIndexerIcon.NZBHYDRA: return 'nzbhydra'; + case LunaIndexerIcon.NZBSU: return 'nzbsu'; + } + throw Exception('Unknown LunaIndexerIcon'); + } + + String get name { + switch(this) { + case LunaIndexerIcon.GENERIC: return 'Generic'; + case LunaIndexerIcon.DOGNZB: return 'DOGnzb'; + case LunaIndexerIcon.DRUNKENSLUG: return 'DrunkenSlug'; + case LunaIndexerIcon.NZBFINDER: return 'NZBFinder'; + case LunaIndexerIcon.NZBGEEK: return 'NZBGeek'; + case LunaIndexerIcon.NZBHYDRA: return 'NZBHydra2'; + case LunaIndexerIcon.NZBSU: return 'NZB.su'; + } + throw Exception('Unknown LunaIndexerIcon'); + } + + IconData get icon { + switch(this) { + case LunaIndexerIcon.GENERIC: return Icons.rss_feed_rounded; + case LunaIndexerIcon.DOGNZB: return Icons.rss_feed_rounded; + case LunaIndexerIcon.DRUNKENSLUG: return Icons.rss_feed_rounded; + case LunaIndexerIcon.NZBFINDER: return Icons.rss_feed_rounded; + case LunaIndexerIcon.NZBGEEK: return Icons.rss_feed_rounded; + case LunaIndexerIcon.NZBHYDRA: return Icons.rss_feed_rounded; + case LunaIndexerIcon.NZBSU: return Icons.rss_feed_rounded; + } + throw Exception('Unknown LunaIndexerIcon'); + } +} \ No newline at end of file diff --git a/lib/core/models/types/indexer_icon.g.dart b/lib/core/models/types/indexer_icon.g.dart new file mode 100644 index 00000000..e35dd172 --- /dev/null +++ b/lib/core/models/types/indexer_icon.g.dart @@ -0,0 +1,71 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'indexer_icon.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class LunaIndexerIconAdapter extends TypeAdapter { + @override + final int typeId = 22; + + @override + LunaIndexerIcon read(BinaryReader reader) { + switch (reader.readByte()) { + case 0: + return LunaIndexerIcon.GENERIC; + case 1: + return LunaIndexerIcon.DOGNZB; + case 2: + return LunaIndexerIcon.DRUNKENSLUG; + case 3: + return LunaIndexerIcon.NZBFINDER; + case 4: + return LunaIndexerIcon.NZBGEEK; + case 5: + return LunaIndexerIcon.NZBHYDRA; + case 6: + return LunaIndexerIcon.NZBSU; + default: + return LunaIndexerIcon.GENERIC; + } + } + + @override + void write(BinaryWriter writer, LunaIndexerIcon obj) { + switch (obj) { + case LunaIndexerIcon.GENERIC: + writer.writeByte(0); + break; + case LunaIndexerIcon.DOGNZB: + writer.writeByte(1); + break; + case LunaIndexerIcon.DRUNKENSLUG: + writer.writeByte(2); + break; + case LunaIndexerIcon.NZBFINDER: + writer.writeByte(3); + break; + case LunaIndexerIcon.NZBGEEK: + writer.writeByte(4); + break; + case LunaIndexerIcon.NZBHYDRA: + writer.writeByte(5); + break; + case LunaIndexerIcon.NZBSU: + writer.writeByte(6); + break; + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LunaIndexerIconAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/core/models/types/log_type.dart b/lib/core/models/types/log_type.dart new file mode 100644 index 00000000..2e6dc07e --- /dev/null +++ b/lib/core/models/types/log_type.dart @@ -0,0 +1,81 @@ +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +part 'log_type.g.dart'; + +@HiveType(typeId: 24, adapterName: 'LunaLogTypeAdapter') +enum LunaLogType { + @HiveField(0) + WARNING, + @HiveField(1) + ERROR, + @HiveField(2) + CRITICAL, + @HiveField(3) + DEBUG, +} + +extension LunaLogTypeExtension on LunaLogType { + LunaLogType fromKey(String key) { + switch(key) { + case 'warning': return LunaLogType.WARNING; + case 'error': return LunaLogType.ERROR; + case 'critical': return LunaLogType.CRITICAL; + case 'debug': return LunaLogType.DEBUG; + } + return null; + } + + String get key { + switch(this) { + case LunaLogType.WARNING: return 'warning'; + case LunaLogType.ERROR: return 'error'; + case LunaLogType.CRITICAL: return 'critical'; + case LunaLogType.DEBUG: return 'debug'; + } + throw Exception('Invalid LunaLogType'); + } + + bool get enabled { + switch(this) { + case LunaLogType.WARNING: return true; + case LunaLogType.ERROR: return true; + case LunaLogType.CRITICAL: return true; + case LunaLogType.DEBUG: return kDebugMode; + } + throw Exception('Invalid LunaLogType'); + } + + String get name { + switch(this) { + case LunaLogType.WARNING: return 'Warning'; + case LunaLogType.ERROR: return 'Error'; + case LunaLogType.CRITICAL: return 'Critical'; + case LunaLogType.DEBUG: return 'Debug'; + } + throw Exception('Invalid LunaLogType'); + } + + String get description => 'View $name Logs'; + + IconData get icon { + switch(this) { + case LunaLogType.WARNING: return Icons.warning; + case LunaLogType.ERROR: return Icons.report_rounded; + case LunaLogType.CRITICAL: return Icons.new_releases; + case LunaLogType.DEBUG: return Icons.bug_report_rounded; + } + throw Exception('Invalid LunaLogType'); + } + + Color get color { + switch(this) { + case LunaLogType.WARNING: return LunaColours.orange; + case LunaLogType.ERROR: return LunaColours.red; + case LunaLogType.CRITICAL: return LunaColours.accent; + case LunaLogType.DEBUG: return LunaColours.blueGrey; + } + throw Exception('Invalid LunaLogType'); + } +} diff --git a/lib/core/models/types/log_type.g.dart b/lib/core/models/types/log_type.g.dart new file mode 100644 index 00000000..cedeba23 --- /dev/null +++ b/lib/core/models/types/log_type.g.dart @@ -0,0 +1,56 @@ +// GENERATED CODE - DO NOT MODIFY BY HAND + +part of 'log_type.dart'; + +// ************************************************************************** +// TypeAdapterGenerator +// ************************************************************************** + +class LunaLogTypeAdapter extends TypeAdapter { + @override + final int typeId = 24; + + @override + LunaLogType read(BinaryReader reader) { + switch (reader.readByte()) { + case 0: + return LunaLogType.WARNING; + case 1: + return LunaLogType.ERROR; + case 2: + return LunaLogType.CRITICAL; + case 3: + return LunaLogType.DEBUG; + default: + return LunaLogType.WARNING; + } + } + + @override + void write(BinaryWriter writer, LunaLogType obj) { + switch (obj) { + case LunaLogType.WARNING: + writer.writeByte(0); + break; + case LunaLogType.ERROR: + writer.writeByte(1); + break; + case LunaLogType.CRITICAL: + writer.writeByte(2); + break; + case LunaLogType.DEBUG: + writer.writeByte(3); + break; + } + } + + @override + int get hashCode => typeId.hashCode; + + @override + bool operator ==(Object other) => + identical(this, other) || + other is LunaLogTypeAdapter && + runtimeType == other.runtimeType && + typeId == other.typeId; +} diff --git a/lib/core/pages.dart b/lib/core/pages.dart new file mode 100644 index 00000000..e41b2e3e --- /dev/null +++ b/lib/core/pages.dart @@ -0,0 +1,2 @@ +export 'pages/invalid_route.dart'; +export 'pages/not_enabled.dart'; diff --git a/lib/core/ui/invalid_route.dart b/lib/core/pages/invalid_route.dart similarity index 100% rename from lib/core/ui/invalid_route.dart rename to lib/core/pages/invalid_route.dart diff --git a/lib/core/pages/not_enabled.dart b/lib/core/pages/not_enabled.dart new file mode 100644 index 00000000..fcd17fa2 --- /dev/null +++ b/lib/core/pages/not_enabled.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class LunaNotEnabledRoute extends StatelessWidget { + final String module; + + LunaNotEnabledRoute({ + Key key, + @required this.module, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: LunaAppBar( + title: module, + scrollControllers: [], + ), + body: LunaMessage.moduleNotEnabled( + context: context, + module: module, + ), + ); + } +} diff --git a/lib/core/system.dart b/lib/core/system.dart index de5d743c..761a51b6 100644 --- a/lib/core/system.dart +++ b/lib/core/system.dart @@ -2,7 +2,6 @@ export 'system/firebase.dart'; export 'system/image_cache.dart'; export 'system/in_app_purchases.dart'; export 'system/localization.dart'; -export 'system/logger.dart'; export 'system/modules.dart'; export 'system/networking.dart'; export 'system/quick_actions.dart'; diff --git a/lib/core/system/firebase.dart b/lib/core/system/firebase.dart index f736b7a9..8d2203e2 100644 --- a/lib/core/system/firebase.dart +++ b/lib/core/system/firebase.dart @@ -1,3 +1,4 @@ +export 'firebase/analytics.dart'; export 'firebase/auth.dart'; export 'firebase/core.dart'; export 'firebase/crashlytics.dart'; diff --git a/lib/core/system/firebase/analytics.dart b/lib/core/system/firebase/analytics.dart new file mode 100644 index 00000000..cfc3da29 --- /dev/null +++ b/lib/core/system/firebase/analytics.dart @@ -0,0 +1,24 @@ +import 'package:firebase_analytics/firebase_analytics.dart'; +import 'package:firebase_analytics/observer.dart'; +import 'package:lunasea/core.dart'; + +class LunaFirebaseAnalytics { + /// Returns an instance of [FirebaseAnalytics]. + /// + /// Throws an error if [LunaFirebase.initialize] has not been called. + static FirebaseAnalytics get instance => FirebaseAnalytics(); + + /// Returns an instance of [FirebaseAnalyticsObserver]. + /// + /// Throws an error if [LunaFirebase.initialize] has not been called. + static FirebaseAnalyticsObserver get observer => FirebaseAnalyticsObserver(analytics: instance); + + /// Set the enabled state of Firebase Analytics. + void setEnabledState() { + bool state = LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS.data; + instance.setAnalyticsCollectionEnabled(state); + } + + /// Log an "app_open" event. + Future appOpened() async => instance.logAppOpen(); +} diff --git a/lib/core/system/firebase/crashlytics.dart b/lib/core/system/firebase/crashlytics.dart index 5eb69de1..c5956443 100644 --- a/lib/core/system/firebase/crashlytics.dart +++ b/lib/core/system/firebase/crashlytics.dart @@ -1,4 +1,5 @@ import 'package:firebase_crashlytics/firebase_crashlytics.dart'; +import 'package:flutter/foundation.dart'; import 'package:lunasea/core.dart'; class LunaFirebaseCrashlytics { @@ -8,10 +9,8 @@ class LunaFirebaseCrashlytics { static FirebaseCrashlytics get instance => FirebaseCrashlytics.instance; /// Set the enabled state of Firebase Crashlytics. - /// - /// If `enabled` is supplied, use that value, else use [LunaDatabaseValue.ENABLED_SENTRY]. void setEnabledState() { - bool state = LunaDatabaseValue.ENABLED_SENTRY.data; + bool state = kReleaseMode && LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data; instance.setCrashlyticsCollectionEnabled(state); } } diff --git a/lib/core/system/localization.dart b/lib/core/system/localization.dart index 3ef6af55..22dcb31a 100644 --- a/lib/core/system/localization.dart +++ b/lib/core/system/localization.dart @@ -25,6 +25,7 @@ enum LunaLanguage { ENGLISH, FRENCH, GERMAN, + ITALIAN, NORWEGIAN_BOKMAL, RUSSIAN, SWEDISH, @@ -35,6 +36,7 @@ extension LunaLanguageExtension on LunaLanguage { if(locale.toLanguageTag() == LunaLanguage.ENGLISH.languageTag) return LunaLanguage.ENGLISH; if(locale.toLanguageTag() == LunaLanguage.FRENCH.languageTag) return LunaLanguage.FRENCH; if(locale.toLanguageTag() == LunaLanguage.GERMAN.languageTag) return LunaLanguage.GERMAN; + if(locale.toLanguageTag() == LunaLanguage.ITALIAN.languageTag) return LunaLanguage.ITALIAN; if(locale.toLanguageTag() == LunaLanguage.NORWEGIAN_BOKMAL.languageTag) return LunaLanguage.NORWEGIAN_BOKMAL; if(locale.toLanguageTag() == LunaLanguage.RUSSIAN.languageTag) return LunaLanguage.RUSSIAN; if(locale.toLanguageTag() == LunaLanguage.SWEDISH.languageTag) return LunaLanguage.SWEDISH; @@ -47,6 +49,7 @@ extension LunaLanguageExtension on LunaLanguage { // Keep all languages enabled in debug mode while LunaSea is being adapted for localization case LunaLanguage.FRENCH: return kDebugMode; case LunaLanguage.GERMAN: return kDebugMode; + case LunaLanguage.ITALIAN: return kDebugMode; case LunaLanguage.NORWEGIAN_BOKMAL: return kDebugMode; case LunaLanguage.RUSSIAN: return kDebugMode; case LunaLanguage.SWEDISH: return kDebugMode; @@ -59,6 +62,7 @@ extension LunaLanguageExtension on LunaLanguage { case LunaLanguage.ENGLISH: return 'English'; case LunaLanguage.FRENCH: return 'French'; case LunaLanguage.GERMAN: return 'German'; + case LunaLanguage.ITALIAN: return 'Italian'; case LunaLanguage.NORWEGIAN_BOKMAL: return 'Norwegian (Bokmål)'; case LunaLanguage.RUSSIAN: return 'Russian'; case LunaLanguage.SWEDISH: return 'Swedish'; @@ -71,6 +75,7 @@ extension LunaLanguageExtension on LunaLanguage { case LunaLanguage.ENGLISH: return 'en'; case LunaLanguage.FRENCH: return 'fr'; case LunaLanguage.GERMAN: return 'de'; + case LunaLanguage.ITALIAN: return 'it'; case LunaLanguage.NORWEGIAN_BOKMAL: return 'nb-NO'; case LunaLanguage.RUSSIAN: return 'ru'; case LunaLanguage.SWEDISH: return 'sv'; @@ -83,6 +88,7 @@ extension LunaLanguageExtension on LunaLanguage { case LunaLanguage.ENGLISH: return Locale('en'); case LunaLanguage.FRENCH: return Locale('fr'); case LunaLanguage.GERMAN: return Locale('de'); + case LunaLanguage.ITALIAN: return Locale('it'); case LunaLanguage.NORWEGIAN_BOKMAL: return Locale('nb', 'NO'); case LunaLanguage.RUSSIAN: return Locale('ru'); case LunaLanguage.SWEDISH: return Locale('sv'); diff --git a/lib/core/system/logger.dart b/lib/core/system/logger.dart deleted file mode 100644 index 1bb7fe17..00000000 --- a/lib/core/system/logger.dart +++ /dev/null @@ -1,72 +0,0 @@ -import 'dart:async'; -import 'dart:io'; -import 'package:f_logs/f_logs.dart' show FLog, DataLogType, FormatType, LogsConfig; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:stack_trace/stack_trace.dart'; - -class LunaLogger { - static String get checkLogsMessage => 'lunasea.CheckLogsMessage'.tr(); - - /// Initialize the logger by setting the timestamp format and capturing errors on [FlutterError.onError]. - void initialize() { - LunaFirebaseCrashlytics().setEnabledState(); - LogsConfig config = FLog.getDefaultConfigurations() - ..formatType = FormatType.FORMAT_SQUARE - ..timestampFormat = 'MMMM dd, y - hh:mm:ss a'; - FLog.applyConfigurations(config); - FlutterError.onError = (FlutterErrorDetails details, { bool forceReport = false }) async { - if (kDebugMode) FlutterError.dumpErrorToConsole(details, forceReport: forceReport); - LunaFirebaseCrashlytics.instance.recordFlutterError(details); - Zone.current.handleUncaughtError(details.exception, details.stack); - }; - } - - /// Log a new debug-level log. - void debug(String text) => FLog.debug( - text: text, - dataLogType: DataLogType.DEFAULT.toString(), - ); - - /// Log a new warning-level log. - void warning(String className, String methodName, String text) => FLog.warning( - className: className, - methodName: methodName, - text: text, - dataLogType: DataLogType.DEFAULT.toString(), - ); - - /// Log a new error-level log. - void error(String text, dynamic error, StackTrace stack) { - if(LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled) LunaFirebaseCrashlytics.instance.recordError(error, stack); - Trace _trace = stack == null ? null : Trace.from(stack); - FLog.error( - className: (_trace?.frames?.length ?? 0) >= 1 ? _trace.frames[1].uri.toString() ?? 'Unknown' : 'Unknown', - methodName: (_trace?.frames?.length ?? 0) >= 1 ? _trace.frames[1].member.toString() ?? 'Unknown' : 'Unknown', - text: text, - exception: error, - stacktrace: stack, - dataLogType: DataLogType.DEFAULT.toString(), - ); - } - - /// Log a new fatal-level log. - void fatal(dynamic error, StackTrace stack) { - if(LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled) LunaFirebaseCrashlytics.instance.recordError(error, stack); - Trace _trace = stack == null ? null : Trace.from(stack); - FLog.fatal( - className: (_trace?.frames?.length ?? 0) >= 1 ? _trace.frames[1].uri.toString() ?? 'Unknown' : 'Unknown', - methodName: (_trace?.frames?.length ?? 0) >= 1 ? _trace.frames[1].member.toString() ?? 'Unknown' : 'Unknown', - text: error.toString(), - exception: error, - stacktrace: stack, - dataLogType: DataLogType.DEFAULT.toString(), - ); - } - - /// Export all logs, and return the [File] object containing the log file. - Future exportLogs() async => FLog.exportLogs(); - /// Clear all logs currently saved to the database. - Future clearLogs() async => FLog.clearLogs(); -} diff --git a/lib/core/system/modules.dart b/lib/core/system/modules.dart index 9833ab03..246c12c9 100644 --- a/lib/core/system/modules.dart +++ b/lib/core/system/modules.dart @@ -91,7 +91,7 @@ extension LunaModuleExtension on LunaModule { case LunaModule.SEARCH: return SearchHomeRouter().route(); case LunaModule.SETTINGS: return SettingsHomeRouter().route(); case LunaModule.SONARR: return SonarrHomeRouter().route(); - case LunaModule.TAUTULLI: return TautulliHomeRouter.ROUTE_NAME; + case LunaModule.TAUTULLI: return TautulliHomeRouter().route(); case LunaModule.WAKE_ON_LAN: return null; } throw Exception('Invalid LunaModule'); @@ -219,7 +219,7 @@ extension LunaModuleExtension on LunaModule { case LunaModule.SEARCH: return; case LunaModule.SETTINGS: return; case LunaModule.SONARR: return SonarrWebhooks().handle(data); - case LunaModule.TAUTULLI: return; + case LunaModule.TAUTULLI: return TautulliWebhooks().handle(data); case LunaModule.WAKE_ON_LAN: return; } throw Exception('Invalid LunaModule'); diff --git a/lib/core/ui.dart b/lib/core/ui.dart index 5c230607..786cd684 100644 --- a/lib/core/ui.dart +++ b/lib/core/ui.dart @@ -16,7 +16,6 @@ export 'ui/header.dart'; export 'ui/highlighted_node.dart'; export 'ui/icons.dart'; export 'ui/input_bar.dart'; -export 'ui/invalid_route.dart'; export 'ui/list_tile.dart'; export 'ui/list_view.dart'; export 'ui/loader.dart'; diff --git a/lib/core/ui/bottom_navigation_bar/bottom_navigation_bar.dart b/lib/core/ui/bottom_navigation_bar/bottom_navigation_bar.dart index ab74611c..cfc46f04 100644 --- a/lib/core/ui/bottom_navigation_bar/bottom_navigation_bar.dart +++ b/lib/core/ui/bottom_navigation_bar/bottom_navigation_bar.dart @@ -33,7 +33,7 @@ class _State extends State { @override void initState() { - _index = widget.pageController.initialPage; + _index = widget.pageController?.initialPage ?? 0; widget.pageController?.addListener(_pageControllerListener); super.initState(); } @@ -93,7 +93,7 @@ class _State extends State { if(index == _index) { if(widget.scrollControllers != null && widget.scrollControllers[index] != null) widget.scrollControllers[index].lunaAnimateToStart(); } else { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } } diff --git a/lib/core/ui/decoration/card_decoration.dart b/lib/core/ui/decoration/card_decoration.dart index 5dc0cf64..c4ff9f86 100644 --- a/lib/core/ui/decoration/card_decoration.dart +++ b/lib/core/ui/decoration/card_decoration.dart @@ -4,6 +4,7 @@ import 'package:lunasea/core.dart'; // ignore: non_constant_identifier_names Decoration LunaCardDecoration({ @required String uri, @required Map headers }) { if(LunaDatabaseValue.THEME_IMAGE_BACKGROUND_OPACITY.data == 0) return null; + if(uri == null || uri.isEmpty) return BoxDecoration(borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS)); return BoxDecoration( image: DecorationImage( image: NetworkImage( @@ -18,6 +19,6 @@ Decoration LunaCardDecoration({ @required String uri, @required Map headers }) { ), fit: BoxFit.cover, ), - borderRadius: BorderRadius.circular(Constants.UI_BORDER_RADIUS), + borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS), ); } diff --git a/lib/core/ui/deprecated/dialogs.dart b/lib/core/ui/deprecated/dialogs.dart index 887674da..78e35ada 100644 --- a/lib/core/ui/deprecated/dialogs.dart +++ b/lib/core/ui/deprecated/dialogs.dart @@ -56,7 +56,7 @@ abstract class LSDialog { static Widget cancel(BuildContext context, { Color textColor = Colors.white, String text }) => TextButton( child: Text( - text ?? 'Cancel', + text ?? 'lunasea.Cancel'.tr(), style: TextStyle( color: textColor, fontSize: LSDialog.BUTTON_SIZE, diff --git a/lib/core/ui/deprecated/messages/typewriter.dart b/lib/core/ui/deprecated/messages/typewriter.dart index 6b0da60f..f6235622 100644 --- a/lib/core/ui/deprecated/messages/typewriter.dart +++ b/lib/core/ui/deprecated/messages/typewriter.dart @@ -1,4 +1,5 @@ import 'dart:async'; +import 'dart:math'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; @@ -39,7 +40,7 @@ class _State extends State with TickerProviderStateMixin { void handleTimer(Timer timer) { _counter++; if(_counter > widget.text.length) _counter = 0; - if(mounted) setState(() => _text = widget.text.substring(0, _counter) + "_"); + if(mounted) setState(() => _text = widget.text.substring(0, min(_counter, widget.text.length)) + "_"); } @override diff --git a/lib/core/ui/deprecated/network_image.dart b/lib/core/ui/deprecated/network_image.dart index 43534516..e517614d 100644 --- a/lib/core/ui/deprecated/network_image.dart +++ b/lib/core/ui/deprecated/network_image.dart @@ -15,7 +15,7 @@ Widget LSNetworkImage({ fit: StackFit.expand, children: [ Image.asset(placeholder), - if(url != null) FadeInImage( + if(url != null && url.isNotEmpty) FadeInImage( height: height, width: width, fadeInDuration: Duration(milliseconds: LunaUI.ANIMATION_IMAGE_FADE_IN_SPEED), @@ -26,6 +26,10 @@ Widget LSNetworkImage({ url, headers: headers, ), + imageErrorBuilder: (context, error, stack) => Container( + height: height, + width: width, + ), ), ], ), diff --git a/lib/core/ui/drawer/drawer_header.dart b/lib/core/ui/drawer/drawer_header.dart index df6a46f5..b99f40f3 100644 --- a/lib/core/ui/drawer/drawer_header.dart +++ b/lib/core/ui/drawer/drawer_header.dart @@ -50,7 +50,7 @@ class LunaDrawerHeader extends UserAccountsDrawerHeader { decoration: BoxDecoration( color: LunaColours.accent, image: DecorationImage( - image: AssetImage('assets/branding/icon_drawer.png'), + image: AssetImage('assets/images/branding/icon_drawer.png'), colorFilter: ColorFilter.mode(LunaColours.primary.withOpacity(0.15), BlendMode.dstATop), fit: BoxFit.cover, ), diff --git a/lib/core/ui/icons/icon_button.dart b/lib/core/ui/icons/icon_button.dart index e94cdd36..2bdc8fdc 100644 --- a/lib/core/ui/icons/icon_button.dart +++ b/lib/core/ui/icons/icon_button.dart @@ -11,6 +11,8 @@ class LunaIconButton extends StatelessWidget { final Function onPressed; final Function onLongPress; final LunaLoadingState loadingState; + final AlignmentGeometry alignment; + final EdgeInsetsGeometry padding; LunaIconButton({ Key key, @@ -18,6 +20,8 @@ class LunaIconButton extends StatelessWidget { this.textSize = 10.0, this.icon, this.iconSize = 24.0, + this.alignment = Alignment.center, + this.padding = const EdgeInsets.all(8.0), this.color = Colors.white, this.onPressed, this.onLongPress, @@ -32,6 +36,8 @@ class LunaIconButton extends StatelessWidget { child: IconButton( icon: loadingState == LunaLoadingState.ACTIVE ? _loader() : _icon(), iconSize: iconSize, + alignment: alignment, + padding: padding, onPressed: _onPressed(), ), onLongPress: _onLongPress(), diff --git a/lib/core/ui/list_view/list_view_modal.dart b/lib/core/ui/list_view/list_view_modal.dart index d2444fa3..b12b4cae 100644 --- a/lib/core/ui/list_view/list_view_modal.dart +++ b/lib/core/ui/list_view/list_view_modal.dart @@ -1,4 +1,5 @@ import 'package:flutter/material.dart'; +import 'package:modal_bottom_sheet/modal_bottom_sheet.dart'; class LunaListViewModal extends StatelessWidget { final List children; @@ -11,7 +12,9 @@ class LunaListViewModal extends StatelessWidget { @override Widget build(BuildContext context) { return Scrollbar( + controller: ModalScrollController.of(context), child: ListView( + controller: ModalScrollController.of(context), children: children, padding: EdgeInsets.only( top: 8.0, diff --git a/lib/core/ui/message/message.dart b/lib/core/ui/message/message.dart index 5950bf55..053d2813 100644 --- a/lib/core/ui/message/message.dart +++ b/lib/core/ui/message/message.dart @@ -80,6 +80,7 @@ class LunaMessage extends StatelessWidget { key: key, text: 'lunasea.ModuleIsNotEnabled'.tr(args: [module]), buttonText: 'lunasea.ReturnToDashboard'.tr(), + //onTap: () async => TautulliActivityDetailsRouter().navigateTo(context, sessionId: '92029620-7B5C-4C02-8769-9EB15626ECFC'), onTap: () async => LunaModule.DASHBOARD.launch(), useSafeArea: useSafeArea, ); diff --git a/lib/core/ui/network_image.dart b/lib/core/ui/network_image.dart index 634b8612..d61782d7 100644 --- a/lib/core/ui/network_image.dart +++ b/lib/core/ui/network_image.dart @@ -27,6 +27,10 @@ class LunaNetworkImage extends ClipRRect { placeholder: AssetImage(placeholderAsset), fit: BoxFit.cover, image: NetworkImage(url, headers: headers?.cast()), + imageErrorBuilder: (context, error, stack) => Container( + height: height, + width: width, + ), ), ], ), diff --git a/lib/core/utilities.dart b/lib/core/utilities.dart index f190f3de..d9edb836 100644 --- a/lib/core/utilities.dart +++ b/lib/core/utilities.dart @@ -2,5 +2,6 @@ export 'utilities/changelog.dart'; export 'utilities/configuration.dart'; export 'utilities/encryption.dart'; export 'utilities/filesystem.dart'; +export 'utilities/logger.dart'; export 'utilities/profile.dart'; export 'utilities/uuid.dart'; diff --git a/lib/core/utilities/filesystem.dart b/lib/core/utilities/filesystem.dart index 0a1d0079..6701e437 100644 --- a/lib/core/utilities/filesystem.dart +++ b/lib/core/utilities/filesystem.dart @@ -1,5 +1,6 @@ import 'dart:io'; -import 'package:share_plus/share_plus.dart'; +import 'package:lunasea/core.dart'; +import 'package:share/share.dart'; import 'package:path_provider/path_provider.dart'; class LunaFileSystem { @@ -13,7 +14,10 @@ class LunaFileSystem { String path = '${tempDirectory.path}/$name'; File file = File(path); await file?.writeAsString(data); - await Share.shareFiles([path]); + await Share.shareFiles([path]) + .catchError((error, stack) { + LunaLogger().error('Failed to share string to sharesheet', error, stack); + }); } /// Given a path to a file, shares the file to the OS-level share sheet with the given name. @@ -22,6 +26,9 @@ class LunaFileSystem { /// If the file does not exist, will simply do nothing. Future exportFileToShareSheet(String path) async { File file = File(path); - if(file.existsSync()) await Share.shareFiles([path]); + if(file.existsSync()) await Share.shareFiles([path]) + .catchError((error, stack) { + LunaLogger().error('Failed to share string to sharesheet', error, stack); + }); } } diff --git a/lib/core/utilities/logger.dart b/lib/core/utilities/logger.dart new file mode 100644 index 00000000..074249ac --- /dev/null +++ b/lib/core/utilities/logger.dart @@ -0,0 +1,129 @@ +import 'dart:async'; +import 'dart:convert'; +import 'dart:io'; +import 'package:dio/dio.dart'; +import 'package:flutter/foundation.dart'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:path_provider/path_provider.dart'; + +class LunaLogger { + static String get checkLogsMessage => 'lunasea.CheckLogsMessage'.tr(); + + /// Initialize the logger by setting the timestamp format and capturing errors on [FlutterError.onError]. + void initialize() { + LunaFirebaseAnalytics().setEnabledState(); + LunaFirebaseCrashlytics().setEnabledState(); + FlutterError.onError = (FlutterErrorDetails details, { bool forceReport = false }) async { + if (kDebugMode) FlutterError.dumpErrorToConsole(details, forceReport: forceReport); + recordCrashlyticsFlutterError(details); + Zone.current.handleUncaughtError(details.exception, details.stack); + }; + _compactDatabase(); + } + + /// Compact the logs database. + /// + /// If the logs box has over [count] entries, will only store the latest 100. + Future _compactDatabase([int count = 100]) async { + if(Database.logsBox.keys.length <= count) return; + List logs = Database.logsBox.values.toList(); + logs.sort((a,b) => (b?.timestamp?.toDouble() ?? double.maxFinite).compareTo(a?.timestamp?.toDouble() ?? double.maxFinite)); + logs.skip(count).forEach((log) => log.delete()); + } + + /// Export all logs, and return the [File] object containing the log file. + Future exportLogs() async { + // Get maps/JSON of all logs + List> logs = []; + Database.logsBox.values.forEach((log) { + if(log != null) logs.add(log.toMap()); + }); + // Create a string + JsonEncoder encoder = JsonEncoder.withIndent(' '); + String data = encoder.convert(logs); + // Write the JSON to the temporary directory, return the file + Directory tempDirectory = await getTemporaryDirectory(); + String path = '${tempDirectory.path}/logs.json'; + File file = File(path); + await file?.writeAsString(data); + return file; + } + + /// Clear all logs currently saved to the database. + Future clearLogs() async => Database().clearLogsBox(); + + /// Records a Crashlytics error if it passes the following checks: + /// - In release mode + /// - Crashlytics is enabled in the instance + /// - Crashlytics is enabled in Hive + /// - The error is not a DioError + Future recordCrashlyticsError(dynamic error, StackTrace stackTrace) async { + if( + kReleaseMode && + LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled && + LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data && + !(error is DioError) + ) LunaFirebaseCrashlytics.instance.recordError(error, stackTrace); + } + + /// Records a Crashlytics flutter error if it passes the following checks: + /// - In release mode + /// - Crashlytics is enabled in the instance + /// - Crashlytics is enabled in Hive + /// - The error is not a DioError + Future recordCrashlyticsFlutterError(FlutterErrorDetails details) async { + if( + kReleaseMode && + LunaFirebaseCrashlytics.instance.isCrashlyticsCollectionEnabled && + LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data && + !(error is DioError) + ) LunaFirebaseCrashlytics.instance.recordFlutterError(details); + } + + /// Log a new debug-level log. + void debug(String message) { + LunaLogHiveObject log =LunaLogHiveObject.withMessage( + type: LunaLogType.WARNING, + message: message, + ); + Database.logsBox.add(log); + } + + /// Log a new warning-level log. + void warning(String className, String methodName, String message) { + LunaLogHiveObject log =LunaLogHiveObject.withMessage( + type: LunaLogType.WARNING, + className: className, + methodName: methodName, + message: message, + ); + Database.logsBox.add(log); + } + + /// Log a new error-level log. + void error(String message, dynamic error, StackTrace stackTrace) { + recordCrashlyticsError(error, stackTrace); + LunaLogHiveObject log =LunaLogHiveObject.withError( + type: LunaLogType.ERROR, + message: message, + error: error, + stackTrace: stackTrace, + ); + Database.logsBox.add(log); + } + + /// Log a new critical-level log. + void critical(dynamic error, StackTrace stackTrace) { + if(!(error is DioError)) { + recordCrashlyticsError(error, stackTrace); + LunaLogHiveObject log =LunaLogHiveObject.withError( + type: LunaLogType.CRITICAL, + message: error?.toString() ?? 'Unknown critical error', + error: error, + stackTrace: stackTrace, + ); + Database.logsBox.add(log); + } + } +} diff --git a/lib/core/widgets.dart b/lib/core/widgets.dart index 94fc4f43..1afba0fb 100644 --- a/lib/core/widgets.dart +++ b/lib/core/widgets.dart @@ -1,3 +1,4 @@ export 'widgets/expandable_list_tile.dart'; +export 'widgets/five_line_card_with_poster.dart'; export 'widgets/four_line_card_with_poster.dart'; export 'widgets/two_line_card_with_poster.dart'; diff --git a/lib/core/widgets/five_line_card_with_poster.dart b/lib/core/widgets/five_line_card_with_poster.dart new file mode 100644 index 00000000..e8ae75b1 --- /dev/null +++ b/lib/core/widgets/five_line_card_with_poster.dart @@ -0,0 +1,150 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; + +class LunaFiveLineCardWithPoster extends StatelessWidget { + final Function onTap; + final Function onLongPress; + final String backgroundUrl; + final String posterUrl; + final String posterPlaceholder; + final String title; + final TextSpan subtitle1; + final TextSpan subtitle2; + final TextSpan subtitle3; + final TextSpan subtitle4; + final int subtitle1MaxLines; + final int subtitle2MaxLines; + final int subtitle3MaxLines; + final int subtitle4MaxLines; + final Widget customSubtitle1; + final Widget customSubtitle2; + final Widget customSubtitle3; + final Widget customSubtitle4; + final bool darken; + final Color titleColor; + final Map posterHeaders; + final LunaIconButton trailing; + final double _height = 105.0; + final double _width = 70.0; + final double _padding = 8.0; + + LunaFiveLineCardWithPoster({ + Key key, + @required this.posterPlaceholder, + @required this.posterUrl, + @required this.posterHeaders, + @required this.title, + this.backgroundUrl, + this.titleColor = Colors.white, + this.subtitle1, + this.subtitle2, + this.subtitle3, + this.subtitle4, + this.subtitle1MaxLines = 1, + this.subtitle2MaxLines = 1, + this.subtitle3MaxLines = 1, + this.subtitle4MaxLines = 1, + this.customSubtitle1, + this.customSubtitle2, + this.customSubtitle3, + this.customSubtitle4, + this.darken = false, + this.onTap, + this.onLongPress, + this.trailing, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return LunaCard( + context: context, + child: InkWell( + child: Row( + children: [ + _poster(context), + _body(context), + if(trailing != null) _trailing(), + ], + ), + onTap: onTap, + onLongPress: onLongPress, + borderRadius: BorderRadius.circular(LunaUI.BORDER_RADIUS), + ), + decoration: backgroundUrl == null ? null : LunaCardDecoration( + uri: backgroundUrl, + headers: posterHeaders, + ), + ); + } + + Widget _poster(BuildContext context) { + return LunaNetworkImage( + url: posterUrl, + placeholderAsset: posterPlaceholder, + height: _height, + width: _width, + headers: posterHeaders, + ); + } + + Widget _body(BuildContext context) { + return Expanded( + child: Padding( + child: Container( + child: Column( + children: [ + _title(), + if(customSubtitle1 != null) customSubtitle1, + if(customSubtitle1 == null && subtitle1 != null) _subtitle(subtitle1, subtitle1MaxLines), + if(customSubtitle2 != null) customSubtitle2, + if(customSubtitle2 == null && subtitle2 != null) _subtitle(subtitle2, subtitle2MaxLines), + if(customSubtitle3 != null) customSubtitle3, + if(customSubtitle3 == null && subtitle3 != null) _subtitle(subtitle3, subtitle3MaxLines), + if(customSubtitle4 != null) customSubtitle4, + if(customSubtitle4 == null && subtitle4 != null) _subtitle(subtitle4, subtitle4MaxLines), + ], + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.start, + mainAxisSize: MainAxisSize.max, + ), + height: (_height-(_padding*2)), + ), + padding: EdgeInsets.all(_padding), + ), + ); + } + + Widget _title() { + return LunaText.title( + text: title, + color: titleColor, + darken: darken, + maxLines: 1, + ); + } + + Widget _subtitle(TextSpan text, int maxLines) { + return RichText( + text: TextSpan( + style: TextStyle( + fontSize: LunaUI.FONT_SIZE_SUBTITLE, + color: darken ? Colors.white30 : Colors.white70, + ), + children: [text], + ), + overflow: TextOverflow.fade, + softWrap: maxLines == 1 ? false : true, + maxLines: maxLines, + ); + } + + Widget _trailing() { + return Container( + child: Padding( + child: trailing, + padding: EdgeInsets.only(right: 12.0), + ), + height: _height, + ); + } +} diff --git a/lib/main.dart b/lib/main.dart index a3d74ae6..01839dc8 100644 --- a/lib/main.dart +++ b/lib/main.dart @@ -6,7 +6,7 @@ import 'package:lunasea/core.dart'; /// LunaSea Entry Point: Initialize & Run Application /// -/// Runs app in Sentry guarded zone to attempt to capture fatal (crashing) errors +/// Runs app in guarded zone to attempt to capture fatal (crashing) errors Future main() async { WidgetsFlutterBinding.ensureInitialized(); await _init(); @@ -20,7 +20,7 @@ Future main() async { child: LunaBIOS(), ), ), - (error, stack) => LunaFirebaseCrashlytics.instance.recordError, + (error, stack) => LunaLogger().critical(error, stack), ); } @@ -93,10 +93,10 @@ class _State extends State { LunaFirebaseMessaging().checkAndHandleInitialMessage(); _firebaseOnMessageListener = LunaFirebaseMessaging().onMessageListener(); _firebaseOnMessageOpenedAppListener = LunaFirebaseMessaging().onMessageOpenedAppListener(); - // Initialize quick actions + // Remaining boot sequence LunaQuickActions().initialize(); - // Check and show changelog LunaChangelog().checkAndShowChangelog(); + LunaFirebaseAnalytics().appOpened(); } @override @@ -114,6 +114,7 @@ class _State extends State { routes: LunaRouter().routes, onGenerateRoute: LunaRouter.router.generator, navigatorKey: LunaState.navigatorKey, + navigatorObservers: [LunaFirebaseAnalytics.observer], darkTheme: LunaTheme().activeTheme(), theme: LunaTheme().activeTheme(), title: 'LunaSea', diff --git a/lib/modules/dashboard/core/adapters/calendar_starting_day.g.dart b/lib/modules/dashboard/core/adapters/calendar_starting_day.g.dart index 5c85540c..392e75a0 100644 --- a/lib/modules/dashboard/core/adapters/calendar_starting_day.g.dart +++ b/lib/modules/dashboard/core/adapters/calendar_starting_day.g.dart @@ -28,7 +28,7 @@ class CalendarStartingDayAdapter extends TypeAdapter { case 6: return CalendarStartingDay.SUNDAY; default: - return null; + return CalendarStartingDay.MONDAY; } } diff --git a/lib/modules/dashboard/core/adapters/calendar_starting_size.g.dart b/lib/modules/dashboard/core/adapters/calendar_starting_size.g.dart index 2cfe0885..1c02c0c8 100644 --- a/lib/modules/dashboard/core/adapters/calendar_starting_size.g.dart +++ b/lib/modules/dashboard/core/adapters/calendar_starting_size.g.dart @@ -20,7 +20,7 @@ class CalendarStartingSizeAdapter extends TypeAdapter { case 2: return CalendarStartingSize.ONE_MONTH; default: - return null; + return CalendarStartingSize.ONE_WEEK; } } diff --git a/lib/modules/dashboard/core/adapters/calendar_starting_type.g.dart b/lib/modules/dashboard/core/adapters/calendar_starting_type.g.dart index 58056b0c..03d30905 100644 --- a/lib/modules/dashboard/core/adapters/calendar_starting_type.g.dart +++ b/lib/modules/dashboard/core/adapters/calendar_starting_type.g.dart @@ -18,7 +18,7 @@ class CalendarStartingTypeAdapter extends TypeAdapter { case 1: return CalendarStartingType.SCHEDULE; default: - return null; + return CalendarStartingType.CALENDAR; } } diff --git a/lib/modules/dashboard/core/api/data/sonarr.dart b/lib/modules/dashboard/core/api/data/sonarr.dart index fcbca15f..e36093a8 100644 --- a/lib/modules/dashboard/core/api/data/sonarr.dart +++ b/lib/modules/dashboard/core/api/data/sonarr.dart @@ -121,7 +121,7 @@ class CalendarSonarrData extends CalendarData { } @override - Future trailingOnLongPress(BuildContext context) async => SonarrReleasesRouter.navigateTo( + Future trailingOnLongPress(BuildContext context) async => SonarrReleasesRouter().navigateTo( context, episodeId: id, ); diff --git a/lib/modules/dashboard/widgets/navigation_bar.dart b/lib/modules/dashboard/widgets/navigation_bar.dart index 5a7a8632..30cbd301 100644 --- a/lib/modules/dashboard/widgets/navigation_bar.dart +++ b/lib/modules/dashboard/widgets/navigation_bar.dart @@ -45,7 +45,7 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index) + widget.pageController.lunaJumpToPage(index) .then((_) => Provider.of(context, listen: false).navigationIndex = index); } } \ No newline at end of file diff --git a/lib/modules/lidarr/routes/add_details.dart b/lib/modules/lidarr/routes/add_details.dart index 75f74c99..bcfffef6 100644 --- a/lib/modules/lidarr/routes/add_details.dart +++ b/lib/modules/lidarr/routes/add_details.dart @@ -143,7 +143,7 @@ class _State extends State { ? 'No summary is available.' : _arguments.data.overview, uri: _arguments.data.posterURI ?? '', - fallbackImage: 'assets/images/lidarr/noartistposter.png', + fallbackImage: 'assets/images/blanks/user.png', squareImage: true, headers: Database.currentProfileObject.getLidarr()['headers'], ), diff --git a/lib/modules/lidarr/routes/lidarr.dart b/lib/modules/lidarr/routes/lidarr.dart index 92ace272..8a7b2980 100644 --- a/lib/modules/lidarr/routes/lidarr.dart +++ b/lib/modules/lidarr/routes/lidarr.dart @@ -82,8 +82,7 @@ class _State extends State { Widget get _appBar => LunaAppBar.dropdown( title: LunaModule.LIDARR.name, profiles: Database.profilesBox.keys.fold([], (value, element) { - if((Database.profilesBox.get(element) as ProfileHiveObject).lidarrEnabled) - value.add(element); + if(Database.profilesBox.get(element)?.lidarrEnabled ?? false) value.add(element); return value; }), actions: _api.enabled diff --git a/lib/modules/lidarr/widgets/artist_navigation_bar.dart b/lib/modules/lidarr/widgets/artist_navigation_bar.dart index c6cf0341..ed90832e 100644 --- a/lib/modules/lidarr/widgets/artist_navigation_bar.dart +++ b/lib/modules/lidarr/widgets/artist_navigation_bar.dart @@ -37,7 +37,7 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index) + widget.pageController.lunaJumpToPage(index) .then((_) => Provider.of(context, listen: false).artistNavigationIndex = index); } } diff --git a/lib/modules/lidarr/widgets/details_album_tile.dart b/lib/modules/lidarr/widgets/details_album_tile.dart index 8240f122..5f2e4c9d 100644 --- a/lib/modules/lidarr/widgets/details_album_tile.dart +++ b/lib/modules/lidarr/widgets/details_album_tile.dart @@ -28,7 +28,7 @@ class _State extends State { widget.data.albumCoverURI() != null && widget.data.albumCoverURI() != '' ? LSNetworkImage( url: widget.data.albumCoverURI(), - placeholder: 'assets/images/lidarr/noalbumart.png', + placeholder: 'assets/images/blanks/audio.png', headers: ((Database.currentProfileObject.getLidarr()['headers'] ?? {}) as Map).cast(), height: _imageDimension, width: _imageDimension, diff --git a/lib/modules/lidarr/widgets/details_overview.dart b/lib/modules/lidarr/widgets/details_overview.dart index 387510e3..342fe563 100644 --- a/lib/modules/lidarr/widgets/details_overview.dart +++ b/lib/modules/lidarr/widgets/details_overview.dart @@ -29,7 +29,7 @@ class _State extends State with AutomaticKeepAliveClientM ? 'No summary is available.' : widget?.data?.overview, uri: widget?.data?.posterURI() ?? '', - fallbackImage: 'assets/images/lidarr/noartistposter.png', + fallbackImage: 'assets/images/blanks/user.png', squareImage: true, headers: Database.currentProfileObject.getLidarr()['headers'], ), diff --git a/lib/modules/lidarr/widgets/navigation_bar.dart b/lib/modules/lidarr/widgets/navigation_bar.dart index 8fb3459a..e0b02bab 100644 --- a/lib/modules/lidarr/widgets/navigation_bar.dart +++ b/lib/modules/lidarr/widgets/navigation_bar.dart @@ -47,7 +47,7 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index) + widget.pageController.lunaJumpToPage(index) .then((_) => Provider.of(context, listen: false).navigationIndex = index); } } diff --git a/lib/modules/lidarr/widgets/search_result_tile.dart b/lib/modules/lidarr/widgets/search_result_tile.dart index fb4ea852..6b900c82 100644 --- a/lib/modules/lidarr/widgets/search_result_tile.dart +++ b/lib/modules/lidarr/widgets/search_result_tile.dart @@ -20,6 +20,14 @@ class LidarrSearchResultTile extends StatelessWidget { expanded: _expanded(context), ); + Color get lunaProtocolColor { + if(!data.isTorrent) return LunaColours.accent; + int seeders = data.seeders ?? 0; + if(seeders > 10) return LunaColours.blue; + if(seeders > 0) return LunaColours.orange; + return LunaColours.red; + } + Widget _expanded(BuildContext context) => LSCard( child: InkWell( child: Row( @@ -37,9 +45,7 @@ class LidarrSearchResultTile extends StatelessWidget { children: [ LSTextHighlighted( text: data.protocol.lunaCapitalizeFirstLetters(), - bgColor: data.isTorrent - ? LunaColours.purple - : LunaColours.blue, + bgColor: lunaProtocolColor, ), ], ), @@ -56,7 +62,7 @@ class LidarrSearchResultTile extends StatelessWidget { if(data.isTorrent) TextSpan( text: '${data.seeders} Seeders\t•\t${data.leechers} Leechers\n', style: TextStyle( - color: LunaColours.purple, + color: lunaProtocolColor, fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), ), @@ -117,9 +123,7 @@ class LidarrSearchResultTile extends StatelessWidget { children: [ TextSpan( style: TextStyle( - color: data.isTorrent - ? LunaColours.purple - : LunaColours.blue, + color: lunaProtocolColor, fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), text: data.protocol.lunaCapitalizeFirstLetters(), @@ -127,7 +131,7 @@ class LidarrSearchResultTile extends StatelessWidget { if(data.isTorrent) TextSpan( text: ' (${data.seeders}/${data.leechers})', style: TextStyle( - color: LunaColours.purple, + color: lunaProtocolColor, fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), ), diff --git a/lib/modules/nzbget/core/api/data/history.dart b/lib/modules/nzbget/core/api/data/history.dart index eb0f4c4f..ae536f51 100644 --- a/lib/modules/nzbget/core/api/data/history.dart +++ b/lib/modules/nzbget/core/api/data/history.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; @@ -57,15 +59,15 @@ class NZBGetHistoryData { } bool get isHideable { - return status.substring(0, 7) == 'SUCCESS'; + return status.substring(0, min(7, status.length)) == 'SUCCESS'; } bool get failed { - return status.substring(0, 7) == 'FAILURE'; + return status.substring(0, min(7, status.length)) == 'FAILURE'; } Color get statusColor { - switch(status.substring(0, 7)) { + switch(status.substring(0, min(7, status.length))) { case 'SUCCESS': return LunaColours.accent; case 'WARNING': return LunaColours.orange; case 'DELETED': return LunaColours.purple; @@ -75,7 +77,7 @@ class NZBGetHistoryData { } String get statusString { - switch(status.substring(0, 7)) { + switch(status.substring(0, min(7, status.length))) { case 'SUCCESS': return 'Completed (${status.substring('SUCCESS/'.length)})'; case 'WARNING': return 'Warning (${status.substring('WARNING/'.length)})'; case 'DELETED': return 'Deleted (${status.substring('DELETED/'.length)})'; diff --git a/lib/modules/nzbget/routes/nzbget.dart b/lib/modules/nzbget/routes/nzbget.dart index edb4d7de..aa33df94 100644 --- a/lib/modules/nzbget/routes/nzbget.dart +++ b/lib/modules/nzbget/routes/nzbget.dart @@ -72,8 +72,7 @@ class _State extends State { Widget get _appBar => LunaAppBar.dropdown( title: 'NZBGet', profiles: Database.profilesBox.keys.fold([], (value, element) { - if((Database.profilesBox.get(element) as ProfileHiveObject).nzbgetEnabled) - value.add(element); + if(Database.profilesBox.get(element)?.nzbgetEnabled ?? false) value.add(element); return value; }), actions: _api.enabled diff --git a/lib/modules/nzbget/widgets/navigation_bar.dart b/lib/modules/nzbget/widgets/navigation_bar.dart index 70a6f2ee..63d7a417 100644 --- a/lib/modules/nzbget/widgets/navigation_bar.dart +++ b/lib/modules/nzbget/widgets/navigation_bar.dart @@ -45,7 +45,7 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index) + widget.pageController.lunaJumpToPage(index) .then((_) => Provider.of(context, listen: false).navigationIndex = index); } } diff --git a/lib/modules/radarr/core/extensions/radarr_movie_file.dart b/lib/modules/radarr/core/extensions/radarr_movie_file.dart index ebe0d5a1..ae259b8e 100644 --- a/lib/modules/radarr/core/extensions/radarr_movie_file.dart +++ b/lib/modules/radarr/core/extensions/radarr_movie_file.dart @@ -12,6 +12,11 @@ extension LunaRadarrMovieFileExtension on RadarrMovieFile { return LunaUI.TEXT_EMDASH; } + String get lunaLanguage { + if(this?.languages == null || this.languages.length == 0) return LunaUI.TEXT_EMDASH; + return this.languages.map((lang) => lang.name).join('\n'); + } + String get lunaQuality { if(this?.quality?.quality?.name != null) return this.quality.quality.name; return LunaUI.TEXT_EMDASH; diff --git a/lib/modules/radarr/core/extensions/radarr_release.dart b/lib/modules/radarr/core/extensions/radarr_release.dart index d0b625f6..5bbcbecd 100644 --- a/lib/modules/radarr/core/extensions/radarr_release.dart +++ b/lib/modules/radarr/core/extensions/radarr_release.dart @@ -19,8 +19,11 @@ extension RadarrReleaseExtension on RadarrRelease { } Color get lunaProtocolColor { - if(this.protocol == RadarrProtocol.USENET) return LunaColours.blue; - return LunaColours.purple; + if(this.protocol == RadarrProtocol.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 { diff --git a/lib/modules/radarr/core/router.dart b/lib/modules/radarr/core/router.dart index d06af1d0..3c94ed93 100644 --- a/lib/modules/radarr/core/router.dart +++ b/lib/modules/radarr/core/router.dart @@ -1,4 +1,5 @@ import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; @@ -17,3 +18,31 @@ class RadarrRouter extends LunaModuleRouter { RadarrTagsRouter().defineRoute(router); } } + +abstract class RadarrPageRouter extends LunaPageRouter { + RadarrPageRouter(String route) : super(route); + + @override + void noParameterRouteDefinition(FluroRouter router, Widget widget, { bool homeRoute = false }) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) { + if(!homeRoute && !context.read().enabled) return LunaNotEnabledRoute(module: 'Radarr'); + return widget; + }), + transitionType: LunaRouter.transitionType, + ); + + @override + void withParameterRouteDefinition( + FluroRouter router, + Widget Function(BuildContext, Map>) handlerFunc, + { bool homeRoute = false } + ) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) { + if(!homeRoute && !context.read().enabled) return LunaNotEnabledRoute(module: 'Radarr'); + return handlerFunc(context, params); + }), + transitionType: LunaRouter.transitionType, + ); +} diff --git a/lib/modules/radarr/core/types/filter_movies.g.dart b/lib/modules/radarr/core/types/filter_movies.g.dart index ad48623b..2b4f9b8b 100644 --- a/lib/modules/radarr/core/types/filter_movies.g.dart +++ b/lib/modules/radarr/core/types/filter_movies.g.dart @@ -26,7 +26,7 @@ class RadarrMoviesFilterAdapter extends TypeAdapter { case 5: return RadarrMoviesFilter.CUTOFF_UNMET; default: - return null; + return RadarrMoviesFilter.ALL; } } diff --git a/lib/modules/radarr/core/types/filter_releases.g.dart b/lib/modules/radarr/core/types/filter_releases.g.dart index 13a70097..a67ba8b7 100644 --- a/lib/modules/radarr/core/types/filter_releases.g.dart +++ b/lib/modules/radarr/core/types/filter_releases.g.dart @@ -20,7 +20,7 @@ class RadarrReleasesFilterAdapter extends TypeAdapter { case 2: return RadarrReleasesFilter.REJECTED; default: - return null; + return RadarrReleasesFilter.ALL; } } diff --git a/lib/modules/radarr/core/types/settings_global.dart b/lib/modules/radarr/core/types/settings_global.dart index abbfcfcd..1e644653 100644 --- a/lib/modules/radarr/core/types/settings_global.dart +++ b/lib/modules/radarr/core/types/settings_global.dart @@ -44,7 +44,7 @@ extension RadarrGlobalSettingsTypeExtension on RadarrGlobalSettingsType { throw Exception('Invalid RadarrGlobalSettingsType'); } - Future _webGUI(BuildContext context) async => Provider.of(context, listen: false).host.lunaOpenGenericLink(); + Future _webGUI(BuildContext context) async => context.read().host.lunaOpenGenericLink(); Future _backupDatabase(BuildContext context) async => RadarrAPIHelper().backupDatabase(context: context); Future _searchAllMissing(BuildContext context) async { bool result = await RadarrDialogs().searchAllMissingMovies(context); diff --git a/lib/modules/radarr/core/types/sorting_movies.g.dart b/lib/modules/radarr/core/types/sorting_movies.g.dart index d29339d8..2c298133 100644 --- a/lib/modules/radarr/core/types/sorting_movies.g.dart +++ b/lib/modules/radarr/core/types/sorting_movies.g.dart @@ -30,7 +30,7 @@ class RadarrMoviesSortingAdapter extends TypeAdapter { case 6: return RadarrMoviesSorting.YEAR; default: - return null; + return RadarrMoviesSorting.ALPHABETICAL; } } diff --git a/lib/modules/radarr/core/types/sorting_releases.g.dart b/lib/modules/radarr/core/types/sorting_releases.g.dart index 8228834d..bbee5a31 100644 --- a/lib/modules/radarr/core/types/sorting_releases.g.dart +++ b/lib/modules/radarr/core/types/sorting_releases.g.dart @@ -26,7 +26,7 @@ class RadarrReleasesSortingAdapter extends TypeAdapter { case 5: return RadarrReleasesSorting.WEIGHT; default: - return null; + return RadarrReleasesSorting.AGE; } } diff --git a/lib/modules/radarr/routes/add_movie/route.dart b/lib/modules/radarr/routes/add_movie/route.dart index bd7d9f76..7caa0a12 100644 --- a/lib/modules/radarr/routes/add_movie/route.dart +++ b/lib/modules/radarr/routes/add_movie/route.dart @@ -9,7 +9,7 @@ class _RadarrAddMovieArguments { _RadarrAddMovieArguments(this.query); } -class RadarrAddMovieRouter extends LunaPageRouter { +class RadarrAddMovieRouter extends RadarrPageRouter { RadarrAddMovieRouter() : super('/radarr/addmovie'); @override @@ -20,11 +20,7 @@ class RadarrAddMovieRouter extends LunaPageRouter { ); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) => _RadarrAddMovieRoute()), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _RadarrAddMovieRoute()); } class _RadarrAddMovieRoute extends StatefulWidget { diff --git a/lib/modules/radarr/routes/add_movie/widgets/discovery_results_tile.dart b/lib/modules/radarr/routes/add_movie/widgets/discovery_results_tile.dart index a9c8ecff..64c99c98 100644 --- a/lib/modules/radarr/routes/add_movie/widgets/discovery_results_tile.dart +++ b/lib/modules/radarr/routes/add_movie/widgets/discovery_results_tile.dart @@ -23,7 +23,7 @@ class _State extends State { backgroundUrl: widget.movie.remotePoster, posterUrl: widget.movie.remotePoster, posterHeaders: context.watch().headers, - posterPlaceholder: 'assets/images/radarr/nomovieposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', title: widget.movie.title, subtitle1: _subtitle1(), subtitle2: _subtitle2(), diff --git a/lib/modules/radarr/routes/add_movie/widgets/search_results_tile.dart b/lib/modules/radarr/routes/add_movie/widgets/search_results_tile.dart index ac59faf2..d5952f68 100644 --- a/lib/modules/radarr/routes/add_movie/widgets/search_results_tile.dart +++ b/lib/modules/radarr/routes/add_movie/widgets/search_results_tile.dart @@ -27,7 +27,7 @@ class _State extends State { backgroundUrl: widget.movie.remotePoster, posterUrl: widget.movie.remotePoster, posterHeaders: context.watch().headers, - posterPlaceholder: 'assets/images/radarr/nomovieposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', title: widget.movie.title, darken: widget.exists, titleColor: widget.isExcluded ? LunaColours.red : Colors.white, diff --git a/lib/modules/radarr/routes/add_movie_details/route.dart b/lib/modules/radarr/routes/add_movie_details/route.dart index b954b4e2..91d1f578 100644 --- a/lib/modules/radarr/routes/add_movie_details/route.dart +++ b/lib/modules/radarr/routes/add_movie_details/route.dart @@ -16,7 +16,7 @@ class _RadarrAddMovieDetailsArguments { } } -class RadarrAddMovieDetailsRouter extends LunaPageRouter { +class RadarrAddMovieDetailsRouter extends RadarrPageRouter { RadarrAddMovieDetailsRouter() : super('/radarr/addmovie/details'); @override @@ -30,11 +30,7 @@ class RadarrAddMovieDetailsRouter extends LunaPageRouter { ); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) => _RadarrMoviesAddDetailsRoute()), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _RadarrMoviesAddDetailsRoute()); } class _RadarrMoviesAddDetailsRoute extends StatefulWidget { diff --git a/lib/modules/radarr/routes/catalogue/route.dart b/lib/modules/radarr/routes/catalogue/route.dart index a1ed0343..28632b9f 100644 --- a/lib/modules/radarr/routes/catalogue/route.dart +++ b/lib/modules/radarr/routes/catalogue/route.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; @@ -86,7 +88,7 @@ class _State extends State with AutomaticKeepAliveClientMi children: [ LunaButton( text: query.length > 20 - ? 'radarr.SearchFor'.tr(args: ['"${query.substring(0, 20)}${LunaUI.TEXT_ELLIPSIS}"']) + ? 'radarr.SearchFor'.tr(args: ['"${query.substring(0, min(20, query.length))}${LunaUI.TEXT_ELLIPSIS}"']) : 'radarr.SearchFor'.tr(args: ['"$query"']), onTap: () async => RadarrAddMovieRouter().navigateTo(context, query: query ?? ''), ), diff --git a/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart b/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart index 4fb74970..2f48e24f 100644 --- a/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart +++ b/lib/modules/radarr/routes/catalogue/widgets/movie_tile.dart @@ -25,7 +25,7 @@ class _State extends State { backgroundUrl: context.read().getPosterURL(widget.movie.id), posterUrl: context.read().getPosterURL(widget.movie.id), posterHeaders: context.read().headers, - posterPlaceholder: 'assets/images/radarr/nomovieposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', darken: !widget.movie.monitored, title: widget.movie.title, subtitle1: _subtitle1(), diff --git a/lib/modules/radarr/routes/edit_movie/route.dart b/lib/modules/radarr/routes/edit_movie/route.dart index 3ede04dc..370bee6a 100644 --- a/lib/modules/radarr/routes/edit_movie/route.dart +++ b/lib/modules/radarr/routes/edit_movie/route.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrMoviesEditRouter extends LunaPageRouter { +class RadarrMoviesEditRouter extends RadarrPageRouter { RadarrMoviesEditRouter() : super('/radarr/editmovie/:movieid'); @override @@ -13,14 +13,10 @@ class RadarrMoviesEditRouter extends LunaPageRouter { String route({ @required int movieId }) => fullRoute.replaceFirst(':movieid', movieId.toString()); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) { - int movieId = params['movieid'] == null || params['movieid'].length == 0 ? -1 : (int.tryParse(params['movieid'][0]) ?? -1); - return _RadarrMoviesEditRoute(movieId: movieId); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int movieId = params['movieid'] == null || params['movieid'].length == 0 ? -1 : (int.tryParse(params['movieid'][0]) ?? -1); + return _RadarrMoviesEditRoute(movieId: movieId); + }); } class _RadarrMoviesEditRoute extends StatefulWidget { diff --git a/lib/modules/radarr/routes/history/route.dart b/lib/modules/radarr/routes/history/route.dart index c105a71d..ce2f680e 100644 --- a/lib/modules/radarr/routes/history/route.dart +++ b/lib/modules/radarr/routes/history/route.dart @@ -4,7 +4,7 @@ import 'package:infinite_scroll_pagination/infinite_scroll_pagination.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrHistoryRouter extends LunaPageRouter { +class RadarrHistoryRouter extends RadarrPageRouter { RadarrHistoryRouter() : super('/radarr/history'); @override diff --git a/lib/modules/radarr/routes/missing/widgets/missing_tile.dart b/lib/modules/radarr/routes/missing/widgets/missing_tile.dart index caa3aa34..7520cfcb 100644 --- a/lib/modules/radarr/routes/missing/widgets/missing_tile.dart +++ b/lib/modules/radarr/routes/missing/widgets/missing_tile.dart @@ -25,7 +25,7 @@ class _State extends State { backgroundUrl: context.read().getPosterURL(widget.movie.id), posterUrl: context.read().getPosterURL(widget.movie.id), posterHeaders: context.read().headers, - posterPlaceholder: 'assets/images/radarr/nomovieposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', darken: !widget.movie.monitored, title: widget.movie.title, subtitle1: _subtitle1(), diff --git a/lib/modules/radarr/routes/movie_details/route.dart b/lib/modules/radarr/routes/movie_details/route.dart index 06405048..aedda255 100644 --- a/lib/modules/radarr/routes/movie_details/route.dart +++ b/lib/modules/radarr/routes/movie_details/route.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrMoviesDetailsRouter extends LunaPageRouter { +class RadarrMoviesDetailsRouter extends RadarrPageRouter { RadarrMoviesDetailsRouter() : super('/radarr/movie/:movieid'); @override @@ -13,14 +13,10 @@ class RadarrMoviesDetailsRouter extends LunaPageRouter { String route({ @required int movieId }) => fullRoute.replaceFirst(':movieid', movieId.toString()); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) { - int movieid = params['movieid'] == null || params['movieid'].length == 0 ? -1 : (int.tryParse(params['movieid'][0]) ?? -1); - return _RadarrMoviesDetailsRoute(movieId: movieid); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int movieId = params['movieid'] == null || params['movieid'].length == 0 ? -1 : (int.tryParse(params['movieid'][0]) ?? -1); + return _RadarrMoviesDetailsRoute(movieId: movieId); + }); } class _RadarrMoviesDetailsRoute extends StatefulWidget { @@ -87,7 +83,7 @@ class _State extends State<_RadarrMoviesDetailsRoute> with LunaLoadCallbackMixin key: _scaffoldKey, appBar: _appBar(), bottomNavigationBar: context.watch().enabled ? _bottomNavigationBar() : null, - body: context.watch().enabled ? _body() : LunaMessage.moduleNotEnabled(context: context, module: 'Radarr'), + body: _body(), ); } diff --git a/lib/modules/radarr/routes/movie_details/widgets/cast_crew_tile.dart b/lib/modules/radarr/routes/movie_details/widgets/cast_crew_tile.dart index f894cf44..929a1c83 100644 --- a/lib/modules/radarr/routes/movie_details/widgets/cast_crew_tile.dart +++ b/lib/modules/radarr/routes/movie_details/widgets/cast_crew_tile.dart @@ -20,7 +20,7 @@ class RadarrMovieDetailsCastCrewTile extends StatelessWidget { } return LunaTwoLineCardWithPoster( title: credits.personName, - posterPlaceholder: 'assets/images/lidarr/noartistposter.png', + posterPlaceholder: 'assets/images/blanks/user.png', posterUrl: credits.images.length == 0 ? null : credits.images[0].url, posterHeaders: {}, subtitle1: TextSpan(text: position), 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 131124cb..1b07dd27 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,18 +22,19 @@ class _State extends State { return LunaTableCard( content: [ LunaTableContent(title: 'relative path', body: widget.movieFile?.lunaRelativePath), - LunaTableContent(title: 'video codec', body: widget.movieFile.mediaInfo.videoCodec ?? LunaUI.TEXT_EMDASH), + LunaTableContent(title: 'video', body: widget.movieFile.mediaInfo.videoCodec ?? LunaUI.TEXT_EMDASH), LunaTableContent( - title: 'audio codec', + 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()), ), LunaTableContent(title: 'size', body: widget.movieFile?.lunaSize), + LunaTableContent(title: 'languages', body: widget.movieFile?.lunaLanguage), LunaTableContent(title: 'quality', body: widget.movieFile?.lunaQuality), + LunaTableContent(title: 'formats', body: widget.movieFile?.lunaCustomFormats), LunaTableContent(title: 'added on', body: widget.movieFile?.lunaDateAdded), - LunaTableContent(title: 'custom formats', body: widget.movieFile?.lunaCustomFormats), ], buttons: [ if(widget.movieFile?.mediaInfo != null) LunaButton.slim( diff --git a/lib/modules/radarr/routes/movie_details/widgets/overview_movie_description_tile.dart b/lib/modules/radarr/routes/movie_details/widgets/overview_movie_description_tile.dart index 312c0243..0d3dffd9 100644 --- a/lib/modules/radarr/routes/movie_details/widgets/overview_movie_description_tile.dart +++ b/lib/modules/radarr/routes/movie_details/widgets/overview_movie_description_tile.dart @@ -12,7 +12,7 @@ class RadarrMovieDetailsOverviewDescriptionTile extends StatelessWidget { Widget build(BuildContext context) { return LunaFourLineCardWithPoster( - posterPlaceholder: 'assets/images/radarr/nomovieposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', backgroundUrl: context.read().getFanartURL(movie.id), posterUrl: context.read().getPosterURL(movie.id), posterHeaders: context.read().headers, diff --git a/lib/modules/radarr/routes/queue/route.dart b/lib/modules/radarr/routes/queue/route.dart index 337c2800..74ef8032 100644 --- a/lib/modules/radarr/routes/queue/route.dart +++ b/lib/modules/radarr/routes/queue/route.dart @@ -1,8 +1,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; +import 'package:lunasea/modules/radarr.dart'; import 'package:lunasea/core.dart'; -class RadarrQueueRouter extends LunaPageRouter { +class RadarrQueueRouter extends RadarrPageRouter { RadarrQueueRouter() : super('/radarr/queue'); @override diff --git a/lib/modules/radarr/routes/radarr/route.dart b/lib/modules/radarr/routes/radarr/route.dart index 9de2a087..72efd687 100644 --- a/lib/modules/radarr/routes/radarr/route.dart +++ b/lib/modules/radarr/routes/radarr/route.dart @@ -3,11 +3,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrHomeRouter extends LunaPageRouter { +class RadarrHomeRouter extends RadarrPageRouter { RadarrHomeRouter() : super('/radarr'); @override - void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _RadarrHomeRoute()); + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _RadarrHomeRoute(), homeRoute: true); } class _RadarrHomeRoute extends StatefulWidget { @@ -57,7 +57,7 @@ class _State extends State<_RadarrHomeRoute> { Widget _appBar() { List profiles = Database.profilesBox.keys.fold([], (value, element) { - if((Database.profilesBox.get(element) as ProfileHiveObject)?.radarrEnabled ?? false) value.add(element); + if(Database.profilesBox.get(element)?.radarrEnabled ?? false) value.add(element); return value; }); List actions; @@ -66,7 +66,7 @@ class _State extends State<_RadarrHomeRoute> { RadarrAppBarGlobalSettingsAction(), ]; return LunaAppBar.dropdown( - title: 'Radarr', + title: LunaModule.RADARR.name, profiles: profiles, actions: actions, pageController: _pageController, @@ -74,19 +74,21 @@ class _State extends State<_RadarrHomeRoute> { ); } - Widget _body() => Selector( - selector: (_, state) => state.enabled, - builder: (context, enabled, _) { - if(!enabled) return LunaMessage.moduleNotEnabled(context: context, module: 'Radarr'); - return PageView( - controller: _pageController, - children: [ - RadarrCatalogueRoute(), - RadarrUpcomingRoute(), - RadarrMissingRoute(), - RadarrMoreRoute(), - ], - ); - } - ); + Widget _body() { + return Selector( + selector: (_, state) => state.enabled, + builder: (context, enabled, _) { + if(!enabled) return LunaMessage.moduleNotEnabled(context: context, module: 'Radarr'); + return PageView( + controller: _pageController, + children: [ + RadarrCatalogueRoute(), + RadarrUpcomingRoute(), + RadarrMissingRoute(), + RadarrMoreRoute(), + ], + ); + } + ); + } } diff --git a/lib/modules/radarr/routes/releases/route.dart b/lib/modules/radarr/routes/releases/route.dart index 30315c68..064f93b3 100644 --- a/lib/modules/radarr/routes/releases/route.dart +++ b/lib/modules/radarr/routes/releases/route.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrReleasesRouter extends LunaPageRouter { +class RadarrReleasesRouter extends RadarrPageRouter { RadarrReleasesRouter() : super('/radarr/releases/:movieid'); @override @@ -13,14 +13,10 @@ class RadarrReleasesRouter extends LunaPageRouter { String route({ @required int movieId }) => fullRoute.replaceFirst(':movieid', movieId.toString()); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) { - int movieId = params['movieid'] == null || params['movieid'].length == 0 ? -1 : (int.tryParse(params['movieid'][0]) ?? -1); - return _RadarrReleasesRoute(movieId: movieId); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int movieId = params['movieid'] == null || params['movieid'].length == 0 ? -1 : (int.tryParse(params['movieid'][0]) ?? -1); + return _RadarrReleasesRoute(movieId: movieId); + }); } class _RadarrReleasesRoute extends StatefulWidget { diff --git a/lib/modules/radarr/routes/releases/widgets/release_tile.dart b/lib/modules/radarr/routes/releases/widgets/release_tile.dart index 836d4266..3e384d54 100644 --- a/lib/modules/radarr/routes/releases/widgets/release_tile.dart +++ b/lib/modules/radarr/routes/releases/widgets/release_tile.dart @@ -72,7 +72,7 @@ class _State extends State { text: widget.release.protocol.readable, backgroundColor: widget.release.lunaProtocolColor, ), - if((widget.release.customFormatScore ?? 0) > 0) LunaHighlightedNode(text: '+${widget.release.customFormatScore}', backgroundColor: LunaColours.orange), + if((widget.release.customFormatScore ?? 0) != 0) LunaHighlightedNode(text: '+${widget.release.customFormatScore}', backgroundColor: LunaColours.orange), ...widget.release.customFormats.map((custom) => LunaHighlightedNode(text: custom.name, backgroundColor: LunaColours.blueGrey)), ]; } diff --git a/lib/modules/radarr/routes/system_status/route.dart b/lib/modules/radarr/routes/system_status/route.dart index 63cd7038..74a39e2f 100644 --- a/lib/modules/radarr/routes/system_status/route.dart +++ b/lib/modules/radarr/routes/system_status/route.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrSystemStatusRouter extends LunaPageRouter { +class RadarrSystemStatusRouter extends RadarrPageRouter { RadarrSystemStatusRouter() : super('/radarr/system/status'); @override @@ -31,7 +31,7 @@ class _State extends State<_RadarrSystemStatusRoute> { key: _scaffoldKey, appBar: _appBar(), bottomNavigationBar: context.watch().enabled ? _bottomNavigationBar() : null, - body: context.watch().enabled ? _body() : LunaMessage.moduleNotEnabled(context: context, module: 'Radarr'), + body: _body(), ); } diff --git a/lib/modules/radarr/routes/system_status/state.dart b/lib/modules/radarr/routes/system_status/state.dart index 47ac1f10..34a6d387 100644 --- a/lib/modules/radarr/routes/system_status/state.dart +++ b/lib/modules/radarr/routes/system_status/state.dart @@ -19,7 +19,7 @@ class RadarrSystemStatusState extends ChangeNotifier { Future fetchDiskSpace(BuildContext context) async { RadarrState state = context.read(); - if(state.enabled) _diskSpace = state.api.diskSpace.getAll(); + if(state.enabled) _diskSpace = state.api.fileSystem.getDiskSpace(); notifyListeners(); await _diskSpace; } diff --git a/lib/modules/radarr/routes/tags/route.dart b/lib/modules/radarr/routes/tags/route.dart index 2d720721..d066d883 100644 --- a/lib/modules/radarr/routes/tags/route.dart +++ b/lib/modules/radarr/routes/tags/route.dart @@ -4,7 +4,7 @@ import 'package:flutter/scheduler.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; -class RadarrTagsRouter extends LunaPageRouter { +class RadarrTagsRouter extends RadarrPageRouter { RadarrTagsRouter() : super('/radarr/tags'); @override diff --git a/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart b/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart index 38f6cd53..7e6838ff 100644 --- a/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart +++ b/lib/modules/radarr/routes/upcoming/widgets/upcoming_tile.dart @@ -25,7 +25,7 @@ class _State extends State { backgroundUrl: context.read().getPosterURL(widget.movie.id), posterUrl: context.read().getPosterURL(widget.movie.id), posterHeaders: context.read().headers, - posterPlaceholder: 'assets/images/radarr/nomovieposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', darken: !widget.movie.monitored, title: widget.movie.title, subtitle1: _subtitle1(), diff --git a/lib/modules/sabnzbd/routes/sabnzbd.dart b/lib/modules/sabnzbd/routes/sabnzbd.dart index 3b22cf4a..e917683c 100644 --- a/lib/modules/sabnzbd/routes/sabnzbd.dart +++ b/lib/modules/sabnzbd/routes/sabnzbd.dart @@ -72,8 +72,7 @@ class _State extends State { Widget get _appBar => LunaAppBar.dropdown( title: 'SABnzbd', profiles: Database.profilesBox.keys.fold([], (value, element) { - if((Database.profilesBox.get(element) as ProfileHiveObject).sabnzbdEnabled) - value.add(element); + if(Database.profilesBox.get(element)?.sabnzbdEnabled ?? false) value.add(element); return value; }), actions: _api.enabled diff --git a/lib/modules/sabnzbd/widgets/navigation_bar.dart b/lib/modules/sabnzbd/widgets/navigation_bar.dart index d11d5abc..04f35c1e 100644 --- a/lib/modules/sabnzbd/widgets/navigation_bar.dart +++ b/lib/modules/sabnzbd/widgets/navigation_bar.dart @@ -45,7 +45,7 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index) + widget.pageController.lunaJumpToPage(index) .then((_) => Provider.of(context, listen: false).navigationIndex = index); } } diff --git a/lib/modules/search/core/router.dart b/lib/modules/search/core/router.dart index 4b5e6ef0..2d182c72 100644 --- a/lib/modules/search/core/router.dart +++ b/lib/modules/search/core/router.dart @@ -1,4 +1,5 @@ import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search.dart'; @@ -12,3 +13,25 @@ class SearchRouter extends LunaModuleRouter { SearchSearchRouter().defineRoute(router); } } + +abstract class SearchPageRouter extends LunaPageRouter { + SearchPageRouter(String route) : super(route); + + @override + void noParameterRouteDefinition(FluroRouter router, Widget widget, { bool homeRoute = false }) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) => widget), + transitionType: LunaRouter.transitionType, + ); + + @override + void withParameterRouteDefinition( + FluroRouter router, + Widget Function(BuildContext, Map>) handlerFunc, + { bool homeRoute = false } + ) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) => handlerFunc(context, params)), + transitionType: LunaRouter.transitionType, + ); +} diff --git a/lib/modules/search/routes/categories/route.dart b/lib/modules/search/routes/categories/route.dart index 9e4ea8d7..52f0ea07 100644 --- a/lib/modules/search/routes/categories/route.dart +++ b/lib/modules/search/routes/categories/route.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search.dart'; -class SearchCategoriesRouter extends LunaPageRouter { +class SearchCategoriesRouter extends SearchPageRouter { SearchCategoriesRouter() : super('/search/categories'); @override diff --git a/lib/modules/search/routes/indexers/route.dart b/lib/modules/search/routes/indexers/route.dart index 5ce23705..5d732ad2 100644 --- a/lib/modules/search/routes/indexers/route.dart +++ b/lib/modules/search/routes/indexers/route.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search.dart'; -class SearchHomeRouter extends LunaPageRouter { +class SearchHomeRouter extends SearchPageRouter { SearchHomeRouter(): super('/search'); @override diff --git a/lib/modules/search/routes/results/route.dart b/lib/modules/search/routes/results/route.dart index ab3dacfb..b0114238 100644 --- a/lib/modules/search/routes/results/route.dart +++ b/lib/modules/search/routes/results/route.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search.dart'; -class SearchResultsRouter extends LunaPageRouter { +class SearchResultsRouter extends SearchPageRouter { SearchResultsRouter() : super('/search/results'); @override diff --git a/lib/modules/search/routes/search/route.dart b/lib/modules/search/routes/search/route.dart index 8ab03b92..9094a1d3 100644 --- a/lib/modules/search/routes/search/route.dart +++ b/lib/modules/search/routes/search/route.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search.dart'; -class SearchSearchRouter extends LunaPageRouter { +class SearchSearchRouter extends SearchPageRouter { SearchSearchRouter() : super('/search/search'); @override diff --git a/lib/modules/search/routes/subcategories/route.dart b/lib/modules/search/routes/subcategories/route.dart index 1b5a6b15..cdea2efc 100644 --- a/lib/modules/search/routes/subcategories/route.dart +++ b/lib/modules/search/routes/subcategories/route.dart @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search.dart'; -class SearchSubcategoriesRouter extends LunaPageRouter { +class SearchSubcategoriesRouter extends SearchPageRouter { SearchSubcategoriesRouter() : super('/search/subcategories'); @override diff --git a/lib/modules/settings/core/router.dart b/lib/modules/settings/core/router.dart index 501ebaa6..633d8530 100644 --- a/lib/modules/settings/core/router.dart +++ b/lib/modules/settings/core/router.dart @@ -1,4 +1,5 @@ import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; @@ -65,3 +66,25 @@ class SettingsRouter extends LunaModuleRouter { SettingsSystemLogsDetailsRouter().defineRoute(router); } } + +abstract class SettingsPageRouter extends LunaPageRouter { + SettingsPageRouter(String route) : super(route); + + @override + void noParameterRouteDefinition(FluroRouter router, Widget widget, { bool homeRoute = false }) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) => widget), + transitionType: LunaRouter.transitionType, + ); + + @override + void withParameterRouteDefinition( + FluroRouter router, + Widget Function(BuildContext, Map>) handlerFunc, + { bool homeRoute = false } + ) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) => handlerFunc(context, params)), + transitionType: LunaRouter.transitionType, + ); +} diff --git a/lib/modules/settings/routes/account/pages/password_reset.dart b/lib/modules/settings/routes/account/pages/password_reset.dart index 746972a7..24d470ed 100644 --- a/lib/modules/settings/routes/account/pages/password_reset.dart +++ b/lib/modules/settings/routes/account/pages/password_reset.dart @@ -1,8 +1,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsAccountPasswordResetRouter extends LunaPageRouter { +class SettingsAccountPasswordResetRouter extends SettingsPageRouter { SettingsAccountPasswordResetRouter() : super('/settings/account/passwordreset'); @override diff --git a/lib/modules/settings/routes/account/pages/signed_out.dart b/lib/modules/settings/routes/account/pages/signed_out.dart index 2ce9c412..cf4910a9 100644 --- a/lib/modules/settings/routes/account/pages/signed_out.dart +++ b/lib/modules/settings/routes/account/pages/signed_out.dart @@ -27,7 +27,7 @@ class _State extends State { Padding( child: Center( child: Image.asset( - 'assets/branding/splash.png', + 'assets/images/branding/splash.png', width: 200.0, ), ), diff --git a/lib/modules/settings/routes/account/route.dart b/lib/modules/settings/routes/account/route.dart index f7dcb9d3..3085096f 100644 --- a/lib/modules/settings/routes/account/route.dart +++ b/lib/modules/settings/routes/account/route.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsAccountRouter extends LunaPageRouter { +class SettingsAccountRouter extends SettingsPageRouter { SettingsAccountRouter() : super('/settings/account'); @override diff --git a/lib/modules/settings/routes/configuration.dart b/lib/modules/settings/routes/configuration.dart index 9a85f3ff..82696bc1 100644 --- a/lib/modules/settings/routes/configuration.dart +++ b/lib/modules/settings/routes/configuration.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules.dart'; -class SettingsConfigurationRouter extends LunaPageRouter { +class SettingsConfigurationRouter extends SettingsPageRouter { SettingsConfigurationRouter() : super('/settings/configuration'); @override diff --git a/lib/modules/settings/routes/configuration_appearance.dart b/lib/modules/settings/routes/configuration_appearance.dart index 513ad492..bac861ee 100644 --- a/lib/modules/settings/routes/configuration_appearance.dart +++ b/lib/modules/settings/routes/configuration_appearance.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationAppearanceRouter extends LunaPageRouter { +class SettingsConfigurationAppearanceRouter extends SettingsPageRouter { SettingsConfigurationAppearanceRouter() : super('/settings/configuration/appearance'); @override diff --git a/lib/modules/settings/routes/configuration_dashboard/pages/calendar_settings.dart b/lib/modules/settings/routes/configuration_dashboard/pages/calendar_settings.dart index ba9f3ab4..3b8de5ca 100644 --- a/lib/modules/settings/routes/configuration_dashboard/pages/calendar_settings.dart +++ b/lib/modules/settings/routes/configuration_dashboard/pages/calendar_settings.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/dashboard.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationDashboardCalendarSettingsRouter extends LunaPageRouter { +class SettingsConfigurationDashboardCalendarSettingsRouter extends SettingsPageRouter { SettingsConfigurationDashboardCalendarSettingsRouter() : super('/settings/configuration/dashboard/calendar'); @override diff --git a/lib/modules/settings/routes/configuration_dashboard/route.dart b/lib/modules/settings/routes/configuration_dashboard/route.dart index 5825cfd2..4706daa9 100644 --- a/lib/modules/settings/routes/configuration_dashboard/route.dart +++ b/lib/modules/settings/routes/configuration_dashboard/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/dashboard.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationDashboardRouter extends LunaPageRouter { +class SettingsConfigurationDashboardRouter extends SettingsPageRouter { SettingsConfigurationDashboardRouter() : super('/settings/configuration/dashboard'); @override diff --git a/lib/modules/settings/routes/configuration_lidarr/pages/connection_details.dart b/lib/modules/settings/routes/configuration_lidarr/pages/connection_details.dart index 77243812..ae4be0ef 100644 --- a/lib/modules/settings/routes/configuration_lidarr/pages/connection_details.dart +++ b/lib/modules/settings/routes/configuration_lidarr/pages/connection_details.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/lidarr.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationLidarrConnectionDetailsRouter extends LunaPageRouter { +class SettingsConfigurationLidarrConnectionDetailsRouter extends SettingsPageRouter { SettingsConfigurationLidarrConnectionDetailsRouter() : super('/settings/configuration/lidarr/connection'); @override diff --git a/lib/modules/settings/routes/configuration_lidarr/pages/default_pages.dart b/lib/modules/settings/routes/configuration_lidarr/pages/default_pages.dart index 0d320b26..de0f03c5 100644 --- a/lib/modules/settings/routes/configuration_lidarr/pages/default_pages.dart +++ b/lib/modules/settings/routes/configuration_lidarr/pages/default_pages.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/lidarr.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationLidarrDefaultPagesRouter extends LunaPageRouter { +class SettingsConfigurationLidarrDefaultPagesRouter extends SettingsPageRouter { SettingsConfigurationLidarrDefaultPagesRouter() : super('/settings/configuration/lidarr/pages'); @override diff --git a/lib/modules/settings/routes/configuration_lidarr/pages/headers.dart b/lib/modules/settings/routes/configuration_lidarr/pages/headers.dart index 69ce1f82..c7fb615f 100644 --- a/lib/modules/settings/routes/configuration_lidarr/pages/headers.dart +++ b/lib/modules/settings/routes/configuration_lidarr/pages/headers.dart @@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationLidarrHeadersRouter extends LunaPageRouter { +class SettingsConfigurationLidarrHeadersRouter extends SettingsPageRouter { SettingsConfigurationLidarrHeadersRouter() : super('/settings/configuration/lidarr/headers'); @override diff --git a/lib/modules/settings/routes/configuration_lidarr/route.dart b/lib/modules/settings/routes/configuration_lidarr/route.dart index d4d8eb55..a43a3314 100644 --- a/lib/modules/settings/routes/configuration_lidarr/route.dart +++ b/lib/modules/settings/routes/configuration_lidarr/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/lidarr.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationLidarrRouter extends LunaPageRouter { +class SettingsConfigurationLidarrRouter extends SettingsPageRouter { SettingsConfigurationLidarrRouter() : super('/settings/configuration/lidarr'); @override diff --git a/lib/modules/settings/routes/configuration_nzbget/pages/connection_details.dart b/lib/modules/settings/routes/configuration_nzbget/pages/connection_details.dart index d2e13c67..05c05a2f 100644 --- a/lib/modules/settings/routes/configuration_nzbget/pages/connection_details.dart +++ b/lib/modules/settings/routes/configuration_nzbget/pages/connection_details.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/nzbget.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationNZBGetConnectionDetailsRouter extends LunaPageRouter { +class SettingsConfigurationNZBGetConnectionDetailsRouter extends SettingsPageRouter { SettingsConfigurationNZBGetConnectionDetailsRouter() : super('/settings/configuration/nzbget/connection'); @override diff --git a/lib/modules/settings/routes/configuration_nzbget/pages/default_pages.dart b/lib/modules/settings/routes/configuration_nzbget/pages/default_pages.dart index c3aa293c..88059177 100644 --- a/lib/modules/settings/routes/configuration_nzbget/pages/default_pages.dart +++ b/lib/modules/settings/routes/configuration_nzbget/pages/default_pages.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/nzbget.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationNZBGetDefaultPagesRouter extends LunaPageRouter { +class SettingsConfigurationNZBGetDefaultPagesRouter extends SettingsPageRouter { SettingsConfigurationNZBGetDefaultPagesRouter() : super('/settings/configuration/nzbget/pages'); @override diff --git a/lib/modules/settings/routes/configuration_nzbget/pages/headers.dart b/lib/modules/settings/routes/configuration_nzbget/pages/headers.dart index f5540052..6a8609f6 100644 --- a/lib/modules/settings/routes/configuration_nzbget/pages/headers.dart +++ b/lib/modules/settings/routes/configuration_nzbget/pages/headers.dart @@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationNZBGetHeadersRouter extends LunaPageRouter { +class SettingsConfigurationNZBGetHeadersRouter extends SettingsPageRouter { SettingsConfigurationNZBGetHeadersRouter() : super('/settings/configuration/nzbget/headers'); @override diff --git a/lib/modules/settings/routes/configuration_nzbget/route.dart b/lib/modules/settings/routes/configuration_nzbget/route.dart index 53ce8d53..b654f4d2 100644 --- a/lib/modules/settings/routes/configuration_nzbget/route.dart +++ b/lib/modules/settings/routes/configuration_nzbget/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/nzbget.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationNZBGetRouter extends LunaPageRouter { +class SettingsConfigurationNZBGetRouter extends SettingsPageRouter { SettingsConfigurationNZBGetRouter() : super('/settings/configuration/nzbget'); @override diff --git a/lib/modules/settings/routes/configuration_quickactions.dart b/lib/modules/settings/routes/configuration_quickactions.dart index c10a3770..18df3585 100644 --- a/lib/modules/settings/routes/configuration_quickactions.dart +++ b/lib/modules/settings/routes/configuration_quickactions.dart @@ -1,8 +1,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationQuickActionsRouter extends LunaPageRouter { +class SettingsConfigurationQuickActionsRouter extends SettingsPageRouter { SettingsConfigurationQuickActionsRouter() : super('/settings/configuration/quickactions'); void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsConfigurationQuickActionsRoute()); diff --git a/lib/modules/settings/routes/configuration_radarr/pages/connection_details.dart b/lib/modules/settings/routes/configuration_radarr/pages/connection_details.dart index 5ffb9a71..03a8e190 100644 --- a/lib/modules/settings/routes/configuration_radarr/pages/connection_details.dart +++ b/lib/modules/settings/routes/configuration_radarr/pages/connection_details.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationRadarrConnectionDetailsRouter extends LunaPageRouter { +class SettingsConfigurationRadarrConnectionDetailsRouter extends SettingsPageRouter { SettingsConfigurationRadarrConnectionDetailsRouter() : super('/settings/configuration/radarr/connection'); @override diff --git a/lib/modules/settings/routes/configuration_radarr/pages/default_pages.dart b/lib/modules/settings/routes/configuration_radarr/pages/default_pages.dart index 768d4881..053a607c 100644 --- a/lib/modules/settings/routes/configuration_radarr/pages/default_pages.dart +++ b/lib/modules/settings/routes/configuration_radarr/pages/default_pages.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationRadarrDefaultPagesRouter extends LunaPageRouter { +class SettingsConfigurationRadarrDefaultPagesRouter extends SettingsPageRouter { SettingsConfigurationRadarrDefaultPagesRouter() : super('/settings/configuration/radarr/pages'); @override diff --git a/lib/modules/settings/routes/configuration_radarr/pages/default_sorting.dart b/lib/modules/settings/routes/configuration_radarr/pages/default_sorting.dart index 6bf50277..df66cf38 100644 --- a/lib/modules/settings/routes/configuration_radarr/pages/default_sorting.dart +++ b/lib/modules/settings/routes/configuration_radarr/pages/default_sorting.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationRadarrDefaultSortingRouter extends LunaPageRouter { +class SettingsConfigurationRadarrDefaultSortingRouter extends SettingsPageRouter { SettingsConfigurationRadarrDefaultSortingRouter() : super('/settings/configuration/radarr/sorting'); @override diff --git a/lib/modules/settings/routes/configuration_radarr/pages/headers.dart b/lib/modules/settings/routes/configuration_radarr/pages/headers.dart index 156b9a2e..07568890 100644 --- a/lib/modules/settings/routes/configuration_radarr/pages/headers.dart +++ b/lib/modules/settings/routes/configuration_radarr/pages/headers.dart @@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationRadarrHeadersRouter extends LunaPageRouter { +class SettingsConfigurationRadarrHeadersRouter extends SettingsPageRouter { SettingsConfigurationRadarrHeadersRouter() : super('/settings/configuration/radarr/headers'); @override diff --git a/lib/modules/settings/routes/configuration_radarr/route.dart b/lib/modules/settings/routes/configuration_radarr/route.dart index 5e89d5da..26e49d4a 100644 --- a/lib/modules/settings/routes/configuration_radarr/route.dart +++ b/lib/modules/settings/routes/configuration_radarr/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/radarr.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationRadarrRouter extends LunaPageRouter { +class SettingsConfigurationRadarrRouter extends SettingsPageRouter { SettingsConfigurationRadarrRouter() : super('/settings/configuration/radarr'); @override diff --git a/lib/modules/settings/routes/configuration_sabnzbd/pages/connection_details.dart b/lib/modules/settings/routes/configuration_sabnzbd/pages/connection_details.dart index b84de25f..c22a0903 100644 --- a/lib/modules/settings/routes/configuration_sabnzbd/pages/connection_details.dart +++ b/lib/modules/settings/routes/configuration_sabnzbd/pages/connection_details.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sabnzbd.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSABnzbdConnectionDetailsRouter extends LunaPageRouter { +class SettingsConfigurationSABnzbdConnectionDetailsRouter extends SettingsPageRouter { SettingsConfigurationSABnzbdConnectionDetailsRouter() : super('/settings/configuration/sabnzbd/connection'); @override diff --git a/lib/modules/settings/routes/configuration_sabnzbd/pages/default_pages.dart b/lib/modules/settings/routes/configuration_sabnzbd/pages/default_pages.dart index 6aa8e48f..f81a557c 100644 --- a/lib/modules/settings/routes/configuration_sabnzbd/pages/default_pages.dart +++ b/lib/modules/settings/routes/configuration_sabnzbd/pages/default_pages.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sabnzbd.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSABnzbdDefaultPagesRouter extends LunaPageRouter { +class SettingsConfigurationSABnzbdDefaultPagesRouter extends SettingsPageRouter { SettingsConfigurationSABnzbdDefaultPagesRouter() : super('/settings/configuration/sabnzbd/pages'); @override diff --git a/lib/modules/settings/routes/configuration_sabnzbd/pages/headers.dart b/lib/modules/settings/routes/configuration_sabnzbd/pages/headers.dart index 24f21e15..e2375241 100644 --- a/lib/modules/settings/routes/configuration_sabnzbd/pages/headers.dart +++ b/lib/modules/settings/routes/configuration_sabnzbd/pages/headers.dart @@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSABnzbdHeadersRouter extends LunaPageRouter { +class SettingsConfigurationSABnzbdHeadersRouter extends SettingsPageRouter { SettingsConfigurationSABnzbdHeadersRouter() : super('/settings/configuration/sabnzbd/headers'); @override diff --git a/lib/modules/settings/routes/configuration_sabnzbd/route.dart b/lib/modules/settings/routes/configuration_sabnzbd/route.dart index 5a3192a3..9ef4dcac 100644 --- a/lib/modules/settings/routes/configuration_sabnzbd/route.dart +++ b/lib/modules/settings/routes/configuration_sabnzbd/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sabnzbd.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSABnzbdRouter extends LunaPageRouter { +class SettingsConfigurationSABnzbdRouter extends SettingsPageRouter { SettingsConfigurationSABnzbdRouter() : super('/settings/configuration/sabnzbd'); @override diff --git a/lib/modules/settings/routes/configuration_search/pages/add_indexer.dart b/lib/modules/settings/routes/configuration_search/pages/add_indexer.dart index f596823a..c2abb3b2 100644 --- a/lib/modules/settings/routes/configuration_search/pages/add_indexer.dart +++ b/lib/modules/settings/routes/configuration_search/pages/add_indexer.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSearchAddRouter extends LunaPageRouter { +class SettingsConfigurationSearchAddRouter extends SettingsPageRouter { SettingsConfigurationSearchAddRouter() : super('/settings/configuration/search/add'); void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsConfigurationSearchAddRoute()); 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 7fa0a274..eea22e86 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 @@ -12,7 +12,7 @@ class _SettingsConfigurationSearchAddHeadersArguments { } } -class SettingsConfigurationSearchAddHeadersRouter extends LunaPageRouter { +class SettingsConfigurationSearchAddHeadersRouter extends SettingsPageRouter { SettingsConfigurationSearchAddHeadersRouter() : super('/settings/configuration/search/add/headers'); @override @@ -25,11 +25,7 @@ class SettingsConfigurationSearchAddHeadersRouter extends LunaPageRouter { ); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) => _SettingsConfigurationSearchAddHeadersRoute()), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsConfigurationSearchAddHeadersRoute()); } class _SettingsConfigurationSearchAddHeadersRoute extends StatefulWidget { diff --git a/lib/modules/settings/routes/configuration_search/pages/edit_indexer.dart b/lib/modules/settings/routes/configuration_search/pages/edit_indexer.dart index 7d9d3ffc..b6673027 100644 --- a/lib/modules/settings/routes/configuration_search/pages/edit_indexer.dart +++ b/lib/modules/settings/routes/configuration_search/pages/edit_indexer.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSearchEditRouter extends LunaPageRouter { +class SettingsConfigurationSearchEditRouter extends SettingsPageRouter { SettingsConfigurationSearchEditRouter() : super('/settings/configuration/search/edit/:indexerid'); @override @@ -13,14 +13,10 @@ class SettingsConfigurationSearchEditRouter extends LunaPageRouter { String route({ @required int indexerId }) => super.fullRoute.replaceFirst(':indexerid', indexerId?.toString() ?? -1); @override - void defineRoute(FluroRouter router) => router.define( - super.fullRoute, - handler: Handler(handlerFunc: (context, params) { - int indexerId = params['indexerid'] == null || params['indexerid'].length == 0 ? -1 : (int.tryParse(params['indexerid'][0]) ?? -1); - return _SettingsConfigurationSearchEditRoute(indexerId: indexerId); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int indexerId = params['indexerid'] == null || params['indexerid'].length == 0 ? -1 : (int.tryParse(params['indexerid'][0]) ?? -1); + return _SettingsConfigurationSearchEditRoute(indexerId: indexerId); + }); } class _SettingsConfigurationSearchEditRoute extends StatefulWidget { 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 6c3be922..abaeb557 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 @@ -2,7 +2,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSearchEditHeadersRouter extends LunaPageRouter { +class SettingsConfigurationSearchEditHeadersRouter extends SettingsPageRouter { SettingsConfigurationSearchEditHeadersRouter() : super('/settings/configuration/search/edit/:indexerid/headers'); @override @@ -12,17 +12,12 @@ class SettingsConfigurationSearchEditHeadersRouter extends LunaPageRouter { String route({ @required int indexerId }) => super.fullRoute.replaceFirst(':indexerid', indexerId?.toString() ?? -1); @override - void defineRoute(FluroRouter router) => router.define( - super.fullRoute, - handler: Handler(handlerFunc: (context, params) { - int indexerId = params['indexerid'] == null || params['indexerid'].length == 0 ? -1 : (int.tryParse(params['indexerid'][0]) ?? -1); - return _SettingsConfigurationSearchEditHeadersRoute(indexerId: indexerId); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int indexerId = params['indexerid'] == null || params['indexerid'].length == 0 ? -1 : (int.tryParse(params['indexerid'][0]) ?? -1); + return _SettingsConfigurationSearchEditHeadersRoute(indexerId: indexerId); + }); } - class _SettingsConfigurationSearchEditHeadersRoute extends StatefulWidget { final int indexerId; diff --git a/lib/modules/settings/routes/configuration_search/route.dart b/lib/modules/settings/routes/configuration_search/route.dart index 4ef565ac..d4ec51af 100644 --- a/lib/modules/settings/routes/configuration_search/route.dart +++ b/lib/modules/settings/routes/configuration_search/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/search/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSearchRouter extends LunaPageRouter { +class SettingsConfigurationSearchRouter extends SettingsPageRouter { SettingsConfigurationSearchRouter() : super('/settings/configuration/search'); @override diff --git a/lib/modules/settings/routes/configuration_sonarr/pages/connection_details.dart b/lib/modules/settings/routes/configuration_sonarr/pages/connection_details.dart index 6837a0a9..12dd6efb 100644 --- a/lib/modules/settings/routes/configuration_sonarr/pages/connection_details.dart +++ b/lib/modules/settings/routes/configuration_sonarr/pages/connection_details.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSonarrConnectionDetailsRouter extends LunaPageRouter { +class SettingsConfigurationSonarrConnectionDetailsRouter extends SettingsPageRouter { SettingsConfigurationSonarrConnectionDetailsRouter() : super('/settings/configuration/sonarr/connection'); @override diff --git a/lib/modules/settings/routes/configuration_sonarr/pages/default_pages.dart b/lib/modules/settings/routes/configuration_sonarr/pages/default_pages.dart index d0dea868..9978aa22 100644 --- a/lib/modules/settings/routes/configuration_sonarr/pages/default_pages.dart +++ b/lib/modules/settings/routes/configuration_sonarr/pages/default_pages.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSonarrDefaultPagesRouter extends LunaPageRouter { +class SettingsConfigurationSonarrDefaultPagesRouter extends SettingsPageRouter { SettingsConfigurationSonarrDefaultPagesRouter() : super('/settings/configuration/sonarr/pages'); @override diff --git a/lib/modules/settings/routes/configuration_sonarr/pages/default_sorting.dart b/lib/modules/settings/routes/configuration_sonarr/pages/default_sorting.dart index 73400e66..f27e481f 100644 --- a/lib/modules/settings/routes/configuration_sonarr/pages/default_sorting.dart +++ b/lib/modules/settings/routes/configuration_sonarr/pages/default_sorting.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSonarrDefaultSortingRouter extends LunaPageRouter { +class SettingsConfigurationSonarrDefaultSortingRouter extends SettingsPageRouter { SettingsConfigurationSonarrDefaultSortingRouter() : super('/settings/configuration/sonarr/sorting'); @override diff --git a/lib/modules/settings/routes/configuration_sonarr/pages/headers.dart b/lib/modules/settings/routes/configuration_sonarr/pages/headers.dart index da1401d4..b7f365b0 100644 --- a/lib/modules/settings/routes/configuration_sonarr/pages/headers.dart +++ b/lib/modules/settings/routes/configuration_sonarr/pages/headers.dart @@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationSonarrHeadersRouter extends LunaPageRouter { +class SettingsConfigurationSonarrHeadersRouter extends SettingsPageRouter { SettingsConfigurationSonarrHeadersRouter() : super('/settings/configuration/sonarr/headers'); @override diff --git a/lib/modules/settings/routes/configuration_sonarr/route.dart b/lib/modules/settings/routes/configuration_sonarr/route.dart index 103a5492..3de501b5 100644 --- a/lib/modules/settings/routes/configuration_sonarr/route.dart +++ b/lib/modules/settings/routes/configuration_sonarr/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SettingsConfigurationSonarrRouter extends LunaPageRouter { +class SettingsConfigurationSonarrRouter extends SettingsPageRouter { SettingsConfigurationSonarrRouter() : super('/settings/configuration/sonarr'); @override diff --git a/lib/modules/settings/routes/configuration_tautulli/pages/connection_details.dart b/lib/modules/settings/routes/configuration_tautulli/pages/connection_details.dart index 03f0e106..e370415c 100644 --- a/lib/modules/settings/routes/configuration_tautulli/pages/connection_details.dart +++ b/lib/modules/settings/routes/configuration_tautulli/pages/connection_details.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationTautulliConnectionDetailsRouter extends LunaPageRouter { +class SettingsConfigurationTautulliConnectionDetailsRouter extends SettingsPageRouter { SettingsConfigurationTautulliConnectionDetailsRouter() : super('/settings/configuration/tautulli/connection'); @override diff --git a/lib/modules/settings/routes/configuration_tautulli/pages/default_pages.dart b/lib/modules/settings/routes/configuration_tautulli/pages/default_pages.dart index 80cee4af..c7591a4d 100644 --- a/lib/modules/settings/routes/configuration_tautulli/pages/default_pages.dart +++ b/lib/modules/settings/routes/configuration_tautulli/pages/default_pages.dart @@ -2,8 +2,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationTautulliDefaultPagesRouter extends LunaPageRouter { +class SettingsConfigurationTautulliDefaultPagesRouter extends SettingsPageRouter { SettingsConfigurationTautulliDefaultPagesRouter() : super('/settings/configuration/tautulli/pages'); @override diff --git a/lib/modules/settings/routes/configuration_tautulli/pages/headers.dart b/lib/modules/settings/routes/configuration_tautulli/pages/headers.dart index a259bfd7..83f2270b 100644 --- a/lib/modules/settings/routes/configuration_tautulli/pages/headers.dart +++ b/lib/modules/settings/routes/configuration_tautulli/pages/headers.dart @@ -2,7 +2,7 @@ import 'package:fluro/fluro.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationTautulliHeadersRouter extends LunaPageRouter { +class SettingsConfigurationTautulliHeadersRouter extends SettingsPageRouter { SettingsConfigurationTautulliHeadersRouter() : super('/settings/configuration/tautulli/headers'); @override diff --git a/lib/modules/settings/routes/configuration_tautulli/route.dart b/lib/modules/settings/routes/configuration_tautulli/route.dart index e1159c9d..0ebf4ce9 100644 --- a/lib/modules/settings/routes/configuration_tautulli/route.dart +++ b/lib/modules/settings/routes/configuration_tautulli/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationTautulliRouter extends LunaPageRouter { +class SettingsConfigurationTautulliRouter extends SettingsPageRouter { SettingsConfigurationTautulliRouter() : super('/settings/configuration/tautulli'); @override diff --git a/lib/modules/settings/routes/configuration_wakeonlan.dart b/lib/modules/settings/routes/configuration_wakeonlan.dart index 0a26bea3..a1236f92 100644 --- a/lib/modules/settings/routes/configuration_wakeonlan.dart +++ b/lib/modules/settings/routes/configuration_wakeonlan.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsConfigurationWakeOnLANRouter extends LunaPageRouter { +class SettingsConfigurationWakeOnLANRouter extends SettingsPageRouter { SettingsConfigurationWakeOnLANRouter() : super('/settings/configuration/wakeonlan'); void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsConfigurationWakeOnLANRoute()); diff --git a/lib/modules/settings/routes/donations/pages/thank_you.dart b/lib/modules/settings/routes/donations/pages/thank_you.dart index b56200a3..0c4e3e99 100644 --- a/lib/modules/settings/routes/donations/pages/thank_you.dart +++ b/lib/modules/settings/routes/donations/pages/thank_you.dart @@ -1,8 +1,9 @@ import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsDonationsThankYouRouter extends LunaPageRouter { +class SettingsDonationsThankYouRouter extends SettingsPageRouter { SettingsDonationsThankYouRouter() : super('/settings/donations/thankyou'); void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsDonationsThankYouRoute()); diff --git a/lib/modules/settings/routes/donations/route.dart b/lib/modules/settings/routes/donations/route.dart index dd9b6f50..67d6a80c 100644 --- a/lib/modules/settings/routes/donations/route.dart +++ b/lib/modules/settings/routes/donations/route.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsDonationsRouter extends LunaPageRouter { +class SettingsDonationsRouter extends SettingsPageRouter { SettingsDonationsRouter() : super('/settings/donations'); @override diff --git a/lib/modules/settings/routes/profiles.dart b/lib/modules/settings/routes/profiles.dart index 4f58c636..f4feec9a 100644 --- a/lib/modules/settings/routes/profiles.dart +++ b/lib/modules/settings/routes/profiles.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsProfilesRouter extends LunaPageRouter { +class SettingsProfilesRouter extends SettingsPageRouter { SettingsProfilesRouter() : super('/settings/profiles'); @override diff --git a/lib/modules/settings/routes/resources.dart b/lib/modules/settings/routes/resources.dart index f4893872..e2ff44fd 100644 --- a/lib/modules/settings/routes/resources.dart +++ b/lib/modules/settings/routes/resources.dart @@ -2,8 +2,9 @@ import 'dart:io'; import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; -class SettingsResourcesRouter extends LunaPageRouter { +class SettingsResourcesRouter extends SettingsPageRouter { SettingsResourcesRouter() : super('/settings/resources'); @override diff --git a/lib/modules/settings/routes/settings.dart b/lib/modules/settings/routes/settings.dart index fa9989f9..1907b85d 100644 --- a/lib/modules/settings/routes/settings.dart +++ b/lib/modules/settings/routes/settings.dart @@ -3,11 +3,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsHomeRouter extends LunaPageRouter { +class SettingsHomeRouter extends SettingsPageRouter { SettingsHomeRouter() : super('/settings'); @override - void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsHomeRoute()); + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SettingsHomeRoute(), homeRoute: true); } class _SettingsHomeRoute extends StatefulWidget { diff --git a/lib/modules/settings/routes/system/route.dart b/lib/modules/settings/routes/system/route.dart index cb6007b0..b686b45a 100644 --- a/lib/modules/settings/routes/system/route.dart +++ b/lib/modules/settings/routes/system/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; import 'package:package_info/package_info.dart'; -class SettingsSystemRouter extends LunaPageRouter { +class SettingsSystemRouter extends SettingsPageRouter { SettingsSystemRouter() : super('/settings/system'); @override @@ -45,8 +45,10 @@ class _State extends State<_SettingsSystemRoute> with LunaScrollControllerMixin SettingsSystemBackupRestoreBackupTile(), SettingsSystemBackupRestoreRestoreTile(), LunaDivider(), + _enableAnalytics(), + _enableCrashlytics(), + LunaDivider(), _language(), - _enableSentry(), _clearConfiguration(), ], ); @@ -91,17 +93,34 @@ class _State extends State<_SettingsSystemRoute> with LunaScrollControllerMixin onTap: () async => SettingsSystemLogsRouter().navigateTo(context), ); } + + Widget _enableAnalytics() { + return LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS.listen( + builder: (context, box, _) => LunaListTile( + context: context, + title: LunaText.title(text: 'Firebase Analytics'), + subtitle: LunaText.subtitle(text: 'User Engagement Tracking'), + trailing: LunaSwitch( + value: LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS.data, + onChanged: (value) async { + LunaDatabaseValue.ENABLE_FIREBASE_ANALYTICS.put(value); + LunaFirebaseAnalytics().setEnabledState(); + }, + ), + ), + ); + } - Widget _enableSentry() { - return LunaDatabaseValue.ENABLED_SENTRY.listen( + Widget _enableCrashlytics() { + return LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.listen( builder: (context, box, _) => LunaListTile( context: context, title: LunaText.title(text: 'Firebase Crashlytics'), subtitle: LunaText.subtitle(text: 'Crash and Error Tracking'), trailing: LunaSwitch( - value: LunaDatabaseValue.ENABLED_SENTRY.data, + value: LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS.data, onChanged: (value) async { - LunaDatabaseValue enabled = LunaDatabaseValue.ENABLED_SENTRY; + LunaDatabaseValue enabled = LunaDatabaseValue.ENABLE_FIREBASE_CRASHLYTICS; if(enabled.data) { bool result = await SettingsDialogs().disableCrashlyticsWarning(context); if(result) enabled.put(value); @@ -124,7 +143,7 @@ class _State extends State<_SettingsSystemRoute> with LunaScrollControllerMixin onTap: () async { bool result = await SettingsDialogs().clearConfiguration(context); if(result) { - Database().setDefaults(clearAlerts: true); + Database().setDefaults(clearEverything: true); LunaFirebaseAuth().signOut(); LunaState.reset(context); showLunaSuccessSnackBar( diff --git a/lib/modules/settings/routes/system_logs/pages/log_details.dart b/lib/modules/settings/routes/system_logs/pages/log_details.dart index 9dfb973b..031e2844 100644 --- a/lib/modules/settings/routes/system_logs/pages/log_details.dart +++ b/lib/modules/settings/routes/system_logs/pages/log_details.dart @@ -1,10 +1,10 @@ import 'package:fluro/fluro.dart'; +import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; -import 'package:f_logs/f_logs.dart' as FLog; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsSystemLogsDetailsRouter extends LunaPageRouter { +class SettingsSystemLogsDetailsRouter extends SettingsPageRouter { SettingsSystemLogsDetailsRouter() : super('/settings/logs/details/:type'); @override @@ -14,19 +14,14 @@ class SettingsSystemLogsDetailsRouter extends LunaPageRouter { String route({ @required String type }) => fullRoute.replaceFirst(':type', type); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) { - String type = params['type'] != null && params['type'].length > 0 ? params['type'][0] : 'All'; - type ??= 'All'; - return _SettingsSystemLogsDetailsRoute(type: type); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + String type = params['type'] != null && params['type'].length > 0 ? params['type'][0] : ''; + return _SettingsSystemLogsDetailsRoute(type: LunaLogType.ERROR.fromKey(type)); + }); } class _SettingsSystemLogsDetailsRoute extends StatefulWidget { - final String type; + final LunaLogType type; _SettingsSystemLogsDetailsRoute({ Key key, @@ -39,23 +34,6 @@ class _SettingsSystemLogsDetailsRoute extends StatefulWidget { class _State extends State<_SettingsSystemLogsDetailsRoute> with LunaScrollControllerMixin { final GlobalKey _scaffoldKey = GlobalKey(); - List levels = []; - - @override - void initState() { - super.initState(); - _setLogLevel(); - } - - void _setLogLevel() { - switch(widget.type) { - case 'All': levels = []; break; - case 'Warning': levels = [FLog.LogLevel.WARNING.toString()]; break; - case 'Error': levels = [FLog.LogLevel.ERROR.toString()]; break; - case 'Fatal': levels = [FLog.LogLevel.FATAL.toString()]; break; - default: levels = []; break; - } - } @override Widget build(BuildContext context) => Scaffold( @@ -66,31 +44,39 @@ class _State extends State<_SettingsSystemLogsDetailsRoute> with LunaScrollContr Widget _appBar() { return LunaAppBar( - title: '${widget.type ?? 'Unknown'} Logs', + title: '${widget.type?.name ?? 'All'} Logs', scrollControllers: [scrollController], ); } Widget _body() { - return FutureBuilder( - future: FLog.FLog.getAllLogsByFilter(logLevels: levels), - builder: (BuildContext context, AsyncSnapshot> snapshot) { - if(snapshot.hasError) { - LunaLogger().error('Unable to fetch logs', snapshot.error, StackTrace.current); - return LunaMessage(text: 'An Error Has Occurred'); - } - if(snapshot.hasData) return _list(snapshot.data); - return LunaLoader(); - }, + return ValueListenableBuilder( + valueListenable: Database.logsBox.listenable(), + builder: (context, box, _) { + List logs = filter(box); + if((logs?.length ?? 0) == 0) return LunaMessage.goBack( + context: context, + text: 'No Logs Found', + ); + return LunaListViewBuilder( + controller: scrollController, + itemCount: logs.length, + itemBuilder: (context, index) => SettingsSystemLogTile(log: logs[index]), + ); + } ); } - Widget _list(List logs) { - if((logs?.length ?? 0) == 0) return LunaMessage(text: 'No Logs Found'); - return LunaListViewBuilder( - controller: scrollController, - itemCount: logs.length, - itemBuilder: (context, index) => SettingsLogsDetailsLogTile(log: logs[index]), - ); + List filter(Box box) { + List logs; + switch(widget.type) { + case LunaLogType.WARNING: logs = box.values.where((log) => log.type == LunaLogType.WARNING).toList(); break; + case LunaLogType.ERROR: logs = box.values.where((log) => log.type == LunaLogType.ERROR).toList(); break; + case LunaLogType.CRITICAL: logs = box.values.where((log) => log.type == LunaLogType.CRITICAL).toList(); break; + case LunaLogType.DEBUG: logs = box.values.where((log) => log.type == LunaLogType.DEBUG).toList(); break; + default: logs = box.values.where((log) => log.type.enabled).toList(); break; + } + logs.sort((a,b) => (b?.timestamp?.toDouble() ?? double.maxFinite).compareTo(a?.timestamp?.toDouble() ?? double.maxFinite)); + return logs; } } diff --git a/lib/modules/settings/routes/system_logs/route.dart b/lib/modules/settings/routes/system_logs/route.dart index 5b75f5c0..c64c302c 100644 --- a/lib/modules/settings/routes/system_logs/route.dart +++ b/lib/modules/settings/routes/system_logs/route.dart @@ -4,7 +4,7 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; -class SettingsSystemLogsRouter extends LunaPageRouter { +class SettingsSystemLogsRouter extends SettingsPageRouter { SettingsSystemLogsRouter() : super('/settings/logs'); @override @@ -44,28 +44,20 @@ class _State extends State<_SettingsSystemLogsRoute> with LunaScrollControllerMi title: LunaText.title(text: 'All Logs'), subtitle: LunaText.subtitle(text: 'View Logs of All Types'), trailing: LunaIconButton(icon: Icons.developer_mode), - onTap: () async => _viewLogs('All'), + onTap: () async => _viewLogs('all'), ), - LunaListTile( - context: context, - title: LunaText.title(text: 'Warning'), - subtitle: LunaText.subtitle(text: 'View Warning Logs'), - trailing: LunaIconButton(icon: Icons.warning), - onTap: () async => _viewLogs('Warning'), - ), - LunaListTile( - context: context, - title: LunaText.title(text: 'Error'), - subtitle: LunaText.subtitle(text: 'View Error Logs'), - trailing: LunaIconButton(icon: Icons.report_rounded), - onTap: () async => _viewLogs('Error'), - ), - LunaListTile( - context: context, - title: LunaText.title(text: 'Fatal'), - subtitle: LunaText.subtitle(text: 'View Fatal Logs'), - trailing: LunaIconButton(icon: Icons.new_releases), - onTap: () async => _viewLogs('Fatal'), + ...List.generate( + LunaLogType.values.length, + (index) { + if(LunaLogType.values[index].enabled) return LunaListTile( + context: context, + title: LunaText.title(text: LunaLogType.values[index].name), + subtitle: LunaText.subtitle(text: LunaLogType.values[index].description), + trailing: LunaIconButton(icon: LunaLogType.values[index].icon), + onTap: () async => _viewLogs(LunaLogType.values[index].key), + ); + return Container(height: 0.0); + }, ), LunaDivider(), _exportLogs(), 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 d7e2ad6b..4cd3dd9f 100644 --- a/lib/modules/settings/routes/system_logs/widgets/log_tile.dart +++ b/lib/modules/settings/routes/system_logs/widgets/log_tile.dart @@ -1,121 +1,42 @@ -import 'package:expandable/expandable.dart'; -import 'package:f_logs/f_logs.dart' as FLog; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; -class SettingsLogsDetailsLogTile extends StatelessWidget { - final FLog.Log log; - final ExpandableController _controller = ExpandableController(); +class SettingsSystemLogTile extends StatelessWidget { + final LunaLogHiveObject log; - SettingsLogsDetailsLogTile({ + SettingsSystemLogTile({ + Key key, @required this.log, - }); + }) : super(key: key); @override - Widget build(BuildContext context) => LSExpandable( - controller: _controller, - collapsed: _collapsed(context), - expanded: _expanded(context), - ); - - Widget _collapsed(BuildContext context) => LSCardTile( - title: LSTitle(text: log.text), - subtitle: RichText( - text: TextSpan( + Widget build(BuildContext context) { + String dateTime = DateTime.fromMillisecondsSinceEpoch(log.timestamp).lunaDateTimeReadable(); + return LunaExpandableListTile( + title: log.message, + collapsedSubtitle1: TextSpan(text: dateTime), + collapsedSubtitle2: TextSpan( + text: log.type.name.toUpperCase(), style: TextStyle( - fontSize: Constants.UI_FONT_SIZE_SUBTITLE, - color: Colors.white70, + color: log.type.color, + fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), - children: [ - TextSpan(text: log.timestamp), - TextSpan(text: '\n'), - TextSpan( - style: TextStyle( - color: log.logLevel.lunaColour, - fontWeight: LunaUI.FONT_WEIGHT_BOLD, - ), - text: log.logLevel.lunaName, - ) - ], ), - ), - padContent: true, - onTap: () => _controller.toggle(), - - ); - - Widget _expanded(BuildContext context) => LSCard( - child: InkWell( - child: Row( - children: [ - Expanded( - child: Padding( - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - LSTitle(text: log.text, softWrap: true, maxLines: 12), - Padding( - child: Wrap( - direction: Axis.horizontal, - runSpacing: 10.0, - children: [ - LSTextHighlighted( - text: log.logLevel.lunaName, - bgColor: log.logLevel.lunaColour, - ), - ], - ), - padding: EdgeInsets.only(top: 8.0, bottom: 2.0), - ), - Padding( - child: RichText( - text: TextSpan( - style: TextStyle( - color: Colors.white70, - fontSize: Constants.UI_FONT_SIZE_SUBTITLE, - ), - children: [ - TextSpan(text: log.timestamp), - if(log?.className != null) TextSpan(text: '\n${log.className}'), - if(log?.methodName != null) TextSpan(text: '\n${log.methodName}'), - ], - ), - ), - padding: EdgeInsets.only(top: 6.0, bottom: (log?.exception != null && (log?.exception?.toLowerCase() ?? 'null') != 'null') ? 10.0 : 0.0), - ), - if(log?.exception != null && (log?.exception?.toLowerCase() ?? 'null') != 'null') Padding( - child: Row( - mainAxisSize: MainAxisSize.min, - children: [ - Expanded( - child: LSButtonSlim( - text: 'Exception', - backgroundColor: LunaColours.red, - onTap: () async => LunaDialogs().textPreview(context, 'Exception', log?.exception ?? 'Unavailable', alignLeft: true), - margin: EdgeInsets.only(right: 6.0), - ), - ), - Expanded( - child: LSButtonSlim( - text: 'Stack Trace', - backgroundColor: LunaColours.blue, - onTap: () async => LunaDialogs().textPreview(context, 'Stack Trace', log?.stacktrace ?? 'Unavailable', alignLeft: true), - margin: EdgeInsets.only(left: 6.0), - ), - ), - ], - ), - padding: EdgeInsets.only(bottom: 2.0), - ), - ], - ), - padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 10.0), - ), - ), - ], - ), - borderRadius: BorderRadius.circular(Constants.UI_BORDER_RADIUS), - onTap: () => _controller.toggle(), - ), - ); + expandedHighlightedNodes: [ + LunaHighlightedNode( + text: log.type.name.toUpperCase(), + backgroundColor: log.type.color, + ), + LunaHighlightedNode( + text: dateTime, + backgroundColor: LunaColours.blueGrey, + ), + ], + expandedTableContent: [ + if(log.className != null && log.className.isNotEmpty) LunaTableContent(title: 'Class', body: log.className), + if(log.methodName != null && log.methodName.isNotEmpty) LunaTableContent(title: 'Method', body: log.methodName), + if(log.error != null && log.error.isNotEmpty) LunaTableContent(title: 'Exception', body: log.error), + ], + ); + } } \ No newline at end of file diff --git a/lib/modules/sonarr/core/extensions.dart b/lib/modules/sonarr/core/extensions.dart index fcd87321..6e348534 100644 --- a/lib/modules/sonarr/core/extensions.dart +++ b/lib/modules/sonarr/core/extensions.dart @@ -2,6 +2,7 @@ export 'extensions/sonarr_calendar.dart'; export 'extensions/sonarr_episode.dart'; export 'extensions/sonarr_history_event_type.dart'; export 'extensions/sonarr_queue_record.dart'; +export 'extensions/sonarr_release.dart'; export 'extensions/sonarr_series_lookup.dart'; export 'extensions/sonarr_series_season.dart'; export 'extensions/sonarr_series.dart'; diff --git a/lib/modules/sonarr/core/extensions/sonarr_release.dart b/lib/modules/sonarr/core/extensions/sonarr_release.dart new file mode 100644 index 00000000..ffb8d78d --- /dev/null +++ b/lib/modules/sonarr/core/extensions/sonarr_release.dart @@ -0,0 +1,13 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +extension SonarrReleaseExtension on SonarrRelease { + Color get lunaProtocolColor { + if((this.protocol?.toLowerCase() ?? '') == 'usenet') return LunaColours.accent; + int seeders = this.seeders ?? 0; + if(seeders > 10) return LunaColours.blue; + if(seeders > 0) return LunaColours.orange; + return LunaColours.red; + } +} diff --git a/lib/modules/sonarr/core/router.dart b/lib/modules/sonarr/core/router.dart index a2ced6c4..867c84ed 100644 --- a/lib/modules/sonarr/core/router.dart +++ b/lib/modules/sonarr/core/router.dart @@ -1,4 +1,5 @@ import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; @@ -7,14 +8,42 @@ class SonarrRouter extends LunaModuleRouter { void defineAllRoutes(FluroRouter router) { SonarrHomeRouter().defineRoute(router); // Series - SonarrSeriesAddRouter.defineRoutes(router); - SonarrSeriesAddDetailsRouter.defineRoutes(router); - SonarrSeriesEditRouter.defineRoutes(router); + SonarrAddSeriesRouter().defineRoute(router); + SonarrAddSeriesDetailsRouter().defineRoute(router); + SonarrEditSeriesRouter().defineRoute(router); SonarrSeriesDetailsRouter().defineRoute(router); SonarrSeasonDetailsRouter().defineRoute(router); // Other SonarrQueueRouter().defineRoute(router); - SonarrReleasesRouter.defineRoutes(router); + SonarrReleasesRouter().defineRoute(router); SonarrTagsRouter().defineRoute(router); } } + +abstract class SonarrPageRouter extends LunaPageRouter { + SonarrPageRouter(String route) : super(route); + + @override + void noParameterRouteDefinition(FluroRouter router, Widget widget, { bool homeRoute = false }) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) { + if(!homeRoute && !context.read().enabled) return LunaNotEnabledRoute(module: 'Sonarr'); + return widget; + }), + transitionType: LunaRouter.transitionType, + ); + + @override + void withParameterRouteDefinition( + FluroRouter router, + Widget Function(BuildContext, Map>) handlerFunc, + { bool homeRoute = false } + ) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) { + if(!homeRoute && !context.read().enabled) return LunaNotEnabledRoute(module: 'Sonarr'); + return handlerFunc(context, params); + }), + transitionType: LunaRouter.transitionType, + ); +} diff --git a/lib/modules/sonarr/core/types/monitor_status.g.dart b/lib/modules/sonarr/core/types/monitor_status.g.dart index 38b70357..ae2a5314 100644 --- a/lib/modules/sonarr/core/types/monitor_status.g.dart +++ b/lib/modules/sonarr/core/types/monitor_status.g.dart @@ -28,7 +28,7 @@ class SonarrMonitorStatusAdapter extends TypeAdapter { case 6: return SonarrMonitorStatus.NONE; default: - return null; + return SonarrMonitorStatus.ALL; } } diff --git a/lib/modules/sonarr/core/types/sorting_releases.g.dart b/lib/modules/sonarr/core/types/sorting_releases.g.dart index 50f34da8..ec9e0c8e 100644 --- a/lib/modules/sonarr/core/types/sorting_releases.g.dart +++ b/lib/modules/sonarr/core/types/sorting_releases.g.dart @@ -26,7 +26,7 @@ class SonarrReleasesSortingAdapter extends TypeAdapter { case 5: return SonarrReleasesSorting.WEIGHT; default: - return null; + return SonarrReleasesSorting.AGE; } } diff --git a/lib/modules/sonarr/core/types/sorting_series.g.dart b/lib/modules/sonarr/core/types/sorting_series.g.dart index 3b516cc7..18730f32 100644 --- a/lib/modules/sonarr/core/types/sorting_series.g.dart +++ b/lib/modules/sonarr/core/types/sorting_series.g.dart @@ -30,7 +30,7 @@ class SonarrSeriesSortingAdapter extends TypeAdapter { case 7: return SonarrSeriesSorting.TYPE; default: - return null; + return SonarrSeriesSorting.ALPHABETICAL; } } diff --git a/lib/modules/sonarr/routes.dart b/lib/modules/sonarr/routes.dart index 3f0c44ee..6332453e 100644 --- a/lib/modules/sonarr/routes.dart +++ b/lib/modules/sonarr/routes.dart @@ -1,13 +1,13 @@ +export 'routes/add_series.dart'; +export 'routes/add_series_details.dart'; +export 'routes/edit_series.dart'; export 'routes/history.dart'; export 'routes/missing.dart'; export 'routes/queue.dart'; export 'routes/releases.dart'; export 'routes/season_details.dart'; export 'routes/series.dart'; -export 'routes/series_add.dart'; -export 'routes/series_add_details.dart'; export 'routes/series_details.dart'; -export 'routes/series_edit.dart'; export 'routes/sonarr.dart'; export 'routes/tags.dart'; export 'routes/upcoming.dart'; diff --git a/lib/modules/sonarr/routes/add_series.dart b/lib/modules/sonarr/routes/add_series.dart new file mode 100644 index 00000000..bef1be1e --- /dev/null +++ b/lib/modules/sonarr/routes/add_series.dart @@ -0,0 +1,2 @@ +export 'add_series/route.dart'; +export 'add_series/widgets.dart'; diff --git a/lib/modules/sonarr/routes/add_series/route.dart b/lib/modules/sonarr/routes/add_series/route.dart new file mode 100644 index 00000000..422f7344 --- /dev/null +++ b/lib/modules/sonarr/routes/add_series/route.dart @@ -0,0 +1,40 @@ +import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/sonarr.dart'; + +class _SonarrAddSeriesArguments { + final String query; + + _SonarrAddSeriesArguments(this.query); +} + +class SonarrAddSeriesRouter extends SonarrPageRouter { + SonarrAddSeriesRouter() : super('/sonarr/addseries'); + + @override + Future navigateTo(BuildContext context, { @required String query }) async => LunaRouter.router.navigateTo( + context, + route(), + routeSettings: RouteSettings(arguments: _SonarrAddSeriesArguments(query)), + ); + + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SonarrAddSeriesRoute()); +} + +class _SonarrAddSeriesRoute extends StatefulWidget { + @override + State createState() => _State(); +} + +class _State extends State<_SonarrAddSeriesRoute> { + final GlobalKey _scaffoldKey = GlobalKey(); + + @override + Widget build(BuildContext context) => Scaffold( + key: _scaffoldKey, + appBar: SonarrSeriesAddAppBar(), + body: SonarrSeriesAddSearchResults(), + ); +} diff --git a/lib/modules/sonarr/routes/series_add/widgets.dart b/lib/modules/sonarr/routes/add_series/widgets.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add/widgets.dart rename to lib/modules/sonarr/routes/add_series/widgets.dart diff --git a/lib/modules/sonarr/routes/series_add/widgets/appbar.dart b/lib/modules/sonarr/routes/add_series/widgets/appbar.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add/widgets/appbar.dart rename to lib/modules/sonarr/routes/add_series/widgets/appbar.dart diff --git a/lib/modules/sonarr/routes/series_add/widgets/search_results.dart b/lib/modules/sonarr/routes/add_series/widgets/search_results.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add/widgets/search_results.dart rename to lib/modules/sonarr/routes/add_series/widgets/search_results.dart diff --git a/lib/modules/sonarr/routes/series_add/widgets/search_results_tile.dart b/lib/modules/sonarr/routes/add_series/widgets/search_results_tile.dart similarity index 93% rename from lib/modules/sonarr/routes/series_add/widgets/search_results_tile.dart rename to lib/modules/sonarr/routes/add_series/widgets/search_results_tile.dart index 3a94361a..6841c34a 100644 --- a/lib/modules/sonarr/routes/series_add/widgets/search_results_tile.dart +++ b/lib/modules/sonarr/routes/add_series/widgets/search_results_tile.dart @@ -44,14 +44,14 @@ class _State extends State { Widget _poster(BuildContext context) { if(widget.series.remotePoster != null) return LSNetworkImage( url: widget.series.remotePoster, - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _height, width: _width, headers: Provider.of(context, listen: false).headers.cast(), ); return ClipRRect( child: Image.asset( - 'assets/images/sonarr/noseriesposter.png', + 'assets/images/blanks/video.png', width: _width, height: _height, ), @@ -122,7 +122,11 @@ class _State extends State { type: SNACKBAR_TYPE.info, ); } else { - SonarrSeriesAddDetailsRouter.navigateTo(context, tvdbId: widget.series.tvdbId ?? -1); + SonarrAddSeriesDetailsRouter().navigateTo( + context, + tvdbId: widget.series.tvdbId ?? -1, + series: widget.series, + ); } } } diff --git a/lib/modules/sonarr/routes/add_series_details.dart b/lib/modules/sonarr/routes/add_series_details.dart new file mode 100644 index 00000000..be0908d4 --- /dev/null +++ b/lib/modules/sonarr/routes/add_series_details.dart @@ -0,0 +1,3 @@ +export 'add_series_details/route.dart'; +export 'add_series_details/state.dart'; +export 'add_series_details/widgets.dart'; diff --git a/lib/modules/sonarr/routes/series_add_details/route.dart b/lib/modules/sonarr/routes/add_series_details/route.dart similarity index 80% rename from lib/modules/sonarr/routes/series_add_details/route.dart rename to lib/modules/sonarr/routes/add_series_details/route.dart index 691fe788..52bb481e 100644 --- a/lib/modules/sonarr/routes/series_add_details/route.dart +++ b/lib/modules/sonarr/routes/add_series_details/route.dart @@ -4,34 +4,44 @@ import 'package:flutter/scheduler.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrSeriesAddDetailsRouter { - static const String ROUTE_NAME = '/sonarr/series/add/details/:tvdbid'; +class _SonarrAddSeriesDetailsArguments { + SonarrSeriesLookup series; - static Future navigateTo(BuildContext context, { - @required int tvdbId, - }) async => LunaRouter.router.navigateTo( - context, - route(tvdbId: tvdbId), - ); - - static String route({ @required int tvdbId }) => ROUTE_NAME - .replaceFirst(':tvdbid', tvdbId?.toString() ?? '-1'); - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _SonarrSeriesAddDetailsRoute( - tvdbId: int.tryParse(params['tvdbid'][0]) ?? -1, - )), - transitionType: LunaRouter.transitionType, - ); + _SonarrAddSeriesDetailsArguments({ + @required this.series, + }) { + assert(series != null); } } -class _SonarrSeriesAddDetailsRoute extends StatefulWidget { +class SonarrAddSeriesDetailsRouter extends SonarrPageRouter { + SonarrAddSeriesDetailsRouter() : super('/sonarr/addseries/:tvdbid'); + + @override + Future navigateTo(BuildContext context, { + @required int tvdbId, + @required SonarrSeriesLookup series, + }) => LunaRouter.router.navigateTo( + context, + route(tvdbId: tvdbId), + routeSettings: RouteSettings(arguments: _SonarrAddSeriesDetailsArguments(series: series)), + ); + + @override route({ + @required int tvdbId, + }) => fullRoute.replaceFirst(':tvdbid', tvdbId.toString()); + + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int tvdbId = params['tvdbid'] == null || params['tvdbid'].length == 0 ? -1 : (int.tryParse(params['tvdbid'][0]) ?? -1); + return _SonarrAddSeriesDetailsRoute(tvdbId: tvdbId); + }); +} + +class _SonarrAddSeriesDetailsRoute extends StatefulWidget { final int tvdbId; - _SonarrSeriesAddDetailsRoute({ + _SonarrAddSeriesDetailsRoute({ Key key, @required this.tvdbId, }): super(key: key); @@ -40,7 +50,7 @@ class _SonarrSeriesAddDetailsRoute extends StatefulWidget { State createState() => _State(); } -class _State extends State<_SonarrSeriesAddDetailsRoute> { +class _State extends State<_SonarrAddSeriesDetailsRoute> { final GlobalKey _scaffoldKey = GlobalKey(); bool _initialLoad = false; diff --git a/lib/modules/sonarr/routes/series_add_details/state.dart b/lib/modules/sonarr/routes/add_series_details/state.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/state.dart rename to lib/modules/sonarr/routes/add_series_details/state.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets.dart b/lib/modules/sonarr/routes/add_series_details/widgets.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets.dart rename to lib/modules/sonarr/routes/add_series_details/widgets.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/appbar_link_action.dart b/lib/modules/sonarr/routes/add_series_details/widgets/appbar_link_action.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/appbar_link_action.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/appbar_link_action.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/button_add_series.dart b/lib/modules/sonarr/routes/add_series_details/widgets/button_add_series.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/button_add_series.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/button_add_series.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_language_profile.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_language_profile.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_language_profile.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_language_profile.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_monitor_status.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_monitor_status.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_monitor_status.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_monitor_status.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_monitored.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_monitored.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_monitored.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_monitored.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_quality_profile.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_quality_profile.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_quality_profile.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_quality_profile.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_root_folder.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_root_folder.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_root_folder.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_root_folder.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_series_type.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_series_type.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_series_type.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_series_type.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_tags.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_tags.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_tags.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_tags.dart diff --git a/lib/modules/sonarr/routes/series_add_details/widgets/tile_use_season_folders.dart b/lib/modules/sonarr/routes/add_series_details/widgets/tile_use_season_folders.dart similarity index 100% rename from lib/modules/sonarr/routes/series_add_details/widgets/tile_use_season_folders.dart rename to lib/modules/sonarr/routes/add_series_details/widgets/tile_use_season_folders.dart diff --git a/lib/modules/sonarr/routes/edit_series.dart b/lib/modules/sonarr/routes/edit_series.dart new file mode 100644 index 00000000..22917768 --- /dev/null +++ b/lib/modules/sonarr/routes/edit_series.dart @@ -0,0 +1,3 @@ +export 'edit_series/route.dart'; +export 'edit_series/state.dart'; +export 'edit_series/widgets.dart'; diff --git a/lib/modules/sonarr/routes/series_edit/route.dart b/lib/modules/sonarr/routes/edit_series/route.dart similarity index 80% rename from lib/modules/sonarr/routes/series_edit/route.dart rename to lib/modules/sonarr/routes/edit_series/route.dart index c76da2fb..3dc30bf9 100644 --- a/lib/modules/sonarr/routes/series_edit/route.dart +++ b/lib/modules/sonarr/routes/edit_series/route.dart @@ -4,34 +4,26 @@ import 'package:flutter/scheduler.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrSeriesEditRouter { - static const String ROUTE_NAME = '/sonarr/series/edit/:seriesid'; +class SonarrEditSeriesRouter extends SonarrPageRouter { + SonarrEditSeriesRouter() : super('/sonarr/editmovie/:seriesid'); - static Future navigateTo(BuildContext context, { - @required int seriesId, - }) async => LunaRouter.router.navigateTo( - context, - route(seriesId: seriesId), - ); + @override + Future navigateTo(BuildContext context, { @required int seriesId }) async => LunaRouter.router.navigateTo(context, route(seriesId: seriesId)); - static String route({ @required int seriesId }) => ROUTE_NAME - .replaceFirst(':seriesid', seriesId?.toString() ?? '-1'); + @override + String route({ @required int seriesId }) => fullRoute.replaceFirst(':seriesid', seriesId.toString()); - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _SonarrSeriesEditRoute( - seriesId: int.tryParse(params['seriesid'][0]) ?? -1, - )), - transitionType: LunaRouter.transitionType, - ); - } + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int seriesId = params['seriesid'] == null || params['seriesid'].length == 0 ? -1 : (int.tryParse(params['seriesid'][0]) ?? -1); + return _SonarrEditSeriesRoute(seriesId: seriesId); + }); } -class _SonarrSeriesEditRoute extends StatefulWidget { +class _SonarrEditSeriesRoute extends StatefulWidget { final int seriesId; - _SonarrSeriesEditRoute({ + _SonarrEditSeriesRoute({ Key key, @required this.seriesId, }) : super(key: key); @@ -40,7 +32,7 @@ class _SonarrSeriesEditRoute extends StatefulWidget { State createState() => _State(); } -class _State extends State<_SonarrSeriesEditRoute> { +class _State extends State<_SonarrEditSeriesRoute> { final GlobalKey _scaffoldKey = GlobalKey(); bool _initialLoad = false; diff --git a/lib/modules/sonarr/routes/series_edit/state.dart b/lib/modules/sonarr/routes/edit_series/state.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/state.dart rename to lib/modules/sonarr/routes/edit_series/state.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets.dart b/lib/modules/sonarr/routes/edit_series/widgets.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets.dart rename to lib/modules/sonarr/routes/edit_series/widgets.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/button_update_series.dart b/lib/modules/sonarr/routes/edit_series/widgets/button_update_series.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/button_update_series.dart rename to lib/modules/sonarr/routes/edit_series/widgets/button_update_series.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_language_profile.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_language_profile.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_language_profile.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_language_profile.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_monitored.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_monitored.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_monitored.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_monitored.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_quality_profile.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_quality_profile.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_quality_profile.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_quality_profile.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_series_path.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_series_path.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_series_path.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_series_path.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_series_type.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_series_type.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_series_type.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_series_type.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_tags.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_tags.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_tags.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_tags.dart diff --git a/lib/modules/sonarr/routes/series_edit/widgets/tile_use_season_folders.dart b/lib/modules/sonarr/routes/edit_series/widgets/tile_use_season_folders.dart similarity index 100% rename from lib/modules/sonarr/routes/series_edit/widgets/tile_use_season_folders.dart rename to lib/modules/sonarr/routes/edit_series/widgets/tile_use_season_folders.dart diff --git a/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart b/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart index 31190c36..3a9e2d57 100644 --- a/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart +++ b/lib/modules/sonarr/routes/missing/widgets/missing_tile.dart @@ -46,7 +46,7 @@ class _State extends State { Widget get _poster => LSNetworkImage( url: Provider.of(context, listen: false).getPosterURL(widget.record.seriesId), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _height, width: _width, headers: Provider.of(context, listen: false).headers.cast(), @@ -166,7 +166,7 @@ class _State extends State { }); } - Future _trailingOnLongPress() async => SonarrReleasesRouter.navigateTo( + Future _trailingOnLongPress() async => SonarrReleasesRouter().navigateTo( context, episodeId: widget.record.id, ); diff --git a/lib/modules/sonarr/routes/queue/route.dart b/lib/modules/sonarr/routes/queue/route.dart index acdb3d05..ffe2447b 100644 --- a/lib/modules/sonarr/routes/queue/route.dart +++ b/lib/modules/sonarr/routes/queue/route.dart @@ -4,7 +4,7 @@ import 'package:flutter/scheduler.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrQueueRouter extends LunaPageRouter { +class SonarrQueueRouter extends SonarrPageRouter { SonarrQueueRouter() : super('/sonarr/queue'); @override diff --git a/lib/modules/sonarr/routes/releases/route.dart b/lib/modules/sonarr/routes/releases/route.dart index c61b6446..33d45e9d 100644 --- a/lib/modules/sonarr/routes/releases/route.dart +++ b/lib/modules/sonarr/routes/releases/route.dart @@ -4,10 +4,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrReleasesRouter { - static const String ROUTE_NAME = '/sonarr/releases'; +class SonarrReleasesRouter extends SonarrPageRouter { + SonarrReleasesRouter() : super('/sonarr/releases'); - static Future navigateTo(BuildContext context, { + @override + Future navigateTo(BuildContext context, { int episodeId, int seriesId, int seasonNumber, @@ -16,33 +17,39 @@ class SonarrReleasesRouter { route(episodeId: episodeId, seriesId: seriesId, seasonNumber: seasonNumber), ); - static String route({ + @override + String route({ int episodeId, int seriesId, int seasonNumber, }) { - if(episodeId != null) return ROUTE_NAME+'/episode/$episodeId'; - if(seriesId != null && seasonNumber != null) return ROUTE_NAME+'/series/$seriesId/season/$seasonNumber'; + if(episodeId != null) return fullRoute+'/episode/$episodeId'; + if(seriesId != null && seasonNumber != null) return fullRoute+'/series/$seriesId/season/$seasonNumber'; return SonarrHomeRouter().route(); } - static void defineRoutes(FluroRouter router) { + @override + void defineRoute(FluroRouter router) { router.define( - ROUTE_NAME+'/episode/:episodeid', - handler: Handler(handlerFunc: (context, params) => _SonarrReleasesRoute( - episodeId: int.tryParse(params['episodeid'][0]) ?? -1, - seriesId: null, - seasonNumber: null, - )), + fullRoute+'/episode/:episodeid', + handler: Handler(handlerFunc: (context, params) { + if(!context.read().enabled) return LunaNotEnabledRoute(module: 'Sonarr'); + int episodeId = params['episodeid'] == null || params['episodeid'].length == 0 ? -1 : (int.tryParse(params['episodeid'][0]) ?? -1); + return _SonarrReleasesRoute(episodeId: episodeId); + }), transitionType: LunaRouter.transitionType, ); router.define( - ROUTE_NAME+'/series/:seriesid/season/:seasonnumber', - handler: Handler(handlerFunc: (context, params) => _SonarrReleasesRoute( - episodeId: null, - seriesId: int.tryParse(params['seriesid'][0]) ?? -1, - seasonNumber: int.tryParse(params['seasonnumber'][0]) ?? -1, - )), + fullRoute+'/series/:seriesid/season/:seasonnumber', + handler: Handler(handlerFunc: (context, params) { + if(!context.read().enabled) return LunaNotEnabledRoute(module: 'Sonarr'); + int seriesId = params['seriesid'] == null || params['seriesid'].length == 0 ? -1 : (int.tryParse(params['seriesid'][0]) ?? -1); + int seasonNumber = params['seasonnumber'] == null || params['seasonnumber'].length == 0 ? -1 : (int.tryParse(params['seasonnumber'][0]) ?? -1); + return _SonarrReleasesRoute( + seriesId: seriesId, + seasonNumber: seasonNumber, + ); + }), transitionType: LunaRouter.transitionType, ); } diff --git a/lib/modules/sonarr/routes/releases/widgets/tile_release.dart b/lib/modules/sonarr/routes/releases/widgets/tile_release.dart index ee40c49f..60d09db4 100644 --- a/lib/modules/sonarr/routes/releases/widgets/tile_release.dart +++ b/lib/modules/sonarr/routes/releases/widgets/tile_release.dart @@ -40,9 +40,7 @@ class _State extends State { children: [ TextSpan( style: TextStyle( - color: widget.release.protocol == 'torrent' - ? LunaColours.purple - : LunaColours.blue, + color: widget.release.lunaProtocolColor, fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), text: widget.release.protocol.lunaCapitalizeFirstLetters(), @@ -50,7 +48,7 @@ class _State extends State { if(widget.release.protocol == 'torrent') TextSpan( text: ' (${widget.release.seeders}/${widget.release.leechers})', style: TextStyle( - color: LunaColours.purple, + color: widget.release.lunaProtocolColor, fontWeight: LunaUI.FONT_WEIGHT_BOLD, ), ), @@ -99,9 +97,7 @@ class _State extends State { children: [ LSTextHighlighted( text: widget.release.protocol.lunaCapitalizeFirstLetters(), - bgColor: widget.release.protocol == 'torrent' - ? LunaColours.purple - : LunaColours.blue, + bgColor: widget.release.lunaProtocolColor, ), LSTextHighlighted( text: widget.release?.indexer ?? 'Unknown', diff --git a/lib/modules/sonarr/routes/season_details/route.dart b/lib/modules/sonarr/routes/season_details/route.dart index de14f6b7..64c4e349 100644 --- a/lib/modules/sonarr/routes/season_details/route.dart +++ b/lib/modules/sonarr/routes/season_details/route.dart @@ -4,7 +4,7 @@ import 'package:flutter/scheduler.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrSeasonDetailsRouter extends LunaPageRouter { +class SonarrSeasonDetailsRouter extends SonarrPageRouter { SonarrSeasonDetailsRouter() : super('/sonarr/series/details/:seriesid/season/:seasonnumber'); @override @@ -20,15 +20,11 @@ class SonarrSeasonDetailsRouter extends LunaPageRouter { }) => fullRoute.replaceFirst(':seriesid', seriesId.toString()).replaceFirst(':seasonnumber', seasonNumber.toString()); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) { - int seriesId = params['seriesid'] == null || params['seriesid'].length == 0 ? -1 : (int.tryParse(params['seriesid'][0]) ?? -1); - int seasonNumber = params['seasonnumber'] == null || params['seasonnumber'].length == 0 ? -1 : (int.tryParse(params['seasonnumber'][0]) ?? -1); - return _SonarrSeasonDetailsRoute(seriesId: seriesId, seasonNumber: seasonNumber); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int seriesId = params['seriesid'] == null || params['seriesid'].length == 0 ? -1 : (int.tryParse(params['seriesid'][0]) ?? -1); + int seasonNumber = params['seasonnumber'] == null || params['seasonnumber'].length == 0 ? -1 : (int.tryParse(params['seasonnumber'][0]) ?? -1); + return _SonarrSeasonDetailsRoute(seriesId: seriesId, seasonNumber: seasonNumber); + }); } class _SonarrSeasonDetailsRoute extends StatefulWidget { @@ -73,7 +69,7 @@ class _State extends State<_SonarrSeasonDetailsRoute> { return Scaffold( key: _scaffoldKey, appBar: _appBar, - body: context.watch().enabled ? _body : LunaMessage.moduleNotEnabled(context: context, module: 'Sonarr'), + body: _body, floatingActionButton: _floatingActionButton, ); } diff --git a/lib/modules/sonarr/routes/season_details/widgets/season_header.dart b/lib/modules/sonarr/routes/season_details/widgets/season_header.dart index 4d6ad348..ba904acd 100644 --- a/lib/modules/sonarr/routes/season_details/widgets/season_header.dart +++ b/lib/modules/sonarr/routes/season_details/widgets/season_header.dart @@ -74,5 +74,5 @@ class SonarrSeasonDetailsSeasonHeader extends StatelessWidget { BuildContext context, int seriesId, int seasonNumber, - ) async => SonarrReleasesRouter.navigateTo(context, seriesId: seriesId, seasonNumber: seasonNumber); + ) async => SonarrReleasesRouter().navigateTo(context, seriesId: seriesId, seasonNumber: seasonNumber); } diff --git a/lib/modules/sonarr/routes/season_details/widgets/tile_episode.dart b/lib/modules/sonarr/routes/season_details/widgets/tile_episode.dart index 8b5678d3..03762a43 100644 --- a/lib/modules/sonarr/routes/season_details/widgets/tile_episode.dart +++ b/lib/modules/sonarr/routes/season_details/widgets/tile_episode.dart @@ -285,7 +285,7 @@ class _State extends State { }); } - Future _interactiveSearch() async => SonarrReleasesRouter.navigateTo( + Future _interactiveSearch() async => SonarrReleasesRouter().navigateTo( context, episodeId: widget.episode.id, ); diff --git a/lib/modules/sonarr/routes/series/widgets/series_tile.dart b/lib/modules/sonarr/routes/series/widgets/series_tile.dart index 0a2f0b3a..971fb9c8 100644 --- a/lib/modules/sonarr/routes/series/widgets/series_tile.dart +++ b/lib/modules/sonarr/routes/series/widgets/series_tile.dart @@ -47,7 +47,7 @@ class _State extends State { Widget get _poster => LSNetworkImage( url: Provider.of(context, listen: false).getPosterURL(widget.series.id), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _height, width: _width, headers: Provider.of(context, listen: false).headers.cast(), diff --git a/lib/modules/sonarr/routes/series_add.dart b/lib/modules/sonarr/routes/series_add.dart deleted file mode 100644 index 680999f3..00000000 --- a/lib/modules/sonarr/routes/series_add.dart +++ /dev/null @@ -1,2 +0,0 @@ -export 'series_add/route.dart'; -export 'series_add/widgets.dart'; diff --git a/lib/modules/sonarr/routes/series_add/route.dart b/lib/modules/sonarr/routes/series_add/route.dart deleted file mode 100644 index fae631cb..00000000 --- a/lib/modules/sonarr/routes/series_add/route.dart +++ /dev/null @@ -1,39 +0,0 @@ -import 'package:fluro/fluro.dart'; -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/sonarr.dart'; - -class SonarrSeriesAddRouter { - static const String ROUTE_NAME = '/sonarr/series/add'; - - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _SonarrSeriesAddRoute()), - transitionType: LunaRouter.transitionType, - ); - } -} - -class _SonarrSeriesAddRoute extends StatefulWidget { - @override - State createState() => _State(); -} - -class _State extends State<_SonarrSeriesAddRoute> { - final GlobalKey _scaffoldKey = GlobalKey(); - - @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: SonarrSeriesAddAppBar(), - body: SonarrSeriesAddSearchResults(), - ); -} diff --git a/lib/modules/sonarr/routes/series_add_details.dart b/lib/modules/sonarr/routes/series_add_details.dart deleted file mode 100644 index 7a99d160..00000000 --- a/lib/modules/sonarr/routes/series_add_details.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'series_add_details/route.dart'; -export 'series_add_details/state.dart'; -export 'series_add_details/widgets.dart'; diff --git a/lib/modules/sonarr/routes/series_details/route.dart b/lib/modules/sonarr/routes/series_details/route.dart index a3f0d6f0..e26eb866 100644 --- a/lib/modules/sonarr/routes/series_details/route.dart +++ b/lib/modules/sonarr/routes/series_details/route.dart @@ -4,7 +4,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; import 'package:tuple/tuple.dart'; -class SonarrSeriesDetailsRouter extends LunaPageRouter { +class SonarrSeriesDetailsRouter extends SonarrPageRouter { SonarrSeriesDetailsRouter() : super('/sonarr/series/details/:seriesid'); @override @@ -14,14 +14,10 @@ class SonarrSeriesDetailsRouter extends LunaPageRouter { String route({ @required int seriesId }) => fullRoute.replaceFirst(':seriesid', seriesId.toString()); @override - void defineRoute(FluroRouter router) => router.define( - fullRoute, - handler: Handler(handlerFunc: (context, params) { - int seriesId = params['seriesid'] == null || params['seriesid'].length == 0 ? -1 : (int.tryParse(params['seriesid'][0]) ?? -1); - return _SonarrSeriesDetailsRoute(seriesId: seriesId); - }), - transitionType: LunaRouter.transitionType, - ); + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int seriesId = params['seriesid'] == null || params['seriesid'].length == 0 ? -1 : (int.tryParse(params['seriesid'][0]) ?? -1); + return _SonarrSeriesDetailsRoute(seriesId: seriesId); + }); } class _SonarrSeriesDetailsRoute extends StatefulWidget { @@ -94,7 +90,7 @@ class _State extends State<_SonarrSeriesDetailsRoute> with LunaLoadCallbackMixin key: _scaffoldKey, appBar: _appBar, bottomNavigationBar: context.watch().enabled ? _bottomNavigationBar : null, - body: context.watch().enabled ? _body : LunaMessage.moduleNotEnabled(context: context, module: 'Sonarr'), + body: _body, ); } diff --git a/lib/modules/sonarr/routes/series_details/widgets/appbar_edit_action.dart b/lib/modules/sonarr/routes/series_details/widgets/appbar_edit_action.dart index 510dfb68..7d3090cc 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/appbar_edit_action.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/appbar_edit_action.dart @@ -21,7 +21,7 @@ class SonarrAppBarSeriesEditAction extends StatelessWidget { SonarrSeries series = snapshot.data.firstWhere((element) => element.id == seriesId, orElse: () => null); if(series != null) return LSIconButton( icon: Icons.edit, - onPressed: () async => SonarrSeriesEditRouter.navigateTo(context, seriesId: series.id), + onPressed: () async => SonarrEditSeriesRouter().navigateTo(context, seriesId: series.id), ); } return Container(); 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 27edbca4..abfb9783 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 @@ -46,7 +46,7 @@ class SonarrAppBarSeriesSettingsAction extends StatelessWidget { static Future _edit( BuildContext context, SonarrSeries series, - ) async => SonarrSeriesEditRouter.navigateTo(context, seriesId: series.id); + ) async => SonarrEditSeriesRouter().navigateTo(context, seriesId: series.id); static Future _monitored( BuildContext context, diff --git a/lib/modules/sonarr/routes/series_details/widgets/navigation_bar.dart b/lib/modules/sonarr/routes/series_details/widgets/navigation_bar.dart index c1f9d91b..be875841 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/navigation_bar.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/navigation_bar.dart @@ -53,6 +53,6 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } diff --git a/lib/modules/sonarr/routes/series_details/widgets/overview.dart b/lib/modules/sonarr/routes/series_details/widgets/overview.dart index 154729bd..f0c568ec 100644 --- a/lib/modules/sonarr/routes/series_details/widgets/overview.dart +++ b/lib/modules/sonarr/routes/series_details/widgets/overview.dart @@ -56,7 +56,7 @@ class SonarrSeriesDetailsOverview extends StatelessWidget { LSNetworkImage( url: Provider.of(context, listen: false).getPosterURL(series.id), headers: Provider.of(context, listen: false).headers.cast(), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _height, width: _width, ), diff --git a/lib/modules/sonarr/routes/series_edit.dart b/lib/modules/sonarr/routes/series_edit.dart deleted file mode 100644 index d7533d4e..00000000 --- a/lib/modules/sonarr/routes/series_edit.dart +++ /dev/null @@ -1,3 +0,0 @@ -export 'series_edit/route.dart'; -export 'series_edit/state.dart'; -export 'series_edit/widgets.dart'; diff --git a/lib/modules/sonarr/routes/sonarr/route.dart b/lib/modules/sonarr/routes/sonarr/route.dart index 901bb06d..8d651b75 100644 --- a/lib/modules/sonarr/routes/sonarr/route.dart +++ b/lib/modules/sonarr/routes/sonarr/route.dart @@ -3,11 +3,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrHomeRouter extends LunaPageRouter { +class SonarrHomeRouter extends SonarrPageRouter { SonarrHomeRouter() : super('/sonarr'); @override - void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SonarrHomeRoute()); + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _SonarrHomeRoute(), homeRoute: true); } class _SonarrHomeRoute extends StatefulWidget { @@ -27,19 +27,21 @@ class _State extends State<_SonarrHomeRoute> { } @override - Widget build(BuildContext context) => WillPopScope( - onWillPop: _onWillPop, - child: ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [ LunaDatabaseValue.ENABLED_PROFILE.key ]), - builder: (context, box, _) => Scaffold( - key: _scaffoldKey, - drawer: _drawer, - appBar: _appBar, - bottomNavigationBar: _bottomNavigationBar, - body: _body, + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: _onWillPop, + child: ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [ LunaDatabaseValue.ENABLED_PROFILE.key ]), + builder: (context, box, _) => Scaffold( + key: _scaffoldKey, + drawer: _drawer(), + appBar: _appBar(), + bottomNavigationBar: _bottomNavigationBar(), + body: _body(), + ), ), - ), - ); + ); + } Future _onWillPop() async { if(_scaffoldKey.currentState.isDrawerOpen) return true; @@ -47,36 +49,47 @@ class _State extends State<_SonarrHomeRoute> { return false; } - Widget get _drawer => LunaDrawer(page: LunaModule.SONARR.key); + Widget _drawer() => LunaDrawer(page: LunaModule.SONARR.key); - Widget get _bottomNavigationBar => SonarrNavigationBar(pageController: _pageController); + Widget _bottomNavigationBar() { + if(context.read().enabled) return SonarrNavigationBar(pageController: _pageController); + return null; + } - List get _tabs => [ - SonarrSeriesRoute(scrollController: _catalogueScrollController), - SonarrUpcomingRoute(), - SonarrMissingRoute(), - SonarrHistoryRoute(), - ]; - - Widget get _body => Selector( - selector: (_, state) => state.enabled, - builder: (context, enabled, _) => PageView( - controller: _pageController, - children: enabled ? _tabs : List.generate(_tabs.length, (_) => LSNotEnabled('Sonarr')), - ), - ); - - Widget get _appBar => LunaAppBar.dropdown( - title: 'Sonarr', - profiles: Database.profilesBox.keys.fold([], (value, element) { - if((Database.profilesBox.get(element) as ProfileHiveObject)?.sonarrEnabled ?? false) value.add(element); + Widget _appBar() { + List profiles = Database.profilesBox.keys.fold([], (value, element) { + if(Database.profilesBox.get(element)?.sonarrEnabled ?? false) value.add(element); return value; - }), - actions: Provider.of(context).enabled - ? [ - SonarrAppBarAddSeriesAction(), - SonarrAppBarGlobalSettingsAction(), - ] - : null, - ); + }); + List actions; + if(context.watch().enabled) actions = [ + SonarrAppBarAddSeriesAction(), + SonarrAppBarGlobalSettingsAction(), + ]; + return LunaAppBar.dropdown( + title: LunaModule.SONARR.name, + profiles: profiles, + actions: actions, + pageController: _pageController, + scrollControllers: SonarrNavigationBar.scrollControllers, + ); + } + + Widget _body() { + return Selector( + selector: (_, state) => state.enabled, + builder: (context, enabled, _) { + if(!enabled) return LunaMessage.moduleNotEnabled(context: context, module: 'Sonarr'); + return PageView( + controller: _pageController, + children: [ + SonarrSeriesRoute(scrollController: _catalogueScrollController), + SonarrUpcomingRoute(), + SonarrMissingRoute(), + SonarrHistoryRoute(), + ], + ); + } + ); + } } 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 21df7214..cad68ede 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 @@ -4,10 +4,13 @@ import 'package:lunasea/modules/sonarr.dart'; class SonarrAppBarAddSeriesAction extends StatelessWidget { @override - Widget build(BuildContext context) => LSIconButton( + Widget build(BuildContext context) => LunaIconButton( icon: Icons.add, onPressed: () async => _onPressed(context), ); - Future _onPressed(BuildContext context) async => SonarrSeriesAddRouter.navigateTo(context); + Future _onPressed(BuildContext context) async => SonarrAddSeriesRouter().navigateTo( + context, + query: '', + ); } diff --git a/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart b/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart index 4a420b4f..3adc124d 100644 --- a/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart +++ b/lib/modules/sonarr/routes/sonarr/widgets/navigation_bar.dart @@ -3,6 +3,8 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; class SonarrNavigationBar extends StatefulWidget { + static List scrollControllers = List.generate(icons.length, (_) => ScrollController()); + static const List icons = [ LunaIcons.television, LunaIcons.upcoming, @@ -57,6 +59,6 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } diff --git a/lib/modules/sonarr/routes/tags/route.dart b/lib/modules/sonarr/routes/tags/route.dart index c5c0b9e6..a1d89c60 100644 --- a/lib/modules/sonarr/routes/tags/route.dart +++ b/lib/modules/sonarr/routes/tags/route.dart @@ -4,7 +4,7 @@ import 'package:flutter/scheduler.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/sonarr.dart'; -class SonarrTagsRouter extends LunaPageRouter { +class SonarrTagsRouter extends SonarrPageRouter { SonarrTagsRouter() : super('/sonarr/tags'); @override diff --git a/lib/modules/sonarr/routes/upcoming/widgets/upcoming_tile.dart b/lib/modules/sonarr/routes/upcoming/widgets/upcoming_tile.dart index 1146f996..7493c22f 100644 --- a/lib/modules/sonarr/routes/upcoming/widgets/upcoming_tile.dart +++ b/lib/modules/sonarr/routes/upcoming/widgets/upcoming_tile.dart @@ -23,7 +23,7 @@ class _State extends State { backgroundUrl: context.read().getBannerURL(widget.record.seriesId), posterUrl: context.read().getPosterURL(widget.record.seriesId), posterHeaders: context.read().headers, - posterPlaceholder: 'assets/images/sonarr/noseriesposter.png', + posterPlaceholder: 'assets/images/blanks/video.png', title: widget.record.series.title, subtitle1: _subtitle1(), subtitle2: _subtitle2(), @@ -104,7 +104,7 @@ class _State extends State { }); } - Future _trailingOnLongPress() async => SonarrReleasesRouter.navigateTo( + Future _trailingOnLongPress() async => SonarrReleasesRouter().navigateTo( context, episodeId: widget.record.id, ); diff --git a/lib/modules/tautulli/core.dart b/lib/modules/tautulli/core.dart index a8e01141..b1bbc931 100644 --- a/lib/modules/tautulli/core.dart +++ b/lib/modules/tautulli/core.dart @@ -1,3 +1,4 @@ +export 'core/api_helper.dart'; export 'core/database.dart'; export 'core/dialogs.dart'; export 'core/extensions.dart'; @@ -5,3 +6,4 @@ export 'core/graphs.dart'; export 'core/router.dart'; export 'core/state.dart'; export 'core/types.dart'; +export 'core/webhooks.dart'; diff --git a/lib/modules/tautulli/core/api_helper.dart b/lib/modules/tautulli/core/api_helper.dart new file mode 100644 index 00000000..a4bddf02 --- /dev/null +++ b/lib/modules/tautulli/core/api_helper.dart @@ -0,0 +1,168 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class TautulliAPIHelper { + /// Backup Tautulli's configuration. + Future backupConfiguration({ + @required BuildContext context, + bool showSnackbar = true, + }) async { + if(context.read().enabled) { + return await context.read().api.system.backupConfig() + .then((_) { + if(showSnackbar) showLunaSuccessSnackBar( + title: 'tautulli.BackingUpConfiguration'.tr(), + message: 'tautulli.BackingUpConfigurationDescription'.tr(), + ); + return true; + }) + .catchError((error, trace) { + LunaLogger().error('Failed to backup configuration', error, trace); + if(showSnackbar) showLunaErrorSnackBar( + title: 'tautulli.BackingUpConfigurationFailed'.tr(), + error: error, + ); + return false; + }); + } + return false; + } + + /// Backup Tautulli's database. + Future backupDatabase({ + @required BuildContext context, + bool showSnackbar = true, + }) async { + if(context.read().enabled) { + return await context.read().api.system.backupDB() + .then((_) { + if(showSnackbar) showLunaSuccessSnackBar( + title: 'tautulli.BackingUpDatabase'.tr(), + message: 'tautulli.BackingUpDatabaseDescription'.tr(), + ); + return true; + }) + .catchError((error, trace) { + LunaLogger().error('Failed to backup database', error, trace); + if(showSnackbar) showLunaErrorSnackBar( + title: 'tautulli.BackingUpDatabaseFailed'.tr(), + error: error, + ); + return false; + }); + } + return false; + } + + /// Delete cache. + Future deleteCache({ + @required BuildContext context, + bool showSnackbar = true, + }) async { + if(context.read().enabled) { + return await context.read().api.system.deleteCache() + .then((_) { + if(showSnackbar) showLunaSuccessSnackBar( + title: 'tautulli.DeletingCache'.tr(), + message: 'tautulli.DeletingCacheDescription'.tr(), + ); + return true; + }) + .catchError((error, trace) { + LunaLogger().error('Failed to delete cache', error, trace); + if(showSnackbar) showLunaErrorSnackBar( + title: 'tautulli.DeletingCacheFailed'.tr(), + error: error, + ); + return false; + }); + } + return false; + } + + /// Delete image cache. + Future deleteImageCache({ + @required BuildContext context, + bool showSnackbar = true, + }) async { + if(context.read().enabled) { + return await context.read().api.system.deleteImageCache() + .then((_) { + if(showSnackbar) showLunaSuccessSnackBar( + title: 'tautulli.DeletingImageCache'.tr(), + message: 'tautulli.DeletingImageCacheDescription'.tr(), + ); + return true; + }) + .catchError((error, trace) { + LunaLogger().error('Failed to delete image cache', error, trace); + if(showSnackbar) showLunaErrorSnackBar( + title: 'tautulli.DeletingImageCacheFailed'.tr(), + error: error, + ); + return false; + }); + } + return false; + } + + /// Delete temporary sessions. + Future deleteTemporarySessions({ + @required BuildContext context, + bool showSnackbar = true, + }) async { + if(context.read().enabled) { + return await context.read().api.activity.deleteTempSessions() + .then((_) { + if(showSnackbar) showLunaSuccessSnackBar( + title: 'tautulli.DeletingTemporarySessions'.tr(), + message: 'tautulli.DeletingTemporarySessionsDescription'.tr(), + ); + return true; + }) + .catchError((error, trace) { + LunaLogger().error('Failed to delete temporary sessions', error, trace); + if(showSnackbar) showLunaErrorSnackBar( + title: 'tautulli.DeletingTemporarySessionsFailed'.tr(), + error: error, + ); + return false; + }); + } + return false; + } + + /// Terminate an active session. + Future terminateSession({ + @required BuildContext context, + @required TautulliSession session, + String terminationMessage, + bool showSnackbar = true, + }) async { + if(context.read().enabled) { + return await context.read().api.activity.terminateSession( + sessionId: session.sessionId, + message: terminationMessage, + ).then((_) { + showLunaSuccessSnackBar( + title: 'tautulli.TerminatedSession'.tr(), + message: [ + session.friendlyName, + session.title, + ].join(LunaUI.TEXT_EMDASH.lunaPad()), + ); + return true; + }) + .catchError((error, stack) { + LunaLogger().error('Failed to delete temporary sessions', error, stack); + if(showSnackbar) showLunaErrorSnackBar( + title: 'tautulli.TerminateSessionFailed'.tr(), + error: error, + ); + return false; + }); + } + return false; + } +} diff --git a/lib/modules/tautulli/core/dialogs.dart b/lib/modules/tautulli/core/dialogs.dart index d6f127cb..fcba98cd 100644 --- a/lib/modules/tautulli/core/dialogs.dart +++ b/lib/modules/tautulli/core/dialogs.dart @@ -2,10 +2,8 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; -class TautulliDialogs { - TautulliDialogs._(); - - static Future> globalSettings(BuildContext context) async { +class TautulliDialogs { + Future> globalSettings(BuildContext context) async { bool _flag = false; TautulliGlobalSettingsType _value; @@ -17,7 +15,7 @@ class TautulliDialogs { await LSDialog.dialog( context: context, - title: 'Tautulli Settings', + title: 'lunasea.Settings'.tr(), content: List.generate( TautulliGlobalSettingsType.values.length, (index) => LSDialog.tile( @@ -29,7 +27,7 @@ class TautulliDialogs { ), contentPadding: LSDialog.listDialogContentPadding(), ); - return [_flag, _value]; + return Tuple2(_flag, _value); } static Future> setDefaultPage(BuildContext context, { @@ -63,7 +61,7 @@ class TautulliDialogs { return [_flag, _index]; } - static Future> terminateSession(BuildContext context) async { + Future> terminateSession(BuildContext context) async { bool _flag = false; GlobalKey _formKey = GlobalKey(); TextEditingController _textController = TextEditingController(text: TautulliDatabaseValue.TERMINATION_MESSAGE.data); @@ -77,22 +75,22 @@ class TautulliDialogs { await LSDialog.dialog( context: context, - title: 'Terminate Session', + title: 'tautulli.TerminateSession'.tr(), buttons: [ LSDialog.button( - text: 'Terminate', + text: 'tautulli.Terminate'.tr(), textColor: LunaColours.red, onPressed: () => _setValues(true), ), ], content: [ - LSDialog.textContent(text: 'Do you want to terminate this session?\n'), - LSDialog.textContent(text: 'You can optionally attach a termination message below.'), + LSDialog.textContent(text: 'tautulli.TerminationConfirmMessage'.tr()+'\n'), + LSDialog.textContent(text: 'tautulli.TerminationAttachMessage'.tr()), Form( key: _formKey, child: LSDialog.textFormInput( controller: _textController, - title: 'Termination Message', + title: 'tautulli.TerminationMessage'.tr(), onSubmitted: (_) => _setValues(true), validator: (_) => null, ), @@ -101,7 +99,7 @@ class TautulliDialogs { contentPadding: LSDialog.inputTextDialogContentPadding(), ); - return [_flag, _textController.text]; + return Tuple2(_flag, _textController.text); } static Future> setRefreshRate(BuildContext context) async { diff --git a/lib/modules/tautulli/core/extensions.dart b/lib/modules/tautulli/core/extensions.dart index 466e7065..d4238d5f 100644 --- a/lib/modules/tautulli/core/extensions.dart +++ b/lib/modules/tautulli/core/extensions.dart @@ -1,3 +1,5 @@ +export 'extensions/tautulli_activity.dart'; export 'extensions/tautulli_history_record.dart'; export 'extensions/tautulli_session.dart'; export 'extensions/tautulli_table_library.dart'; +export 'extensions/tautulli_transcode_decision.dart'; diff --git a/lib/modules/tautulli/core/extensions/tautulli_activity.dart b/lib/modules/tautulli/core/extensions/tautulli_activity.dart new file mode 100644 index 00000000..b166cc43 --- /dev/null +++ b/lib/modules/tautulli/core/extensions/tautulli_activity.dart @@ -0,0 +1,30 @@ +import 'package:lunasea/modules/tautulli.dart'; +import 'package:lunasea/core.dart'; + +extension TautulliActivityExtension on TautulliActivity { + String get lunaSessionsHeader { + if(this.streamCount == null || this.streamCount == 0) return 'tautulli.sessionsMany'.tr(args: ['0']); + if(this.streamCount == 1) return 'tautulli.SessionsOne'.tr(); + return 'tautulli.SessionsMany'.tr(args: [this.streamCount.toString()]); + } + + String get lunaSessions { + String value = '${'tautulli.Sessions'.tr()}: '; + value += [ + if((this.streamCountDirectPlay ?? 0) > 0) '${this.streamCountDirectPlay} ${this.streamCountDirectPlay == 1 ? 'tautulli.DirectPlay'.tr() : 'tautulli.DirectPlays'.tr()}', + if((this.streamCountDirectStream ?? 0) > 0) '${this.streamCountDirectStream} ${this.streamCountDirectStream == 1 ? 'tautulli.DirectStream'.tr() : 'tautulli.DirectStreams'.tr()}', + if((this.streamCountTranscode ?? 0) > 0) '${this.streamCountTranscode} ${this.streamCountTranscode == 1 ? 'tautulli.Transcode'.tr() : 'tautulli.Transcodes.tr()'}', + ].join(', '); + return value; + } + + String get lunaBandwidth { + String value = '${'tautulli.Bandwidth'.tr()}: ${this.totalBandwidth?.lunaKilobytesToString(bytes: false, decimals: 1) ?? '0.0'}ps ('; + value += [ + if((this.lanBandwidth ?? 0) > 0) 'LAN: ${this.lanBandwidth.lunaKilobytesToString(bytes: false, decimals: 1)}ps', + if((this.wanBandwidth ?? 0) > 0) 'WAN: ${this.wanBandwidth.lunaKilobytesToString(bytes: false, decimals: 1)}ps', + ].join(', '); + value += ')'; + return value; + } +} \ No newline at end of file diff --git a/lib/modules/tautulli/core/extensions/tautulli_session.dart b/lib/modules/tautulli/core/extensions/tautulli_session.dart index 0bd2aab9..51302ae3 100644 --- a/lib/modules/tautulli/core/extensions/tautulli_session.dart +++ b/lib/modules/tautulli/core/extensions/tautulli_session.dart @@ -1,31 +1,171 @@ import 'dart:math'; - import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; extension TautulliSessionExtension on TautulliSession { - String get lsFullTitle => [ - if(this.title != null && this.title.isNotEmpty) '${this.title}', - if(this.parentTitle != null && this.parentTitle.isNotEmpty) '\n${this.parentTitle}', - if(this.grandparentTitle != null && this.grandparentTitle.isNotEmpty) '\n${this.grandparentTitle}', - ].join(); + String get lunaContainer { + return [ + this.streamContainerDecision.localizedName, + ' (', + this.container.toUpperCase(), + if(this.streamContainerDecision != null && this.streamContainerDecision != TautulliTranscodeDecision.DIRECT_PLAY) + ' ${LunaUI.TEXT_ARROW_RIGHT} ${this.streamContainer.toUpperCase()}', + ')', + ].join(); + } - String get lsTitle => this.grandparentTitle == null || this.grandparentTitle.isEmpty - ? this.parentTitle == null || this.parentTitle.isEmpty - ? this.title == null || this.title.isEmpty - ? 'Unknown Title' - : this.title - : this.parentTitle - : this.grandparentTitle; + String get lunaVideo { + return [ + this.videoDecision.localizedName, + ' (${this.videoCodec?.toUpperCase() ?? LunaUI.TEXT_EMDASH} ', + if(this.transcodeHardwareDecoding) '(HW) ', + this.videoFullResolution, + if(this.transcodeVideoCodec.isNotEmpty) ' ${LunaUI.TEXT_ARROW_RIGHT} ', + if(this.transcodeVideoCodec.isNotEmpty) '${this.transcodeVideoCodec.toUpperCase()} ', + if(this.transcodeVideoCodec.isNotEmpty && this.transcodeHardwareDecoding) '(HW) ', + if(this.transcodeVideoCodec.isNotEmpty) this.streamVideoFullResolution, + ')', + ].join(); + } - String get lsDuration { - double _percent = this.progressPercent/100; - String _progress = Duration(seconds: (this.streamDuration.inSeconds*_percent).floor()).lunaTimestamp; + String get lunaAudio { + return [ + this.audioDecision.localizedName, + ' (', + this.audioCodec?.toUpperCase() ?? LunaUI.TEXT_EMDASH, + if((this.audioChannelLayout?.split('(')?.length ?? 0) > 0) ' ${this.audioChannelLayout?.split('(')[0]}', + if(this.transcodeAudioCodec.isNotEmpty) ' ${LunaUI.TEXT_ARROW_RIGHT} ', + if(this.transcodeAudioCodec.isNotEmpty) this.transcodeAudioCodec?.toUpperCase() ?? LunaUI.TEXT_EMDASH, + if(this.transcodeAudioCodec.isNotEmpty && (this.streamAudioChannelLayout?.split('(')?.length ?? 0) > 0) + ' ${this.streamAudioChannelLayout?.split('(')[0]}', + ')', + ].join(); + } + + String get lunaSubtitle { + if(!this.subtitles) return 'tautulli.None'.tr(); + return [ + this.streamSubtitleDecision == TautulliTranscodeDecision.NULL ? 'tautulli.DirectPlay'.tr() : this.streamSubtitleDecision.localizedName, + if(this.subtitleCodec != null && this.subtitleCodec.isNotEmpty) '(${this.subtitleCodec?.toUpperCase() ?? LunaUI.TEXT_EMDASH})', + ].join(' '); + } + + String get lunaTitle { + if(this.grandparentTitle != null && this.grandparentTitle.isNotEmpty) return this.grandparentTitle; + if(this.parentTitle != null && this.parentTitle.isNotEmpty) return this.parentTitle; + if(this.title != null && this.title.isNotEmpty) return this.title; + return LunaUI.TEXT_EMDASH; + } + + String get lunaFullTitle { + return [ + if(this.title != null && this.title.isNotEmpty) this.title, + if(this.parentTitle != null && this.parentTitle.isNotEmpty) this.parentTitle, + if(this.grandparentTitle != null && this.grandparentTitle.isNotEmpty) this.grandparentTitle, + ].join('\n'); + } + + String get lunaYear { + if(this.year != null) return this.year.toString(); + return LunaUI.TEXT_EMDASH; + } + + String get lunaDuration { + double _percent = (this.progressPercent ?? 0)/100; + String _progress = Duration(seconds: ((this.streamDuration ?? Duration(seconds: 0)).inSeconds*_percent).floor()).lunaTimestamp; String _total = this.streamDuration.lunaTimestamp; return '$_progress/$_total (${this.progressPercent}%)'; } + + String get lunaLibraryName { + if(this.libraryName != null && this.libraryName.isNotEmpty) return this.libraryName; + return LunaUI.TEXT_EMDASH; + } + + String get lunaFriendlyName { + if(this.friendlyName != null && this.friendlyName.isNotEmpty) return this.friendlyName; + return LunaUI.TEXT_EMDASH; + } + + String get lunaIPAddress { + if(this.ipAddress != null && this.ipAddress.isNotEmpty) return this.ipAddress; + return LunaUI.TEXT_EMDASH; + } + + String get lunaPlatform { + return [ + this.platform ?? LunaUI.TEXT_EMDASH, + if(this.platformVersion != null && this.platformVersion.isNotEmpty) '(${this.platformVersion})', + ].join(' '); + } + + String get lunaProduct { + if(this.product != null && this.product.isNotEmpty) return this.product; + return LunaUI.TEXT_EMDASH; + } + + String get lunaPlayer { + if(this.player != null && this.player.isNotEmpty) return this.player; + return LunaUI.TEXT_EMDASH; + } + + String get lunaQuality { + return [ + this.qualityProfile ?? LunaUI.TEXT_EMDASH, + if(this.streamBitrate != null) '(${this.streamBitrate.lunaKilobytesToString(bytes: false, decimals: 1)}ps)', + ].join(' '); + } + + String get lunaBandwidth { + if(this.bandwidth != null) return '${this.bandwidth.lunaKilobytesToString(bytes: false, decimals: 1)}ps'; + return LunaUI.TEXT_EMDASH; + } + + String lunaArtworkPath(BuildContext context) { + switch(this.mediaType) { + case TautulliMediaType.EPISODE: return context.read().getImageURLFromRatingKey(this.grandparentRatingKey); + case TautulliMediaType.TRACK: return context.read().getImageURLFromRatingKey(this.parentRatingKey); + case TautulliMediaType.MOVIE: + case TautulliMediaType.LIVE: + default: return context.read().getImageURLFromRatingKey(this.ratingKey); + } + } + + String get lunaTranscodeDecision { + switch(this.transcodeDecision) { + case TautulliTranscodeDecision.TRANSCODE: + String _transcodeStatus = this.transcodeThrottled ? 'tautulli.Throttled'.tr() : '${this.transcodeSpeed ?? 0.0}x'; + return [ + this.transcodeDecision.localizedName, + ' ($_transcodeStatus)', + ].join(); + case TautulliTranscodeDecision.DIRECT_PLAY: + case TautulliTranscodeDecision.COPY: + case TautulliTranscodeDecision.BURN: + case TautulliTranscodeDecision.NULL: return this.transcodeDecision.localizedName; + default: return 'tautulli.None'.tr(); + } + } + + IconData get lunaSessionStateIcon { + switch(this.state) { + case TautulliSessionState.PAUSED: return Icons.pause; + case TautulliSessionState.PLAYING: return Icons.play_arrow; + case TautulliSessionState.BUFFERING: + default: return Icons.compare_arrows; + } + } + + double get lunaSessionStateIconOffset { + switch(this.state) { + case TautulliSessionState.PAUSED: return -2.0; + case TautulliSessionState.PLAYING: return -3.0; + case TautulliSessionState.BUFFERING: + default: return 0.0; + } + } String get lunaETA { try { @@ -35,101 +175,10 @@ extension TautulliSessionExtension on TautulliSession { return DateTime.now().add(_eta).lunaTime; } catch (error, stack) { LunaLogger().error('Failed to calculate ETA', error, stack); - return 'Unknown'; + return 'lunasea.Unknown'.tr(); } } - String get lsBandwidth => '${this.bandwidth.lunaKilobytesToString(bytes: false, decimals: 1)}ps'; - - String get lsQuality => '${this.qualityProfile} (${this.streamBitrate.lunaKilobytesToString(bytes: false, decimals: 1)}ps)'; - - String get lsStream { - switch(this.transcodeDecision) { - case TautulliTranscodeDecision.TRANSCODE: - String _transcodeStatus = this.transcodeThrottled ? 'Throttled' : '${this.transcodeSpeed ?? 0.0}x'; - return [ - 'Transcode', - ' ($_transcodeStatus)', - ].join(); - case TautulliTranscodeDecision.COPY: return 'Direct Stream'; - case TautulliTranscodeDecision.DIRECT_PLAY: return 'Direct Play'; - case TautulliTranscodeDecision.NULL: - default: return 'Unknown Transcode Decision'; - } - } - - String get lsContainer => [ - this.streamContainerDecision.name, - ' (', - this.container.toUpperCase(), - if(this.streamContainerDecision != null && this.streamContainerDecision != TautulliTranscodeDecision.DIRECT_PLAY) - ' ${LunaUI.TEXT_ARROW_RIGHT} ${this.streamContainer.toUpperCase()}', - ')', - ].join(); - - String get lsVideo => [ - this.videoDecision.name, - ' (', - '${this.videoCodec.toUpperCase()} ', - if(this.transcodeHardwareDecoding) '(HW) ', - this.videoFullResolution, - if(this.transcodeVideoCodec.isNotEmpty) ' ${LunaUI.TEXT_ARROW_RIGHT} ', - if(this.transcodeVideoCodec.isNotEmpty) '${this.transcodeVideoCodec.toUpperCase()} ', - if(this.transcodeVideoCodec.isNotEmpty && this.transcodeHardwareDecoding) '(HW) ', - if(this.transcodeVideoCodec.isNotEmpty) this.streamVideoFullResolution, - ')', - ].join(); - - String get lsAudio => [ - this.audioDecision.name, - ' (', - this.audioCodec.toUpperCase(), - if(this.transcodeAudioCodec.isNotEmpty) ' ${LunaUI.TEXT_ARROW_RIGHT} ', - if(this.transcodeAudioCodec.isNotEmpty) this.transcodeAudioCodec.toUpperCase(), - ')', - ].join(); - - String get lsSubtitle => [ - this.streamSubtitleDecision == TautulliTranscodeDecision.NULL ? 'Direct Play' : this.streamSubtitleDecision.name, - ' (', - this.subtitleCodec.toUpperCase(), - ')', - ].join(); - - String lsArtworkPath(BuildContext context) { - switch(this.mediaType) { - case TautulliMediaType.EPISODE: return context.watch().getImageURLFromRatingKey(this.grandparentRatingKey); - case TautulliMediaType.TRACK: return context.watch().getImageURLFromRatingKey(this.parentRatingKey); - case TautulliMediaType.MOVIE: - case TautulliMediaType.LIVE: - default: return context.watch().getImageURLFromRatingKey(this.ratingKey); - } - } - - double get lsTranscodeProgress => min(1.0, max(0, this.transcodeProgress/100)); - double get lsProgressPercent => min(1.0, max(0, this.progressPercent/100)); - - IconData get lsStateIcon { - switch(this.state) { - case TautulliSessionState.PAUSED: return Icons.pause; - case TautulliSessionState.PLAYING: return Icons.play_arrow; - case TautulliSessionState.BUFFERING: - default: return Icons.compare_arrows; - } - } - - String get lsTranscodeDecision { - switch(this.transcodeDecision) { - case TautulliTranscodeDecision.TRANSCODE: - String _transcodeStatus = this.transcodeThrottled ? 'Throttled' : '${this.transcodeSpeed ?? 0.0}x'; - return [ - 'Transcode', - ' ($_transcodeStatus)', - ].join(); - case TautulliTranscodeDecision.DIRECT_PLAY: - case TautulliTranscodeDecision.COPY: - case TautulliTranscodeDecision.NULL: - default: return this.transcodeDecision.name ?? 'Unknown'; - } - } + double get lunaTranscodeProgress => min(1.0, max(0, this.transcodeProgress/100)); + double get lunaProgressPercent => min(1.0, max(0, this.progressPercent/100)); } diff --git a/lib/modules/tautulli/core/extensions/tautulli_transcode_decision.dart b/lib/modules/tautulli/core/extensions/tautulli_transcode_decision.dart new file mode 100644 index 00000000..c1623108 --- /dev/null +++ b/lib/modules/tautulli/core/extensions/tautulli_transcode_decision.dart @@ -0,0 +1,15 @@ +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +extension LunaTautulliTranscodeDecisionExtension on TautulliTranscodeDecision { + String get localizedName { + switch(this) { + case TautulliTranscodeDecision.TRANSCODE: return 'tautulli.Transcode'.tr(); + case TautulliTranscodeDecision.COPY: return 'tautulli.DirectStream'.tr(); + case TautulliTranscodeDecision.DIRECT_PLAY: return 'tautulli.DirectPlay'.tr(); + case TautulliTranscodeDecision.BURN: return 'tautulli.Burn'.tr(); + case TautulliTranscodeDecision.NULL: + default: return 'tautulli.None'.tr(); + } + } +} \ No newline at end of file diff --git a/lib/modules/tautulli/core/graphs/graph.dart b/lib/modules/tautulli/core/graphs/graph.dart index a383ea2e..af747565 100644 --- a/lib/modules/tautulli/core/graphs/graph.dart +++ b/lib/modules/tautulli/core/graphs/graph.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:fl_chart/fl_chart.dart'; import 'package:lunasea/core.dart'; @@ -32,7 +34,7 @@ class TautulliGraphHelper { reservedSize: 8.0, getTitles: (value) => data.categories[value.truncate()].length > maxTitleLength+1 ? [ - data.categories[value.truncate()].substring(0, maxTitleLength).toUpperCase(), + data.categories[value.truncate()].substring(0, min(maxTitleLength, data.categories[value.truncate()].length)).toUpperCase(), if(titleOverFlowShowEllipsis) Constants.TEXT_ELLIPSIS, ].join() : data.categories[value.truncate()].toUpperCase(), diff --git a/lib/modules/tautulli/core/router.dart b/lib/modules/tautulli/core/router.dart index 30ffd264..e55d3c9d 100644 --- a/lib/modules/tautulli/core/router.dart +++ b/lib/modules/tautulli/core/router.dart @@ -1,33 +1,62 @@ import 'package:fluro/fluro.dart'; +import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; class TautulliRouter extends LunaModuleRouter { @override void defineAllRoutes(FluroRouter router) { - TautulliHomeRouter.defineRoutes(router); + TautulliHomeRouter().defineRoute(router); // Details - TautulliActivityDetailsRouter.defineRoutes(router); - TautulliIPAddressDetailsRouter.defineRoutes(router); - TautulliLibrariesDetailsRouter.defineRoutes(router); - TautulliHistoryDetailsRouter.defineRoutes(router); - TautulliUserDetailsRouter.defineRoutes(router); - TautulliMediaDetailsRouter.defineRoutes(router); + TautulliActivityDetailsRouter().defineRoute(router); + TautulliIPAddressDetailsRouter().defineRoute(router); + TautulliLibrariesDetailsRouter().defineRoute(router); + TautulliHistoryDetailsRouter().defineRoute(router); + TautulliUserDetailsRouter().defineRoute(router); + TautulliMediaDetailsRouter().defineRoute(router); // More/* - TautulliCheckForUpdatesRouter.defineRoutes(router); - TautulliSearchRouter.defineRoutes(router); - TautulliGraphsRouter.defineRoutes(router); - TautulliLibrariesRouter.defineRoutes(router); - TautulliSyncedItemsRouter.defineRoutes(router); - TautulliStatisticsRouter.defineRoutes(router); - TautulliRecentlyAddedRouter.defineRoutes(router); + TautulliCheckForUpdatesRouter().defineRoute(router); + TautulliSearchRouter().defineRoute(router); + TautulliGraphsRouter().defineRoute(router); + TautulliLibrariesRouter().defineRoute(router); + TautulliSyncedItemsRouter().defineRoute(router); + TautulliStatisticsRouter().defineRoute(router); + TautulliRecentlyAddedRouter().defineRoute(router); // Logs - TautulliLogsRouter.defineRoutes(router); - TautulliLogsLoginsRouter.defineRoutes(router); - TautulliLogsNewslettersRouter.defineRoutes(router); - TautulliLogsNotificationsRouter.defineRoutes(router); - TautulliLogsPlexMediaScannerRouter.defineRoutes(router); - TautulliLogsPlexMediaServerRouter.defineRoutes(router); - TautulliLogsTautulliRouter.defineRoutes(router); + TautulliLogsRouter().defineRoute(router); + TautulliLogsLoginsRouter().defineRoute(router); + TautulliLogsNewslettersRouter().defineRoute(router); + TautulliLogsNotificationsRouter().defineRoute(router); + TautulliLogsPlexMediaScannerRouter().defineRoute(router); + TautulliLogsPlexMediaServerRouter().defineRoute(router); + TautulliLogsTautulliRouter().defineRoute(router); } } + +abstract class TautulliPageRouter extends LunaPageRouter { + TautulliPageRouter(String route) : super(route); + + @override + void noParameterRouteDefinition(FluroRouter router, Widget widget, { bool homeRoute = false }) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) { + if(!homeRoute && !context.read().enabled) return LunaNotEnabledRoute(module: 'Tautulli'); + return widget; + }), + transitionType: LunaRouter.transitionType, + ); + + @override + void withParameterRouteDefinition( + FluroRouter router, + Widget Function(BuildContext, Map>) handlerFunc, + { bool homeRoute = false } + ) => router.define( + fullRoute, + handler: Handler(handlerFunc: (context, params) { + if(!homeRoute && !context.read().enabled) return LunaNotEnabledRoute(module: 'Tautulli'); + return handlerFunc(context, params); + }), + transitionType: LunaRouter.transitionType, + ); +} diff --git a/lib/modules/tautulli/core/types.dart b/lib/modules/tautulli/core/types.dart index 77fc94dd..e80358b4 100644 --- a/lib/modules/tautulli/core/types.dart +++ b/lib/modules/tautulli/core/types.dart @@ -1,3 +1,3 @@ -export 'types/global_settings.dart'; +export 'types/settings_global.dart'; export 'types/media_details_switcher.dart'; export 'types/statistics_time_range.dart'; diff --git a/lib/modules/tautulli/core/types/global_settings.dart b/lib/modules/tautulli/core/types/global_settings.dart deleted file mode 100644 index beec52b9..00000000 --- a/lib/modules/tautulli/core/types/global_settings.dart +++ /dev/null @@ -1,36 +0,0 @@ -import 'package:flutter/material.dart'; - -enum TautulliGlobalSettingsType { - WEB_GUI, - BACKUP_CONFIG, - BACKUP_DB, - DELETE_CACHE, - DELETE_IMAGE_CACHE, - DELETE_TEMP_SESSIONS, -} - -extension TautulliGlobalSettingsTypeExtension on TautulliGlobalSettingsType { - IconData get icon { - switch(this) { - case TautulliGlobalSettingsType.WEB_GUI: return Icons.language; - case TautulliGlobalSettingsType.BACKUP_CONFIG: return Icons.note; - case TautulliGlobalSettingsType.BACKUP_DB: return Icons.save; - case TautulliGlobalSettingsType.DELETE_CACHE: return Icons.cached; - case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: return Icons.image; - case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: return Icons.delete_sweep; - } - throw Exception('Invalid TautulliGlobalSettingsType'); - } - - String get name { - switch(this) { - case TautulliGlobalSettingsType.BACKUP_CONFIG: return 'Backup Configuration'; - case TautulliGlobalSettingsType.BACKUP_DB: return 'Backup Database'; - case TautulliGlobalSettingsType.WEB_GUI: return 'View Web GUI'; - case TautulliGlobalSettingsType.DELETE_CACHE: return 'Delete Cache'; - case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: return 'Delete Image Cache'; - case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: return 'Delete Temp Sessions'; - } - throw Exception('Invalid TautulliGlobalSettingsType'); - } -} diff --git a/lib/modules/tautulli/core/types/media_details_switcher.dart b/lib/modules/tautulli/core/types/media_details_switcher.dart index bece1efe..0eb59297 100644 --- a/lib/modules/tautulli/core/types/media_details_switcher.dart +++ b/lib/modules/tautulli/core/types/media_details_switcher.dart @@ -34,5 +34,5 @@ extension TautulliMediaDetailsSwitcherTypeExtension on TautulliMediaDetailsSwitc @required BuildContext context, @required TautulliMediaType mediaType, @required int ratingKey - }) => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: ratingKey, mediaType: mediaType); + }) => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: ratingKey, mediaType: mediaType); } diff --git a/lib/modules/tautulli/core/types/settings_global.dart b/lib/modules/tautulli/core/types/settings_global.dart new file mode 100644 index 00000000..4f26c8f8 --- /dev/null +++ b/lib/modules/tautulli/core/types/settings_global.dart @@ -0,0 +1,57 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +enum TautulliGlobalSettingsType { + WEB_GUI, + BACKUP_CONFIG, + BACKUP_DB, + DELETE_CACHE, + DELETE_IMAGE_CACHE, + DELETE_TEMP_SESSIONS, +} + +extension TautulliGlobalSettingsTypeExtension on TautulliGlobalSettingsType { + IconData get icon { + switch(this) { + case TautulliGlobalSettingsType.WEB_GUI: return Icons.language; + case TautulliGlobalSettingsType.BACKUP_CONFIG: return Icons.note; + case TautulliGlobalSettingsType.BACKUP_DB: return Icons.save; + case TautulliGlobalSettingsType.DELETE_CACHE: return Icons.cached; + case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: return Icons.image; + case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: return Icons.delete_sweep; + } + throw Exception('Invalid TautulliGlobalSettingsType'); + } + + String get name { + switch(this) { + case TautulliGlobalSettingsType.BACKUP_CONFIG: return 'tautulli.BackupConfiguration'.tr(); + case TautulliGlobalSettingsType.BACKUP_DB: return 'tautulli.BackupDatabase'.tr(); + case TautulliGlobalSettingsType.WEB_GUI: return 'tautulli.ViewWebGUI'.tr(); + case TautulliGlobalSettingsType.DELETE_CACHE: return 'tautulli.DeleteCache'.tr(); + case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: return 'tautulli.DeleteImageCache'.tr(); + case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: return 'tautulli.DeleteTemporarySessions'.tr(); + } + throw Exception('Invalid TautulliGlobalSettingsType'); + } + + Future execute(BuildContext context) async { + switch(this) { + case TautulliGlobalSettingsType.WEB_GUI: return _webGUI(context); + case TautulliGlobalSettingsType.BACKUP_CONFIG: return _backupConfig(context); + case TautulliGlobalSettingsType.BACKUP_DB: return _backupDatabase(context); + case TautulliGlobalSettingsType.DELETE_CACHE: return _deleteCache(context); + case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: return _deleteImageCache(context); + case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: return _deleteTemporarySessions(context); + } + throw Exception('Invalid TautulliGlobalSettingsType'); + } + + Future _webGUI(BuildContext context) async => context.read().host.lunaOpenGenericLink(); + Future _backupConfig(BuildContext context) async => TautulliAPIHelper().backupConfiguration(context: context); + Future _backupDatabase(BuildContext context) async => TautulliAPIHelper().backupDatabase(context: context); + Future _deleteCache(BuildContext context) async => TautulliAPIHelper().deleteCache(context: context); + Future _deleteImageCache(BuildContext context) async => TautulliAPIHelper().deleteImageCache(context: context); + Future _deleteTemporarySessions(BuildContext context) async => TautulliAPIHelper().deleteTemporarySessions(context: context); +} diff --git a/lib/modules/tautulli/core/webhooks.dart b/lib/modules/tautulli/core/webhooks.dart new file mode 100644 index 00000000..7f41a92f --- /dev/null +++ b/lib/modules/tautulli/core/webhooks.dart @@ -0,0 +1,86 @@ +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class TautulliWebhooks extends LunaWebhooks { + @override + Future handle(Map data) async { + _EventType event = _EventType.PLAYBACK_PAUSE.fromKey(data['event']); + if(event == null) LunaLogger().warning( + 'TautulliWebhooks', + 'handle', + 'Unknown event type: ${data['event'] ?? 'null'}', + ); + event?.execute(data); + } +} + +enum _EventType { + PLAYBACK_ERROR, + PLAYBACK_PAUSE, + PLAYBACK_RESUME, + PLAYBACK_START, + PLAYBACK_STOP, +} + +extension _EventTypeExtension on _EventType { + _EventType fromKey(String key) { + switch(key) { + case 'PlaybackError': return _EventType.PLAYBACK_ERROR; + case 'PlaybackPause': return _EventType.PLAYBACK_PAUSE; + case 'PlaybackResume': return _EventType.PLAYBACK_RESUME; + case 'PlaybackStart': return _EventType.PLAYBACK_START; + case 'PlaybackStop': return _EventType.PLAYBACK_STOP; + } + return null; + } + + Future execute(Map data) async { + switch(this) { + case _EventType.PLAYBACK_ERROR: return _playbackErrorEvent(data); + case _EventType.PLAYBACK_PAUSE: return _playbackPauseEvent(data); + case _EventType.PLAYBACK_RESUME: return _playbackResumeEvent(data); + case _EventType.PLAYBACK_START: return _playbackStartEvent(data); + case _EventType.PLAYBACK_STOP: return _playbackStopEvent(data); + } + } + + Future _playbackErrorEvent(Map data) async { + int userId = int.tryParse(data['user_id']); + if(userId != null) return TautulliUserDetailsRouter().navigateTo( + LunaState.navigatorKey.currentContext, + userId: userId, + ); + } + + Future _playbackPauseEvent(Map data) async { + String sessionId = data['session_id']; + if(sessionId != null) return TautulliActivityDetailsRouter().navigateTo( + LunaState.navigatorKey.currentContext, + sessionId: sessionId, + ); + } + + Future _playbackResumeEvent(Map data) async { + String sessionId = data['session_id']; + if(sessionId != null) return TautulliActivityDetailsRouter().navigateTo( + LunaState.navigatorKey.currentContext, + sessionId: sessionId, + ); + } + + Future _playbackStartEvent(Map data) async { + String sessionId = data['session_id']; + if(sessionId != null) return TautulliActivityDetailsRouter().navigateTo( + LunaState.navigatorKey.currentContext, + sessionId: sessionId, + ); + } + + Future _playbackStopEvent(Map data) async { + int userId = int.tryParse(data['user_id']); + if(userId != null) return TautulliUserDetailsRouter().navigateTo( + LunaState.navigatorKey.currentContext, + userId: userId, + ); + } +} \ No newline at end of file diff --git a/lib/modules/tautulli/routes/activity/route.dart b/lib/modules/tautulli/routes/activity/route.dart index f1ef9098..b7e16209 100644 --- a/lib/modules/tautulli/routes/activity/route.dart +++ b/lib/modules/tautulli/routes/activity/route.dart @@ -12,7 +12,7 @@ class TautulliActivityRoute extends StatefulWidget { State createState() => _State(); } -class _State extends State with AutomaticKeepAliveClientMixin { +class _State extends State with AutomaticKeepAliveClientMixin, LunaLoadCallbackMixin { final GlobalKey _scaffoldKey = GlobalKey(); final GlobalKey _refreshKey = GlobalKey(); @@ -20,56 +20,58 @@ class _State extends State with AutomaticKeepAliveClientM bool get wantKeepAlive => true; @override - Widget build(BuildContext context) { - super.build(context); - return Scaffold( - key: _scaffoldKey, - body: _body, - ); - } - - Future _refresh() async { + Future loadCallback() async { context.read().resetActivity(); await context.read().activity; } - Widget get _body => LSRefreshIndicator( - refreshKey: _refreshKey, - onRefresh: _refresh, - child: Selector>( - selector: (_, state) => state.activity, - builder: (context, activity, _) => FutureBuilder( - future: activity, + @override + Widget build(BuildContext context) { + super.build(context); + return Scaffold( + key: _scaffoldKey, + body: _body(), + ); + } + + Widget _body() { + return LunaRefreshIndicator( + context: context, + key: _refreshKey, + onRefresh: loadCallback, + child: FutureBuilder( + future: context.select>((state) => state.activity), builder: (context, AsyncSnapshot snapshot) { if(snapshot.hasError) { - if(snapshot.connectionState != ConnectionState.waiting) { - LunaLogger().error('Unable to fetch Tautulli activity', snapshot.error, StackTrace.current); - } - return LSErrorMessage(onTapHandler: () async => _refreshKey.currentState.show()); + if(snapshot.connectionState != ConnectionState.waiting) LunaLogger().error( + 'Unable to fetch Tautulli activity', + snapshot.error, + snapshot.stackTrace, + ); + return LunaMessage.error(onTap: _refreshKey.currentState.show); } - if(snapshot.hasData) return snapshot.data.streamCount == 0 - ? _noActivity() - : _activity(snapshot.data); - return LSLoader(); + if(snapshot.hasData) return _list(snapshot.data); + return LunaLoader(); }, ), - ), - ); + ); + } - Widget _activity(TautulliActivity activity) => LSListView( - children: [ - TautulliActivityStatus(activity: activity), - ...List.generate( - activity.sessions.length, - (index) => TautulliActivityTile(session: activity.sessions[index]), - ), - ], - ); - - Widget _noActivity() => LSGenericMessage( - text: 'No Active Streams', - showButton: true, - buttonText: 'Refresh', - onTapHandler: () async => _refreshKey.currentState.show(), - ); + Widget _list(TautulliActivity activity) { + if((activity?.sessions?.length ?? 0) == 0) return LunaMessage( + text: 'tautulli.NoActiveStreams'.tr(), + buttonText: 'lunasea.Refresh'.tr(), + onTap: _refreshKey.currentState.show, + ); + return LunaListView( + controller: TautulliNavigationBar.scrollControllers[0], + children: [ + TautulliActivityStatus(activity: activity), + ...List.generate( + activity.sessions.length, + (index) => TautulliActivityTile(session: activity.sessions[index]), + ), + ], + ); + } } diff --git a/lib/modules/tautulli/routes/activity/widgets/activity_status.dart b/lib/modules/tautulli/routes/activity/widgets/activity_status.dart index 59b11862..6fa46e96 100644 --- a/lib/modules/tautulli/routes/activity/widgets/activity_status.dart +++ b/lib/modules/tautulli/routes/activity/widgets/activity_status.dart @@ -1,6 +1,6 @@ import 'package:flutter/material.dart'; -import 'package:tautulli/tautulli.dart'; import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; class TautulliActivityStatus extends StatelessWidget { final TautulliActivity activity; @@ -11,31 +11,13 @@ class TautulliActivityStatus extends StatelessWidget { }): super(key: key); @override - Widget build(BuildContext context) => LSHeader( - text: '${activity.streamCount} ${activity.streamCount == 1 ? 'Session' : 'Sessions'}', - subtitle: [ - sessions, - bandwidth, - ].join('\n'), - ); - - String get sessions { - String value = 'Sessions: '; - value += [ - if((activity.streamCountDirectPlay ?? 0) > 0) '${activity.streamCountDirectPlay} ${activity.streamCountDirectPlay == 1 ? 'Direct Play' : 'Direct Plays'}', - if((activity.streamCountDirectStream ?? 0) > 0) '${activity.streamCountDirectStream} ${activity.streamCountDirectStream == 1 ? 'Direct Stream' : 'Direct Streams'}', - if((activity.streamCountTranscode ?? 0) > 0) '${activity.streamCountTranscode} ${activity.streamCountTranscode == 1 ? 'Transcode' : 'Transcodes'}', - ].join(', '); - return value; - } - - String get bandwidth { - String value = 'Bandwidth: ${activity.totalBandwidth?.lunaKilobytesToString(bytes: false, decimals: 1) ?? '0.0'}ps ('; - value += [ - if((activity.lanBandwidth ?? 0) > 0) 'LAN: ${activity.lanBandwidth.lunaKilobytesToString(bytes: false, decimals: 1)}ps', - if((activity.wanBandwidth ?? 0) > 0) 'WAN: ${activity.wanBandwidth.lunaKilobytesToString(bytes: false, decimals: 1)}ps', - ].join(', '); - value += ')'; - return value; + Widget build(BuildContext context) { + return LunaHeader( + text: activity.lunaSessionsHeader, + subtitle: [ + activity.lunaSessions, + activity.lunaBandwidth, + ].join('\n'), + ); } } diff --git a/lib/modules/tautulli/routes/activity/widgets/activity_tile.dart b/lib/modules/tautulli/routes/activity/widgets/activity_tile.dart index a644ce60..60da5350 100644 --- a/lib/modules/tautulli/routes/activity/widgets/activity_tile.dart +++ b/lib/modules/tautulli/routes/activity/widgets/activity_tile.dart @@ -7,9 +7,6 @@ import 'package:lunasea/modules/tautulli.dart'; class TautulliActivityTile extends StatelessWidget { final TautulliSession session; final bool disableOnTap; - final double _height = 105.0; - final double _width = 70.0; - final double _padding = 8.0; TautulliActivityTile({ Key key, @@ -18,117 +15,112 @@ class TautulliActivityTile extends StatelessWidget { }) : super(key: key); @override - Widget build(BuildContext context) => LSCard( - child: disableOnTap - ? _body(context) - : InkWell( - child: _body(context), - borderRadius: BorderRadius.circular(Constants.UI_BORDER_RADIUS), - onTap: () async => _enterDetails(context), - ), - decoration: session.art != null && session.art.isNotEmpty - ? LunaCardDecoration( - uri: context.watch().getImageURLFromPath( - session.art, - width: MediaQuery.of(context).size.width.truncate(), - ), - headers: context.watch().headers, - ) - : null, - ); + Widget build(BuildContext context) { + return LunaFiveLineCardWithPoster( + title: session.lunaTitle, + posterUrl: session.lunaArtworkPath(context), + posterHeaders: context.read().headers, + posterPlaceholder: 'assets/images/blanks/video.png', + backgroundUrl: context.watch().getImageURLFromPath( + session.art, + width: MediaQuery.of(context).size.width.truncate(), + ), + subtitle1: _subtitle1(), + subtitle2: _subtitle2(), + customSubtitle3: _subtitle3(), + customSubtitle4: _subtitle4(), + onTap: disableOnTap ? null : () async => _enterDetails(context), + ); + } - Widget _body(BuildContext context) => Row( - children: [ - _poster(context), - Expanded(child: _mediaInfo), - ], - mainAxisAlignment: MainAxisAlignment.start, - crossAxisAlignment: CrossAxisAlignment.start, - ); - - Widget get _mediaInfo => Padding( - child: Container( - child: Column( + TextSpan _subtitle1() { + if(session.mediaType == TautulliMediaType.EPISODE) { + return TextSpan( children: [ - LSTitle(text: session.lsTitle, maxLines: 1), - _subtitle, - LSSubtitle(text: session.lsTranscodeDecision, maxLines: 1), - _user, - _progressBar, + TextSpan(text: session.parentTitle), + TextSpan(text: LunaUI.TEXT_EMDASH.lunaPad()), + TextSpan(text: 'tautulli.Episode'.tr(args: [session.mediaIndex?.toString() ?? LunaUI.TEXT_EMDASH])), + TextSpan(text: ': '), + TextSpan( + style: TextStyle( + fontStyle: FontStyle.italic, + ), + text: session.title ?? LunaUI.TEXT_EMDASH, + ), ], - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.start, - mainAxisSize: MainAxisSize.max, - ), - height: (_height-(_padding*2)), - ), - padding: EdgeInsets.all(_padding), - ); + ); + } + if(session.mediaType == TautulliMediaType.MOVIE) { + return TextSpan(text: session.year.toString()); + } + if(session.mediaType == TautulliMediaType.TRACK) { + return TextSpan( + children: [ + TextSpan(text: session.parentTitle), + TextSpan(text: LunaUI.TEXT_EMDASH.lunaPad()), + TextSpan( + style: TextStyle( + fontStyle: FontStyle.italic, + ), + text: session.title, + ), + ], + ); + } + if(session.mediaType == TautulliMediaType.LIVE) { + return TextSpan(text: session.title); + } + return TextSpan(text: LunaUI.TEXT_EMDASH); + } - Widget get _subtitle => RichText( - text: TextSpan( - style: TextStyle( - color: Colors.white70, - fontSize: Constants.UI_FONT_SIZE_SUBTITLE, - ), - children: [ - // Television - if(session.mediaType == TautulliMediaType.EPISODE) TextSpan(text: 'S${session.parentMediaIndex}\t•\tE${session.mediaIndex}'), - if(session.mediaType == TautulliMediaType.EPISODE) TextSpan(text: '\t—\t${session.title}'), - // Movie - if(session.mediaType == TautulliMediaType.MOVIE) TextSpan(text: session.year.toString()), - // Music - if(session.mediaType == TautulliMediaType.TRACK) TextSpan(text: session.title), - if(session.mediaType == TautulliMediaType.TRACK) TextSpan(text: '\t—\t${session.parentTitle}'), - // Live - if(session.mediaType == TautulliMediaType.LIVE) TextSpan(text: session.title), - ], - ), - softWrap: false, - maxLines: 1, - overflow: TextOverflow.fade, - ); + TextSpan _subtitle2() { + return TextSpan(text: session.lunaTranscodeDecision); + } - Widget _poster(BuildContext context) => LSNetworkImage( - url: session.lsArtworkPath(context), - placeholder: 'assets/images/sonarr/noseriesposter.png', - height: _height, - width: _width, - headers: context.watch().headers.cast(), - ); - - Widget get _user => Row( - children: [ - Icon( - session.lsStateIcon, - size: Constants.UI_FONT_SIZE_SUBTITLE, - color: Colors.white70, - ), - LSSubtitle(text: '\t${session.friendlyName}'), - ], - ); - - Widget get _progressBar => Padding( - child: Stack( + Widget _subtitle3() { + return Row( children: [ - LinearPercentIndicator( - percent: session.lsTranscodeProgress, - padding: EdgeInsets.symmetric(horizontal: 2.0), - progressColor: LunaColours.splash.withOpacity(0.30), - backgroundColor: Colors.transparent, - lineHeight: 4.0, - ), - LinearPercentIndicator( - percent: session.lsProgressPercent, - padding: EdgeInsets.symmetric(horizontal: 2.0), - progressColor: LunaColours.accent, - backgroundColor: LunaColours.accent.withOpacity(0.15), - lineHeight: 4.0, + Container( + child: Icon( + session.lunaSessionStateIcon, + size: LunaUI.FONT_SIZE_SUBTITLE, + color: Colors.white70, + ), + alignment: Alignment.centerLeft, + width: 16.0+session.lunaSessionStateIconOffset, + transform: Matrix4.translationValues(session.lunaSessionStateIconOffset, 0.0, 0.0), ), + LunaText.subtitle(text: session.lunaFriendlyName), ], - ), - padding: EdgeInsets.only(top: _padding), - ); + ); + } - Future _enterDetails(BuildContext context) async => TautulliActivityDetailsRouter.navigateTo(context, sessionId: session.sessionId); + Widget _subtitle4() { + return Padding( + child: Stack( + children: [ + LinearPercentIndicator( + percent: session.lunaTranscodeProgress, + padding: EdgeInsets.symmetric(horizontal: 2.0), + progressColor: LunaColours.splash.withOpacity(0.30), + backgroundColor: Colors.transparent, + lineHeight: 4.0, + ), + LinearPercentIndicator( + percent: session.lunaProgressPercent, + padding: EdgeInsets.symmetric(horizontal: 2.0), + progressColor: LunaColours.accent, + backgroundColor: LunaColours.accent.withOpacity(0.15), + lineHeight: 4.0, + ), + ], + ), + padding: EdgeInsets.only(top: 4.0), + ); + } + + Future _enterDetails(BuildContext context) async => TautulliActivityDetailsRouter().navigateTo( + context, + sessionId: session.sessionId, + ); } diff --git a/lib/modules/tautulli/routes/activity_details/route.dart b/lib/modules/tautulli/routes/activity_details/route.dart index 2e4f765e..9b1da5a0 100644 --- a/lib/modules/tautulli/routes/activity_details/route.dart +++ b/lib/modules/tautulli/routes/activity_details/route.dart @@ -4,31 +4,20 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliActivityDetailsRouter { - static const String ROUTE_NAME = '/tautulli/activity/details/:sessionid'; +class TautulliActivityDetailsRouter extends TautulliPageRouter { + TautulliActivityDetailsRouter() : super('/tautulli/activity/:sessionid'); - static Future navigateTo(BuildContext context, { - @required String sessionId, - }) async => LunaRouter.router.navigateTo( - context, - route(sessionId: sessionId), - ); + @override + Future navigateTo(BuildContext context, { @required String sessionId }) async => LunaRouter.router.navigateTo(context, route(sessionId: sessionId)); - static String route({ @required String sessionId }) => ROUTE_NAME.replaceFirst(':sessionid', sessionId ?? '0'); + @override + String route({ @required String sessionId }) => fullRoute.replaceFirst(':sessionid', sessionId); - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliActivityDetailsRoute( - sessionId: params['sessionid'] != null && params['sessionid'].length != 0 - ? params['sessionid'][0] ?? '-1' - : '-1', - )), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliActivityDetailsRouter._(); + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + String sessionId = params['sessionid'] == null || params['sessionid'].length == 0 ? null : params['sessionid'][0]; + return _TautulliActivityDetailsRoute(sessionId: sessionId); + }); } class _TautulliActivityDetailsRoute extends StatefulWidget { @@ -43,7 +32,7 @@ class _TautulliActivityDetailsRoute extends StatefulWidget { State createState() => _State(); } -class _State extends State<_TautulliActivityDetailsRoute> { +class _State extends State<_TautulliActivityDetailsRoute> with LunaScrollControllerMixin { final GlobalKey _scaffoldKey = GlobalKey(); final GlobalKey _refreshKey = GlobalKey(); @@ -53,52 +42,68 @@ class _State extends State<_TautulliActivityDetailsRoute> { } @override - Widget build(BuildContext context) => Scaffold( - key: _scaffoldKey, - appBar: _appBar, - body: _body, - ); + Widget build(BuildContext context) { + return Scaffold( + key: _scaffoldKey, + appBar: _appBar(), + body: _body(), + ); + } - Widget get _appBar => LunaAppBar( - title: 'Activity Details', - actions: [ - TautulliActivityDetailsUser(sessionId: widget.sessionId), - TautulliActivityDetailsMetadata(sessionId: widget.sessionId), - ] - ); + Widget _appBar() { + return LunaAppBar( + title: 'tautulli.ActivityDetails'.tr(), + scrollControllers: [scrollController], + actions: [ + TautulliActivityDetailsUserAction(sessionId: widget.sessionId), + TautulliActivityDetailsMetadataAction(sessionId: widget.sessionId), + ] + ); + } - Widget get _body => LSRefreshIndicator( - refreshKey: _refreshKey, - onRefresh: _refresh, - child: Selector>( - selector: (_, state) => state.activity, - builder: (context, future, _) => FutureBuilder( - future: future, + Widget _body() { + return LunaRefreshIndicator( + context: context, + key: _refreshKey, + onRefresh: _refresh, + child: FutureBuilder( + future: context.select>((state) => state.activity), builder: (context, AsyncSnapshot snapshot) { if(snapshot.hasError) { - if(snapshot.connectionState != ConnectionState.waiting) { - LunaLogger().error('Unable to pull Tautulli activity session', snapshot.error, StackTrace.current); - } - return LSErrorMessage(onTapHandler: () => _refresh()); + if(snapshot.connectionState != ConnectionState.waiting) LunaLogger().error( + 'Unable to pull Tautulli activity session', + snapshot.error, + snapshot.stackTrace, + ); + return LunaMessage.error(onTap: _refreshKey.currentState.show); } if(snapshot.hasData) { TautulliSession session = snapshot.data.sessions.firstWhere((element) => element.sessionId == widget.sessionId, orElse: () => null); - return session == null - ? _deadSession() - : _activeSession(session); + return _session(session); } - return LSLoader(); + return LunaLoader(); }, ), - ), - ); + ); + } - Widget _activeSession(TautulliSession session) => TautulliActivityDetailsInformation(session: session); - - Widget _deadSession() => LSGenericMessage( - text: 'Session Ended', - showButton: true, - buttonText: 'Back', - onTapHandler: () async => Navigator.of(context).pop(), - ); + Widget _session(TautulliSession session) { + if(session == null) return LunaMessage.goBack( + context: context, + text: 'tautulli.SessionEnded'.tr(), + ); + return LunaListView( + controller: scrollController, + children: [ + TautulliActivityTile(session: session, disableOnTap: true), + TautulliActivityDetailsTerminateSessionButton(session: session), + LunaHeader(text: 'tautulli.Metadata'.tr()), + TautulliActivityDetailsMetadataBlock(session: session), + LunaHeader(text: 'tautulli.Player'.tr()), + TautulliActivityDetailsPlayerBlock(session: session), + LunaHeader(text: 'tautulli.Stream'.tr()), + TautulliActivityDetailsStreamBlock(session: session), + ], + ); + } } diff --git a/lib/modules/tautulli/routes/activity_details/widgets.dart b/lib/modules/tautulli/routes/activity_details/widgets.dart index 7130e84b..e2b6174e 100644 --- a/lib/modules/tautulli/routes/activity_details/widgets.dart +++ b/lib/modules/tautulli/routes/activity_details/widgets.dart @@ -1,4 +1,6 @@ -export 'widgets/information.dart'; -export 'widgets/metadata.dart'; -export 'widgets/terminate_session.dart'; -export 'widgets/user.dart'; +export 'widgets/appbar_metadata_action.dart'; +export 'widgets/appbar_user_action.dart'; +export 'widgets/block_metadata.dart'; +export 'widgets/block_player.dart'; +export 'widgets/block_stream.dart'; +export 'widgets/button_terminate_session.dart'; diff --git a/lib/modules/tautulli/routes/activity_details/widgets/metadata.dart b/lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart similarity index 63% rename from lib/modules/tautulli/routes/activity_details/widgets/metadata.dart rename to lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart index 7bfa00ba..69712eb7 100644 --- a/lib/modules/tautulli/routes/activity_details/widgets/metadata.dart +++ b/lib/modules/tautulli/routes/activity_details/widgets/appbar_metadata_action.dart @@ -3,32 +3,35 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliActivityDetailsMetadata extends StatelessWidget { +class TautulliActivityDetailsMetadataAction extends StatelessWidget { final String sessionId; - TautulliActivityDetailsMetadata({ + TautulliActivityDetailsMetadataAction({ Key key, @required this.sessionId, }): super(key: key); @override - Widget build(BuildContext context) => Selector>( - selector: (_, state) => state.activity, - builder: (context, future, _) => FutureBuilder( - future: future, + Widget build(BuildContext context) { + return FutureBuilder( + future: context.select>((state) => state.activity), builder: (context, AsyncSnapshot snapshot) { if(snapshot.hasError) return Container(); if(snapshot.hasData) { TautulliSession session = snapshot.data.sessions.firstWhere((element) => element.sessionId == sessionId, orElse: () => null); - if(session != null) return LSIconButton( + if(session != null) return LunaIconButton( icon: Icons.info_outline, onPressed: () async => _onPressed(context, session), ); } return Container(); }, - ), - ); + ); + } - Future _onPressed(BuildContext context, TautulliSession session) => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: session.ratingKey, mediaType: session.mediaType); + Future _onPressed(BuildContext context, TautulliSession session) => TautulliMediaDetailsRouter().navigateTo( + context, + ratingKey: session.ratingKey, + mediaType: session.mediaType, + ); } diff --git a/lib/modules/tautulli/routes/activity_details/widgets/user.dart b/lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart similarity index 68% rename from lib/modules/tautulli/routes/activity_details/widgets/user.dart rename to lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart index 4bbf1d82..527de9cb 100644 --- a/lib/modules/tautulli/routes/activity_details/widgets/user.dart +++ b/lib/modules/tautulli/routes/activity_details/widgets/appbar_user_action.dart @@ -3,34 +3,33 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliActivityDetailsUser extends StatelessWidget { +class TautulliActivityDetailsUserAction extends StatelessWidget { final String sessionId; - TautulliActivityDetailsUser({ + TautulliActivityDetailsUserAction({ Key key, @required this.sessionId, }): super(key: key); @override - Widget build(BuildContext context) => Selector>( - selector: (_, state) => state.activity, - builder: (context, future, _) => FutureBuilder( - future: future, + Widget build(BuildContext context) { + return FutureBuilder( + future: context.select>((state) => state.activity), builder: (context, AsyncSnapshot snapshot) { if(snapshot.hasError) return Container(); if(snapshot.hasData) { TautulliSession session = snapshot.data.sessions.firstWhere((element) => element.sessionId == sessionId, orElse: () => null); - if(session != null) return LSIconButton( + if(session != null) return LunaIconButton( icon: Icons.person, onPressed: () async => _onPressed(context, session.userId), ); } return Container(); }, - ), - ); + ); + } - Future _onPressed(BuildContext context, int userId) => TautulliUserDetailsRouter.navigateTo( + Future _onPressed(BuildContext context, int userId) => TautulliUserDetailsRouter().navigateTo( context, userId: userId, ); diff --git a/lib/modules/tautulli/routes/activity_details/widgets/block_metadata.dart b/lib/modules/tautulli/routes/activity_details/widgets/block_metadata.dart new file mode 100644 index 00000000..e481436e --- /dev/null +++ b/lib/modules/tautulli/routes/activity_details/widgets/block_metadata.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class TautulliActivityDetailsMetadataBlock extends StatelessWidget { + final TautulliSession session; + + TautulliActivityDetailsMetadataBlock({ + Key key, + @required this.session, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return LunaTableCard( + content: [ + LunaTableContent(title: 'tautulli.Title'.tr(), body: session.lunaFullTitle), + if(session.year != null) LunaTableContent(title: 'tautulli.Year'.tr(), body: session.lunaYear), + LunaTableContent(title: 'tautulli.Duration'.tr(), body: session.lunaDuration), + LunaTableContent(title: 'tautulli.ETA'.tr(), body: session.lunaETA), + LunaTableContent(title: 'tautulli.Library'.tr(), body: session.lunaLibraryName), + LunaTableContent(title: 'tautulli.User'.tr(), body: session.lunaFriendlyName), + ], + ); + } +} diff --git a/lib/modules/tautulli/routes/activity_details/widgets/block_player.dart b/lib/modules/tautulli/routes/activity_details/widgets/block_player.dart new file mode 100644 index 00000000..9bc7fd3a --- /dev/null +++ b/lib/modules/tautulli/routes/activity_details/widgets/block_player.dart @@ -0,0 +1,25 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class TautulliActivityDetailsPlayerBlock extends StatelessWidget { + final TautulliSession session; + + TautulliActivityDetailsPlayerBlock({ + Key key, + @required this.session, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return LunaTableCard( + content: [ + LunaTableContent(title: 'tautulli.Location'.tr(), body: session.lunaIPAddress), + LunaTableContent(title: 'tautulli.Platform'.tr(), body: session.lunaPlatform), + LunaTableContent(title: 'tautulli.Product'.tr(), body: session.lunaProduct), + LunaTableContent(title: 'tautulli.Player'.tr(), body: session.lunaPlayer), + LunaTableContent(title: 'tautulli.Quality'.tr(), body: session.lunaQuality), + ], + ); + } +} diff --git a/lib/modules/tautulli/routes/activity_details/widgets/block_stream.dart b/lib/modules/tautulli/routes/activity_details/widgets/block_stream.dart new file mode 100644 index 00000000..500ebef0 --- /dev/null +++ b/lib/modules/tautulli/routes/activity_details/widgets/block_stream.dart @@ -0,0 +1,26 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class TautulliActivityDetailsStreamBlock extends StatelessWidget { + final TautulliSession session; + + TautulliActivityDetailsStreamBlock({ + Key key, + @required this.session, + }) : super(key: key); + + @override + Widget build(BuildContext context) { + return LunaTableCard( + content: [ + LunaTableContent(title: 'tautulli.Bandwidth'.tr(), body: session.lunaBandwidth), + LunaTableContent(title: 'tautulli.Stream'.tr(), body: session.lunaTranscodeDecision), + LunaTableContent(title: 'tautulli.Container'.tr(), body: session.lunaContainer), + LunaTableContent(title: 'tautulli.Video'.tr(), body: session.lunaVideo), + LunaTableContent(title: 'tautulli.Audio'.tr(), body: session.lunaAudio), + LunaTableContent(title: 'tautulli.Subtitle'.tr(), body: session.lunaSubtitle), + ], + ); + } +} diff --git a/lib/modules/tautulli/routes/activity_details/widgets/button_terminate_session.dart b/lib/modules/tautulli/routes/activity_details/widgets/button_terminate_session.dart new file mode 100644 index 00000000..cc1af6b2 --- /dev/null +++ b/lib/modules/tautulli/routes/activity_details/widgets/button_terminate_session.dart @@ -0,0 +1,32 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; +import 'package:tautulli/tautulli.dart'; + +class TautulliActivityDetailsTerminateSessionButton extends StatelessWidget { + final TautulliSession session; + + TautulliActivityDetailsTerminateSessionButton({ + Key key, + @required this.session, + }): super(key: key); + + @override + Widget build(BuildContext context) { + return LunaButtonContainer( + children: [ + LunaButton( + text: 'tautulli.TerminateSession'.tr(), + backgroundColor: LunaColours.red, + onTap: () async { + Tuple2 _result = await TautulliDialogs().terminateSession(context); + if(_result.item1) TautulliAPIHelper().terminateSession(context: context, session: session, terminationMessage: _result.item2) + .then((value) { + if(value) Navigator.of(context).pop(); + }); + }, + ), + ], + ); + } +} diff --git a/lib/modules/tautulli/routes/activity_details/widgets/information.dart b/lib/modules/tautulli/routes/activity_details/widgets/information.dart deleted file mode 100644 index b94d1847..00000000 --- a/lib/modules/tautulli/routes/activity_details/widgets/information.dart +++ /dev/null @@ -1,65 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/tautulli.dart'; -import 'package:tautulli/tautulli.dart'; - -class TautulliActivityDetailsInformation extends StatelessWidget { - final TautulliSession session; - - TautulliActivityDetailsInformation({ - Key key, - @required this.session, - }): super(key: key); - - @override - Widget build(BuildContext context) => LSListView( - children: [ - TautulliActivityTile(session: session, disableOnTap: true), - TautulliActivityDetailsTerminateSession(session: session), - _metadataBlock, - _playerBlock, - _streamBlock, - ], - ); - - Widget get _metadataBlock => LSTableBlock( - title: 'Metadata', - children: [ - LSTableContent(title: 'title', body: session.lsFullTitle), - LSTableContent(title: 'year', body: session.year.toString()), - LSTableContent(title: 'duration', body: session.lsDuration), - LSTableContent(title: 'eta', body: session.lunaETA), - LSTableContent(title: 'library', body: session.libraryName), - LSTableContent(title: 'user', body: session.friendlyName), - ] - ); - - Widget get _playerBlock => LSTableBlock( - title: 'Player', - children: [ - LSTableContent(title: 'location', body: session.ipAddress), - LSTableContent(title: 'platform', body: [ - session.platform, - if(session.platformVersion != null && session.platformVersion.isNotEmpty) '(${session.platformVersion})', - ].join(' ')), - LSTableContent(title: 'product', body: session.product), - LSTableContent(title: 'player', body: session.player), - LSTableContent(title: 'quality', body: session.lsQuality), - ], - ); - - Widget get _streamBlock => LSTableBlock( - title: 'Stream', - children: [ - LSTableContent(title: 'bandwidth', body: session.lsBandwidth), - LSTableContent(title: 'stream', body: session.lsStream), - LSTableContent(title: 'container', body: session.lsContainer), - if(session.streamVideoDecision != null && session.streamVideoDecision != TautulliTranscodeDecision.NULL) - LSTableContent(title: 'video', body: session.lsVideo), - if(session.streamAudioDecision != null && session.streamAudioDecision != TautulliTranscodeDecision.NULL) - LSTableContent(title: 'audio', body: session.lsAudio), - if(session.subtitles != null && session.subtitles) - LSTableContent(title: 'subtitle', body: session.lsSubtitle), - ], - ); -} diff --git a/lib/modules/tautulli/routes/activity_details/widgets/terminate_session.dart b/lib/modules/tautulli/routes/activity_details/widgets/terminate_session.dart deleted file mode 100644 index dc087194..00000000 --- a/lib/modules/tautulli/routes/activity_details/widgets/terminate_session.dart +++ /dev/null @@ -1,46 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/tautulli.dart'; -import 'package:tautulli/tautulli.dart'; - -class TautulliActivityDetailsTerminateSession extends StatelessWidget { - final TautulliSession session; - - TautulliActivityDetailsTerminateSession({ - Key key, - @required this.session, - }): super(key: key); - - @override - Widget build(BuildContext context) => LSButton( - text: 'Terminate Session', - backgroundColor: LunaColours.red, - onTap: () async => _onPressed(context), - ); - - Future _onPressed(BuildContext context) async { - List _values = await TautulliDialogs.terminateSession(context); - if(_values[0]) { - context.read().api.activity.terminateSession( - sessionId: session.sessionId, - message: _values[1] != null && (_values[1] as String).isNotEmpty ? _values[1] : null, - ) - .then((_) { - LSSnackBar( - context: context, - title: 'Terminated Session', - message: '${session.friendlyName}\t${Constants.TEXT_EMDASH}\t${session.title}', - ); - Navigator.of(context).pop(); - }) - .catchError((error, trace) { - LunaLogger().error('Unable to terminate session: ${session.sessionId}', error, trace); - LSSnackBar( - context: context, - title: 'Failed to Terminate Session', - type: SNACKBAR_TYPE.failure, - ); - }); - } - } -} diff --git a/lib/modules/tautulli/routes/check_for_updates/route.dart b/lib/modules/tautulli/routes/check_for_updates/route.dart index 838a57dc..94afb352 100644 --- a/lib/modules/tautulli/routes/check_for_updates/route.dart +++ b/lib/modules/tautulli/routes/check_for_updates/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliCheckForUpdatesRouter { - static const ROUTE_NAME = '/tautulli/more/checkforupdates'; +class TautulliCheckForUpdatesRouter extends TautulliPageRouter { + TautulliCheckForUpdatesRouter() : super('/tautulli/more/checkforupdates'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliCheckForUpdatesRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliCheckForUpdatesRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliCheckForUpdatesRoute()); } class _TautulliCheckForUpdatesRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/check_for_updates/widgets/tautulli_tile.dart b/lib/modules/tautulli/routes/check_for_updates/widgets/tautulli_tile.dart index 46a1e54b..d74a55c2 100644 --- a/lib/modules/tautulli/routes/check_for_updates/widgets/tautulli_tile.dart +++ b/lib/modules/tautulli/routes/check_for_updates/widgets/tautulli_tile.dart @@ -1,3 +1,5 @@ +import 'dart:math'; + import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:tautulli/tautulli.dart'; @@ -51,10 +53,10 @@ class TautulliCheckForUpdatesTautulliTile extends StatelessWidget { ), ), if(update.update) TextSpan( - text: 'Current Version: ${update.currentRelease?? update.currentVersion?.substring(0, 7) ?? 'Unknown'}\n', + text: 'Current Version: ${update.currentRelease?? update.currentVersion?.substring(0, min(7, update.currentVersion?.length ?? 0)) ?? 'Unknown'}\n', ), if(update.update) TextSpan( - text: 'Latest Version: ${update.latestRelease?? update.latestVersion?.substring(0, 7) ?? 'Unknown'}\n', + text: 'Latest Version: ${update.latestRelease?? update.latestVersion?.substring(0, min(7, update.latestVersion?.length ?? 0)) ?? 'Unknown'}\n', ), TextSpan(text: 'Install Type: ${update.installType}'), ], diff --git a/lib/modules/tautulli/routes/graphs/route.dart b/lib/modules/tautulli/routes/graphs/route.dart index 5f7c5810..8e02dfe0 100644 --- a/lib/modules/tautulli/routes/graphs/route.dart +++ b/lib/modules/tautulli/routes/graphs/route.dart @@ -1,27 +1,12 @@ -import 'package:fluro/fluro.dart'; import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; -class TautulliGraphsRouter { - static const String ROUTE_NAME = '/tautulli/more/graphs'; +class TautulliGraphsRouter extends TautulliPageRouter { + TautulliGraphsRouter() : super('/tautulli/graphs'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliGraphsRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliGraphsRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliGraphsRoute()); } class _TautulliGraphsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart index 1fb4a7df..46383f89 100644 --- a/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/graphs/widgets/navigation_bar.dart @@ -53,6 +53,6 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } diff --git a/lib/modules/tautulli/routes/history/widgets/history_tile.dart b/lib/modules/tautulli/routes/history/widgets/history_tile.dart index 2347d4f0..dc8d8069 100644 --- a/lib/modules/tautulli/routes/history/widgets/history_tile.dart +++ b/lib/modules/tautulli/routes/history/widgets/history_tile.dart @@ -41,7 +41,7 @@ class TautulliHistoryTile extends StatelessWidget { headers: context.watch().headers.cast(), height: _imageDimension, width: _imageDimension/1.5, - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', ); Widget get _details => Expanded( @@ -106,7 +106,7 @@ class TautulliHistoryTile extends StatelessWidget { ], ); - Future _onTap(BuildContext context) async => TautulliHistoryDetailsRouter.navigateTo( + Future _onTap(BuildContext context) async => TautulliHistoryDetailsRouter().navigateTo( context, ratingKey: history.ratingKey, sessionKey: history.sessionKey, diff --git a/lib/modules/tautulli/routes/history_details/route.dart b/lib/modules/tautulli/routes/history_details/route.dart index 30771681..4e25f817 100644 --- a/lib/modules/tautulli/routes/history_details/route.dart +++ b/lib/modules/tautulli/routes/history_details/route.dart @@ -5,10 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliHistoryDetailsRouter { - static const String ROUTE_NAME = '/tautulli/history/details/:ratingkey/:key/:value'; +class TautulliHistoryDetailsRouter extends TautulliPageRouter { + TautulliHistoryDetailsRouter() : super('/tautulli/history/:ratingkey/:key/:value'); - static Future navigateTo(BuildContext context, { + @override + Future navigateTo(BuildContext context, { @required int ratingKey, int referenceId, int sessionKey, @@ -17,30 +18,29 @@ class TautulliHistoryDetailsRouter { route(ratingKey: ratingKey, referenceId: referenceId, sessionKey: sessionKey), ); - static String route({ + @override + String route({ @required int ratingKey, int referenceId, int sessionKey, }) { - String _route = '/tautulli'; - if(referenceId != null) _route = '/tautulli/history/details/$ratingKey/referenceid/$referenceId'; - if(sessionKey != null) _route = '/tautulli/history/details/$ratingKey/sessionkey/$sessionKey'; + String _route = TautulliHomeRouter().route(); + if(referenceId != null) _route = fullRoute.replaceFirst(':ratingkey', ratingKey.toString()).replaceFirst(':key', 'referenceid').replaceFirst(':value', referenceId.toString()); + if(sessionKey != null) _route = fullRoute.replaceFirst(':ratingkey', ratingKey.toString()).replaceFirst(':key', 'sessionkey').replaceFirst(':value', sessionKey.toString()); return _route; } - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliHistoryDetailsRoute( - ratingKey: int.tryParse(params['ratingkey'][0]), - sessionKey: params['key'][0] == 'sessionkey' ? int.tryParse(params['value'][0]) : null, - referenceId: params['key'][0] == 'referenceid' ? int.tryParse(params['value'][0]) : null, - )), - transitionType: LunaRouter.transitionType, + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int ratingKey = params['ratingkey'] == null || params['ratingkey'].length == 0 ? -1 : int.tryParse(params['ratingkey'][0]) ?? -1; + int referenceId = params['value'] == null || params['value'].length == 0 ? -1 : int.tryParse(params['value'][0]) ?? -1; + int sessionKey = params['value'] == null || params['value'].length == 0 ? -1 : int.tryParse(params['value'][0]) ?? -1; + return _TautulliHistoryDetailsRoute( + ratingKey: ratingKey, + referenceId: params['key'][0] == 'referenceid' ? referenceId : null, + sessionKey: params['key'][0] == 'sessionkey' ? sessionKey : null, ); - } - - TautulliHistoryDetailsRouter._(); + }); } class _TautulliHistoryDetailsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/history_details/widgets/information.dart b/lib/modules/tautulli/routes/history_details/widgets/information.dart index 0c29c6a4..78c9c85c 100644 --- a/lib/modules/tautulli/routes/history_details/widgets/information.dart +++ b/lib/modules/tautulli/routes/history_details/widgets/information.dart @@ -26,7 +26,7 @@ class TautulliHistoryDetailsInformation extends StatelessWidget { children: [ LSTableContent(title: 'status', body: history.lsStatus), LSTableContent(title: 'title', body: history.lsFullTitle), - LSTableContent(title: 'year', body: history.year.toString()), + if(history.year != null) LSTableContent(title: 'year', body: history.year.toString()), LSTableContent(title: 'user', body: history.friendlyName), ], ); diff --git a/lib/modules/tautulli/routes/history_details/widgets/metadata.dart b/lib/modules/tautulli/routes/history_details/widgets/metadata.dart index a2cb62cc..d0e03f8a 100644 --- a/lib/modules/tautulli/routes/history_details/widgets/metadata.dart +++ b/lib/modules/tautulli/routes/history_details/widgets/metadata.dart @@ -34,5 +34,5 @@ class TautulliHistoryDetailsMetadata extends StatelessWidget { }, ); - Future _onPressed(BuildContext context, TautulliHistoryRecord record) => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: record.ratingKey, mediaType: record.mediaType); + Future _onPressed(BuildContext context, TautulliHistoryRecord record) => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: record.ratingKey, mediaType: record.mediaType); } diff --git a/lib/modules/tautulli/routes/history_details/widgets/user.dart b/lib/modules/tautulli/routes/history_details/widgets/user.dart index f690d8a5..46c4b814 100644 --- a/lib/modules/tautulli/routes/history_details/widgets/user.dart +++ b/lib/modules/tautulli/routes/history_details/widgets/user.dart @@ -34,7 +34,7 @@ class TautulliHistoryDetailsUser extends StatelessWidget { }, ); - Future _onPressed(BuildContext context, int userId) => TautulliUserDetailsRouter.navigateTo( + Future _onPressed(BuildContext context, int userId) => TautulliUserDetailsRouter().navigateTo( context, userId: userId, ); diff --git a/lib/modules/tautulli/routes/ipaddress_details/route.dart b/lib/modules/tautulli/routes/ipaddress_details/route.dart index a2530397..a339c9b3 100644 --- a/lib/modules/tautulli/routes/ipaddress_details/route.dart +++ b/lib/modules/tautulli/routes/ipaddress_details/route.dart @@ -5,29 +5,20 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliIPAddressDetailsRouter { - static const String ROUTE_NAME = '/tautulli/ipaddress/:ipaddress'; +class TautulliIPAddressDetailsRouter extends TautulliPageRouter { + TautulliIPAddressDetailsRouter() : super('/tautulli/ipaddress/:ipaddress'); - static Future navigateTo(BuildContext context, { - @required String ip, - }) async => LunaRouter.router.navigateTo( - context, - route(ip: ip), - ); + @override + Future navigateTo(BuildContext context, { @required String ipAddress }) async => LunaRouter.router.navigateTo(context, route(ipAddress: ipAddress)); - static String route({ @required String ip }) => ROUTE_NAME.replaceFirst(':ipaddress', ip ?? '0'); + @override + String route({ @required String ipAddress }) => fullRoute.replaceFirst(':ipaddress', ipAddress); - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliIPAddressRoute( - ipAddress: params['ipaddress'] != null && params['ipaddress'].length != 0 ? params['ipaddress'][0] : null, - )), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliIPAddressDetailsRouter._(); + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + String ipAddress = params['ipaddress'] == null || params['ipaddress'].length == 0 ? null : params['ipaddress'][0]; + return _TautulliIPAddressRoute(ipAddress: ipAddress); + }); } class _TautulliIPAddressRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/libraries/route.dart b/lib/modules/tautulli/routes/libraries/route.dart index 6d42b3c3..6df12caa 100644 --- a/lib/modules/tautulli/routes/libraries/route.dart +++ b/lib/modules/tautulli/routes/libraries/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLibrariesRouter { - static const String ROUTE_NAME = '/tautulli/libraries/list'; +class TautulliLibrariesRouter extends TautulliPageRouter { + TautulliLibrariesRouter() : super('/tautulli/libraries'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLibrariesRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLibrariesRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLibrariesRoute()); } class _TautulliLibrariesRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/libraries/widgets/library_tile.dart b/lib/modules/tautulli/routes/libraries/widgets/library_tile.dart index bde7867e..9f2c2e54 100644 --- a/lib/modules/tautulli/routes/libraries/widgets/library_tile.dart +++ b/lib/modules/tautulli/routes/libraries/widgets/library_tile.dart @@ -47,5 +47,5 @@ class TautulliLibrariesLibraryTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) => TautulliLibrariesDetailsRouter.navigateTo(context, sectionId: library.sectionId); + Future _onTap(BuildContext context) => TautulliLibrariesDetailsRouter().navigateTo(context, sectionId: library.sectionId); } diff --git a/lib/modules/tautulli/routes/libraries_details/route.dart b/lib/modules/tautulli/routes/libraries_details/route.dart index f993240d..cf5117cb 100644 --- a/lib/modules/tautulli/routes/libraries_details/route.dart +++ b/lib/modules/tautulli/routes/libraries_details/route.dart @@ -3,31 +3,20 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; -class TautulliLibrariesDetailsRouter { - static const String ROUTE_NAME = '/tautulli/libraries/details/:sectionid'; +class TautulliLibrariesDetailsRouter extends TautulliPageRouter { + TautulliLibrariesDetailsRouter() : super('/tautulli/libraries/:sectionid'); - static Future navigateTo(BuildContext context, { - @required int sectionId, - }) async => LunaRouter.router.navigateTo( - context, - route(sectionId: sectionId), - ); + @override + Future navigateTo(BuildContext context, { @required int sectionId }) async => LunaRouter.router.navigateTo(context, route(sectionId: sectionId)); - static String route({ @required int sectionId }) => ROUTE_NAME.replaceFirst(':sectionid', sectionId?.toString() ?? '-1'); + @override + String route({ @required int sectionId }) => fullRoute.replaceFirst(':sectionid', sectionId.toString()); - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLibrariesDetailsRoute( - sectionId: params['sectionid'] != null && params['sectionid'].length != 0 - ? int.tryParse(params['sectionid'][0]) ?? -1 - : -1, - )), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLibrariesDetailsRouter._(); + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int sectionId = params['sectionid'] == null || params['sectionid'].length == 0 ? -1 : int.tryParse(params['sectionid'][0]) ?? -1; + return _TautulliLibrariesDetailsRoute(sectionId: sectionId); + }); } class _TautulliLibrariesDetailsRoute extends StatefulWidget { 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 1d31a3a6..564871fd 100644 --- a/lib/modules/tautulli/routes/libraries_details/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/libraries_details/widgets/navigation_bar.dart @@ -53,6 +53,6 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } diff --git a/lib/modules/tautulli/routes/libraries_details/widgets/user_stats_tile.dart b/lib/modules/tautulli/routes/libraries_details/widgets/user_stats_tile.dart index 3dbec637..1a0d8b91 100644 --- a/lib/modules/tautulli/routes/libraries_details/widgets/user_stats_tile.dart +++ b/lib/modules/tautulli/routes/libraries_details/widgets/user_stats_tile.dart @@ -32,7 +32,7 @@ class TautulliLibrariesDetailsUserStatsTile extends StatelessWidget { Widget _userThumb(BuildContext context) => LSNetworkImage( url: context.watch().getImageURLFromPath(user.userThumb), headers: context.watch().headers.cast(), - placeholder: 'assets/images/tautulli/nouserthumb.png', + placeholder: 'assets/images/blanks/user.png', height: _imageDimension, width: _imageDimension, ); @@ -94,7 +94,7 @@ class TautulliLibrariesDetailsUserStatsTile extends StatelessWidget { ], ); - Future _onPressed(BuildContext context) => TautulliUserDetailsRouter.navigateTo( + Future _onPressed(BuildContext context) => TautulliUserDetailsRouter().navigateTo( context, userId: user.userId, ); diff --git a/lib/modules/tautulli/routes/logs/route.dart b/lib/modules/tautulli/routes/logs/route.dart index 2f8cf4a9..ac0e463d 100644 --- a/lib/modules/tautulli/routes/logs/route.dart +++ b/lib/modules/tautulli/routes/logs/route.dart @@ -3,25 +3,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; -class TautulliLogsRouter { - static const String ROUTE_NAME = '/tautulli/logs/list'; +class TautulliLogsRouter extends TautulliPageRouter { + TautulliLogsRouter() : super('/tautulli/logs'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsRoute()); } class _TautulliLogsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/logs/widgets/logins_tile.dart b/lib/modules/tautulli/routes/logs/widgets/logins_tile.dart index 40245641..23fe2ad3 100644 --- a/lib/modules/tautulli/routes/logs/widgets/logins_tile.dart +++ b/lib/modules/tautulli/routes/logs/widgets/logins_tile.dart @@ -14,5 +14,5 @@ class TautulliLogsLoginsTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsLoginsRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsLoginsRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/logs/widgets/newsletters_tile.dart b/lib/modules/tautulli/routes/logs/widgets/newsletters_tile.dart index 187097f4..c6f2cef0 100644 --- a/lib/modules/tautulli/routes/logs/widgets/newsletters_tile.dart +++ b/lib/modules/tautulli/routes/logs/widgets/newsletters_tile.dart @@ -14,5 +14,5 @@ class TautulliLogsNewslettersTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsNewslettersRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsNewslettersRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/logs/widgets/notifications_tile.dart b/lib/modules/tautulli/routes/logs/widgets/notifications_tile.dart index a43b9907..15fea7ca 100644 --- a/lib/modules/tautulli/routes/logs/widgets/notifications_tile.dart +++ b/lib/modules/tautulli/routes/logs/widgets/notifications_tile.dart @@ -14,5 +14,5 @@ class TautulliLogsNotificationsTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsNotificationsRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsNotificationsRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/logs/widgets/plex_media_scanner.dart b/lib/modules/tautulli/routes/logs/widgets/plex_media_scanner.dart index 93eb0f58..9fc35a8e 100644 --- a/lib/modules/tautulli/routes/logs/widgets/plex_media_scanner.dart +++ b/lib/modules/tautulli/routes/logs/widgets/plex_media_scanner.dart @@ -14,5 +14,5 @@ class TautulliLogsPlexMediaScannerTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsPlexMediaScannerRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsPlexMediaScannerRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/logs/widgets/plex_media_server_tile.dart b/lib/modules/tautulli/routes/logs/widgets/plex_media_server_tile.dart index 70aff506..a6f75156 100644 --- a/lib/modules/tautulli/routes/logs/widgets/plex_media_server_tile.dart +++ b/lib/modules/tautulli/routes/logs/widgets/plex_media_server_tile.dart @@ -14,5 +14,5 @@ class TautulliLogsPlexMediaServerTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsPlexMediaServerRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsPlexMediaServerRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/logs/widgets/tautulli_tile.dart b/lib/modules/tautulli/routes/logs/widgets/tautulli_tile.dart index 09e605f7..7f216ff7 100644 --- a/lib/modules/tautulli/routes/logs/widgets/tautulli_tile.dart +++ b/lib/modules/tautulli/routes/logs/widgets/tautulli_tile.dart @@ -14,5 +14,5 @@ class TautulliLogsTautulliTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsTautulliRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsTautulliRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/logs_logins/route.dart b/lib/modules/tautulli/routes/logs_logins/route.dart index 2772cf4f..9ec861ec 100644 --- a/lib/modules/tautulli/routes/logs_logins/route.dart +++ b/lib/modules/tautulli/routes/logs_logins/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLogsLoginsRouter { - static const String ROUTE_NAME = '/tautulli/logs/logins'; +class TautulliLogsLoginsRouter extends TautulliPageRouter { + TautulliLogsLoginsRouter() : super('/tautulli/logs/logins'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsLoginsRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsLoginsRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsLoginsRoute()); } class _TautulliLogsLoginsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/logs_newsletters/route.dart b/lib/modules/tautulli/routes/logs_newsletters/route.dart index aa45e538..4c0c9cd0 100644 --- a/lib/modules/tautulli/routes/logs_newsletters/route.dart +++ b/lib/modules/tautulli/routes/logs_newsletters/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLogsNewslettersRouter { - static const String ROUTE_NAME = '/tautulli/logs/newsletters'; +class TautulliLogsNewslettersRouter extends TautulliPageRouter { + TautulliLogsNewslettersRouter() : super('/tautulli/logs/newsletters'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsNewslettersRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsNewslettersRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsNewslettersRoute()); } class _TautulliLogsNewslettersRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/logs_notifications/route.dart b/lib/modules/tautulli/routes/logs_notifications/route.dart index 2369975e..e9926e63 100644 --- a/lib/modules/tautulli/routes/logs_notifications/route.dart +++ b/lib/modules/tautulli/routes/logs_notifications/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLogsNotificationsRouter { - static const String ROUTE_NAME = '/tautulli/logs/notifications'; +class TautulliLogsNotificationsRouter extends TautulliPageRouter { + TautulliLogsNotificationsRouter() : super('/tautulli/logs/notifications'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsNotificationsRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsNotificationsRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsNotificationsRoute()); } class _TautulliLogsNotificationsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/logs_plex_media_scanner/route.dart b/lib/modules/tautulli/routes/logs_plex_media_scanner/route.dart index a74f6726..878e1692 100644 --- a/lib/modules/tautulli/routes/logs_plex_media_scanner/route.dart +++ b/lib/modules/tautulli/routes/logs_plex_media_scanner/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLogsPlexMediaScannerRouter { - static const String ROUTE_NAME = '/tautulli/logs/plexmediascanner'; +class TautulliLogsPlexMediaScannerRouter extends TautulliPageRouter { + TautulliLogsPlexMediaScannerRouter() : super('/tautulli/logs/plexmediascanner'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsPlexMediaScannerRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsPlexMediaScannerRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsPlexMediaScannerRoute()); } class _TautulliLogsPlexMediaScannerRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/logs_plex_media_server/route.dart b/lib/modules/tautulli/routes/logs_plex_media_server/route.dart index daad535b..785a4a10 100644 --- a/lib/modules/tautulli/routes/logs_plex_media_server/route.dart +++ b/lib/modules/tautulli/routes/logs_plex_media_server/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLogsPlexMediaServerRouter { - static const String ROUTE_NAME = '/tautulli/logs/plexmediaserver'; +class TautulliLogsPlexMediaServerRouter extends TautulliPageRouter { + TautulliLogsPlexMediaServerRouter() : super('/tautulli/logs/plexmediaserver'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsPlexMediaServerRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsPlexMediaServerRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsPlexMediaServerRoute()); } class _TautulliLogsPlexMediaServerRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/logs_tautulli/route.dart b/lib/modules/tautulli/routes/logs_tautulli/route.dart index 4e2ddea1..321bdd01 100644 --- a/lib/modules/tautulli/routes/logs_tautulli/route.dart +++ b/lib/modules/tautulli/routes/logs_tautulli/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliLogsTautulliRouter { - static const String ROUTE_NAME = '/tautulli/logs/tautulli'; +class TautulliLogsTautulliRouter extends TautulliPageRouter { + TautulliLogsTautulliRouter() : super('/tautulli/logs/tautulli'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliLogsTautulliRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliLogsTautulliRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliLogsTautulliRoute()); } class _TautulliLogsTautulliRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/media_details/route.dart b/lib/modules/tautulli/routes/media_details/route.dart index c56c5b94..452685e8 100644 --- a/lib/modules/tautulli/routes/media_details/route.dart +++ b/lib/modules/tautulli/routes/media_details/route.dart @@ -4,40 +4,27 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliMediaDetailsRouter { - static const String ROUTE_NAME = '/tautulli/media/details/:mediatype/:ratingkey'; +class TautulliMediaDetailsRouter extends TautulliPageRouter { + TautulliMediaDetailsRouter() : super('/tautulli/media/:mediatype/:ratingkey'); - static Future navigateTo(BuildContext context, { + @override + Future navigateTo(BuildContext context, { @required int ratingKey, @required TautulliMediaType mediaType, - }) async => LunaRouter.router.navigateTo( - context, - route(ratingKey: ratingKey, mediaType: mediaType), - ); + }) async => LunaRouter.router.navigateTo(context, route(ratingKey: ratingKey, mediaType: mediaType)); - static String route({ + @override + String route({ @required int ratingKey, @required TautulliMediaType mediaType, - }) => ROUTE_NAME - .replaceFirst(':mediatype', mediaType?.value ?? 'mediatype') - .replaceFirst(':ratingkey', ratingKey.toString()); - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliMediaDetailsRoute( - ratingKey: params['ratingkey'] != null && params['ratingkey'].length != 0 - ? int.tryParse(params['ratingkey'][0]) - : null, - mediaType: params['mediatype'] != null && params['mediatype'].length != 0 - ? TautulliMediaType.NULL.from(params['mediatype'][0]) - : null, - )), - transitionType: LunaRouter.transitionType, - ); - } + }) => fullRoute.replaceFirst(':mediatype', mediaType?.value ?? 'mediatype').replaceFirst(':ratingkey', ratingKey.toString()); - TautulliMediaDetailsRouter._(); + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + TautulliMediaType mediaType = params['mediatype'] == null || params['mediatype'].length == 0 ? null : TautulliMediaType.NULL.from(params['mediatype'][0]); + int ratingKey = params['ratingkey'] == null || params['ratingkey'].length == 0 ? -1 : int.tryParse(params['ratingkey'][0]) ?? -1; + return _TautulliMediaDetailsRoute(ratingKey: ratingKey, mediaType: mediaType); + }); } class _TautulliMediaDetailsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/media_details/widgets/metadata_header.dart b/lib/modules/tautulli/routes/media_details/widgets/metadata_header.dart index 11cc7470..6201a550 100644 --- a/lib/modules/tautulli/routes/media_details/widgets/metadata_header.dart +++ b/lib/modules/tautulli/routes/media_details/widgets/metadata_header.dart @@ -56,7 +56,7 @@ class TautulliMediaDetailsMetadataHeaderTile extends StatelessWidget { Widget _poster(BuildContext context) { return LSNetworkImage( url: context.watch().getImageURLFromPath(_posterLink), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _height, width: _width, headers: context.watch().headers.cast(), 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 56488dc1..30fc453d 100644 --- a/lib/modules/tautulli/routes/media_details/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/media_details/widgets/navigation_bar.dart @@ -53,6 +53,6 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } diff --git a/lib/modules/tautulli/routes/more/widgets/check_for_updates_tile.dart b/lib/modules/tautulli/routes/more/widgets/check_for_updates_tile.dart index 33de3219..dba7d848 100644 --- a/lib/modules/tautulli/routes/more/widgets/check_for_updates_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/check_for_updates_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreCheckForUpdatesTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliCheckForUpdatesRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliCheckForUpdatesRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/graphs_tile.dart b/lib/modules/tautulli/routes/more/widgets/graphs_tile.dart index af2050b9..5c3e6376 100644 --- a/lib/modules/tautulli/routes/more/widgets/graphs_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/graphs_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreGraphsTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliGraphsRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliGraphsRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/libraries_tile.dart b/lib/modules/tautulli/routes/more/widgets/libraries_tile.dart index eda8f319..9afb1af0 100644 --- a/lib/modules/tautulli/routes/more/widgets/libraries_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/libraries_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreLibrariesTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLibrariesRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLibrariesRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/logs_tile.dart b/lib/modules/tautulli/routes/more/widgets/logs_tile.dart index fcf8a1ea..90eccbee 100644 --- a/lib/modules/tautulli/routes/more/widgets/logs_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/logs_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreLogsTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliLogsRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliLogsRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/recently_added_tile.dart b/lib/modules/tautulli/routes/more/widgets/recently_added_tile.dart index 46a286ab..3ab3bbc7 100644 --- a/lib/modules/tautulli/routes/more/widgets/recently_added_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/recently_added_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreRecentlyAddedTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliRecentlyAddedRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliRecentlyAddedRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/search_tile.dart b/lib/modules/tautulli/routes/more/widgets/search_tile.dart index c37e7097..3d294271 100644 --- a/lib/modules/tautulli/routes/more/widgets/search_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/search_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreSearchTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliSearchRouter.navigateTo(context: context); + Future _onTap(BuildContext context) async => TautulliSearchRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/statistics_tile.dart b/lib/modules/tautulli/routes/more/widgets/statistics_tile.dart index 3a456421..1ebedc69 100644 --- a/lib/modules/tautulli/routes/more/widgets/statistics_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/statistics_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreStatisticsTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliStatisticsRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliStatisticsRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/more/widgets/synced_items_tile.dart b/lib/modules/tautulli/routes/more/widgets/synced_items_tile.dart index 69d45b66..5043528f 100644 --- a/lib/modules/tautulli/routes/more/widgets/synced_items_tile.dart +++ b/lib/modules/tautulli/routes/more/widgets/synced_items_tile.dart @@ -14,5 +14,5 @@ class TautulliMoreSyncedItemsTile extends StatelessWidget { onTap: () async => _onTap(context), ); - Future _onTap(BuildContext context) async => TautulliSyncedItemsRouter.navigateTo(context); + Future _onTap(BuildContext context) async => TautulliSyncedItemsRouter().navigateTo(context); } diff --git a/lib/modules/tautulli/routes/recently_added/route.dart b/lib/modules/tautulli/routes/recently_added/route.dart index cff1cc4d..f7c59777 100644 --- a/lib/modules/tautulli/routes/recently_added/route.dart +++ b/lib/modules/tautulli/routes/recently_added/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliRecentlyAddedRouter { - static const String ROUTE_NAME = '/tautulli/recentlyadded/list'; +class TautulliRecentlyAddedRouter extends TautulliPageRouter { + TautulliRecentlyAddedRouter() : super('/tautulli/recentlyadded'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliRecentlyAddedRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliRecentlyAddedRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliRecentlyAddedRoute()); } class _TautulliRecentlyAddedRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/recently_added/widgets/content_tile.dart b/lib/modules/tautulli/routes/recently_added/widgets/content_tile.dart index b065bccc..f6a1cce8 100644 --- a/lib/modules/tautulli/routes/recently_added/widgets/content_tile.dart +++ b/lib/modules/tautulli/routes/recently_added/widgets/content_tile.dart @@ -56,7 +56,7 @@ class TautulliRecentlyAddedContentTile extends StatelessWidget { return LSNetworkImage( url: context.watch().getImageURLFromPath(_posterLink), headers: context.watch().headers.cast(), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _imageDimension, width: _imageDimension/1.5, ); @@ -126,5 +126,5 @@ class TautulliRecentlyAddedContentTile extends StatelessWidget { Widget get _library => LSSubtitle(text: recentlyAdded.libraryName); - Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: recentlyAdded.ratingKey, mediaType: recentlyAdded.mediaType); + Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: recentlyAdded.ratingKey, mediaType: recentlyAdded.mediaType); } diff --git a/lib/modules/tautulli/routes/search/route.dart b/lib/modules/tautulli/routes/search/route.dart index 2cc32159..7bbedfb3 100644 --- a/lib/modules/tautulli/routes/search/route.dart +++ b/lib/modules/tautulli/routes/search/route.dart @@ -3,27 +3,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; -class TautulliSearchRouter { - static const String ROUTE_NAME = '/tautulli/search/library'; +class TautulliSearchRouter extends TautulliPageRouter { + TautulliSearchRouter() : super('/tautulli/search'); - static Future navigateTo({ - @required BuildContext context, - }) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliSearchRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliSearchRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliSearchRoute()); } class _TautulliSearchRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/search/widgets/search_result_tile.dart b/lib/modules/tautulli/routes/search/widgets/search_result_tile.dart index 8776d6b1..5b2296a0 100644 --- a/lib/modules/tautulli/routes/search/widgets/search_result_tile.dart +++ b/lib/modules/tautulli/routes/search/widgets/search_result_tile.dart @@ -39,7 +39,7 @@ class TautulliSearchResultTile extends StatelessWidget { headers: context.watch().headers.cast(), height: _imageDimension, width: _imageDimension/1.5, - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', ); Widget get _details => Expanded( @@ -95,5 +95,5 @@ class TautulliSearchResultTile extends StatelessWidget { ), ); - Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: result.ratingKey, mediaType: mediaType); + Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: result.ratingKey, mediaType: mediaType); } diff --git a/lib/modules/tautulli/routes/statistics/route.dart b/lib/modules/tautulli/routes/statistics/route.dart index 42ee2f1a..214ae975 100644 --- a/lib/modules/tautulli/routes/statistics/route.dart +++ b/lib/modules/tautulli/routes/statistics/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliStatisticsRouter { - static const String ROUTE_NAME = '/tautulli/statistics/list'; +class TautulliStatisticsRouter extends TautulliPageRouter { + TautulliStatisticsRouter() : super('/tautulli/statistics'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliStatisticsRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliStatisticsRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliStatisticsRoute()); } class _TautulliStatisticsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/statistics/widgets/media_tile.dart b/lib/modules/tautulli/routes/statistics/widgets/media_tile.dart index c5e25643..59c6da07 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/media_tile.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/media_tile.dart @@ -41,7 +41,7 @@ class TautulliStatisticsMediaTile extends StatelessWidget { Widget _poster(BuildContext context) => LSNetworkImage( url: context.watch().getImageURLFromPath(data['thumb']), headers: context.watch().headers.cast(), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _imageDimension, width: _imageDimension/1.5, ); @@ -112,5 +112,5 @@ class TautulliStatisticsMediaTile extends StatelessWidget { overflow: TextOverflow.fade, ); - Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: data['rating_key'], mediaType: mediaType); + Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: data['rating_key'], mediaType: mediaType); } \ No newline at end of file diff --git a/lib/modules/tautulli/routes/statistics/widgets/platform_tile.dart b/lib/modules/tautulli/routes/statistics/widgets/platform_tile.dart index 283b9ce9..2c834157 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/platform_tile.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/platform_tile.dart @@ -29,7 +29,7 @@ class TautulliStatisticsPlatformTile extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(Constants.UI_BORDER_RADIUS), image: DecorationImage( - image: AssetImage('assets/images/tautulli/platform.png'), + image: AssetImage('assets/images/blanks/platform.png'), fit: BoxFit.cover, ), ), diff --git a/lib/modules/tautulli/routes/statistics/widgets/recently_watched_tile.dart b/lib/modules/tautulli/routes/statistics/widgets/recently_watched_tile.dart index 1753f101..759d1959 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/recently_watched_tile.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/recently_watched_tile.dart @@ -39,7 +39,7 @@ class TautulliStatisticsRecentlyWatchedTile extends StatelessWidget { Widget _poster(BuildContext context) => LSNetworkImage( url: context.watch().getImageURLFromPath(data['thumb']), headers: context.watch().headers.cast(), - placeholder: 'assets/images/sonarr/noseriesposter.png', + placeholder: 'assets/images/blanks/video.png', height: _imageDimension, width: _imageDimension/1.5, ); @@ -90,5 +90,5 @@ class TautulliStatisticsRecentlyWatchedTile extends StatelessWidget { overflow: TextOverflow.fade, ); - Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: data['rating_key'], mediaType: TautulliMediaType.NULL.from(data['media_type'])); + Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: data['rating_key'], mediaType: TautulliMediaType.NULL.from(data['media_type'])); } diff --git a/lib/modules/tautulli/routes/statistics/widgets/stream_tile.dart b/lib/modules/tautulli/routes/statistics/widgets/stream_tile.dart index 8f79f69e..b9d632cd 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/stream_tile.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/stream_tile.dart @@ -28,7 +28,7 @@ class TautulliStatisticsStreamTile extends StatelessWidget { decoration: BoxDecoration( borderRadius: BorderRadius.circular(Constants.UI_BORDER_RADIUS), image: DecorationImage( - image: AssetImage('assets/images/tautulli/streams.png'), + image: AssetImage('assets/images/blanks/stream.png'), fit: BoxFit.cover, ), ), diff --git a/lib/modules/tautulli/routes/statistics/widgets/user_tile.dart b/lib/modules/tautulli/routes/statistics/widgets/user_tile.dart index c65a2bed..87b6d7f2 100644 --- a/lib/modules/tautulli/routes/statistics/widgets/user_tile.dart +++ b/lib/modules/tautulli/routes/statistics/widgets/user_tile.dart @@ -30,7 +30,7 @@ class TautulliStatisticsUserTile extends StatelessWidget { Widget _poster(BuildContext context) => LSNetworkImage( url: context.watch().getImageURLFromPath(data['user_thumb']), headers: context.watch().headers.cast(), - placeholder: 'assets/images/tautulli/nouserthumb.png', + placeholder: 'assets/images/blanks/user.png', height: _imageDimension, width: _imageDimension/1.5, ); @@ -116,7 +116,7 @@ class TautulliStatisticsUserTile extends StatelessWidget { type: SNACKBAR_TYPE.failure, ); } else { - TautulliUserDetailsRouter.navigateTo(context, userId: _user.userId); + TautulliUserDetailsRouter().navigateTo(context, userId: _user.userId); } } } \ No newline at end of file diff --git a/lib/modules/tautulli/routes/synced_items/route.dart b/lib/modules/tautulli/routes/synced_items/route.dart index 34b0ed7a..93f3ab12 100644 --- a/lib/modules/tautulli/routes/synced_items/route.dart +++ b/lib/modules/tautulli/routes/synced_items/route.dart @@ -5,25 +5,11 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliSyncedItemsRouter { - static const String ROUTE_NAME = '/tautulli/synceditems/list'; +class TautulliSyncedItemsRouter extends TautulliPageRouter { + TautulliSyncedItemsRouter() : super('/tautulli/synceditems'); - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliSyncedItemsRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliSyncedItemsRouter._(); + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliSyncedItemsRoute()); } class _TautulliSyncedItemsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/synced_items/widgets/synced_item_tile.dart b/lib/modules/tautulli/routes/synced_items/widgets/synced_item_tile.dart index 36a2e845..603b4213 100644 --- a/lib/modules/tautulli/routes/synced_items/widgets/synced_item_tile.dart +++ b/lib/modules/tautulli/routes/synced_items/widgets/synced_item_tile.dart @@ -59,5 +59,5 @@ class TautulliSyncedItemTile extends StatelessWidget { padContent: true, ); - Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: syncedItem.ratingKey, mediaType: TautulliMediaType.NULL.from(syncedItem.metadataType)); + Future _onTap(BuildContext context) async => TautulliMediaDetailsRouter().navigateTo(context, ratingKey: syncedItem.ratingKey, mediaType: TautulliMediaType.NULL.from(syncedItem.metadataType)); } diff --git a/lib/modules/tautulli/routes/tautulli/route.dart b/lib/modules/tautulli/routes/tautulli/route.dart index 2f2ebf01..c23ba82e 100644 --- a/lib/modules/tautulli/routes/tautulli/route.dart +++ b/lib/modules/tautulli/routes/tautulli/route.dart @@ -3,25 +3,11 @@ import 'package:flutter/material.dart'; import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; -class TautulliHomeRouter { - static const ROUTE_NAME = '/tautulli'; - - static Future navigateTo(BuildContext context) async => LunaRouter.router.navigateTo( - context, - route(), - ); - - static String route() => ROUTE_NAME; - - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliHomeRoute()), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliHomeRouter._(); +class TautulliHomeRouter extends TautulliPageRouter { + TautulliHomeRouter() : super('/tautulli'); + + @override + void defineRoute(FluroRouter router) => super.noParameterRouteDefinition(router, _TautulliHomeRoute(), homeRoute: true); } class _TautulliHomeRoute extends StatefulWidget { @@ -40,19 +26,21 @@ class _State extends State<_TautulliHomeRoute> { } @override - Widget build(BuildContext context) => WillPopScope( - onWillPop: _onWillPop, - child: ValueListenableBuilder( - valueListenable: Database.lunaSeaBox.listenable(keys: [ LunaDatabaseValue.ENABLED_PROFILE.key ]), - builder: (context, box, _) => Scaffold( - key: _scaffoldKey, - drawer: _drawer, - appBar: _appBar, - bottomNavigationBar: _bottomNavigationBar, - body: _body, + Widget build(BuildContext context) { + return WillPopScope( + onWillPop: _onWillPop, + child: ValueListenableBuilder( + valueListenable: Database.lunaSeaBox.listenable(keys: [ LunaDatabaseValue.ENABLED_PROFILE.key ]), + builder: (context, box, _) => Scaffold( + key: _scaffoldKey, + drawer: _drawer(), + appBar: _appBar(), + bottomNavigationBar: _bottomNavigationBar(), + body: _body(), + ), ), - ), - ); + ); + } Future _onWillPop() async { if(_scaffoldKey.currentState.isDrawerOpen) return true; @@ -60,31 +48,46 @@ class _State extends State<_TautulliHomeRoute> { return false; } - Widget get _drawer => LunaDrawer(page: LunaModule.TAUTULLI.key); + Widget _drawer() => LunaDrawer(page: LunaModule.TAUTULLI.key); - Widget get _bottomNavigationBar => TautulliNavigationBar(pageController: _pageController); + Widget _bottomNavigationBar() { + if(context.read().enabled) return TautulliNavigationBar(pageController: _pageController); + return null; + } - List get _tabs => [ - TautulliActivityRoute(), - TautulliUsersRoute(), - TautulliHistoryRoute(), - TautulliMoreRoute(), - ]; - - Widget get _body => Selector( - selector: (_, state) => state.enabled, - builder: (context, enabled, _) => PageView( - controller: _pageController, - children: enabled ? _tabs : List.generate(_tabs.length, (_) => LSNotEnabled('Tautulli')), - ), - ); - - Widget get _appBar => LunaAppBar.dropdown( - title: 'Tautulli', - profiles: Database.profilesBox.keys.fold([], (value, element) { - if((Database.profilesBox.get(element) as ProfileHiveObject)?.tautulliEnabled ?? false) value.add(element); + Widget _appBar() { + List profiles = Database.profilesBox.keys.fold([], (value, element) { + if(Database.profilesBox.get(element)?.tautulliEnabled ?? false) value.add(element); return value; - }), - actions: context.read().enabled ? [TautulliGlobalSettings()] : null, - ); + }); + List actions; + if(context.watch().enabled) actions = [ + TautulliAppBarGlobalSettingsAction(), + ]; + return LunaAppBar.dropdown( + title: LunaModule.TAUTULLI.name, + profiles: profiles, + actions: actions, + pageController: _pageController, + scrollControllers: TautulliNavigationBar.scrollControllers, + ); + } + + Widget _body() { + return Selector( + selector: (_, state) => state.enabled, + builder: (context, enabled, _) { + if(!enabled) return LunaMessage.moduleNotEnabled(context: context, module: 'Tautulli'); + return PageView( + controller: _pageController, + children: [ + TautulliActivityRoute(), + TautulliUsersRoute(), + TautulliHistoryRoute(), + TautulliMoreRoute(), + ], + ); + }, + ); + } } diff --git a/lib/modules/tautulli/routes/tautulli/widgets.dart b/lib/modules/tautulli/routes/tautulli/widgets.dart index 99990c95..d41e48dc 100644 --- a/lib/modules/tautulli/routes/tautulli/widgets.dart +++ b/lib/modules/tautulli/routes/tautulli/widgets.dart @@ -1,2 +1,2 @@ -export 'widgets/global_settings.dart'; +export 'widgets/appbar_global_settings_action.dart'; export 'widgets/navigation_bar.dart'; 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 new file mode 100644 index 00000000..df2946ae --- /dev/null +++ b/lib/modules/tautulli/routes/tautulli/widgets/appbar_global_settings_action.dart @@ -0,0 +1,16 @@ +import 'package:flutter/material.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class TautulliAppBarGlobalSettingsAction extends StatelessWidget { + @override + Widget build(BuildContext context) { + return LunaIconButton( + icon: Icons.more_vert, + onPressed: () async { + Tuple2 values = await TautulliDialogs().globalSettings(context); + if(values.item1) values.item2.execute(context); + }, + ); + } +} diff --git a/lib/modules/tautulli/routes/tautulli/widgets/global_settings.dart b/lib/modules/tautulli/routes/tautulli/widgets/global_settings.dart deleted file mode 100644 index c436490f..00000000 --- a/lib/modules/tautulli/routes/tautulli/widgets/global_settings.dart +++ /dev/null @@ -1,111 +0,0 @@ -import 'package:flutter/material.dart'; -import 'package:lunasea/core.dart'; -import 'package:lunasea/modules/tautulli.dart'; - -class TautulliGlobalSettings extends StatelessWidget { - @override - Widget build(BuildContext context) => LSIconButton( - icon: Icons.more_vert, - onPressed: () async => _handler(context), - ); - - Future _handler(BuildContext context) async { - List values = await TautulliDialogs.globalSettings(context); - if(values[0]) switch(values[1] as TautulliGlobalSettingsType) { - case TautulliGlobalSettingsType.WEB_GUI: _webGUI(context); break; - case TautulliGlobalSettingsType.BACKUP_CONFIG: _backupConfig(context); break; - case TautulliGlobalSettingsType.BACKUP_DB: _backupDB(context); break; - case TautulliGlobalSettingsType.DELETE_CACHE: _deleteCache(context); break; - case TautulliGlobalSettingsType.DELETE_IMAGE_CACHE: _deleteImageCache(context); break; - case TautulliGlobalSettingsType.DELETE_TEMP_SESSIONS: _deleteTempSessions(context); break; - default: LunaLogger().warning('TautulliGlobalSettings', '_handler', 'Unknown case: ${(values[1] as TautulliGlobalSettings)}'); - } - } - - Future _webGUI(BuildContext context) async => context.read().host.lunaOpenGenericLink(); - - Future _backupConfig(BuildContext context) async { - context.read().api.system.backupConfig() - .then((_) => LSSnackBar( - context: context, - title: 'Backing Up Configuration${Constants.TEXT_ELLIPSIS}', - message: 'Backing up your configuration in the background', - )) - .catchError((error, trace) { - LunaLogger().error('Failed to backup configuration', error, trace); - LSSnackBar( - context: context, - title: 'Failed to Backup Configuration', - type: SNACKBAR_TYPE.failure, - ); - }); - } - - Future _backupDB(BuildContext context) async { - context.read().api.system.backupDB() - .then((_) => LSSnackBar( - context: context, - title: 'Backing Up Database${Constants.TEXT_ELLIPSIS}', - message: 'Backing up your database in the background', - )) - .catchError((error, trace) { - LunaLogger().error('Failed to backup database', error, trace); - LSSnackBar( - context: context, - title: 'Failed to Backup Database', - type: SNACKBAR_TYPE.failure, - ); - }); - } - - Future _deleteCache(BuildContext context) async { - context.read().api.system.deleteCache() - .then((_) => LSSnackBar( - context: context, - title: 'Deleting Cache${Constants.TEXT_ELLIPSIS}', - message: 'Tautulli cache is being deleted', - )) - .catchError((error, trace) { - LunaLogger().error('Failed to delete cache', error, trace); - LSSnackBar( - context: context, - title: 'Failed to Delete Cache', - type: SNACKBAR_TYPE.failure, - ); - }); - } - - Future _deleteImageCache(BuildContext context) async { - context.read().api.system.deleteImageCache() - .then((_) => LSSnackBar( - context: context, - title: 'Deleting Image Cache${Constants.TEXT_ELLIPSIS}', - message: 'Tautulli image cache is being deleted', - )) - .catchError((error, trace) { - LunaLogger().error('Failed to delete image cache', error, trace); - LSSnackBar( - context: context, - title: 'Failed to Delete Image Cache', - type: SNACKBAR_TYPE.failure, - ); - }); - } - - Future _deleteTempSessions(BuildContext context) async { - context.read().api.activity.deleteTempSessions() - .then((_) => LSSnackBar( - context: context, - title: 'Deleting Temporary Sessions${Constants.TEXT_ELLIPSIS}', - message: 'Temporary sessions are being deleted', - )) - .catchError((error, trace) { - LunaLogger().error('Failed to delete temporary sessions', error, trace); - LSSnackBar( - context: context, - title: 'Failed to Delete Temporary Sessions', - type: SNACKBAR_TYPE.failure, - ); - }); - } -} \ No newline at end of file diff --git a/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart b/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart index 109022c9..27653968 100644 --- a/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/tautulli/widgets/navigation_bar.dart @@ -4,6 +4,9 @@ import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; class TautulliNavigationBar extends StatefulWidget { + final PageController pageController; + static List scrollControllers = List.generate(icons.length, (_) => ScrollController()); + static const List icons = [ LunaIcons.monitoring, LunaIcons.user, @@ -11,14 +14,13 @@ class TautulliNavigationBar extends StatefulWidget { Icons.more_horiz, ]; - static const List titles = [ - 'Activity', - 'Users', - 'History', - 'More', + static List get titles => [ + 'tautulli.Activity'.tr(), + 'tautulli.Users'.tr(), + 'tautulli.History'.tr(), + 'tautulli.More'.tr(), ]; - final PageController pageController; TautulliNavigationBar({ Key key, @@ -30,12 +32,13 @@ class TautulliNavigationBar extends StatefulWidget { } class _State extends State { - int _index = TautulliDatabaseValue.NAVIGATION_INDEX_USER_DETAILS.data; + int _index; @override void initState() { - super.initState(); + _index = widget.pageController?.initialPage ?? 0; widget.pageController?.addListener(_pageControllerListener); + super.initState(); } @override @@ -45,35 +48,31 @@ class _State extends State { } void _pageControllerListener() { - if(widget.pageController.page.round() == _index) return; + if((widget.pageController?.page?.round() ?? _index) == _index) return; setState(() => _index = widget.pageController.page.round()); } @override - Widget build(BuildContext context) => Consumer( - builder: (context, state, _) => LSBottomNavigationBar( - index: _index, - onTap: _navOnTap, + Widget build(BuildContext context) { + return LunaBottomNavigationBar( + pageController: widget.pageController, + scrollControllers: TautulliNavigationBar.scrollControllers, icons: TautulliNavigationBar.icons, titles: TautulliNavigationBar.titles, - leadingOnGButton: [ + leadingOnTab: [ FutureBuilder( - future: state.activity, + future: context.watch().activity, builder: (BuildContext context, AsyncSnapshot snapshot) => LunaNavigationBarBadge( text: snapshot.hasData ? snapshot.data.streamCount.toString() : '?', icon: TautulliNavigationBar.icons[0], isActive: _index == 0, - showBadge: state.enabled && _index != 0 && snapshot.hasData && snapshot.data.streamCount > 0, + showBadge: context.read().enabled && _index != 0 && snapshot.hasData && snapshot.data.streamCount > 0, ), ), null, null, null, ], - ), - ); - - Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + ); } } diff --git a/lib/modules/tautulli/routes/users/widgets/user_tile.dart b/lib/modules/tautulli/routes/users/widgets/user_tile.dart index 6ec26e86..5fa44529 100644 --- a/lib/modules/tautulli/routes/users/widgets/user_tile.dart +++ b/lib/modules/tautulli/routes/users/widgets/user_tile.dart @@ -38,10 +38,9 @@ class TautulliUserTile extends StatelessWidget { : null, ); - Widget _userThumb(BuildContext context) => LSNetworkImage( - url: context.watch().getImageURLFromPath(user.userThumb), - headers: context.watch().headers.cast(), - placeholder: 'assets/images/tautulli/nouserthumb.png', + Widget _userThumb(BuildContext context) => LunaNetworkImage( + url: user.userThumb, + placeholderAsset: 'assets/images/blanks/user.png', height: _imageDimension, width: _imageDimension, ); @@ -103,5 +102,5 @@ class TautulliUserTile extends StatelessWidget { ], ); - Future _enterDetails(BuildContext context) async => TautulliUserDetailsRouter.navigateTo(context, userId: user.userId); + Future _enterDetails(BuildContext context) async => TautulliUserDetailsRouter().navigateTo(context, userId: user.userId); } diff --git a/lib/modules/tautulli/routes/users_details/route.dart b/lib/modules/tautulli/routes/users_details/route.dart index d841eab4..1ec875f8 100644 --- a/lib/modules/tautulli/routes/users_details/route.dart +++ b/lib/modules/tautulli/routes/users_details/route.dart @@ -5,29 +5,20 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/tautulli.dart'; import 'package:tautulli/tautulli.dart'; -class TautulliUserDetailsRouter { - static const String ROUTE_NAME = '/tautulli/users/details/:userid'; +class TautulliUserDetailsRouter extends TautulliPageRouter { + TautulliUserDetailsRouter() : super('/tautulli/user/:userid'); - static Future navigateTo(BuildContext context, { - @required int userId, - }) async => LunaRouter.router.navigateTo( - context, - route(userId: userId), - ); + @override + Future navigateTo(BuildContext context, { @required int userId }) async => LunaRouter.router.navigateTo(context, route(userId: userId)); - static String route({ @required int userId }) => ROUTE_NAME.replaceFirst(':userid', userId.toString()); + @override + String route({ @required int userId }) => fullRoute.replaceFirst(':userid', userId.toString()); - static void defineRoutes(FluroRouter router) { - router.define( - ROUTE_NAME, - handler: Handler(handlerFunc: (context, params) => _TautulliUserDetailsRoute( - userId: int.tryParse(params['userid'][0]) ?? -1, - )), - transitionType: LunaRouter.transitionType, - ); - } - - TautulliUserDetailsRouter._(); + @override + void defineRoute(FluroRouter router) => super.withParameterRouteDefinition(router, (context, params) { + int userId = params['userid'] == null || params['userid'].length == 0 ? -1 : int.tryParse(params['userid'][0]) ?? -1; + return _TautulliUserDetailsRoute(userId: userId); + }); } class _TautulliUserDetailsRoute extends StatefulWidget { diff --git a/lib/modules/tautulli/routes/users_details/widgets/ip_addresses.dart b/lib/modules/tautulli/routes/users_details/widgets/ip_addresses.dart index 8561d212..97a15000 100644 --- a/lib/modules/tautulli/routes/users_details/widgets/ip_addresses.dart +++ b/lib/modules/tautulli/routes/users_details/widgets/ip_addresses.dart @@ -111,6 +111,6 @@ class _State extends State with AutomaticKeepAli ) : null, padContent: true, - onTap: () async => TautulliIPAddressDetailsRouter.navigateTo(context, ip: record.ipAddress), + onTap: () async => TautulliIPAddressDetailsRouter().navigateTo(context, ipAddress: record.ipAddress), ); } 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 f10fee4b..404629e8 100644 --- a/lib/modules/tautulli/routes/users_details/widgets/navigation_bar.dart +++ b/lib/modules/tautulli/routes/users_details/widgets/navigation_bar.dart @@ -57,6 +57,6 @@ class _State extends State { ); Future _navOnTap(int index) async { - widget.pageController.lunaAnimateToPage(index); + widget.pageController.lunaJumpToPage(index); } } diff --git a/localization/lunasea/de.json b/localization/lunasea/de.json index f1be6570..fbf39f0e 100644 --- a/localization/lunasea/de.json +++ b/localization/lunasea/de.json @@ -1,15 +1,16 @@ { "lunasea.AnErrorHasOccurred": "Ein Fehler ist aufgetreten", + "lunasea.Cancel": "Abbrechen", "lunasea.ChangeProfiles": "Profile wechseln", - "lunasea.CheckLogsMessage": "Überprüfe die Logs für mehr Details", + "lunasea.CheckLogsMessage": "Überprüfe die Protokolle für mehr Details", "lunasea.ComingSoon": "Bald verfügbar", - "lunasea.Dashboard": "Dashboard", + "lunasea.Dashboard": "Instrumentenanlage", "lunasea.GoBack": "Zurück", - "lunasea.ModuleIsNotEnabled": "{} Ist Nicht Aktiviert", + "lunasea.ModuleIsNotEnabled": "{} ist nicht aktiviert", "lunasea.Refresh": "Aktualisieren", - "lunasea.ReturnToDashboard": "Zurück zum Dashboard", - "lunasea.SearchTextBar": "Suche…", + "lunasea.ReturnToDashboard": "Zurück zur Instrumentenanlage", + "lunasea.SearchTextBar": "Suche …", "lunasea.Settings": "Einstellungen", - "lunasea.TryAgain": "Erneut Versuchen", + "lunasea.TryAgain": "Erneut versuchen", "lunasea.Unknown": "Unbekannt" } diff --git a/localization/lunasea/en.json b/localization/lunasea/en.json index b805e0c1..9524ecb4 100644 --- a/localization/lunasea/en.json +++ b/localization/lunasea/en.json @@ -1,5 +1,6 @@ { "lunasea.AnErrorHasOccurred": "An Error Has Occurred", + "lunasea.Cancel": "Cancel", "lunasea.ChangeProfiles": "Change Profiles", "lunasea.CheckLogsMessage": "Check the logs for more details", "lunasea.ComingSoon": "Coming Soon", diff --git a/localization/lunasea/fr.json b/localization/lunasea/fr.json index 8a5d3a73..d8dd3a39 100644 --- a/localization/lunasea/fr.json +++ b/localization/lunasea/fr.json @@ -1,7 +1,8 @@ { "lunasea.AnErrorHasOccurred": "Une erreur s'est produite", + "lunasea.Cancel": "Annuler", "lunasea.ChangeProfiles": "Changer de profil", - "lunasea.CheckLogsMessage": "Vérifier les logs pour plus de détails", + "lunasea.CheckLogsMessage": "Vérifier les journaux pour plus de détails", "lunasea.ComingSoon": "Prochainement", "lunasea.Dashboard": "Tableau de bord", "lunasea.GoBack": "Retour en arrière", diff --git a/localization/lunasea/it.json b/localization/lunasea/it.json new file mode 100644 index 00000000..b84b812e --- /dev/null +++ b/localization/lunasea/it.json @@ -0,0 +1,15 @@ +{ + "lunasea.AnErrorHasOccurred": "C'è stato un errore", + "lunasea.ChangeProfiles": "Cambia profili", + "lunasea.CheckLogsMessage": "Controlla i registri per maggiori dettagli", + "lunasea.ComingSoon": "Prossimamente", + "lunasea.Dashboard": "Pannello di controllo", + "lunasea.GoBack": "Indietro", + "lunasea.ModuleIsNotEnabled": "{} non è abilitato", + "lunasea.Refresh": "Ricarica", + "lunasea.ReturnToDashboard": "Torna al pannello di controllo", + "lunasea.SearchTextBar": "Ricerca…", + "lunasea.Settings": "Impostazioni", + "lunasea.TryAgain": "Riprova", + "lunasea.Unknown": "Sconosciuto" +} diff --git a/localization/lunasea/sv.json b/localization/lunasea/sv.json index 0589d4a4..6b2e36a4 100644 --- a/localization/lunasea/sv.json +++ b/localization/lunasea/sv.json @@ -1,6 +1,15 @@ { "lunasea.AnErrorHasOccurred": "Ett fel har inträffat", + "lunasea.ChangeProfiles": "Byta Profil", + "lunasea.CheckLogsMessage": "Kolla loggen för mera detaljer", + "lunasea.ComingSoon": "Kommer Snart", + "lunasea.Dashboard": "Instrumentbräda", + "lunasea.GoBack": "Tillbaka", + "lunasea.ModuleIsNotEnabled": "{} Är Inte Aktiverad", "lunasea.Refresh": "Uppdatera", + "lunasea.ReturnToDashboard": "Gå Tillbaka till Instrumentbrädan", "lunasea.SearchTextBar": "Sök…", - "lunasea.Settings": "Inställningar" + "lunasea.Settings": "Inställningar", + "lunasea.TryAgain": "Försök Igen", + "lunasea.Unknown": "Okänd" } diff --git a/localization/radarr/de.json b/localization/radarr/de.json index bf6dc894..b9cd203d 100644 --- a/localization/radarr/de.json +++ b/localization/radarr/de.json @@ -14,7 +14,7 @@ "radarr.DateAdded": "Hinzugefügt am", "radarr.Discover": "Entdecken", "radarr.DownloadFailed": "Herunterladen gescheitert", - "radarr.DownloadIgnored": "Download ignoriert", + "radarr.DownloadIgnored": "Herunterladen ignoriert", "radarr.EditMovie": "Film bearbeiten", "radarr.FilterCatalogue": "Katalog filtern", "radarr.GrabbedFrom": "Gegrabbed von {}", @@ -57,7 +57,7 @@ "radarr.SortCatalogue": "Katalog sortieren", "radarr.Studio": "Studio", "radarr.SystemStatus": "Systemstatus", - "radarr.SystemStatusDescription": "Systemstatus & Speicherplatz", + "radarr.SystemStatusDescription": "Systemstatus und Speicherplatz", "radarr.Tags": "Tags", "radarr.TagsDescription": "Verwalte deine Tags", "radarr.Type": "Typ", diff --git a/localization/radarr/fr.json b/localization/radarr/fr.json index 094659a8..942ff0e9 100644 --- a/localization/radarr/fr.json +++ b/localization/radarr/fr.json @@ -13,8 +13,8 @@ "radarr.CutoffUnmet": "Qualité préférée non atteinte", "radarr.DateAdded": "Date ajoutée", "radarr.Discover": "Découvrir", - "radarr.DownloadFailed": "Echec du téléchargement", - "radarr.DownloadIgnored": "Télécharger Ignoré", + "radarr.DownloadFailed": "Échec du téléchargement", + "radarr.DownloadIgnored": "Téléchargement ignoré", "radarr.EditMovie": "Modifier le film", "radarr.FilterCatalogue": "Catalogue des filtres", "radarr.GrabbedFrom": "Récupéré depuis {}", @@ -38,7 +38,7 @@ "radarr.NoMoviesFound": "Aucun film trouvé", "radarr.NoResultsFound": "Aucun résultat", "radarr.NoSummaryIsAvailable": "Aucun résumé n'est disponible.", - "radarr.QualityProfile": "Profil de la qualité", + "radarr.QualityProfile": "Profil de qualité", "radarr.Queue": "File d'attente", "radarr.QueueDescription": "Voir le contenu actif et en attente", "radarr.RefreshMovie": "Rafraichir le film", @@ -58,8 +58,8 @@ "radarr.Studio": "Studio", "radarr.SystemStatus": "État du système", "radarr.SystemStatusDescription": "État du système et espace disque", - "radarr.Tags": "Tags", - "radarr.TagsDescription": "Gérer vos tags", + "radarr.Tags": "Étiquettes", + "radarr.TagsDescription": "Gérer vos étiquettes", "radarr.Type": "Type", "radarr.UnmonitorMovie": "Ne plus surveiller le film", "radarr.Unmonitored": "Non surveillé", diff --git a/localization/radarr/it.json b/localization/radarr/it.json new file mode 100644 index 00000000..4458da50 --- /dev/null +++ b/localization/radarr/it.json @@ -0,0 +1,73 @@ +{ + "radarr.AddMovie": "Aggiungi Film", + "radarr.AddMovieAndSearch": "Aggiungi + Cerca", + "radarr.Age": "Età", + "radarr.All": "Tutti", + "radarr.Alphabetical": "Alfabetico", + "radarr.Approved": "Approvato", + "radarr.AvailabilityUnknown": "Disponibilità Sconosciuta", + "radarr.AvailableIn": "Disponibile in {}", + "radarr.AvailableToday": "Disponibile Oggi", + "radarr.BackupDatabase": "Fai un backup della banca dati", + "radarr.CinemaDateUnknown": "Data Cinema Sconosciuta", + "radarr.CutoffUnmet": "Soglia Non Raggiunta", + "radarr.DateAdded": "Data Aggiunta", + "radarr.Discover": "Scopri", + "radarr.DownloadFailed": "Scaricamento fallito", + "radarr.DownloadIgnored": "Scaricamento ignorato", + "radarr.EditMovie": "Modifica il film", + "radarr.FilterCatalogue": "Filtra catalogo", + "radarr.GrabbedFrom": "Preso da {}", + "radarr.History": "Cronologia", + "radarr.HistoryDescription": "Visualizza l'attività recente", + "radarr.InCinemasIn": "Nei cinema in {}", + "radarr.InCinemasToday": "Nei cinema oggi", + "radarr.MinimumAvailability": "Disponibilità minima", + "radarr.Missing": "Mancante", + "radarr.MonitorMovie": "Monitora il film", + "radarr.Monitored": "Monitorato", + "radarr.MonitoredDescription": "Monitora per nuove versioni", + "radarr.More": "Di più", + "radarr.MovieFileDeleted": "File film eliminato", + "radarr.MovieFileRenamed": "File film rinominato", + "radarr.MovieImported": "Film importato ({})", + "radarr.MovieNotFound": "Film non trovato", + "radarr.MoviePath": "Percorso film", + "radarr.Movies": "Film", + "radarr.NoHistoryFound": "Nessuna cronologia trovata", + "radarr.NoMoviesFound": "Nessun film trovato", + "radarr.NoResultsFound": "Nessun risultato trovato", + "radarr.NoSummaryIsAvailable": "Nessun riepilogo disponibile.", + "radarr.QualityProfile": "Profilo qualità", + "radarr.Queue": "Coda", + "radarr.QueueDescription": "Visualizza il contenuto attivo e in coda", + "radarr.RefreshMovie": "Ricarica il film", + "radarr.Rejected": "Rifiutato", + "radarr.Released": "Rilasciato", + "radarr.ReleasedToday": "Rilasciato oggi", + "radarr.RemoveMovie": "Rimuovi il film", + "radarr.RootFolder": "Cartella root", + "radarr.RunRSSSync": "Esegui sincronizzazione RSS", + "radarr.Runtime": "Durata", + "radarr.Search": "Cerca", + "radarr.SearchAllMissing": "Cerca tutti mancanti", + "radarr.SearchFor": "Cerco {}", + "radarr.Seeders": "Seeder", + "radarr.Size": "Dimensioni", + "radarr.SortCatalogue": "Ordina catalogo", + "radarr.Studio": "Studio", + "radarr.SystemStatus": "Stato sistema", + "radarr.SystemStatusDescription": "Stato sistema e spazio su disco", + "radarr.Tags": "Etichette", + "radarr.TagsDescription": "Gestisci le tue etichette", + "radarr.Type": "Tipo", + "radarr.UnmonitorMovie": "Non monitorare il film", + "radarr.Unmonitored": "Non monitorato", + "radarr.Upcoming": "Imminente", + "radarr.UpdateLibrary": "Aggiorna la libreria", + "radarr.UpdateMovie": "Aggiorna il film", + "radarr.ViewWebGUI": "Visualizza Web GUI", + "radarr.Wanted": "Ricercato", + "radarr.Weight": "Peso", + "radarr.Year": "Anno" +} diff --git a/localization/radarr/sv.json b/localization/radarr/sv.json index 32921f81..aaf7fc39 100644 --- a/localization/radarr/sv.json +++ b/localization/radarr/sv.json @@ -1,33 +1,73 @@ { "radarr.AddMovie": "Lägg till Film", "radarr.AddMovieAndSearch": "Lägg till + Sök", + "radarr.Age": "Ålder", + "radarr.All": "Alla", + "radarr.Alphabetical": "Alfabetiskt", + "radarr.Approved": "Godkänd", + "radarr.AvailabilityUnknown": "Tillgänglighet Okänd", + "radarr.AvailableIn": "Tillgänglig i {}", + "radarr.AvailableToday": "Tillgänglig Idag", + "radarr.BackupDatabase": "Säkerhetskopiera Databasen", + "radarr.CinemaDateUnknown": "Okänt Biograf Datum", + "radarr.CutoffUnmet": "Avgränsande ej tillgodosedd", + "radarr.DateAdded": "Datum tillagt", "radarr.Discover": "Utforska", + "radarr.DownloadFailed": "Nedladdning Misslyckades", + "radarr.DownloadIgnored": "Ignorerad Nedladdning", "radarr.EditMovie": "Redigera Film", "radarr.FilterCatalogue": "Filterkatalog", + "radarr.GrabbedFrom": "Hämtad från {}", "radarr.History": "Historik", "radarr.HistoryDescription": "Visa Senaste Aktivitet", + "radarr.InCinemasIn": "Visas på Biograf {}", + "radarr.InCinemasToday": "På Biograf Idag", "radarr.MinimumAvailability": "Minsta Tillgänglighet", "radarr.Missing": "Saknas", + "radarr.MonitorMovie": "Bevaka Film", "radarr.Monitored": "Bevakad", "radarr.MonitoredDescription": "Bevaka för nya utgåvor", "radarr.More": "Mer", + "radarr.MovieFileDeleted": "Filmfil Raderad", + "radarr.MovieFileRenamed": "Filmfil Omdöpt", + "radarr.MovieImported": "Film Importerad ({})", "radarr.MovieNotFound": "Film Hittades Inte", "radarr.MoviePath": "Film Sökväg", "radarr.Movies": "Filmer", + "radarr.NoHistoryFound": "Ingen Historik Hittad", "radarr.NoMoviesFound": "Inga Filmer Funna", "radarr.NoResultsFound": "Inga Resultat Funna", "radarr.NoSummaryIsAvailable": "Ingen sammanfattning finns tillgänglig.", "radarr.QualityProfile": "Kvalitetsprofil", "radarr.Queue": "Kö", "radarr.QueueDescription": "Visa Aktivt & Köat Innehåll", + "radarr.RefreshMovie": "Uppdatera Film", + "radarr.Rejected": "Avvisad", + "radarr.Released": "Släppt", + "radarr.ReleasedToday": "Släpptes Idag", + "radarr.RemoveMovie": "Ta Bort Film", "radarr.RootFolder": "Rotmapp", + "radarr.RunRSSSync": "Kör RSS Synkronisering", + "radarr.Runtime": "Speltid", "radarr.Search": "Sök", + "radarr.SearchAllMissing": "Sök Alla Saknade", "radarr.SearchFor": "Sök efter {}", + "radarr.Seeders": "Seedare", + "radarr.Size": "Storlek", "radarr.SortCatalogue": "Sortera Katalog", + "radarr.Studio": "Studio", "radarr.SystemStatus": "Systemstatus", "radarr.SystemStatusDescription": "Systemstatus & Disk Utrymme", "radarr.Tags": "Taggar", "radarr.TagsDescription": "Hantera Dina Taggar", + "radarr.Type": "Typ", + "radarr.UnmonitorMovie": "Obevaka Film", + "radarr.Unmonitored": "Obevakad", "radarr.Upcoming": "Kommande", - "radarr.UpdateMovie": "Uppdatera Film" + "radarr.UpdateLibrary": "Uppdatera Bibliotek", + "radarr.UpdateMovie": "Uppdatera Film", + "radarr.ViewWebGUI": "Visa Webb GUI", + "radarr.Wanted": "Önskad", + "radarr.Weight": "Vikt", + "radarr.Year": "År" } diff --git a/localization/search/de.json b/localization/search/de.json index 866d2a10..438d773f 100644 --- a/localization/search/de.json +++ b/localization/search/de.json @@ -4,8 +4,8 @@ "search.FailedToDownloadNZB": "Herunterladen der NZB fehlgeschlagen", "search.DownloadToDevice": "Auf Gerät herunterladen", "search.DownloadingNZBToDevice": "Lädt NZB auf deinem Gerät herunter", - "search.Downloading": "Herunterladen…", - "search.Download": "Download", + "search.Downloading": "Herunterladen …", + "search.Download": "Herunterladen", "search.Comments": "Kommentare", "search.Categories": "Kategorien", "search.Category": "Kategorie", @@ -15,7 +15,7 @@ "search.Subcategories": "Unterkategorien", "search.Size": "Größe", "search.SentTo": "An {} gesendet", - "search.SentNZBData": "NZB Daten gesendet", + "search.SentNZBData": "NZB-Daten gesendet", "search.Search": "Suche", "search.Results": "Ergebnisse", "search.NoSubcategoriesFound": "Keine Unterkategorien gefunden", diff --git a/localization/search/fr.json b/localization/search/fr.json new file mode 100644 index 00000000..ff480f3d --- /dev/null +++ b/localization/search/fr.json @@ -0,0 +1,23 @@ +{ + "search.Subcategories": "Sous-catégories", + "search.Size": "Taille", + "search.SentTo": "Envoyé à {}", + "search.SentNZBData": "Données NZB envoyées", + "search.Search": "Rechercher", + "search.Results": "Résultats", + "search.NoSubcategoriesFound": "Aucune sous-catégorie trouvée", + "search.NoResultsFound": "Aucun résultat", + "search.NoCategoriesFound": "Aucune catégorie trouvée", + "search.FailedToSend": "Erreur lors de l'envoi", + "search.FailedToDownloadNZB": "Erreur lors du téléchargement du NZB", + "search.DownloadToDevice": "Télécharger sur l'appareil", + "search.DownloadingNZBToDevice": "Télécharger le NZB sur votre appareil", + "search.Downloading": "Téléchargement en cours…", + "search.Download": "Télécharger", + "search.Comments": "Commentaires", + "search.Categories": "Catégories", + "search.Category": "Catégorie", + "search.Alphabetical": "Alphabétique", + "search.AllSubcategories": "Toutes les sous-catégories", + "search.Age": "Âge" +} diff --git a/localization/search/it.json b/localization/search/it.json new file mode 100644 index 00000000..1ff8b683 --- /dev/null +++ b/localization/search/it.json @@ -0,0 +1,23 @@ +{ + "search.Subcategories": "Sottocategorie", + "search.Size": "Dimensioni", + "search.SentTo": "Invia a {}", + "search.SentNZBData": "Dati NZB inviati", + "search.Search": "Cerca", + "search.Results": "Risultati", + "search.NoSubcategoriesFound": "Nessuna sottocategoria trovata", + "search.NoResultsFound": "Nessun risultato trovato", + "search.NoCategoriesFound": "Nessuna categoria trovata", + "search.FailedToSend": "Invio non riuscito", + "search.FailedToDownloadNZB": "Impossibile scaricare NZB", + "search.DownloadToDevice": "Scarica sul dispositivo", + "search.DownloadingNZBToDevice": "Scaricamento di NZB sul tuo dispositivo", + "search.Downloading": "Scaricamento in corso…", + "search.Download": "Scarica", + "search.Comments": "Commenti", + "search.Categories": "Categorie", + "search.Category": "Categoria", + "search.Alphabetical": "Alfabetico", + "search.AllSubcategories": "Tutte Le Sottocategorie", + "search.Age": "Età" +} diff --git a/localization/search/sv.json b/localization/search/sv.json new file mode 100644 index 00000000..41b8d439 --- /dev/null +++ b/localization/search/sv.json @@ -0,0 +1,23 @@ +{ + "search.Size": "Storlek", + "search.Search": "Sök", + "search.NoResultsFound": "Inga Resultat Funna", + "search.Alphabetical": "Alfabetiskt", + "search.Age": "Ålder", + "search.Subcategories": "Underkategorier", + "search.SentTo": "Skickat till {}", + "search.SentNZBData": "NZB Data Skickat", + "search.Results": "Resultat", + "search.NoSubcategoriesFound": "Inga Underkategorier Funna", + "search.NoCategoriesFound": "Inga Kategorier Funna", + "search.FailedToSend": "Misslyckades att Skicka", + "search.FailedToDownloadNZB": "Misslyckades med att Ladda ned NZB", + "search.DownloadToDevice": "Ladda ned till Enhet", + "search.DownloadingNZBToDevice": "Laddar ned NZB till din enhet", + "search.Downloading": "Laddar ned…", + "search.Download": "Ladda ned", + "search.Comments": "Kommentarer", + "search.Categories": "Kategorier", + "search.Category": "Kategori", + "search.AllSubcategories": "Alla Underkategorier" +} diff --git a/localization/tautulli/de.json b/localization/tautulli/de.json new file mode 100644 index 00000000..ba200db4 --- /dev/null +++ b/localization/tautulli/de.json @@ -0,0 +1,70 @@ +{ + "tautulli.TerminateSessionFailed": "Abbrechen der Sitzung fehlgeschlagen", + "tautulli.TerminateSession": "Sitzung abbrechen", + "tautulli.TerminatedSession": "Abgebrochene Sitzung", + "tautulli.TerminationConfirmMessage": "Möchtest du diese Sitzung abbrechen?", + "tautulli.Terminate": "Abbrechen", + "tautulli.Episode": "Folge {}", + "tautulli.Year": "Jahr", + "tautulli.ViewWebGUI": "Weboberfläche ansehen", + "tautulli.Video": "Video", + "tautulli.Users": "Benutzer", + "tautulli.User": "Benutzer", + "tautulli.Transcodes": "Transkodierungen", + "tautulli.Transcode": "Transkodieren", + "tautulli.Title": "Titel", + "tautulli.Throttled": "Throttled", + "tautulli.TerminationMessage": "Abbruch-Begründung", + "tautulli.TerminationAttachMessage": "Du kannst optional unten eine Abbruch-Begründung angeben.", + "tautulli.Subtitle": "Untertitel", + "tautulli.Stream": "Stream", + "tautulli.SessionsMany": "{} Sitzungen", + "tautulli.SessionsOne": "1 Sitzung", + "tautulli.Sessions": "Sitzungen", + "tautulli.SessionEnded": "Sitzung beendet", + "tautulli.Season": "Staffel {}", + "tautulli.Quality": "Qualität", + "tautulli.Product": "Produkt", + "tautulli.Player": "Player", + "tautulli.Platform": "Plattform", + "tautulli.NoActiveStreams": "Keine aktiven Streams", + "tautulli.None": "Nichts", + "tautulli.More": "Mehr", + "tautulli.Metadata": "Metadaten", + "tautulli.Location": "Ort", + "tautulli.Library": "Bibliothek", + "tautulli.History": "Verlauf", + "tautulli.ETA": "Restzeit", + "tautulli.Duration": "Dauer", + "tautulli.DirectStreams": "Direct Streams", + "tautulli.DirectStream": "Direct Stream", + "tautulli.DirectPlays": "Direct Plays", + "tautulli.DirectPlay": "Direct Play", + "tautulli.DeletingTemporarySessionsFailed": "Löschen der temporären Sitzungen fehlgeschlagen", + "tautulli.DeletingTemporarySessionsDescription": "Temporäre Sitzungen werden gelöscht", + "tautulli.DeletingTemporarySessions": "Lösche temporäre Sitzungen…", + "tautulli.DeletingImageCacheFailed": "Löschen des Bild-Zwischenspeicher fehlgeschlagen", + "tautulli.DeletingImageCacheDescription": "Tautulli Bild-Zwischenspeicher wird gelöscht", + "tautulli.DeletingImageCache": "Lösche Bild-Zwischenspeicher…", + "tautulli.DeletingCacheFailed": "Löschen des Zwischenspeichers fehlgeschlagen", + "tautulli.DeletingCacheDescription": "Tautulli Zwischenspeicher wird gelöscht", + "tautulli.DeletingCache": "Lösche Zwischenspeicher…", + "tautulli.DeleteTemporarySessions": "Lösche temporäre Sitzungen", + "tautulli.DeleteImageCache": "Bild-Zwischenspeicher löschen", + "tautulli.DeleteCache": "Zwischenspeicher löschen", + "tautulli.Copy": "Kopieren", + "tautulli.Container": "Container", + "tautulli.Burn": "Einbrennen", + "tautulli.Bandwidth": "Bandbreite", + "tautulli.BackupDatabase": "Datenbank sichern", + "tautulli.BackupConfiguration": "Konfiguration sichern", + "tautulli.BackingUpDatabaseFailed": "Sichern der Datenbank fehlgeschlagen", + "tautulli.BackingUpDatabaseDescription": "Deine Datenbank wird im Hintergrund gesichert", + "tautulli.BackingUpDatabase": "Datenbank wird gesichert…", + "tautulli.BackingUpConfigurationFailed": "Sichern der Konfiguration fehlgeschlagen", + "tautulli.BackingUpConfigurationDescription": "Deine Konfiguration wird im Hintergrund gesichert", + "tautulli.BackingUpConfiguration": "Konfiguration wird gesichert…", + "tautulli.Audio": "Audio", + "tautulli.ActivityDetails": "Aktivitätsdetails", + "tautulli.Activity": "Aktivität" +} diff --git a/localization/tautulli/en.json b/localization/tautulli/en.json new file mode 100644 index 00000000..c4b799c0 --- /dev/null +++ b/localization/tautulli/en.json @@ -0,0 +1,70 @@ +{ + "tautulli.Activity": "Activity", + "tautulli.ActivityDetails": "Activity Details", + "tautulli.Audio": "Audio", + "tautulli.BackingUpConfiguration": "Backing Up Configuration…", + "tautulli.BackingUpConfigurationDescription": "Backing up your configuration in the background", + "tautulli.BackingUpConfigurationFailed": "Failed to Backup Configuration", + "tautulli.BackingUpDatabase": "Backing Up Database…", + "tautulli.BackingUpDatabaseDescription": "Backing up your database in the background", + "tautulli.BackingUpDatabaseFailed": "Failed to Backup Database", + "tautulli.BackupConfiguration": "Backup Configuration", + "tautulli.BackupDatabase": "Backup Database", + "tautulli.Bandwidth": "Bandwidth", + "tautulli.Burn": "Burn", + "tautulli.Container": "Container", + "tautulli.Copy": "Copy", + "tautulli.DeleteCache": "Delete Cache", + "tautulli.DeleteImageCache": "Delete Image Cache", + "tautulli.DeleteTemporarySessions": "Delete Temporary Sessions", + "tautulli.DeletingCache": "Deleting Cache…", + "tautulli.DeletingCacheDescription": "Tautulli cache is being deleted", + "tautulli.DeletingCacheFailed": "Failed to Delete Cache", + "tautulli.DeletingImageCache": "Deleting Image Cache…", + "tautulli.DeletingImageCacheDescription": "Tautulli image cache is being deleted", + "tautulli.DeletingImageCacheFailed": "Failed to Delete Image Cache", + "tautulli.DeletingTemporarySessions": "Deleting Temporary Sessions…", + "tautulli.DeletingTemporarySessionsDescription": "Temporary sessions are being deleted", + "tautulli.DeletingTemporarySessionsFailed": "Failed to Delete Temporary Sessions", + "tautulli.DirectPlay": "Direct Play", + "tautulli.DirectPlays": "Direct Plays", + "tautulli.DirectStream": "Direct Stream", + "tautulli.DirectStreams": "Direct Streams", + "tautulli.Duration": "Duration", + "tautulli.Episode": "Episode {}", + "tautulli.ETA": "ETA", + "tautulli.History": "History", + "tautulli.Library": "Library", + "tautulli.Location": "Location", + "tautulli.Metadata": "Metadata", + "tautulli.More": "More", + "tautulli.None": "None", + "tautulli.NoActiveStreams": "No Active Streams", + "tautulli.Platform": "Platform", + "tautulli.Player": "Player", + "tautulli.Product": "Product", + "tautulli.Quality": "Quality", + "tautulli.Season": "Season {}", + "tautulli.SessionEnded": "Session Ended", + "tautulli.Sessions": "Sessions", + "tautulli.SessionsOne": "1 Session", + "tautulli.SessionsMany": "{} Sessions", + "tautulli.Stream": "Stream", + "tautulli.Subtitle": "Subtitle", + "tautulli.Terminate": "Terminate", + "tautulli.TerminationAttachMessage": "You can optionally attach a termination message below.", + "tautulli.TerminationConfirmMessage": "Do you want to terminate this session?", + "tautulli.TerminationMessage": "Termination Message", + "tautulli.TerminatedSession": "Terminated Session", + "tautulli.TerminateSession": "Terminate Session", + "tautulli.TerminateSessionFailed": "Failed to Terminate Session", + "tautulli.Throttled": "Throttled", + "tautulli.Title": "Title", + "tautulli.Transcode": "Transcode", + "tautulli.Transcodes": "Transcodes", + "tautulli.User": "User", + "tautulli.Users": "Users", + "tautulli.Video": "Video", + "tautulli.ViewWebGUI": "View Web GUI", + "tautulli.Year": "Year" +} diff --git a/localization/tautulli/fr.json b/localization/tautulli/fr.json new file mode 100644 index 00000000..f6622106 --- /dev/null +++ b/localization/tautulli/fr.json @@ -0,0 +1,70 @@ +{ + "tautulli.Burn": "Brûler", + "tautulli.Year": "Année", + "tautulli.ViewWebGUI": "Afficher l'interface Web", + "tautulli.Video": "Vidéo", + "tautulli.Users": "Utilisateurs", + "tautulli.User": "Utilisateur", + "tautulli.Transcodes": "Transcodes", + "tautulli.Transcode": "Transcode", + "tautulli.Title": "Titre", + "tautulli.Throttled": "Throttled", + "tautulli.TerminateSessionFailed": "Échec de la fin de la session", + "tautulli.TerminateSession": "Mettre fin à la session", + "tautulli.TerminatedSession": "Session terminée", + "tautulli.TerminationMessage": "Message de fin de session", + "tautulli.TerminationConfirmMessage": "Voulez-vous mettre fin à cette session ?", + "tautulli.TerminationAttachMessage": "Vous pouvez éventuellement joindre un message ci-dessous.", + "tautulli.Terminate": "Terminer", + "tautulli.Subtitle": "Sous-titre", + "tautulli.Stream": "Stream", + "tautulli.SessionsMany": "{} Sessions", + "tautulli.SessionsOne": "1 Session", + "tautulli.Sessions": "Sessions", + "tautulli.SessionEnded": "Session terminée", + "tautulli.Season": "Saison {}", + "tautulli.Quality": "Qualité", + "tautulli.Product": "Produit", + "tautulli.Player": "Player", + "tautulli.Platform": "Platforme", + "tautulli.NoActiveStreams": "Aucun stream en cours", + "tautulli.None": "Aucun", + "tautulli.More": "Plus", + "tautulli.Metadata": "Métadonnées", + "tautulli.Location": "Localisation", + "tautulli.Library": "Bibliothèque", + "tautulli.History": "Historique", + "tautulli.ETA": "Temps restant", + "tautulli.Episode": "Épisode {}", + "tautulli.Duration": "Durée", + "tautulli.DirectStreams": "Direct Streams", + "tautulli.DirectStream": "Direct Stream", + "tautulli.DirectPlays": "Lectures directe", + "tautulli.DirectPlay": "Lecture directe", + "tautulli.DeletingTemporarySessionsFailed": "Échec de la suppression des sessions temporaires", + "tautulli.DeletingTemporarySessionsDescription": "Les sessions temporaires ont été supprimés", + "tautulli.DeletingImageCacheDescription": "Le cache des images de Tautulli a été supprimé", + "tautulli.DeletingTemporarySessions": "Suppression des sessions temporaires…", + "tautulli.DeletingImageCacheFailed": "Échec de la suppression du cache d'image", + "tautulli.DeletingImageCache": "Suppression du cache des images…", + "tautulli.DeletingCacheFailed": "Échec de la suppression du cache", + "tautulli.DeletingCacheDescription": "Le cache de Tautulli est en cours de suppression", + "tautulli.DeletingCache": "Suppression du cache en cours…", + "tautulli.DeleteTemporarySessions": "Supprimer les sessions temporaires", + "tautulli.DeleteImageCache": "Supprimer le cache des images", + "tautulli.DeleteCache": "Supprimer le cache", + "tautulli.Copy": "Copier", + "tautulli.Container": "Container", + "tautulli.Bandwidth": "Bande passante", + "tautulli.BackupDatabase": "Sauvegarder la base de donnée", + "tautulli.BackupConfiguration": "Sauvegarder la configuration", + "tautulli.BackingUpDatabaseFailed": "Échec de la sauvegarde de la base de données", + "tautulli.BackingUpDatabaseDescription": "Sauvegarde de votre base de données en arrière-plan", + "tautulli.BackingUpDatabase": "Sauvegarde de la base de données…", + "tautulli.BackingUpConfigurationFailed": "Échec de la sauvegarde de la configuration", + "tautulli.BackingUpConfigurationDescription": "Sauvegarde de votre configuration en arrière-plan", + "tautulli.BackingUpConfiguration": "Sauvegarde de la configuration…", + "tautulli.Audio": "Audio", + "tautulli.ActivityDetails": "Détails de l'activité", + "tautulli.Activity": "Activité" +} diff --git a/localization/tautulli/it.json b/localization/tautulli/it.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/localization/tautulli/it.json @@ -0,0 +1 @@ +{} diff --git a/localization/tautulli/nb-NO.json b/localization/tautulli/nb-NO.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/localization/tautulli/nb-NO.json @@ -0,0 +1 @@ +{} diff --git a/localization/tautulli/ru.json b/localization/tautulli/ru.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/localization/tautulli/ru.json @@ -0,0 +1 @@ +{} diff --git a/localization/tautulli/sv.json b/localization/tautulli/sv.json new file mode 100644 index 00000000..0967ef42 --- /dev/null +++ b/localization/tautulli/sv.json @@ -0,0 +1 @@ +{} diff --git a/pubspec.lock b/pubspec.lock index 99ff5636..24b789eb 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -42,7 +42,7 @@ packages: name: badges url: "https://pub.dartlang.org" source: hosted - version: "1.1.6" + version: "1.2.0" build: dependency: transitive description: @@ -63,7 +63,7 @@ packages: name: build_daemon url: "https://pub.dartlang.org" source: hosted - version: "2.1.8" + version: "2.1.9" build_resolvers: dependency: transitive description: @@ -98,7 +98,7 @@ packages: name: built_value url: "https://pub.dartlang.org" source: hosted - version: "8.0.0" + version: "8.0.2" characters: dependency: transitive description: @@ -140,7 +140,7 @@ packages: name: cloud_firestore url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" cloud_firestore_platform_interface: dependency: transitive description: @@ -154,14 +154,14 @@ packages: name: cloud_firestore_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" code_builder: dependency: transitive description: name: code_builder url: "https://pub.dartlang.org" source: hosted - version: "3.6.0" + version: "3.7.0" collection: dependency: transitive description: @@ -238,14 +238,14 @@ packages: name: dbus url: "https://pub.dartlang.org" source: hosted - version: "0.2.1" + version: "0.2.3" dio: dependency: "direct main" description: name: dio url: "https://pub.dartlang.org" source: hosted - version: "3.0.10" + version: "4.0.0-beta7" easy_localization: dependency: "direct main" description: @@ -281,13 +281,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "4.1.4" - f_logs: - dependency: "direct main" - description: - name: f_logs - url: "https://pub.dartlang.org" - source: hosted - version: "1.3.0-alpha-02" ffi: dependency: transitive description: @@ -309,13 +302,41 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "3.0.0" + firebase: + dependency: transitive + description: + name: firebase + url: "https://pub.dartlang.org" + source: hosted + version: "9.0.0" + firebase_analytics: + dependency: "direct main" + description: + name: firebase_analytics + url: "https://pub.dartlang.org" + source: hosted + version: "7.1.1" + firebase_analytics_platform_interface: + dependency: transitive + description: + name: firebase_analytics_platform_interface + url: "https://pub.dartlang.org" + source: hosted + version: "1.1.0" + firebase_analytics_web: + dependency: transitive + description: + name: firebase_analytics_web + url: "https://pub.dartlang.org" + source: hosted + version: "0.2.0+1" firebase_auth: dependency: "direct main" description: name: firebase_auth url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" firebase_auth_platform_interface: dependency: transitive description: @@ -329,14 +350,14 @@ packages: name: firebase_auth_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.2" firebase_core: dependency: "direct main" description: name: firebase_core url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" firebase_core_platform_interface: dependency: transitive description: @@ -350,7 +371,7 @@ packages: name: firebase_core_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" firebase_crashlytics: dependency: "direct main" description: @@ -385,7 +406,7 @@ packages: name: firebase_messaging_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" firebase_storage: dependency: "direct main" description: @@ -406,7 +427,7 @@ packages: name: firebase_storage_web url: "https://pub.dartlang.org" source: hosted - version: "1.0.0" + version: "1.0.1" fixnum: dependency: transitive description: @@ -427,7 +448,7 @@ packages: name: flash url: "https://pub.dartlang.org" source: hosted - version: "1.3.2" + version: "1.5.0" fluro: dependency: "direct main" description: @@ -484,7 +505,7 @@ packages: name: google_nav_bar url: "https://pub.dartlang.org" source: hosted - version: "4.0.2" + version: "5.0.3" graphs: dependency: transitive description: @@ -528,7 +549,7 @@ packages: source: hosted version: "2.2.0" http_parser: - dependency: "direct overridden" + dependency: transitive description: name: http_parser url: "https://pub.dartlang.org" @@ -540,14 +561,14 @@ packages: name: in_app_purchase url: "https://pub.dartlang.org" source: hosted - version: "0.5.0" + version: "0.5.1" infinite_scroll_pagination: dependency: "direct main" description: name: infinite_scroll_pagination url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "3.0.1" intl: dependency: "direct main" description: @@ -610,7 +631,7 @@ packages: name: modal_bottom_sheet url: "https://pub.dartlang.org" source: hosted - version: "1.0.0+1" + version: "2.0.0" nested: dependency: transitive description: @@ -820,70 +841,28 @@ packages: name: quiver url: "https://pub.dartlang.org" source: hosted - version: "2.1.5" + version: "3.0.0" radarr: dependency: "direct main" description: name: radarr url: "https://pub.dartlang.org" source: hosted - version: "1.1.4+1" - sembast: - dependency: transitive - description: - name: sembast - url: "https://pub.dartlang.org" - source: hosted - version: "2.4.10+4" - share_plus: + version: "2.0.0-pre.1" + share: dependency: "direct main" description: - name: share_plus + name: share url: "https://pub.dartlang.org" source: hosted - version: "2.0.0" - share_plus_linux: - dependency: transitive - description: - name: share_plus_linux - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - share_plus_macos: - dependency: transitive - description: - name: share_plus_macos - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - share_plus_platform_interface: - dependency: transitive - description: - name: share_plus_platform_interface - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - share_plus_web: - dependency: transitive - description: - name: share_plus_web - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" - share_plus_windows: - dependency: transitive - description: - name: share_plus_windows - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.0" + version: "2.0.1" shared_preferences: dependency: transitive description: name: shared_preferences url: "https://pub.dartlang.org" source: hosted - version: "2.0.3" + version: "2.0.4" shared_preferences_linux: dependency: transitive description: @@ -951,14 +930,14 @@ packages: name: sliver_tools url: "https://pub.dartlang.org" source: hosted - version: "0.2.0-nullsafety" + version: "0.2.0" sonarr: dependency: "direct main" description: name: sonarr url: "https://pub.dartlang.org" source: hosted - version: "1.1.1+1" + version: "2.0.0-pre.1" source_gen: dependency: transitive description: @@ -1001,13 +980,20 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "1.1.0" - synchronized: - dependency: transitive + supercharged: + dependency: "direct main" description: - name: synchronized + name: supercharged url: "https://pub.dartlang.org" source: hosted - version: "3.0.0" + version: "2.0.0" + supercharged_dart: + dependency: transitive + description: + name: supercharged_dart + url: "https://pub.dartlang.org" + source: hosted + version: "2.0.0" table_calendar: dependency: "direct main" description: @@ -1021,7 +1007,7 @@ packages: name: tautulli url: "https://pub.dartlang.org" source: hosted - version: "1.2.2+1" + version: "2.0.0-pre.2" term_glyph: dependency: transitive description: @@ -1042,7 +1028,7 @@ packages: name: tuple url: "https://pub.dartlang.org" source: hosted - version: "1.0.3" + version: "2.0.0" typed_data: dependency: transitive description: @@ -1119,7 +1105,7 @@ packages: name: wake_on_lan url: "https://pub.dartlang.org" source: hosted - version: "1.1.2+1" + version: "2.0.1" watcher: dependency: transitive description: @@ -1155,13 +1141,6 @@ packages: url: "https://pub.dartlang.org" source: hosted version: "5.0.2" - xxtea: - dependency: transitive - description: - name: xxtea - url: "https://pub.dartlang.org" - source: hosted - version: "2.0.3" yaml: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index aa50ab07..c035880b 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -1,63 +1,58 @@ name: lunasea description: Self-Hosted Controller -version: 5.0.0+50000012 +version: 5.0.0+50000013 publish_to: 'none' environment: sdk: ">=2.7.0 <3.0.0" dependencies: - badges: ^1.1.6 - cloud_firestore: ^1.0.0 - connectivity_plus: ^1.0.0 - convert: ^3.0.0 - dio: ^3.0.10 - easy_localization: ^3.0.0 - encrypt: ^5.0.0-beta.1 - expandable: ^4.1.4 - file_picker: ^3.0.0 - firebase_auth: ^1.0.0 - firebase_core: ^1.0.0 - firebase_crashlytics: ^1.0.0 - firebase_messaging: ^9.0.0 - firebase_storage: ^8.0.0 - flash: ^1.3.2 - fluro: ^2.0.3 flutter: sdk: flutter - flutter_spinkit: ^5.0.0 - flutter_sticky_header: ^0.5.0 - fl_chart: ^0.20.1 - f_logs: ^1.3.0-alpha-02 - google_nav_bar: ^4.0.2 - hive: ^2.0.0 - hive_flutter: ^1.0.0 - in_app_purchase: ^0.5.0 - infinite_scroll_pagination: ^3.0.0 - intl: ^0.17.0 - modal_bottom_sheet: ^1.0.0+1 - network_info_plus: ^1.0.0 - package_info: ^2.0.0 - path_provider: ^2.0.1 - percent_indicator: ^2.1.9+1 - provider: ^5.0.0 - quick_actions: ^0.5.0 - share_plus: ^2.0.0 - stack_trace: ^1.10.0 - table_calendar: ^2.3.3 - tuple: ^1.0.3 - url_launcher: ^6.0.2 - uuid: ^3.0.1 - xml: ^5.0.2 - # Comet.Tools Packages - radarr: ^1.1.4+1 - sonarr: ^1.1.1+1 - tautulli: ^1.2.2+1 - wake_on_lan: ^1.1.2+1 - -dependency_overrides: - http_parser: ^4.0.0 - intl: ^0.17.0 - path_provider: ^2.0.1 + badges: ^1.2.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + cloud_firestore: ^1.0.1 # ANDROID IOS MACOS WEB + connectivity_plus: ^1.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + convert: ^3.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + dio: ^4.0.0-beta7 # ANDROID IOS LINUX MACOS WEB WINDOWS + easy_localization: ^3.0.0 # ANDROID IOS LINUX MACOS WEB + encrypt: ^5.0.0-beta.1 # ANDROID IOS LINUX MACOS WEB WINDOWS + expandable: ^4.1.4 # ANDROID IOS LINUX MACOS WEB WINDOWS + file_picker: ^3.0.0 # ANDROID IOS WEB + firebase_analytics: ^7.1.1 # ANDROID IOS WEB + firebase_auth: ^1.0.1 # ANDROID IOS MACOS WEB + firebase_core: ^1.0.1 # ANDROID IOS MACOS WEB + firebase_crashlytics: ^1.0.0 # ANDROID IOS MACOS + firebase_messaging: ^9.0.0 # ANDROID IOS MACOS WEB + firebase_storage: ^8.0.0 # ANDROID IOS MACOS WEB + flash: ^1.5.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + fluro: ^2.0.3 # ANDROID IOS LINUX MACOS WEB WINDOWS + flutter_spinkit: ^5.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + flutter_sticky_header: ^0.5.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + fl_chart: ^0.20.1 # ANDROID IOS LINUX MACOS WEB WINDOWS + google_nav_bar: ^5.0.3 # ANDROID IOS LINUX MACOS WEB WINDOWS + hive: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + hive_flutter: ^1.0.0 # ANDROID IOS LINUX MACOS WINDOWS + in_app_purchase: ^0.5.1 # ANDROID IOS + infinite_scroll_pagination: ^3.0.1 # ANDROID IOS LINUX MACOS WEB WINDOWS + intl: ^0.17.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + modal_bottom_sheet: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + network_info_plus: ^1.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + package_info: ^2.0.0 # ANDROID IOS MACOS + path_provider: ^2.0.1 # ANDROID IOS LINUX MACOS WINDOWS + percent_indicator: ^2.1.9+1 # ANDROID IOS LINUX MACOS WEB WINDOWS + provider: ^5.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + quick_actions: ^0.5.0 # ANDROID IOS + radarr: ^2.0.0-pre.1 # ANDROID IOS LINUX MACOS WEB WINDOWS + share: ^2.0.1 # ANDROID IOS + sonarr: ^2.0.0-pre.1 # ANDROID IOS LINUX MACOS WEB WINDOWS + stack_trace: ^1.10.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + supercharged: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + table_calendar: ^2.3.3 # ANDROID IOS LINUX MACOS WEB WINDOWS + tautulli: ^2.0.0-pre.2 # ANDROID IOS LINUX MACOS WEB WINDOWS + tuple: ^2.0.0 # ANDROID IOS LINUX MACOS WEB WINDOWS + url_launcher: ^6.0.2 # ANDROID IOS LINUX MACOS WEB WINDOWS + uuid: ^3.0.1 # ANDROID IOS LINUX MACOS WEB WINDOWS + wake_on_lan: ^2.0.1 # ANDROID IOS LINUX MACOS WINDOWS + xml: ^5.0.2 # ANDROID IOS LINUX MACOS WEB WINDOWS dev_dependencies: analyzer: ^1.1.0 @@ -70,13 +65,9 @@ flutter: # System Assets - assets/changelog.json - assets/localization/ - - assets/branding/ - # Other - - assets/images/colors/ - - assets/images/lidarr/ - - assets/images/radarr/ - - assets/images/sonarr/ - - assets/images/tautulli/ + # Images + - assets/images/blanks/ + - assets/images/branding/ - assets/images/services/ fonts: - family: CustomIcons @@ -86,14 +77,12 @@ flutter: flutter_icons: android: true ios: true - image_path: "assets/branding/icon.png" + image_path: "assets/images/branding/icon.png" adaptive_icon_background: "#32323E" - adaptive_icon_foreground: "assets/branding/icon_adaptive.png" + adaptive_icon_foreground: "assets/images/branding/icon_adaptive.png" flutter_native_splash: - image: "assets/branding/splash.png" + image: "assets/images/branding/splash.png" color: "#32323E" -scripts: - build: flutter packages pub run build_runner build --delete-conflicting-outputs - build_localizations: dart ./scripts/build_localizations.dart +scripts: derry.yaml diff --git a/scripts/build/aab.sh b/scripts/build/aab.sh index 9b79182b..d9474dac 100755 --- a/scripts/build/aab.sh +++ b/scripts/build/aab.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash -cd ../.. # Remove old builds rm -rf output/*.aab # Clean and build diff --git a/scripts/build/apk.sh b/scripts/build/apk.sh index 8ff1fb35..9effbf47 100755 --- a/scripts/build/apk.sh +++ b/scripts/build/apk.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash -cd ../.. # Remove old builds rm -rf output/*.apk # Clean and build diff --git a/scripts/build/ipa.sh b/scripts/build/ipa.sh index e61df06c..61ce08ce 100755 --- a/scripts/build/ipa.sh +++ b/scripts/build/ipa.sh @@ -1,6 +1,5 @@ #!/usr/bin/env bash -cd ../.. # Remove old builds rm -rf build rm -rf output/*.ipa diff --git a/scripts/build_localizations.dart b/scripts/generate/localization.dart similarity index 100% rename from scripts/build_localizations.dart rename to scripts/generate/localization.dart