mirror of
https://github.com/jagandeepbrar/lunasea.git
synced 2026-08-30 20:24:25 +00:00
[Release] v4.1.0+40100005 (#274)
NEW - [Sonarr/Queue] Check and update the queue in the background every 60 seconds - [Sonarr/Queue] Ability to view and manage your queue - [Sonarr/Queue] Ability to delete an item in the queue - [Sonarr/Sorting] Ability to set the initial sorting direction alongside the sorting type for series and releases TWEAKS - [Radarr] Use Radarr v3 icon across the UI - [Settings/Dialogs] Small tweaks and additional notes for entering hosts and passwords - [Settings/Host Dialog] Add validator on host to ensure user adds http:// or https:// FIXES - [UI/Checkbox] Fix overly vibrant checkbox background - [Sonarr/Add] Fix possible grey screen when adding a show with no seasons yet - [Flutter] Upgraded Flutter & Packages
This commit is contained in:
432
CHANGELOG.md
Normal file
432
CHANGELOG.md
Normal file
@@ -0,0 +1,432 @@
|
||||
# LunaSea Changelog
|
||||
|
||||
## [Beta/TestFlight] v4.1.0 (40100005)
|
||||
|
||||
#### NEW
|
||||
- `[Sonarr/Queue]` Check and update the queue in the background every 60 seconds
|
||||
- `[Sonarr/Queue]` Ability to view and manage your queue
|
||||
- `[Sonarr/Queue]` Ability to delete an item in the queue
|
||||
- `[Sonarr/Sorting]` Ability to set the initial sorting direction alongside the sorting type for series and releases
|
||||
|
||||
#### TWEAKS
|
||||
- `[Radarr]` Use Radarr v3 icon across the UI
|
||||
- `[Settings/Dialogs]` Small tweaks and additional notes for entering hosts and passwords
|
||||
- `[Settings/Host Dialog]` Add validator on host to ensure user adds http:// or https://
|
||||
|
||||
#### FIXES
|
||||
- `[UI/Checkbox]` Fix overly vibrant checkbox background
|
||||
- `[Sonarr/Add]` Fix possible grey screen when adding a show with no seasons yet
|
||||
- `[Flutter]` Upgraded Flutter & Packages
|
||||
|
||||
---
|
||||
|
||||
## [Beta/TestFlight] v4.1.0 (40100004)
|
||||
|
||||
#### FIXES
|
||||
- `[Sonarr/v2]` Fix grey screen when attempting to add a new series
|
||||
|
||||
#### TWEAKS
|
||||
- `[Packages]` Updated transitive Flutter packages
|
||||
|
||||
---
|
||||
|
||||
## [Beta/TestFlight] v4.1.0 (40100003)
|
||||
|
||||
#### NEW
|
||||
- `[Sonarr]` Ability to manage your tags
|
||||
- `[Sonarr/Add]` Ability to set tags when adding a new series
|
||||
- `[Sonarr/Edit]` Ability to update tags when editing a series
|
||||
|
||||
#### FIXES
|
||||
- `[Routing]` Fixed some issues with routing
|
||||
- `[Sonarr/Add]` After adding a series, hitting back will now show the series as added
|
||||
|
||||
---
|
||||
|
||||
## [Beta/TestFlight] v4.1.0 (40100002)
|
||||
|
||||
#### NEW
|
||||
- `[Images]` Ability to set (or entirely disable) the opacity of the background image for cards
|
||||
- `[Sonarr]` Ability to set the default sorting type for series and releases
|
||||
- `[Tautulli/Activity]` Show the ETA for when the session will be completed
|
||||
- `[Tautulli/Activity]` Show if the hardware transcoding is being used on the stream
|
||||
|
||||
#### FIXES
|
||||
- `[Networking]` Ensure that insecure (HTTP/80) connections are allowed at the platform-level
|
||||
- `[Flutter]` Upgraded Flutter & Packages
|
||||
|
||||
---
|
||||
|
||||
## [Beta/TestFlight] v4.1.0 (40100001)
|
||||
|
||||
#### NEW
|
||||
- `[Networking]` Strict TLS/SSL validation is now disabled globally
|
||||
- `[Routing]` Hold the AppBar back button to pop back to the home page of the module
|
||||
- `[Settings/Sonarr]` Toggle to enable Sonarr v3 features
|
||||
- `[Sonarr]` Complete rewrite of Sonarr
|
||||
- `[Sonarr]` State is now held across module switches
|
||||
- `[Sonarr/Overview]` View tags applied to series
|
||||
- `[Sonarr/Catalogue]` (v3 only) Ability to set and update language profile
|
||||
- `[Sonarr/Catalogue]` Ability to view all, only monitored, or only unmonitored series
|
||||
- `[Sonarr/Releases]` (v3 only) Ability to interactively search for season packs
|
||||
- `[Sonarr/Releases]` Ability to view all, only approved, or only rejected releases
|
||||
|
||||
#### TWEAKS
|
||||
- `[Settings]` Removed all toggles for strict TLS
|
||||
- `[Sonarr]` Many tweaks to Sonarr's design
|
||||
- `[Sonarr/Add]` (v3 only) Tapping an already-added series will take you to the series page
|
||||
- `[Sonarr/Add]` Automatically navigate to newly added series
|
||||
- `[Sonarr/Series]` Toggling monitored state of series has now been moved to the edit prompt
|
||||
|
||||
#### FIXES
|
||||
- `[Images]` Images will now load for invalid/self-signed certificates
|
||||
- `[Tautulli/Activity]` Fix grey screen for music activity
|
||||
- `[TextField]` Fix TextField actions (cut, copy, paste, etc.) not showing
|
||||
- `[Timestamps]` Fix 12:xx AM being shown as 00:xx AM
|
||||
- `[Everything]` Additional small bug fixes
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v4.0.0 (400102)
|
||||
|
||||
#### NEW
|
||||
- `[Module]` Tautulli support
|
||||
- `[Calendar]` Ability to set how many days in the past and future to fetch calendar entries for
|
||||
- `[Drawer]` Categorical folders are now optional
|
||||
- `[Drawer]` If using folders, ability to set the initial expanded state
|
||||
- `[Locale]` Ability to use 24 hour timestamps
|
||||
- `[Quick Actions]` Ability to set upto four homescreen quick actions
|
||||
- `[Search]` Ability to set custom headers for individual indexers
|
||||
- `[Settings]` Complete overhaul of the settings
|
||||
- `[Settings/Resources]` (iOS) Added link to join TestFlight
|
||||
|
||||
#### TWEAKS
|
||||
- `[Home/Calendar]` Separate calendar view type into its own preference
|
||||
- `[Home/Calendar]` Show no modules enabled message when there are no automation modules enabled, not just no modules overall
|
||||
- `[Home/Calendar]` Default past and future days is now 14 days for each
|
||||
- `[Images]` Images are no longer cached to the device storage to heavily improve performance & reduce crashing on older/lower-end devices
|
||||
- `[Images]` Fetch images at specific resolutions instead of full resolution to reduce network performance and decrease memory pressure
|
||||
- `[Search]` Improved detection of adult categories
|
||||
- `[Settings]` Settings now replaces the active module/route and shows the drawer on the base route
|
||||
- `[Settings/System]` Removed clear image cache tile
|
||||
- `[UI]` Added new loading animation design
|
||||
|
||||
#### FIXES
|
||||
- `[Flutter]` Updated packages & Flutter
|
||||
- `[General]` Many small bug fixes
|
||||
- `[LunaSea]` Many behind the scenes changes to reduce memory pressure
|
||||
- `[LunaSea]` Heavy improvements and fixes to the navigation routing
|
||||
- `[Settings/Logs]` Logs could be shown in reverse order
|
||||
- `[Text]` Fixed "squished" text on iOS 14 and higher devices
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v3.3.0 (330002)
|
||||
|
||||
#### NEW
|
||||
- `[Home/Calendar]` New "schedule" view
|
||||
- `[Home/Modules]` Option to use module "brand colour" or the LunaSea list colours
|
||||
- `[Search]` Option to hide adult categories
|
||||
- `[-arr/Catalogue]` Ability to sort by date added
|
||||
- `[-arr/Search]` Show the indexer/tracker on the collapsed tile
|
||||
|
||||
#### TWEAKS
|
||||
- None
|
||||
|
||||
#### FIXES
|
||||
- `[Sonarr]` Fixed multiple errors related to parsing fetched episode data
|
||||
- `[Everything]` Multiple smaller crash/error fixes
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v3.2.0 (320003)
|
||||
|
||||
#### NEW
|
||||
- `[Drawer]` Add the LunaSea logo to the header
|
||||
- `[Logging]` Integrated Sentry, an open-source exception/crash log aggregation tool
|
||||
- `[Settings/System]` Added toggle (under system -> advanced) to disable Sentry logging
|
||||
|
||||
#### TWEAKS
|
||||
- `[System]` Implemented new image caching backend
|
||||
- `[APIs]` Improved exception logging
|
||||
- `[Logging]` Improved on-device logger to have more useful stack traces
|
||||
|
||||
#### FIXES
|
||||
- `[-arr/Details]` Fixed crash related to state management
|
||||
- `[radarr/Add]` Fixed crash when a searched movie does not have a minimum availability value available
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v3.1.0 (310004)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Settings/Resources]` Added Discord invite link for official server
|
||||
- `[-arr]` Ability to search and enter interactive search from all upcoming and missing pages
|
||||
- `[-arr/Add]` Ability to jump directly into newly added content from toast notification
|
||||
- `[Radarr/Delete]` Ability to add to exclusion list when deleting content
|
||||
- `[Clients]` Hide and show queue pause/start FAB on scroll
|
||||
- `[Clients/History]` History tiles are now expandable in-line
|
||||
- `[SABnzbd/Statistics]` Show both temporary and final storage space
|
||||
- `[Calendar]` Ability to search/enter interactive search directly from calendar tiles
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[Development]` Updated Flutter packages
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[API/Host]` Correctly handle cases where host ends with a forward slash
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v3.0.0 (300100)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Search]` Releases are now shown as an expandable tile
|
||||
- `[Search/Category Results]` Ability to sort and filter results
|
||||
- `[Search/Search Results]` Ability to sort search results
|
||||
- `[-rr/Catalogue]` Many additional sorting options
|
||||
- `[-rr/Releases]` Releases are now shown as an expandable tile
|
||||
- `[-rr/Releases]` Ability to sort, hide, and filter releases
|
||||
- `[Sonarr/Add]` Ability to set initial episode monitoring state
|
||||
- `[Sonarr/Episodes]` Episodes are now shown as an expandable tile
|
||||
- `[Radarr/Releases]` Shows custom format tags
|
||||
- `[Clients]` FAB icon animates between queue state
|
||||
- `[Images]` Ability to clear network image cache
|
||||
- `[UI/AMOLED Theme]` Optional setting to add subtle border
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[Changelog]` Removed integrated changelog, redirects to documentation changelog
|
||||
- `[-rr]` Use the term "Interactive" instead of "Manual" for search
|
||||
- `[-rr/Links]` Normalize size of images
|
||||
- `[Sonarr/Upcoming]` Now shows dates in-line as a styled header
|
||||
- `[Sonarr/Season View]` Now shows season number in-line as a styled header
|
||||
- `[UI/Font]` Adjusted font size across entire application
|
||||
- `[UI/Dropdowns]` Change dropdowns to popup menus
|
||||
- `[UI]` Rounder radius around tiles, popups, etc.
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Home/Calendar]` Row height is now statically set to prevent huge calendar on larger displays
|
||||
- `[Sonarr/Seasons]` Fixed crash related to seasons with no statistics data for percentage of season completion
|
||||
- `[Sonarr/Episodes]` Episode numbers greater than 100 could cause a line-break
|
||||
- `[Sonarr/Episodes]` Fixed/safe-guarded layout crash on incomplete episode data received
|
||||
- `[Sonarr/Queue]` Safe-guarded Sonarr queue results when results are null
|
||||
- `[Snackbar]` Snackbar wouldn't adopt AMOLED styling when enabled
|
||||
- `[State]` Fixed crashes caused by setting the state of an unmounted widget
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v2.3.0 (230004)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Module]` Wake on LAN support
|
||||
- `[Settings/Modules]` Ability to set custom headers to be attached to module requests
|
||||
- `[Settings/Changelog]` Changelog is now displayed as a route, not a dialog
|
||||
- `[UX]` Hitting the back button on apex/primary routes will now open the drawer instead of closing the application
|
||||
- `[UX]` Enable landscape mode for iPhones
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[-rr/Details]` Removed sliver AppBar and fanart as it caused unwanted scrolling interference (A revamped overview page in the future will bring back the fanart images)
|
||||
- `[-rr/Details]` Switched from AppBar tabs to bottom navigation bar
|
||||
- `[-rr/Release]` Do not show warning message when triggering a release download from details page on rejected release
|
||||
- `[Dialogs]` Reimplemented all dialogs
|
||||
- `[Dialogs]` Keyboard type is now set for all inputs
|
||||
- `[Dialogs]` All inputs are now validated (to some extent) and can be submitted via the Keyboard
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[SnackBar]` SnackBar could cause UI locking when doing swipe-back gestures
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v2.2.0 (220003)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Donations]` Added donation IAPs
|
||||
- `[Profiles]` Added rapid-profile switcher
|
||||
- `[Settings]` Added license attributions
|
||||
- `[Settings]` Added feedback link
|
||||
- `[-rr/Add]` Search bar will now be autofocused
|
||||
- `[SABnzbd]` Added statistics for individual servers
|
||||
- `[NZBGet]` Option to use basic authentication instead of URL-encoded authentication
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[UI]` Removed custom letter spacing
|
||||
- `[Settings]` Added subheaders
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Database]` Cleanly exit on clean application exit to prevent corruption
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v2.1.0 (66)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Branding]` New icon & splash screen
|
||||
- `[Links]` Ability to set which browser you open links in (iOS only)
|
||||
- `[Home/Calendar]` Ability to set starting day of week
|
||||
- `[Home/Calendar]` Ability to set starting calendar size
|
||||
- `[Home/Calendar]` Ability to enable and disable specific modules that show up in the calendar
|
||||
- `[Appearance/Theme]` Option to enable AMOLED black theme
|
||||
- `[Platform]` LunaSea is now buildable & available for Android
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[Settings]` Redesign of settings page
|
||||
- `[General]` Use the term "Modules" instead of "Services"
|
||||
- `[-rr/Details]` Background image header/appbar is now collapsed by default
|
||||
- `[-rr/Details]` Left align title to match the rest of LunaSea
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Sonarr]` Toast for toggling season monitor state would show monitor status of the series, not the season
|
||||
- `[Settings/Backup]` Backing up your configuration would always fail
|
||||
- `[Search]` Would show an empty screen if you deleted all indexers while search is open
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v2.0.1 (55)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[SABnzbd]` Ability to upload .rar & .gz archives
|
||||
- `[-rr/Add]` All configurable values are now stored in cold database, persisting between sessions
|
||||
- `[-rr/Add]` Root folders now also show available space for the folder
|
||||
- `[Search]` When sending an NZB to a client, there is now an action in the toast to jump directly to the respective client
|
||||
- `[Automation/Search]` When downloading a release manually, there is now an action in the toast to pop back to the main screen of the automation service
|
||||
- `[Settings]` Ability to disable SSL/TLS validation for all services
|
||||
- `[HTTP]` With the above, support for self-signed SSL certificates
|
||||
|
||||
#### TWEAKS
|
||||
- `[Descriptions]` Adjusted alignment and consistency when no summary is available
|
||||
- `[Search]` Removed redundant “Sending” toast since it very quickly gets covered by the follow-up toast
|
||||
- `[Automation]` Edit content prompt now shows full title of the content
|
||||
- `[Clients]` Opening the edit menu now shows the full title of the job
|
||||
- `[UI]` Tweaked design of content headers
|
||||
- `[Settings]` Added headers to automation and client pages to separate regular and advanced configuration options
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[HTTP]` Safer handling of redirects
|
||||
- `[Routes]` Make route changes asynchronous to help minimize stutters
|
||||
- `[Radarr/Add]` Fixed wrong title for minimum availability card
|
||||
- `[Restore Configuration]` Error message had typos
|
||||
- `[UI]` Fixed uneven font sizing in some prompts
|
||||
- `[NZBGet/SABnzbd]` Failure on uploading an NZB would show no error message
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v2.0.0 (333)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[iOS]` Built for iOS 13.4
|
||||
- `[Indexers/Search]` Full support for browsing and searching Newznab-based indexers!
|
||||
- `[Indexers/Search]` Support for NZBHydra2
|
||||
- `[Indexers/Search]` Download NZB files directly to your device
|
||||
- `[Indexers/Search]` Send NZB files directly from the indexer to your client of choice
|
||||
- `[-rr/Catalogue]` Catalogue search bar is now stickied
|
||||
- `[-rr/History]` Ability to enter content
|
||||
- `[-rr/Add]` More information (year, seasons, etc.) shown in result tiles
|
||||
- `[NZBGet]` Ability to search through fetched history
|
||||
- `[SABnzbd]` Ability to search through fetched history
|
||||
- `[Settings/Configuration]` Ability to clear configuration
|
||||
- `[Drawer]` Ability to switch profiles in navigation Drawer
|
||||
- `[Snackbar]` New snackbar style, design, and formatting
|
||||
- `[Everything]` All services now dynamically reload on profile changes
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[Everything]` Reimplemented... everything
|
||||
- `[Everything]` Moved away from FABs (where possible) to buttons
|
||||
- `[Navigation]` Ability to swipe left and right between bottom navigation tabs (except Settings)
|
||||
- `[Navigation Bar]` Slightly redesigned
|
||||
- `[Home/Summary]` Redesigned summary page
|
||||
- `[Home/Summary]` Removed fetching of series count, movie count, and artist count
|
||||
- `[Home/Calendar]` Now only shows 1 dot for each day instead of 3
|
||||
- `[Home/Calendar]` Highlights today as well as selected day
|
||||
- `[Home/Calendar]` Now shows the day of the week on the calendar
|
||||
- `[Home/Calendar]` Now defaults to showing 1 week (swipe down to show two weeks or one month)
|
||||
- `[Settings]` No longer a need to save configuration settings, everything is saved automatically
|
||||
- `[Search Bar]` "X" to clear search bars
|
||||
- `[-rr/Catalogue]` Sorting now scrolls back to top
|
||||
- `[-rr/Catalogue]` Moved hide unmonitored button to stickied search bar
|
||||
- `[-rr/Add]` Selected profile, folders, etc. are stored in state until application is closed or profile is switched
|
||||
- `[-rr/Images]` Images now show placeholder, transition to real content on load
|
||||
- `[Sonarr/Episodes]` Multi-select episodes with single tap anywhere on tile, now highlighted for easier distinction
|
||||
- `[SABnzbd]` Limit queue to first 100 results
|
||||
- `[SABnzbd]` Lowered refresh rate to 2 seconds from 1 second
|
||||
- `[NZBGet]` Limit queue to first 100 results
|
||||
- `[NZBGet]` Lowered refresh rate to 2 seconds from 1 second
|
||||
- `[UI]` Reduced elevation of UI in general
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Sonarr/Search]` Searching for an entire season now executes a season search instead of individual episode searches
|
||||
- `[Logs]` Fixed bug where logs could not load in some cases and always show "Logs Not Found"
|
||||
- `[Radarr/Search]` Now correctly retains search state to prevent needless researching & API hits
|
||||
- `[Configuration]` Deleting or renaming "default" profile could cause a new "default" profile to be created on next launch
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v1.1.0 (44)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[Home]` Calendar view for upcoming -rr content
|
||||
- `[Sonarr]` Ability to toggle single episode monitored status
|
||||
- `[Sonarr]` Ability to delete file
|
||||
- `[Radarr]` Split missing tab into missing and upcoming
|
||||
- `[-rr]` Long-press tile on non-catalogue pages to view catalogue entry
|
||||
- `[-rr]` Ability to delete files when deleting catalogue entries
|
||||
- `[Documentation]` Added a link to WIP documentation
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Prompts]` All prompts now use the correct colour ordering
|
||||
- `[NZBGet]` Adjusted authentication method to interfere less with custom auth setups
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[Drawer]` Dropdown groups are open by default until more services are added
|
||||
- `[Settings]` Minor tile shuffling and rewording
|
||||
- `[Navigation]` New style for the navigation bars
|
||||
- `[Navigation]` Added custom icons to navigation bars
|
||||
- `[Releases]` Easier to differentiate the release's protocol
|
||||
|
||||
---
|
||||
|
||||
## [Stable/Production] v1.0.0 (33)
|
||||
|
||||
#### NEW
|
||||
|
||||
- `[-rr]` When adding new content, checks if content is already in your library
|
||||
- `[-rr]` Ability to sort catalogue by size of alphabetical
|
||||
- `[Settings]` Ability to rename a profile
|
||||
- `[SAB/NZBGet]` Ability to pause the queue for some amount of time
|
||||
- `[NZBGet]` Ability to filter out successful history entries
|
||||
|
||||
#### FIXES
|
||||
|
||||
- `[Radarr]` Fetching quality profiles could fail
|
||||
- `[SAB/NZBGet]` Percentage calculation could fail causing a grey screen
|
||||
- `[SAB/NZBGet]` Connection error now cancels timer until manual refresh (cleaner logs)
|
||||
|
||||
#### TWEAKS
|
||||
|
||||
- `[Build]` Adjusted how build number is presented
|
||||
- `[Sonarr]` Now shows size on disk on catalogue page
|
||||
- `[Lidarr]` Now shows size on disk on catalogue page
|
||||
- `[Settings]` Successful connection test now also triggers save
|
||||
- `[Settings]` Save button is now more obvious/clear
|
||||
- `[Settings]` Adjusted and added more tips when adding hosts
|
||||
@@ -31,8 +31,8 @@ LunaSea even comes with support for multiple instances of applications using pro
|
||||
|
||||
1. A MacOS Machine
|
||||
2. An AppleID account (does not require developer account)
|
||||
3. [Flutter Framework (Beta Channel)](https://flutter.dev/)
|
||||
4. [XCode 11.4 or Higher](https://apps.apple.com/ca/app/xcode/id497799835?mt=12)
|
||||
3. [Flutter Framework (Stable Channel)](https://flutter.dev/)
|
||||
4. [XCode](https://apps.apple.com/ca/app/xcode/id497799835?mt=12)
|
||||
5. [Developer Certificate Configured](https://github.com/LunaSeaApp/LunaSea/wiki/Setup-of-Development-Certificate)
|
||||
|
||||
#### Developing
|
||||
@@ -72,8 +72,8 @@ LunaSea even comes with support for multiple instances of applications using pro
|
||||
|
||||
#### Requirements
|
||||
|
||||
1. Android SDK/Android Studio Installed & Configured
|
||||
2. [Flutter Framework (Beta Channel)](https://flutter.dev/)
|
||||
1. [Android SDK/Android Studio Installed & Configured](https://developer.android.com/studio)
|
||||
2. [Flutter Framework (Stable Channel)](https://flutter.dev/)
|
||||
3. [Keystore Configured](https://github.com/LunaSeaApp/LunaSea/wiki/Configure-Keystore)
|
||||
|
||||
#### Developing
|
||||
|
||||
Binary file not shown.
@@ -107,4 +107,4 @@ SPEC CHECKSUMS:
|
||||
|
||||
PODFILE CHECKSUM: d583357f6c19d22241654320250048fb085838b3
|
||||
|
||||
COCOAPODS: 1.9.3
|
||||
COCOAPODS: 1.10.0
|
||||
|
||||
@@ -5,7 +5,7 @@ import 'package:lunasea/core.dart';
|
||||
class LunaDialogs {
|
||||
LunaDialogs._();
|
||||
|
||||
static Future<List<dynamic>> editText(BuildContext context, String title, { String prefill = '' }) async {
|
||||
static Future<List<dynamic>> editText(BuildContext context, String title, { String prefill = '', List<TextSpan> extraText }) async {
|
||||
bool _flag = false;
|
||||
final _formKey = GlobalKey<FormState>();
|
||||
final _textController = TextEditingController()..text = prefill;
|
||||
@@ -27,6 +27,7 @@ class LunaDialogs {
|
||||
),
|
||||
],
|
||||
content: [
|
||||
if((extraText?.length ?? 0) != 0) LSDialog.richText(children: extraText),
|
||||
Form(
|
||||
key: _formKey,
|
||||
child: LSDialog.textFormInput(
|
||||
@@ -37,7 +38,7 @@ class LunaDialogs {
|
||||
),
|
||||
),
|
||||
],
|
||||
contentPadding: LSDialog.inputDialogContentPadding(),
|
||||
contentPadding: (extraText?.length ?? 0) == 0 ? LSDialog.inputDialogContentPadding() : LSDialog.inputTextDialogContentPadding(),
|
||||
);
|
||||
return [_flag, _textController.text];
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class LunaTheme {
|
||||
splashColor: LunaColours.splash,
|
||||
dialogBackgroundColor: LunaColours.secondary,
|
||||
dividerColor: LunaColours.accent.withAlpha(0),
|
||||
toggleableActiveColor: LunaColours.accent,
|
||||
dividerTheme: DividerThemeData(
|
||||
color: LunaColours.accent,
|
||||
indent: 100.0,
|
||||
@@ -65,6 +66,7 @@ class LunaTheme {
|
||||
splashColor: LunaColours.splash,
|
||||
dialogBackgroundColor: Colors.black,
|
||||
dividerColor: LunaColours.accent.withAlpha(0),
|
||||
toggleableActiveColor: LunaColours.accent,
|
||||
dividerTheme: DividerThemeData(
|
||||
color: LunaColours.accent,
|
||||
indent: 72.0,
|
||||
|
||||
@@ -37,4 +37,5 @@ class CustomIcons {
|
||||
static const IconData discord = IconData(0xe81c, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData tautulli = IconData(0xe81d, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData plex = IconData(0xe81e, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
static const IconData radarr = IconData(0xe81f, fontFamily: _kFontFam, fontPackage: _kFontPkg);
|
||||
}
|
||||
|
||||
@@ -11,7 +11,7 @@ class RadarrConstants {
|
||||
name: 'Radarr',
|
||||
description: 'Manage Movies',
|
||||
settingsDescription: 'Configure Radarr',
|
||||
icon: CustomIcons.movies,
|
||||
icon: CustomIcons.radarr,
|
||||
route: '/radarr',
|
||||
color: Color(0xFFFEC333),
|
||||
);
|
||||
|
||||
@@ -31,14 +31,18 @@ class SettingsDialogs {
|
||||
content: [
|
||||
LSDialog.richText(
|
||||
children: [
|
||||
LSDialog.textSpanContent(text: '•\tThis is the URL in which you access the web GUI for the service\n'),
|
||||
LSDialog.textSpanContent(text: '•\tYou must include either '),
|
||||
LSDialog.textSpanContent(text: '${Constants.TEXT_BULLET}\tThis is the URL in which you access the web GUI for the service\n'),
|
||||
LSDialog.textSpanContent(text: '${Constants.TEXT_BULLET}\tYou must include either '),
|
||||
LSDialog.bolded(text: 'http://'),
|
||||
LSDialog.textSpanContent(text: ' or '),
|
||||
LSDialog.bolded(text: 'https://\n'),
|
||||
LSDialog.textSpanContent(text: '•\tWhen not using a reverse proxy, please include the port: '),
|
||||
LSDialog.textSpanContent(text: '${Constants.TEXT_BULLET}\tDo not use '),
|
||||
LSDialog.bolded(text: 'localhost'),
|
||||
LSDialog.textSpanContent(text: ' or '),
|
||||
LSDialog.bolded(text: '127.0.0.1\n'),
|
||||
LSDialog.textSpanContent(text: '${Constants.TEXT_BULLET}\tWhen not using a reverse proxy, please include the port: '),
|
||||
LSDialog.bolded(text: 'url:port\n'),
|
||||
LSDialog.textSpanContent(text: '•\tTo add basic authentication, please set a custom header in the advanced section'),
|
||||
LSDialog.textSpanContent(text: '${Constants.TEXT_BULLET}\tTo add basic authentication, please set a custom header in the advanced section'),
|
||||
],
|
||||
),
|
||||
Form(
|
||||
@@ -48,7 +52,14 @@ class SettingsDialogs {
|
||||
title: title,
|
||||
keyboardType: TextInputType.url,
|
||||
onSubmitted: (_) => _setValues(true),
|
||||
validator: (_) => null,
|
||||
validator: (value) {
|
||||
// Allow empty value
|
||||
if(value == '') return null;
|
||||
// Test for https:// or http://
|
||||
RegExp exp = RegExp(r"^(http|https)://", caseSensitive: false);
|
||||
if(exp.hasMatch(value)) return null;
|
||||
return 'Host must include http:// or https://';
|
||||
},
|
||||
),
|
||||
),
|
||||
],
|
||||
|
||||
@@ -2,7 +2,7 @@ import 'dart:io';
|
||||
import 'package:fluro/fluro.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/settings.dart';
|
||||
import 'package:lunasea/modules.dart';
|
||||
|
||||
class SettingsCustomizationRouter {
|
||||
static const ROUTE_NAME = '/settings/customization';
|
||||
@@ -107,9 +107,9 @@ class _State extends State<_SettingsCustomizationRoute> with AutomaticKeepAliveC
|
||||
onTap: () async => SettingsCustomizationLidarrRouter.navigateTo(context),
|
||||
),
|
||||
LSCardTile(
|
||||
title: LSTitle(text: 'Radarr'),
|
||||
title: LSTitle(text: RadarrConstants.MODULE_MAP.name),
|
||||
subtitle: LSSubtitle(text: 'Radarr Customizations'),
|
||||
trailing: LSIconButton(icon: CustomIcons.movies),
|
||||
trailing: LSIconButton(icon: RadarrConstants.MODULE_MAP.icon),
|
||||
onTap: () async => SettingsCustomizationRadarrRouter.navigateTo(context),
|
||||
),
|
||||
LSCardTile(
|
||||
|
||||
@@ -67,9 +67,11 @@ class _State extends State<_SettingsCustomizationSonarrRoute> {
|
||||
List<Widget> get _defaultSorting => [
|
||||
LSHeader(
|
||||
text: 'Default Sorting',
|
||||
subtitle: 'Choose the default sorting type for sortable lists',
|
||||
subtitle: 'Choose default sorting options for sortable lists',
|
||||
),
|
||||
SettingsCustomizationSonarrDefaultSortingReleasesTile(),
|
||||
SettingsCustomizationSonarrDefaultSortingReleasesAscendingTile(),
|
||||
SettingsCustomizationSonarrDefaultSortingSeriesTile(),
|
||||
SettingsCustomizationSonarrDefaultSortingSeriesAscendingTile(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
export 'widgets/default_pages_home.dart';
|
||||
export 'widgets/default_pages_series_details.dart';
|
||||
export 'widgets/default_sorting_releases_ascending.dart';
|
||||
export 'widgets/default_sorting_releases.dart';
|
||||
export 'widgets/default_sorting_series_ascending.dart';
|
||||
export 'widgets/default_sorting_series.dart';
|
||||
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationSonarrDefaultSortingReleasesTile extends StatelessWid
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.DEFAULT_SORTING_RELEASES.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Releases'),
|
||||
title: LSTitle(text: 'Releases Category'),
|
||||
subtitle: LSSubtitle(text: (SonarrDatabaseValue.DEFAULT_SORTING_RELEASES.data as SonarrReleasesSorting).readable),
|
||||
trailing: LSIconButton(icon: Icons.arrow_forward_ios),
|
||||
onTap: () async => _defaultSorting(context),
|
||||
@@ -20,8 +20,8 @@ class SettingsCustomizationSonarrDefaultSortingReleasesTile extends StatelessWid
|
||||
if(_values[0]) {
|
||||
SonarrDatabaseValue.DEFAULT_SORTING_RELEASES.put(SonarrReleasesSorting.values[_values[1]]);
|
||||
// Reset the state of the sorting
|
||||
context.read<SonarrState>().releasesSortType = SonarrReleasesSorting.values[_values[1]];
|
||||
context.read<SonarrState>().releasesSortAscending = true;
|
||||
context.read<SonarrState>().releasesSortType = SonarrDatabaseValue.DEFAULT_SORTING_RELEASES.data;
|
||||
context.read<SonarrState>().releasesSortAscending = SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/sonarr.dart';
|
||||
|
||||
class SettingsCustomizationSonarrDefaultSortingReleasesAscendingTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Releases Sort Direction'),
|
||||
subtitle: LSSubtitle(text: SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING.data
|
||||
? 'Ascending'
|
||||
: 'Descending'
|
||||
),
|
||||
trailing: Switch(
|
||||
value: SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING.data,
|
||||
onChanged: (value) {
|
||||
SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING.put(value);
|
||||
// Reset the state of the sorting
|
||||
context.read<SonarrState>().releasesSortType = SonarrDatabaseValue.DEFAULT_SORTING_RELEASES.data;
|
||||
context.read<SonarrState>().releasesSortAscending = SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING.data;
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationSonarrDefaultSortingSeriesTile extends StatelessWidge
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.DEFAULT_SORTING_SERIES.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Series'),
|
||||
title: LSTitle(text: 'Series Category'),
|
||||
subtitle: LSSubtitle(text: (SonarrDatabaseValue.DEFAULT_SORTING_SERIES.data as SonarrSeriesSorting).readable),
|
||||
trailing: LSIconButton(icon: Icons.arrow_forward_ios),
|
||||
onTap: () async => _defaultSorting(context),
|
||||
@@ -20,8 +20,8 @@ class SettingsCustomizationSonarrDefaultSortingSeriesTile extends StatelessWidge
|
||||
if(_values[0]) {
|
||||
SonarrDatabaseValue.DEFAULT_SORTING_SERIES.put(SonarrSeriesSorting.values[_values[1]]);
|
||||
// Reset the state of the sorting
|
||||
context.read<SonarrState>().seriesSortType = SonarrSeriesSorting.values[_values[1]];
|
||||
context.read<SonarrState>().seriesSortAscending = true;
|
||||
context.read<SonarrState>().seriesSortType = SonarrDatabaseValue.DEFAULT_SORTING_SERIES.data;
|
||||
context.read<SonarrState>().seriesSortAscending = SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,26 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/sonarr.dart';
|
||||
|
||||
class SettingsCustomizationSonarrDefaultSortingSeriesAscendingTile extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Series Sort Direction'),
|
||||
subtitle: LSSubtitle(text: SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.data
|
||||
? 'Ascending'
|
||||
: 'Descending'
|
||||
),
|
||||
trailing: Switch(
|
||||
value: SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.data,
|
||||
onChanged: (value) {
|
||||
SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.put(value);
|
||||
// Reset the state of the sorting
|
||||
context.read<SonarrState>().seriesSortType = SonarrDatabaseValue.DEFAULT_SORTING_SERIES.data;
|
||||
context.read<SonarrState>().seriesSortAscending = SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.data;
|
||||
},
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -19,6 +19,11 @@ class SettingsModulesNZBGetPasswordTile extends StatelessWidget {
|
||||
context,
|
||||
'NZBGet Password',
|
||||
prefill: Database.currentProfileObject.nzbgetPass ?? '',
|
||||
extraText: [
|
||||
LSDialog.textSpanContent(text: '${Constants.TEXT_BULLET}\tIf your password includes special characters, considering adding a '),
|
||||
LSDialog.bolded(text: 'basic authentication'),
|
||||
LSDialog.textSpanContent(text: ' header with your username and password instead for better support'),
|
||||
],
|
||||
);
|
||||
if(_values[0]) {
|
||||
Database.currentProfileObject.nzbgetPass = _values[1];
|
||||
|
||||
@@ -28,6 +28,8 @@ enum SonarrDatabaseValue {
|
||||
ADD_SERIES_DEFAULT_ROOT_FOLDER,
|
||||
DEFAULT_SORTING_SERIES,
|
||||
DEFAULT_SORTING_RELEASES,
|
||||
DEFAULT_SORTING_SERIES_ASCENDING,
|
||||
DEFAULT_SORTING_RELEASES_ASCENDING,
|
||||
UPCOMING_FUTURE_DAYS,
|
||||
QUEUE_REFRESH_RATE,
|
||||
CONTENT_LOAD_LENGTH,
|
||||
@@ -50,6 +52,8 @@ extension SonarrDatabaseValueExtension on SonarrDatabaseValue {
|
||||
case SonarrDatabaseValue.ADD_SERIES_DEFAULT_ROOT_FOLDER: return 'SONARR_ADD_SERIES_DEFAULT_ROOT_FOLDER';
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_SERIES: return 'SONARR_DEFAULT_SORTING_SERIES';
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_RELEASES: return 'SONARR_DEFAULT_SORTING_RELEASES';
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING: return 'SONARR_DEFAULT_SORTING_SERIES_ASCENDING';
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING: return 'SONARR_DEFAULT_SORTING_RELEASES_ASCENDING';
|
||||
}
|
||||
throw Exception('key not found');
|
||||
}
|
||||
@@ -71,6 +75,8 @@ extension SonarrDatabaseValueExtension on SonarrDatabaseValue {
|
||||
case SonarrDatabaseValue.ADD_SERIES_DEFAULT_ROOT_FOLDER : return _box.get(this.key, defaultValue: null);
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_SERIES: return _box.get(this.key, defaultValue: SonarrSeriesSorting.ALPHABETICAL);
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_RELEASES: return _box.get(this.key, defaultValue: SonarrReleasesSorting.WEIGHT);
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING: return _box.get(this.key, defaultValue: true);
|
||||
case SonarrDatabaseValue.DEFAULT_SORTING_RELEASES_ASCENDING: return _box.get(this.key, defaultValue: true);
|
||||
}
|
||||
throw Exception('data not found');
|
||||
}
|
||||
|
||||
@@ -557,6 +557,48 @@ class SonarrDialogs {
|
||||
return [_flag];
|
||||
}
|
||||
|
||||
static Future<List<dynamic>> confirmDeleteQueue(BuildContext context) async {
|
||||
bool _flag = false;
|
||||
|
||||
void _setValues(bool flag) {
|
||||
_flag = flag;
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
context: context,
|
||||
title: 'Remove From Queue',
|
||||
buttons: [
|
||||
LSDialog.button(
|
||||
text: 'Remove',
|
||||
textColor: LunaColours.red,
|
||||
onPressed: () => _setValues(true),
|
||||
),
|
||||
],
|
||||
content: [
|
||||
LSDialog.textContent(text: 'Are you sure you want to remove this from the queue?\n'),
|
||||
Selector<SonarrState, bool>(
|
||||
selector: (_, state) => state.removeQueueBlacklist,
|
||||
builder: (context, value, text) => CheckboxListTile(
|
||||
title: text,
|
||||
value: value,
|
||||
onChanged: (selected) => Provider.of<SonarrState>(context, listen: false).removeQueueBlacklist = selected,
|
||||
contentPadding: LSDialog.tileContentPadding(),
|
||||
),
|
||||
child: Text(
|
||||
'Blacklist',
|
||||
style: TextStyle(
|
||||
fontSize: LSDialog.BODY_SIZE,
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
contentPadding: LSDialog.textDialogContentPadding(),
|
||||
);
|
||||
return [_flag];
|
||||
}
|
||||
|
||||
static Future<List<dynamic>> confirmDeleteEpisodeFile(BuildContext context) async {
|
||||
bool _flag = false;
|
||||
|
||||
|
||||
@@ -1,6 +1,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_series_lookup.dart';
|
||||
export 'extensions/sonarr_series_season.dart';
|
||||
export 'extensions/sonarr_series.dart';
|
||||
|
||||
33
lib/modules/sonarr/core/extensions/sonarr_queue_record.dart
Normal file
33
lib/modules/sonarr/core/extensions/sonarr_queue_record.dart
Normal file
@@ -0,0 +1,33 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/sonarr.dart';
|
||||
|
||||
extension SonarrQueueRecordExtension on SonarrQueueRecord {
|
||||
String get lunaStatusText {
|
||||
switch(this?.status?.toLowerCase() ?? '') {
|
||||
case 'delay': return 'Pending';
|
||||
case 'downloading': return 'Downloading';
|
||||
case 'completed': return 'Completed';
|
||||
case 'paused': return 'Paused';
|
||||
}
|
||||
return this?.status ?? 'Unknown';
|
||||
}
|
||||
|
||||
IconData get lunaStatusIcon {
|
||||
switch(this?.status?.toLowerCase() ?? '') {
|
||||
case 'delay': return Icons.schedule;
|
||||
case 'downloading': return Icons.cloud_download;
|
||||
case 'completed': return Icons.cloud_download;
|
||||
case 'paused': return Icons.pause;
|
||||
}
|
||||
return Icons.help;
|
||||
}
|
||||
|
||||
Color get lunaStatusColor {
|
||||
if(this?.status?.toLowerCase() == 'completed') switch(this?.trackedDownloadStatus?.toLowerCase()) {
|
||||
case 'warning': return LunaColours.orange;
|
||||
case 'ok': return LunaColours.purple;
|
||||
}
|
||||
return Colors.white;
|
||||
}
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
import 'dart:async';
|
||||
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/sonarr.dart';
|
||||
|
||||
@@ -5,10 +7,17 @@ class SonarrState extends LunaGlobalState {
|
||||
SonarrState() {
|
||||
reset();
|
||||
}
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_getQueueTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
@override
|
||||
void reset() {
|
||||
// Reset stored data
|
||||
_queue = null;
|
||||
_series = null;
|
||||
_missing = null;
|
||||
_upcoming = null;
|
||||
@@ -23,6 +32,7 @@ class SonarrState extends LunaGlobalState {
|
||||
_releasesSearchQuery = '';
|
||||
// Reinitialize
|
||||
resetProfile();
|
||||
resetQueue();
|
||||
resetSeries();
|
||||
resetUpcoming();
|
||||
resetMissing();
|
||||
@@ -78,6 +88,45 @@ class SonarrState extends LunaGlobalState {
|
||||
)
|
||||
: null;
|
||||
}
|
||||
|
||||
/////////////
|
||||
/// QUEUE ///
|
||||
/////////////
|
||||
|
||||
/// Timer to handle refreshing queue data
|
||||
Timer _getQueueTimer;
|
||||
|
||||
/// Cancel the periodic timer
|
||||
void createQueueTimer() => _getQueueTimer = Timer.periodic(
|
||||
Duration(seconds: SonarrDatabaseValue.QUEUE_REFRESH_RATE.data),
|
||||
(_) => queue = _api.queue.getQueue(),
|
||||
);
|
||||
|
||||
/// Cancel the queue timer
|
||||
void cancelQueueTimer() => _getQueueTimer?.cancel();
|
||||
|
||||
/// Storing queue data
|
||||
Future<List<SonarrQueueRecord>> _queue;
|
||||
Future<List<SonarrQueueRecord>> get queue => _queue;
|
||||
set queue(Future<List<SonarrQueueRecord>> queue) {
|
||||
assert(queue != null);
|
||||
_queue = queue;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
/// Reset the queue:
|
||||
/// - Cancel timer & clear state of future
|
||||
/// - Recreate timer (if enabled)
|
||||
/// - Set initial state of the future
|
||||
void resetQueue() {
|
||||
cancelQueueTimer();
|
||||
_queue = null;
|
||||
if(_api != null) {
|
||||
_queue = _api.queue.getQueue();
|
||||
createQueueTimer();
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
////////////////
|
||||
/// EPISODES ///
|
||||
@@ -173,7 +222,7 @@ class SonarrState extends LunaGlobalState {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool _releasesSortAscending = true;
|
||||
bool _releasesSortAscending = SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.data;
|
||||
bool get releasesSortAscending => _releasesSortAscending;
|
||||
set releasesSortAscending(bool releasesSortAscending) {
|
||||
assert(releasesSortAscending != null);
|
||||
@@ -209,7 +258,7 @@ class SonarrState extends LunaGlobalState {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
bool _seriesSortAscending = true;
|
||||
bool _seriesSortAscending = SonarrDatabaseValue.DEFAULT_SORTING_SERIES_ASCENDING.data;
|
||||
bool get seriesSortAscending => _seriesSortAscending;
|
||||
set seriesSortAscending(bool seriesSortAscending) {
|
||||
assert(seriesSortAscending != null);
|
||||
@@ -356,6 +405,18 @@ class SonarrState extends LunaGlobalState {
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
////////////////////
|
||||
/// DELETE QUEUE ///
|
||||
////////////////////
|
||||
|
||||
bool _removeQueueBlacklist = false;
|
||||
bool get removeQueueBlacklist => _removeQueueBlacklist;
|
||||
set removeQueueBlacklist(bool removeQueueBlacklist) {
|
||||
assert(removeQueueBlacklist != null);
|
||||
_removeQueueBlacklist = removeQueueBlacklist;
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
//////////////
|
||||
/// IMAGES ///
|
||||
//////////////
|
||||
|
||||
@@ -35,6 +35,7 @@ extension SonarrMonitorStatusExtension on SonarrMonitorStatus {
|
||||
}
|
||||
|
||||
void process(List<SonarrSeriesSeason> season) {
|
||||
if(season == null || season.length == 0) return;
|
||||
switch(this) {
|
||||
case SonarrMonitorStatus.ALL: _all(season); break;
|
||||
case SonarrMonitorStatus.MISSING: _missing(season); break;
|
||||
|
||||
@@ -1,6 +1,8 @@
|
||||
import 'package:fluro/fluro.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/scheduler.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/sonarr.dart';
|
||||
|
||||
class SonarrQueueRouter {
|
||||
static const String ROUTE_NAME = '/sonarr/queue/list';
|
||||
@@ -28,12 +30,24 @@ class _SonarrQueueRoute extends StatefulWidget {
|
||||
|
||||
class _State extends State<_SonarrQueueRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
SchedulerBinding.instance.scheduleFrameCallback((_) => _refresh());
|
||||
}
|
||||
|
||||
Future<void> _refresh() async {
|
||||
context.read<SonarrState>().resetQueue();
|
||||
await context.read<SonarrState>().queue;
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
key: _scaffoldKey,
|
||||
appBar: _appBar,
|
||||
body: LSGenericMessage(text: 'Coming Soon!'),
|
||||
body: _body,
|
||||
);
|
||||
|
||||
Widget get _appBar => LunaAppBar(
|
||||
@@ -41,4 +55,48 @@ class _State extends State<_SonarrQueueRoute> {
|
||||
title: 'Queue',
|
||||
popUntil: '/sonarr',
|
||||
);
|
||||
|
||||
Widget get _body => LSRefreshIndicator(
|
||||
refreshKey: _refreshKey,
|
||||
onRefresh: _refresh,
|
||||
child: FutureBuilder(
|
||||
future: context.watch<SonarrState>().queue,
|
||||
builder: (context, AsyncSnapshot<List<SonarrQueueRecord>> snapshot) {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
LunaLogger.error(
|
||||
'_SonarrQueueRoute',
|
||||
'_body',
|
||||
'Unable to fetch Sonarr queue',
|
||||
snapshot.error,
|
||||
null,
|
||||
uploadToSentry: !(snapshot.error is DioError),
|
||||
);
|
||||
}
|
||||
return LSErrorMessage(onTapHandler: () async => _refreshKey.currentState.show());
|
||||
}
|
||||
if(snapshot.hasData) return snapshot.data.length == 0
|
||||
? _emptyQueue
|
||||
: _queue(snapshot.data);
|
||||
return LSLoader();
|
||||
},
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _emptyQueue => LSGenericMessage(
|
||||
text: 'Empty Queue',
|
||||
buttonText: 'Refresh',
|
||||
showButton: true,
|
||||
onTapHandler: () async => _refreshKey.currentState.show(),
|
||||
);
|
||||
|
||||
Widget _queue(List<SonarrQueueRecord> queue) => LSListView(
|
||||
children: List.generate(
|
||||
queue.length,
|
||||
(index) => SonarrQueueQueueTile(
|
||||
key: ObjectKey(queue[index].id),
|
||||
record: queue[index],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -0,0 +1 @@
|
||||
export 'widgets/queue_tile.dart';
|
||||
|
||||
195
lib/modules/sonarr/modules/queue/widgets/queue_tile.dart
Normal file
195
lib/modules/sonarr/modules/queue/widgets/queue_tile.dart
Normal file
@@ -0,0 +1,195 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:expandable/expandable.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/sonarr.dart';
|
||||
|
||||
class SonarrQueueQueueTile extends StatelessWidget {
|
||||
final SonarrQueueRecord record;
|
||||
|
||||
SonarrQueueQueueTile({
|
||||
Key key,
|
||||
@required this.record,
|
||||
}) : super(key: key);
|
||||
|
||||
final ExpandableController _controller = ExpandableController();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LSExpandable(
|
||||
controller: _controller,
|
||||
collapsed: _collapsed(context),
|
||||
expanded: _expanded(context),
|
||||
);
|
||||
|
||||
Widget _collapsed(BuildContext context) => LSCardTile(
|
||||
title: LSTitle(text: record.title),
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
color: Colors.white70,
|
||||
),
|
||||
children: [
|
||||
TextSpan(text: record.series.title),
|
||||
TextSpan(text: '\nSeason ${record.episode.seasonNumber} ${Constants.TEXT_EMDASH} Episode ${record.episode.episodeNumber}\n'),
|
||||
TextSpan(
|
||||
text: record?.quality?.quality?.name ?? 'Unknown',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w600,
|
||||
color: LunaColours.accent,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
maxLines: 3,
|
||||
overflow: TextOverflow.fade,
|
||||
softWrap: false,
|
||||
),
|
||||
trailing: Padding(
|
||||
child: LSIconButton(icon: record.lunaStatusIcon, color: record.lunaStatusColor),
|
||||
padding: EdgeInsets.only(bottom: 14.0),
|
||||
),
|
||||
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: record.title, softWrap: true, maxLines: 12),
|
||||
Padding(
|
||||
child: Wrap(
|
||||
direction: Axis.horizontal,
|
||||
runSpacing: 10.0,
|
||||
children: [
|
||||
LSTextHighlighted(
|
||||
text: record.protocol.lsLanguage_Capitalize(),
|
||||
bgColor: record.protocol == 'torrent'
|
||||
? LunaColours.purple
|
||||
: LunaColours.blue,
|
||||
),
|
||||
LSTextHighlighted(
|
||||
text: record?.quality?.quality?.name ?? 'Unknown',
|
||||
bgColor: LunaColours.accent,
|
||||
),
|
||||
LSTextHighlighted(
|
||||
text: record.lunaStatusText,
|
||||
bgColor: LunaColours.blueGrey,
|
||||
),
|
||||
if(record.trackedDownloadStatus != null && record.trackedDownloadStatus.isNotEmpty) LSTextHighlighted(
|
||||
text: record.trackedDownloadStatus,
|
||||
bgColor: LunaColours.blueGrey,
|
||||
),
|
||||
],
|
||||
),
|
||||
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: record.episode.seasonNumber == 0
|
||||
? 'Specials ${Constants.TEXT_EMDASH} Episode ${record.episode.episodeNumber}\n'
|
||||
: 'Season ${record.episode.seasonNumber} ${Constants.TEXT_EMDASH} Episode ${record.episode.episodeNumber}\n',
|
||||
style: TextStyle(
|
||||
color: LunaColours.accent,
|
||||
fontWeight: FontWeight.w600,
|
||||
fontSize: Constants.UI_FONT_SIZE_STICKYHEADER,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: record.episode.airDateUtc == null
|
||||
? 'Unknown Date'
|
||||
: DateFormat.yMMMMd().format(record.episode.airDateUtc.toLocal()),
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
),
|
||||
),
|
||||
TextSpan(text: '\n\n'),
|
||||
TextSpan(
|
||||
text: record.episode.overview == null || record.episode.overview.isEmpty
|
||||
? 'No overview is available.'
|
||||
: record.episode.overview,
|
||||
style: TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
),
|
||||
padding: EdgeInsets.only(top: 6.0, bottom: 10.0),
|
||||
),
|
||||
Padding(
|
||||
child: Row(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
if(record?.statusMessages != null && (record?.statusMessages?.isNotEmpty ?? false)) Expanded(
|
||||
child: LSButtonSlim(
|
||||
text: 'Warnings',
|
||||
backgroundColor: LunaColours.orange,
|
||||
onTap: () async => LunaDialogs.textPreview(context, 'Warnings', record.statusMessages.fold('', (warnings, status) {
|
||||
warnings += status.messages.fold<String>('', (message, element) => message += '\n${Constants.TEXT_BULLET} $element');
|
||||
return warnings.trim();
|
||||
})),
|
||||
margin: EdgeInsets.only(right: 6.0),
|
||||
),
|
||||
),
|
||||
Expanded(
|
||||
child: LSButtonSlim(
|
||||
text: 'Delete',
|
||||
backgroundColor: LunaColours.red,
|
||||
onTap: () async => _deleteQueueRecord(context),
|
||||
margin: record?.statusMessages != null && (record?.statusMessages?.isNotEmpty ?? false)
|
||||
? EdgeInsets.only(left: 6.0)
|
||||
: EdgeInsets.zero,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
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(),
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> _deleteQueueRecord(BuildContext context) async {
|
||||
List _values = await SonarrDialogs.confirmDeleteQueue(context);
|
||||
if(_values[0]) context.read<SonarrState>().api.queue.deleteQueue(
|
||||
id: record.id,
|
||||
blacklist: context.read<SonarrState>().removeQueueBlacklist,
|
||||
).then((value) {
|
||||
context.read<SonarrState>().resetQueue();
|
||||
showLunaSuccessSnackBar(context: context, title: 'Removed From Queue', message: record.title);
|
||||
})
|
||||
.catchError((error, stack) {
|
||||
LunaLogger.error(
|
||||
'SonarrQueueQueueTile',
|
||||
'_deleteQueueRecord',
|
||||
'Failed to remove item from queue: ${record.id}',
|
||||
error,
|
||||
stack,
|
||||
uploadToSentry: !(error is DioError),
|
||||
);
|
||||
showLunaErrorSnackBar(context: context, title: 'Failed to Delete From Queue');
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -77,8 +77,8 @@ class _State extends State<SonarrSeriesSeasonDetailsEpisodeTile> {
|
||||
children: [
|
||||
TextSpan(
|
||||
text: widget.episode.seasonNumber == 0
|
||||
? 'Specials / Episode ${widget.episode.episodeNumber}\n'
|
||||
: 'Season ${widget.episode.seasonNumber} / Episode ${widget.episode.episodeNumber}\n',
|
||||
? 'Specials ${Constants.TEXT_EMDASH} Episode ${widget.episode.episodeNumber}\n'
|
||||
: 'Season ${widget.episode.seasonNumber} ${Constants.TEXT_EMDASH} Episode ${widget.episode.episodeNumber}\n',
|
||||
style: TextStyle(
|
||||
color: LunaColours.accent,
|
||||
fontWeight: FontWeight.w600,
|
||||
|
||||
@@ -24,13 +24,7 @@ class SonarrAppBarGlobalSettingsAction extends StatelessWidget {
|
||||
|
||||
Future<void> _webGUI(BuildContext context) async => Provider.of<SonarrState>(context, listen: false).host.lsLinks_OpenLink();
|
||||
|
||||
Future<void> _viewQueue(BuildContext context) async => LSSnackBar(
|
||||
context: context,
|
||||
title: 'Coming Soon!',
|
||||
message: 'This feature has not yet been implemented',
|
||||
type: SNACKBAR_TYPE.info,
|
||||
);
|
||||
//Future<void> _viewQueue(BuildContext context) async => SonarrQueueRouter.navigateTo(context);
|
||||
Future<void> _viewQueue(BuildContext context) async => SonarrQueueRouter.navigateTo(context);
|
||||
|
||||
Future<void> _manageTags(BuildContext context) async => SonarrTagsRouter.navigateTo(context);
|
||||
|
||||
|
||||
24
pubspec.lock
24
pubspec.lock
@@ -56,14 +56,14 @@ packages:
|
||||
name: build
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.5.0"
|
||||
version: "1.5.1"
|
||||
build_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_config
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.4.2"
|
||||
version: "0.4.3"
|
||||
build_daemon:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -84,14 +84,14 @@ packages:
|
||||
name: build_runner
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.10.4"
|
||||
version: "1.10.6"
|
||||
build_runner_core:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: build_runner_core
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "6.0.3"
|
||||
version: "6.1.1"
|
||||
built_collection:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -182,7 +182,7 @@ packages:
|
||||
name: dart_style
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.9"
|
||||
version: "1.3.10"
|
||||
dartx:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -294,7 +294,7 @@ packages:
|
||||
name: fluro
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.7.7"
|
||||
version: "1.7.8"
|
||||
flutter:
|
||||
dependency: "direct main"
|
||||
description: flutter
|
||||
@@ -458,7 +458,7 @@ packages:
|
||||
name: json_annotation
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "3.1.0"
|
||||
version: "3.1.1"
|
||||
logging:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -500,14 +500,14 @@ packages:
|
||||
name: node_interop
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.2.0"
|
||||
version: "1.2.1"
|
||||
node_io:
|
||||
dependency: transitive
|
||||
description:
|
||||
name: node_io
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.1.1"
|
||||
version: "1.2.0"
|
||||
package_config:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -736,7 +736,7 @@ packages:
|
||||
name: sonarr
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "0.0.2-pre.3"
|
||||
version: "0.0.4"
|
||||
source_gen:
|
||||
dependency: transitive
|
||||
description:
|
||||
@@ -792,7 +792,7 @@ packages:
|
||||
name: table_calendar
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "2.3.0"
|
||||
version: "2.3.1"
|
||||
tautulli:
|
||||
dependency: "direct main"
|
||||
description:
|
||||
@@ -813,7 +813,7 @@ packages:
|
||||
name: time
|
||||
url: "https://pub.dartlang.org"
|
||||
source: hosted
|
||||
version: "1.3.0"
|
||||
version: "1.4.0"
|
||||
timing:
|
||||
dependency: transitive
|
||||
description:
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
name: lunasea
|
||||
description: Self Hosted Manager
|
||||
version: 4.1.0+40100004
|
||||
version: 4.1.0+40100005
|
||||
publish_to: 'none'
|
||||
environment:
|
||||
sdk: ">=2.7.0 <3.0.0"
|
||||
@@ -14,7 +14,7 @@ dependencies:
|
||||
file_picker: ^1.13.3
|
||||
flare_flutter: ^2.0.6
|
||||
flash: ^1.3.1
|
||||
fluro: ^1.7.7
|
||||
fluro: ^1.7.8
|
||||
flutter:
|
||||
sdk: flutter
|
||||
flutter_spinkit: ^4.1.2+1
|
||||
@@ -35,13 +35,13 @@ dependencies:
|
||||
quick_actions: ^0.4.0+10
|
||||
sentry: ^3.0.1
|
||||
stack_trace: ^1.9.6
|
||||
table_calendar: ^2.3.0
|
||||
table_calendar: ^2.3.1
|
||||
tuple: ^1.0.3
|
||||
url_launcher: ^5.7.10
|
||||
uuid: ^2.2.2
|
||||
xml_parser: ^0.1.2
|
||||
# Comet.Tools Packages
|
||||
sonarr: ^0.0.2-pre.3
|
||||
sonarr: ^0.0.4
|
||||
tautulli: ^1.1.0
|
||||
wake_on_lan: ^1.1.1+2
|
||||
|
||||
|
||||
Reference in New Issue
Block a user