mirror of
https://github.com/jagandeepbrar/lunasea.git
synced 2026-08-31 04:32:32 +00:00
[Release] v1.1.0 (44) (#151)
* [Settings] Added some dividers * [Prompts] All prompts now use correct colour ordering (#123) * [Sonarr] Ability to toggle single episode monitored status (#124) * [Documentation] Added link to WIP documentation (#125) * [Navigation] Adjusted styling of navigation bars (#128) * [Sonarr] Added the ability to delete episode files (#129) * [UI] Tweaking aspects of the user interface (#131) * [Home] Prepping for calendar and statistics page * [Icons] Updated icons used in drawers and navbars * [NZBGet] Changed method of authentication (#133) * [Icons] Added RSS feed icon * [TestFlight] v1.1.0 (11) * [Radarr] Added 'Upcoming' page (#134) * [-rr] Easier to differentiate release protocol (#135) * [Lidarr/Sonarr] Longpress tile in missing/upcoming to go to artist/series page (#136) * [TestFlight] v1.1.0 (22) * [Icons] Tweaked icons (#142) * [Icons] Tweaked navigation icons * [Refactoring] Started basic folder structure refactoring... * [Icons, Drawer] Revert forward arrow, keep drawer categories always expanded * [-rr] Ability to delete files when deleting catalogue entry (#143) * [Radarr] Ability to delete files when removing catalogue entry * [Sonarr] Ability to delete files when removing catalogue entry * [Lidarr] Ability to delete files when removing catalogue entry * [-rr] Updated delete dialog text for deleting media * [Refactoring] Small folder structure refactor * [Home] Calendar view for upcoming -rr content (#144) * [Home] Added styled calendar widget * [Refactoring] Cleaning folder structure, again * [Refactoring] Major code structure refactoring * [Redux] Implemented empty redux store for future use * [Refactor, Calendar] Continuing refactor, Calendar now supports Sonarr * [Calendar] Calendar now supports Radarr * [Calendar] Calendar now supports Lidarr * [TestFlight] v1.1.0 (33) * [TestFlight] Hotfix v1.1.0 (44)
This commit is contained in:
1
.gitignore
vendored
1
.gitignore
vendored
@@ -42,3 +42,4 @@ LunaSea.ipa
|
||||
ios/build/
|
||||
ExportOptions.plist
|
||||
api_responses/
|
||||
pre_archive
|
||||
|
||||
BIN
assets/CustomIcons.ttf
Normal file
BIN
assets/CustomIcons.ttf
Normal file
Binary file not shown.
Binary file not shown.
@@ -1,50 +0,0 @@
|
||||
{
|
||||
"name": "CustomIcons",
|
||||
"css_prefix_text": "",
|
||||
"css_use_suffix": false,
|
||||
"hinting": true,
|
||||
"units_per_em": 1000,
|
||||
"ascent": 850,
|
||||
"glyphs": [
|
||||
{
|
||||
"uid": "0f79e958e1ed08e14ccbd7369b5d4440",
|
||||
"css": "sabnzbd",
|
||||
"code": 59392,
|
||||
"src": "custom_icons",
|
||||
"selected": true,
|
||||
"svg": {
|
||||
"path": "M252.3 109.8C249.8 110.8 244.6 114.4 240.8 117.8L233.8 124.1 233.8 289.9 233.8 455.6 178.7 455.2C119 454.9 113.8 456 107.7 470.7 101.1 486.8 105.8 497.6 130.9 523.4L154 547.2 146.1 558.9 138.1 570.6 139.6 639.9C140.4 678 141 712 140.9 715.4 140.9 718.8 140.7 735.8 140.4 753.3L140 785.1 150 794.1 160.1 803.1 265.4 802.9C323.4 802.7 373.5 801.5 376.9 800.2 387.1 796.1 397.1 803.7 438.9 847.4 498 909.1 496.9 909.1 555.9 848.1 602.4 799.9 607.1 796.3 617.8 800.3 630.7 805.2 829.7 803.8 839.6 798.7 854.8 790.8 855.4 786.1 855.4 674.1L855.4 570.1 848 559.2 840.7 548.4 861.8 527.4C893.6 495.9 898.6 479.8 882.3 462.3 876.1 455.6 873.9 455.4 820.2 455.4L764.6 455.4 764.6 290.8 764.6 126.3 756.1 117.8 747.6 109.2 502.2 108.7C367.3 108.4 254.8 108.9 252.3 109.8M735.4 310.8L735.4 483.1 798.7 483.1 862 483.1 828.8 516.9 795.7 550.8 765.5 550.8 735.4 550.8 735.3 519.2C735.3 471.7 735.4 471.8 666.3 473.8 601.8 475.8 603.1 474.9 603.1 520.3L603.1 550.8 493.1 550.9C432.6 551 342.2 551 292.3 550.9L201.5 550.7 169.2 517.7 136.9 484.6 199.2 483.8 261.5 483 261.5 310.7 261.5 138.5 498.5 138.5 735.4 138.5 735.4 310.8M708.4 539.2L709.2 576.9 766.9 577.8 824.6 578.6 824.6 675.5 824.6 772.3 727.7 772.3 630.8 772.3 630.8 636.9 630.8 501.5 669.1 501.5 707.5 501.5 708.4 539.2M363.1 598.5L363.1 618.5 306.2 618.5 249.2 618.5 249.2 636.9 249.2 655.4 306.2 655.4 363.1 655.4 363.1 713.8 363.1 772.3 266.2 772.3 169.2 772.3 169.2 752.4 169.2 732.4 226.9 731.6 284.6 730.8 285.5 713.1 286.5 695.4 227.8 695.4 169.2 695.4 169.2 636.9 169.2 578.5 266.2 578.5 363.1 578.5 363.1 598.5M593.8 675.4L593.8 772.3 496.9 772.3 400 772.3 400 713.8 400 655.4 456.9 655.4 513.8 655.4 513.8 636.9 513.8 618.5 456.9 618.5 400 618.5 400 598.5 400 578.5 496.9 578.5 593.8 578.5 593.8 675.4M708.4 674.6L709.2 730.8 726.9 731.7 744.6 732.6 744.6 675.5 744.6 618.5 726.1 618.5 707.6 618.5 708.4 674.6M480 713.8L480 732.3 496.9 732.3 513.8 732.3 513.8 713.8 513.8 695.4 496.9 695.4 480 695.4 480 713.8M529.2 831.9L497.7 863.8 475.8 840.5C463.7 827.7 449.7 813.3 444.7 808.6L435.6 800 498.1 800 560.6 800 529.2 831.9",
|
||||
"width": 1000
|
||||
},
|
||||
"search": [
|
||||
"sabnzbd"
|
||||
]
|
||||
},
|
||||
{
|
||||
"uid": "f08ba9f0e8f9b426a92efcaa59c1e932",
|
||||
"css": "reddit-alien",
|
||||
"code": 62081,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "0f6a2573a7b6df911ed199bb63717e27",
|
||||
"css": "github-circled",
|
||||
"code": 61595,
|
||||
"src": "fontawesome"
|
||||
},
|
||||
{
|
||||
"uid": "bbf307b0e5e61f59d838e83455cabecc",
|
||||
"css": "nzbget",
|
||||
"code": 59394,
|
||||
"src": "custom_icons",
|
||||
"selected": true,
|
||||
"svg": {
|
||||
"path": "M412.9 68.7C131 119.7-26.3 441.8 104.3 701 250.5 991.1 661.2 1026.6 852 765.6 1089.5 440.7 810-3.1 412.9 68.7M599.6 117C892.5 197.1 993.1 558.1 783.4 776.7 591 977.3 257.7 922.7 138.8 671.2 38 457.9 147.6 200.5 371.5 124.8 435.9 103.1 536.1 99.6 599.6 117M421.9 294.9L421.9 324.2 502 324.2 582 324.2 582 294.9 582 265.6 502 265.6 421.9 265.6 421.9 294.9M421.9 380.9L421.9 410.2 502 410.2 582 410.2 582 380.9 582 351.6 502 351.6 421.9 351.6 421.9 380.9M421.4 438.4C421.2 441.1 421.3 461.4 421.8 483.4L422.6 523.4 367.4 523.4C321.3 523.4 312.6 524.3 315.2 528.9 320.1 537.4 499.3 718.8 502.8 718.8 506.7 718.8 695.3 530.3 695.3 526.3 695.3 524.7 669.9 523.4 638.8 523.4L582.3 523.4 581.2 479.5 580.1 435.5 501 434.5C439.2 433.7 421.8 434.5 421.4 438.4",
|
||||
"width": 1000
|
||||
},
|
||||
"search": [
|
||||
"nzbget"
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
||||
Binary file not shown.
|
Before Width: | Height: | Size: 8.6 KiB |
@@ -1 +0,0 @@
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0, 0, 400,400"><g id="svgg"><path id="path0" d="M165.178 27.480 C 52.387 47.868,-10.502 176.727,41.734 280.416 C 100.189 396.449,264.475 410.632,340.792 306.234 C 435.804 176.261,323.988 -1.227,165.178 27.480 M239.844 46.792 C 357.017 78.848,397.230 223.232,313.342 310.684 C 236.388 390.906,103.089 369.090,55.531 268.490 C 15.191 183.157,59.034 80.211,148.611 49.930 C 174.362 41.225,214.453 39.846,239.844 46.792 M168.750 117.969 L 168.750 129.688 200.781 129.688 L 232.813 129.688 232.813 117.969 L 232.813 106.250 200.781 106.250 L 168.750 106.250 168.750 117.969 M168.750 152.344 L 168.750 164.063 200.781 164.063 L 232.813 164.063 232.813 152.344 L 232.813 140.625 200.781 140.625 L 168.750 140.625 168.750 152.344 M168.570 175.358 C 168.471 176.450,168.538 184.551,168.720 193.359 L 169.049 209.375 146.947 209.375 C 128.528 209.375,125.053 209.737,126.094 211.545 C 128.059 214.957,199.705 287.500,201.111 287.500 C 202.691 287.500,278.125 212.114,278.125 210.535 C 278.125 209.897,267.953 209.375,255.520 209.375 L 232.915 209.375 232.473 191.797 L 232.031 174.219 200.391 173.796 C 175.696 173.466,168.710 173.809,168.570 175.358 " stroke="none" fill="#000000" fill-rule="evenodd"></path></g></svg>
|
||||
|
Before Width: | Height: | Size: 1.3 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 5.4 KiB |
@@ -1 +0,0 @@
|
||||
<svg id="svg" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="400" height="400" viewBox="0, 0, 400,400"><g id="svgg"><path id="path0" d="M100.923 43.935 C 99.908 44.312,97.831 45.755,96.308 47.140 L 93.538 49.660 93.538 115.948 L 93.538 182.236 71.486 182.098 C 47.591 181.947,45.526 182.396,43.093 188.268 C 40.421 194.720,42.322 199.047,52.359 209.361 L 61.608 218.865 58.433 223.544 L 55.258 228.223 55.832 255.958 C 56.148 271.212,56.391 284.800,56.373 286.154 C 56.356 287.508,56.264 294.339,56.170 301.334 L 56.000 314.052 60.019 317.641 L 64.039 321.231 106.173 321.144 C 129.347 321.097,149.415 320.614,150.769 320.071 C 154.845 318.436,158.848 321.484,175.571 338.955 C 199.201 363.642,198.778 363.640,222.345 339.228 C 240.959 319.947,242.831 318.503,247.105 320.128 C 252.288 322.098,331.882 321.514,335.822 319.477 C 341.914 316.327,342.154 314.437,342.154 269.652 L 342.154 228.036 339.210 223.699 L 336.267 219.361 344.730 210.963 C 357.422 198.369,359.452 191.916,352.925 184.923 C 350.429 182.249,349.578 182.154,328.093 182.154 L 305.846 182.154 305.846 116.336 L 305.846 50.518 302.434 47.105 L 299.022 43.692 200.895 43.471 C 146.926 43.349,101.938 43.558,100.923 43.935 M294.154 124.308 L 294.154 193.231 319.469 193.231 L 344.785 193.231 331.526 206.769 L 318.268 220.308 306.211 220.308 L 294.154 220.308 294.135 207.692 C 294.107 188.671,294.169 188.712,266.521 189.538 C 240.730 190.309,241.231 189.941,241.231 208.136 L 241.231 220.308 197.231 220.359 C 173.031 220.387,136.892 220.384,116.923 220.352 L 80.615 220.293 67.692 207.070 L 54.769 193.846 79.692 193.513 L 104.615 193.180 104.615 124.282 L 104.615 55.385 199.385 55.385 L 294.154 55.385 294.154 124.308 M283.347 215.692 L 283.692 230.769 306.769 231.104 L 329.846 231.439 329.846 270.181 L 329.846 308.923 291.077 308.923 L 252.308 308.923 252.308 254.769 L 252.308 200.615 267.654 200.615 L 283.001 200.615 283.347 215.692 M145.231 239.385 L 145.231 247.385 122.462 247.385 L 99.692 247.385 99.692 254.769 L 99.692 262.154 122.462 262.154 L 145.231 262.154 145.231 285.538 L 145.231 308.923 106.462 308.923 L 67.692 308.923 67.692 300.950 L 67.692 292.977 90.769 292.643 L 113.846 292.308 114.215 285.231 L 114.584 278.154 91.138 278.154 L 67.692 278.154 67.692 254.769 L 67.692 231.385 106.462 231.385 L 145.231 231.385 145.231 239.385 M237.538 270.154 L 237.538 308.923 198.769 308.923 L 160.000 308.923 160.000 285.538 L 160.000 262.154 182.769 262.154 L 205.538 262.154 205.538 254.769 L 205.538 247.385 182.769 247.385 L 160.000 247.385 160.000 239.385 L 160.000 231.385 198.769 231.385 L 237.538 231.385 237.538 270.154 M283.357 269.846 L 283.692 292.308 290.769 292.677 L 297.846 293.046 297.846 270.215 L 297.846 247.385 290.434 247.385 L 283.021 247.385 283.357 269.846 M192.000 285.538 L 192.000 292.923 198.769 292.923 L 205.538 292.923 205.538 285.538 L 205.538 278.154 198.769 278.154 L 192.000 278.154 192.000 285.538 M211.679 332.760 L 199.098 345.520 190.318 336.199 C 185.489 331.072,179.892 325.331,177.880 323.439 L 174.221 320.000 199.240 320.000 L 224.259 320.000 211.679 332.760 " stroke="none" fill="#000000" fill-rule="evenodd"></path></g></svg>
|
||||
|
Before Width: | Height: | Size: 3.1 KiB |
4
lib/core.dart
Normal file
4
lib/core.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
export 'package:lunasea/core/app_state.dart';
|
||||
export 'package:lunasea/core/constants.dart';
|
||||
export 'package:lunasea/core/extensions.dart';
|
||||
export 'package:lunasea/core/reducers.dart';
|
||||
10
lib/core/app_state.dart
Normal file
10
lib/core/app_state.dart
Normal file
@@ -0,0 +1,10 @@
|
||||
import 'package:redux/redux.dart';
|
||||
|
||||
final appReducer = combineReducers<AppState>([
|
||||
|
||||
]);
|
||||
|
||||
class AppState {
|
||||
AppState();
|
||||
factory AppState.initialState() => AppState();
|
||||
}
|
||||
@@ -29,12 +29,6 @@ class Constants {
|
||||
"fixes": ['Unable to fetch changes'],
|
||||
"tweaks": ['Unable to fetch changes'],
|
||||
}];
|
||||
static const Map LOWEST_VERSION = {
|
||||
'major': 0,
|
||||
'minor': 0,
|
||||
'revision': 0,
|
||||
'code': 0,
|
||||
};
|
||||
//Filesystem
|
||||
static const FILESYSTEM_INVALID = '<<INVALID_FILESYSTEM>>';
|
||||
static const ENCRYPTION_FAILURE = '<<INVALID_ENCRYPTION>>';
|
||||
3
lib/core/extensions.dart
Normal file
3
lib/core/extensions.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'package:lunasea/core/extensions/bytes.dart';
|
||||
export 'package:lunasea/core/extensions/datetime.dart';
|
||||
export 'package:lunasea/core/extensions/functions.dart';
|
||||
13
lib/core/extensions/bytes.dart
Normal file
13
lib/core/extensions/bytes.dart
Normal file
@@ -0,0 +1,13 @@
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
extension BytesExtension on int {
|
||||
String toStringFromBytes({ int decimals = 2 }) {
|
||||
int position = 0;
|
||||
double size = this.toDouble();
|
||||
while(size > 1024) {
|
||||
size /= 1024;
|
||||
position++;
|
||||
}
|
||||
return '${size.toStringAsFixed(decimals)} ${Constants.BYTE_SIZES[position]}';
|
||||
}
|
||||
}
|
||||
5
lib/core/extensions/datetime.dart
Normal file
5
lib/core/extensions/datetime.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
extension DateTimeExtension on DateTime {
|
||||
DateTime round() {
|
||||
return DateTime(this.year, this.month, this.day);
|
||||
}
|
||||
}
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:url_launcher/url_launcher.dart';
|
||||
|
||||
class Functions {
|
||||
0
lib/core/reducers.dart
Normal file
0
lib/core/reducers.dart
Normal file
5
lib/logic.dart
Normal file
5
lib/logic.dart
Normal file
@@ -0,0 +1,5 @@
|
||||
export 'package:lunasea/logic/abstracts.dart';
|
||||
export 'package:lunasea/logic/automation.dart';
|
||||
export 'package:lunasea/logic/clients.dart';
|
||||
export 'package:lunasea/logic/calendar.dart';
|
||||
export 'package:lunasea/logic/system.dart';
|
||||
9
lib/logic/abstracts.dart
Normal file
9
lib/logic/abstracts.dart
Normal file
@@ -0,0 +1,9 @@
|
||||
export 'package:lunasea/logic/abstracts/calendar.dart';
|
||||
|
||||
abstract class API {
|
||||
void logWarning(String methodName, String text);
|
||||
void logError(String methodName, String text, Object error);
|
||||
Future<bool> testConnection(List<dynamic> values);
|
||||
}
|
||||
|
||||
abstract class Entry {}
|
||||
1
lib/logic/abstracts/calendar.dart
Normal file
1
lib/logic/abstracts/calendar.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'package:lunasea/logic/abstracts/calendar/entry.dart';
|
||||
17
lib/logic/abstracts/calendar/entry.dart
Normal file
17
lib/logic/abstracts/calendar/entry.dart
Normal file
@@ -0,0 +1,17 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/abstracts.dart';
|
||||
|
||||
abstract class CalendarEntry implements Entry {
|
||||
int id;
|
||||
String title;
|
||||
|
||||
TextSpan get subtitle;
|
||||
IconButton get trailing;
|
||||
String get bannerURI;
|
||||
Future<void> enterContent(BuildContext context);
|
||||
|
||||
CalendarEntry(
|
||||
this.id,
|
||||
this.title,
|
||||
);
|
||||
}
|
||||
3
lib/logic/automation.dart
Normal file
3
lib/logic/automation.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'package:lunasea/logic/automation/lidarr.dart';
|
||||
export 'package:lunasea/logic/automation/radarr.dart';
|
||||
export 'package:lunasea/logic/automation/sonarr.dart';
|
||||
@@ -1,8 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/system/logger.dart';
|
||||
|
||||
class LidarrAPI {
|
||||
LidarrAPI._();
|
||||
@@ -214,13 +213,13 @@ class LidarrAPI {
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<bool> removeArtist(int artistID) async {
|
||||
static Future<bool> removeArtist(int artistID, { deleteFiles = false }) async {
|
||||
List<dynamic> values = Values.lidarrValues;
|
||||
if(values[0] == false) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String uri = '${values[1]}/api/v1/artist/$artistID?apikey=${values[2]}';
|
||||
String uri = '${values[1]}/api/v1/artist/$artistID?apikey=${values[2]}&deleteFiles=$deleteFiles';
|
||||
http.Response response = await http.delete(
|
||||
Uri.encodeFull(uri),
|
||||
);
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class LidarrAlbumEntry {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class LidarrCatalogueEntry {
|
||||
String title;
|
||||
@@ -46,7 +46,7 @@ class LidarrCatalogueEntry {
|
||||
}
|
||||
|
||||
String get subtitle {
|
||||
return '$albums\t•\t$tracks\n${Functions.bytesToReadable(sizeOnDisk)}';
|
||||
return '$albums\t•\t$tracks\n${sizeOnDisk.toStringFromBytes()}';
|
||||
}
|
||||
|
||||
String get tracks {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
abstract class LidarrHistoryEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class LidarrMissingEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LidarrTrackEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/automation/radarr.dart';
|
||||
import 'package:lunasea/system/logger.dart';
|
||||
|
||||
class RadarrAPI {
|
||||
RadarrAPI._();
|
||||
@@ -245,13 +244,13 @@ class RadarrAPI {
|
||||
return false;
|
||||
}
|
||||
|
||||
static Future<bool> removeMovie(int id) async {
|
||||
static Future<bool> removeMovie(int id, {bool deleteFiles = false }) async {
|
||||
List<dynamic> values = Values.radarrValues;
|
||||
if(values[0] == false) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String uri = '${values[1]}/api/movie/$id?apikey=${values[2]}';
|
||||
String uri = '${values[1]}/api/movie/$id?apikey=${values[2]}&deleteFiles=$deleteFiles';
|
||||
http.Response response = await http.delete(
|
||||
Uri.encodeFull(uri),
|
||||
);
|
||||
@@ -470,29 +469,65 @@ class RadarrAPI {
|
||||
Uri.encodeFull(uri),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
List<RadarrMissingEntry> _availableEntries = [];
|
||||
List<RadarrMissingEntry> _entries = [];
|
||||
List body = json.decode(response.body);
|
||||
for(var entry in body) {
|
||||
if(!entry['downloaded'] && entry['monitored'] && entry['status'] == 'released') {
|
||||
var _quality = entry['qualityProfileId'] != null ? _qualities[entry['qualityProfileId']] : null;
|
||||
_entries.add(
|
||||
RadarrMissingEntry(
|
||||
entry['id'] ?? -1,
|
||||
entry['title'] ?? 'Unknown Title',
|
||||
entry['sortTitle'] ?? 'Unknown Title',
|
||||
entry['studio'] ?? 'Unknown Studio',
|
||||
entry['physicalRelease'] ?? '',
|
||||
entry['inCinemas'] ?? '',
|
||||
_quality != null ? _quality.name : '',
|
||||
entry['year'] ?? 0,
|
||||
entry['runtime'] ?? 0,
|
||||
entry['status'] ?? 'Unknown Status',
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
//Sort the list by the appropriate dates
|
||||
_entries.sort((a,b) {
|
||||
if(a.physicalReleaseObject == null) return 1;
|
||||
if(b.physicalReleaseObject == null) return -1;
|
||||
return b.physicalReleaseObject.compareTo(a.physicalReleaseObject);
|
||||
});
|
||||
return _entries;
|
||||
} else {
|
||||
logError('getMissing', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('getMissing', 'Failed to fetch missing movies', e);
|
||||
return null;
|
||||
}
|
||||
logWarning('getMissing', 'Failed to fetch missing movies');
|
||||
return null;
|
||||
}
|
||||
|
||||
static Future<List<RadarrMissingEntry>> getUpcoming() async {
|
||||
List<dynamic> values = Values.radarrValues;
|
||||
if(values[0] == false) {
|
||||
return null;
|
||||
}
|
||||
try {
|
||||
Map<int, RadarrQualityProfile> _qualities = await getQualityProfiles();
|
||||
if(_qualities != null) {
|
||||
String uri = '${values[1]}/api/movie?apikey=${values[2]}';
|
||||
http.Response response = await http.get(
|
||||
Uri.encodeFull(uri),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
List<RadarrMissingEntry> _cinemaEntries = [];
|
||||
List<RadarrMissingEntry> _announcedEntries = [];
|
||||
List body = json.decode(response.body);
|
||||
for(var entry in body) {
|
||||
if(!entry['downloaded'] && entry['monitored']) {
|
||||
var _quality = entry['qualityProfileId'] != null ? _qualities[entry['qualityProfileId']] : null;
|
||||
if(entry['status'] == 'released') {
|
||||
_availableEntries.add(
|
||||
RadarrMissingEntry(
|
||||
entry['id'] ?? -1,
|
||||
entry['title'] ?? 'Unknown Title',
|
||||
entry['sortTitle'] ?? 'Unknown Title',
|
||||
entry['studio'] ?? 'Unknown Studio',
|
||||
entry['physicalRelease'] ?? '',
|
||||
entry['inCinemas'] ?? '',
|
||||
_quality != null ? _quality.name : '',
|
||||
entry['year'] ?? 0,
|
||||
entry['runtime'] ?? 0,
|
||||
entry['status'] ?? 'Unknown Status',
|
||||
),
|
||||
);
|
||||
}
|
||||
if(entry['status'] == 'inCinemas') {
|
||||
_cinemaEntries.add(
|
||||
RadarrMissingEntry(
|
||||
@@ -527,12 +562,7 @@ class RadarrAPI {
|
||||
}
|
||||
}
|
||||
}
|
||||
//Sort the lists by the appropriate dates
|
||||
_availableEntries.sort((a,b) {
|
||||
if(a.physicalReleaseObject == null) return 1;
|
||||
if(b.physicalReleaseObject == null) return -1;
|
||||
return b.physicalReleaseObject.compareTo(a.physicalReleaseObject);
|
||||
});
|
||||
//Sort entries
|
||||
_cinemaEntries.sort((a,b) {
|
||||
if(a.physicalReleaseObject == null) return 1;
|
||||
if(b.physicalReleaseObject == null) return -1;
|
||||
@@ -543,16 +573,16 @@ class RadarrAPI {
|
||||
if(b.inCinemasObject == null) return -1;
|
||||
return a.inCinemasObject.compareTo(b.inCinemasObject);
|
||||
});
|
||||
return [_availableEntries, _cinemaEntries, _announcedEntries].expand((x) => x).toList();
|
||||
return [_cinemaEntries, _announcedEntries].expand((x) => x).toList();
|
||||
} else {
|
||||
logError('getMissing', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
logError('getUpcoming', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('getMissing', 'Failed to fetch missing movies', e);
|
||||
logError('getUpcoming', 'Failed to fetch upcoming movies', e);
|
||||
return null;
|
||||
}
|
||||
logWarning('getMissing', 'Failed to fetch missing movies');
|
||||
logWarning('getUpcoming', 'Failed to fetch upcoming movies');
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class RadarrCatalogueEntry {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
abstract class RadarrHistoryEntry {
|
||||
String movieTitle;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class RadarrMissingEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class RadarrUpcomingEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/logic/automation/sonarr.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/system/logger.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/automation/sonarr.dart';
|
||||
|
||||
class SonarrAPI {
|
||||
SonarrAPI._();
|
||||
@@ -93,13 +92,13 @@ class SonarrAPI {
|
||||
return false;
|
||||
}
|
||||
|
||||
static Future<bool> removeSeries(int seriesID) async {
|
||||
static Future<bool> removeSeries(int seriesID, { deleteFiles = false }) async {
|
||||
List<dynamic> values = Values.sonarrValues;
|
||||
if(values[0] == false) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String uri = '${values[1]}/api/series/$seriesID?apikey=${values[2]}';
|
||||
String uri = '${values[1]}/api/series/$seriesID?apikey=${values[2]}&deleteFiles=$deleteFiles';
|
||||
http.Response response = await http.delete(
|
||||
Uri.encodeFull(uri),
|
||||
);
|
||||
@@ -578,6 +577,7 @@ class SonarrAPI {
|
||||
entry['episodeNumber'] ?? 0,
|
||||
entry['airDateUtc'] ?? '',
|
||||
entry['id'] ?? -1,
|
||||
entry['episodeFileId'] ?? -1,
|
||||
entry['monitored'] ?? false,
|
||||
entry['hasFile'] ?? false,
|
||||
quality ?? 'Unknown Quality',
|
||||
@@ -1075,4 +1075,64 @@ class SonarrAPI {
|
||||
logWarning('downloadRelease', 'Failed to download release ($guid)');
|
||||
return false;
|
||||
}
|
||||
|
||||
static Future<bool> toggleEpisodeMonitored(int episodeID, bool status) async {
|
||||
List<dynamic> values = Values.sonarrValues;
|
||||
if(values[0] == false) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String uriGet = '${values[1]}/api/episode/$episodeID?apikey=${values[2]}';
|
||||
String uriPut = '${values[1]}/api/episode?apikey=${values[2]}';
|
||||
http.Response response = await http.get(
|
||||
Uri.encodeFull(uriGet),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
Map body = json.decode(response.body);
|
||||
body['monitored'] = status;
|
||||
response = await http.put(
|
||||
Uri.encodeFull(uriPut),
|
||||
body: json.encode(body),
|
||||
headers: {
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
);
|
||||
if(response.statusCode == 202) {
|
||||
return true;
|
||||
} else {
|
||||
logError('toggleSeasonMonitored', '<PUT> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
} else {
|
||||
logError('toggleSeasonMonitored', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
} catch (e) {
|
||||
logError('toggleEpisodeMonitored', 'Failed to toggle episode monitored state ($episodeID, $status)', e);
|
||||
return false;
|
||||
}
|
||||
logWarning('toggleEpisodeMonitored', 'Failed to toggle episode monitored state ($episodeID, $status)');
|
||||
return false;
|
||||
}
|
||||
|
||||
static Future<bool> deleteEpisodeFile(int episodeFileID) async {
|
||||
List<dynamic> values = Values.sonarrValues;
|
||||
if(values[0] == false) {
|
||||
return false;
|
||||
}
|
||||
try {
|
||||
String uri = '${values[1]}/api/episodefile/$episodeFileID?apikey=${values[2]}';
|
||||
http.Response response = await http.delete(
|
||||
Uri.encodeFull(uri),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
return true;
|
||||
} else {
|
||||
logError('deleteEpisodeFile', '<DELETE> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
} catch (e) {
|
||||
logError('deleteEpisodeFile', 'Failed to delete episode file ($episodeFileID)', e);
|
||||
return false;
|
||||
}
|
||||
logWarning('deleteEpisodeFile', 'Failed to delete episode file ($episodeFileID)');
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class SonarrCatalogueEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/sonarr.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
|
||||
class SonarrEpisodeEntry {
|
||||
@@ -10,6 +10,7 @@ class SonarrEpisodeEntry {
|
||||
int seasonNumber;
|
||||
int episodeNumber;
|
||||
int episodeID;
|
||||
int episodeFileID;
|
||||
int size;
|
||||
bool isMonitored;
|
||||
bool hasFile;
|
||||
@@ -23,6 +24,7 @@ class SonarrEpisodeEntry {
|
||||
this.episodeNumber,
|
||||
this.airDate,
|
||||
this.episodeID,
|
||||
this.episodeFileID,
|
||||
this.isMonitored,
|
||||
this.hasFile,
|
||||
this.quality,
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
abstract class SonarrHistoryEntry {
|
||||
String seriesTitle;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class SonarrMissingEntry {
|
||||
String showTitle;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class SonarrSearchEntry {
|
||||
String title;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
class SonarrUpcomingEntry {
|
||||
String seriesTitle;
|
||||
|
||||
2
lib/logic/calendar.dart
Normal file
2
lib/logic/calendar.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'package:lunasea/logic/calendar/api.dart';
|
||||
export 'package:lunasea/logic/calendar/entry.dart';
|
||||
145
lib/logic/calendar/api.dart
Normal file
145
lib/logic/calendar/api.dart
Normal file
@@ -0,0 +1,145 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/abstracts.dart';
|
||||
import 'package:lunasea/logic/calendar.dart';
|
||||
|
||||
class CalendarAPI extends API {
|
||||
@override
|
||||
void logError(String methodName, String text, Object error) {
|
||||
Logger.error('package:lunasea/logic/home/api.dart', methodName, 'Home: $text', error, StackTrace.current);
|
||||
}
|
||||
|
||||
@override
|
||||
void logWarning(String methodName, String text) {
|
||||
Logger.warning('package:lunasea/logic/home/api.dart', methodName, 'Home: $text');
|
||||
}
|
||||
|
||||
Future<Map<DateTime, List>> getUpcoming(DateTime today) async {
|
||||
Map<DateTime, List> _upcoming = {};
|
||||
await _getLidarrUpcoming(_upcoming, today);
|
||||
await _getRadarrUpcoming(_upcoming, today);
|
||||
await _getSonarrUpcoming(_upcoming, today);
|
||||
return _upcoming;
|
||||
}
|
||||
|
||||
Future<void> _getLidarrUpcoming(Map<DateTime, List> map, DateTime today, { int startOffset = 7, int endOffset = 60 }) async {
|
||||
try {
|
||||
List<dynamic> values = Values.lidarrValues;
|
||||
if(values[0]) {
|
||||
String start = DateFormat('y-MM-dd').format(today.subtract(Duration(days: startOffset)));
|
||||
String end = DateFormat('y-MM-dd').format(today.add(Duration(days: endOffset)));
|
||||
String uri = '${values[1]}/api/v1/calendar?apikey=${values[2]}&start=$start&end=$end';
|
||||
http.Response response = await http.get(Uri.encodeFull(uri));
|
||||
if(response.statusCode == 200) {
|
||||
List body = json.decode(response.body);
|
||||
if(body.length > 0) {
|
||||
for(var entry in body) {
|
||||
DateTime date = DateTime.tryParse(entry['releaseDate'] ?? '')?.toLocal()?.round();
|
||||
if(date != null) {
|
||||
List day = map[date] ?? [];
|
||||
day.add(CalendarLidarrEntry(
|
||||
id: entry['id'] ?? 0,
|
||||
title: entry['artist']['artistName'] ?? 'Unknown Artist',
|
||||
albumTitle: entry['title'] ?? 'Unknown Album Title',
|
||||
artistId: entry['artist']['id'] ?? 0,
|
||||
hasAllFiles: (entry['statistics'] != null ? entry['statistics']['percentOfTracks'] ?? 0 : 0) == 100,
|
||||
));
|
||||
map[date] = day;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logError('_getLidarrUpcoming', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('_getLidarrUpcoming', 'Failed to fetch Lidarr upcoming content', e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getRadarrUpcoming(Map<DateTime, List> map, DateTime today, { int startOffset = 7, int endOffset = 60 }) async {
|
||||
try {
|
||||
List<dynamic> values = Values.radarrValues;
|
||||
if(values[0]) {
|
||||
String start = DateFormat('y-MM-dd').format(today.subtract(Duration(days: startOffset)));
|
||||
String end = DateFormat('y-MM-dd').format(today.add(Duration(days: endOffset)));
|
||||
String uri = '${values[1]}/api/calendar?apikey=${values[2]}&start=$start&end=$end';
|
||||
http.Response response = await http.get(Uri.encodeFull(uri));
|
||||
if(response.statusCode == 200) {
|
||||
List body = json.decode(response.body);
|
||||
if(body.length > 0) {
|
||||
for(var entry in body) {
|
||||
DateTime date = DateTime.tryParse(entry['physicalRelease'] ?? '')?.toLocal()?.round();
|
||||
if(date != null) {
|
||||
List day = map[date] ?? [];
|
||||
day.add(CalendarRadarrEntry(
|
||||
id: entry['id'] ?? 0,
|
||||
title: entry['title'] ?? 'Unknown Title',
|
||||
hasFile: entry['hasFile'] ?? false,
|
||||
fileQualityProfile: entry['hasFile'] ? entry['movieFile']['quality']['quality']['name'] : '',
|
||||
year: entry['year'] ?? 0,
|
||||
runtime: entry['runtime'] ?? 0,
|
||||
));
|
||||
map[date] = day;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logError('_getRadarrUpcoming', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('_getRadarrUpcoming', 'Failed to fetch Radarr upcoming content', e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _getSonarrUpcoming(Map<DateTime, List> map, DateTime today, { int startOffset = 7, int endOffset = 60 }) async {
|
||||
try {
|
||||
List<dynamic> values = Values.sonarrValues;
|
||||
if(values[0]) {
|
||||
String start = DateFormat('y-MM-dd').format(today.subtract(Duration(days: startOffset)));
|
||||
String end = DateFormat('y-MM-dd').format(today.add(Duration(days: endOffset)));
|
||||
String uri = '${values[1]}/api/calendar?apikey=${values[2]}&start=$start&end=$end';
|
||||
http.Response response = await http.get(Uri.encodeFull(uri));
|
||||
if(response.statusCode == 200) {
|
||||
List body = json.decode(response.body);
|
||||
if(body.length > 0) {
|
||||
for(var entry in body) {
|
||||
DateTime date = DateTime.tryParse(entry['airDateUtc'] ?? '')?.toLocal()?.round();
|
||||
if(date != null) {
|
||||
List day = map[date] ?? [];
|
||||
day.add(CalendarSonarrEntry(
|
||||
id: entry['id'] ?? 0,
|
||||
seriesID: entry['seriesId'] ?? 0,
|
||||
title: entry['series']['title'] ?? 'Unknown Series',
|
||||
episodeTitle: entry['title'] ?? 'Unknown Episode Title',
|
||||
seasonNumber: entry['seasonNumber'] ?? -1,
|
||||
episodeNumber: entry['episodeNumber'] ?? -1,
|
||||
airTime: entry['airDateUtc'] ?? '',
|
||||
hasFile: entry['hasFile'] ?? false,
|
||||
fileQualityProfile: entry['hasFile'] ? entry['episodeFile']['quality']['quality']['name'] : '',
|
||||
));
|
||||
map[date] = day;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
logError('_getSonarrUpcoming', '<GET> HTTP Status Code (${response.statusCode})', null);
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
logError('_getSonarrUpcoming', 'Failed to fetch Sonarr upcoming content', e);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Future<bool> testConnection(List values) async {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
3
lib/logic/calendar/entry.dart
Normal file
3
lib/logic/calendar/entry.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'package:lunasea/logic/calendar/entry/lidarr.dart';
|
||||
export 'package:lunasea/logic/calendar/entry/radarr.dart';
|
||||
export 'package:lunasea/logic/calendar/entry/sonarr.dart';
|
||||
71
lib/logic/calendar/entry/lidarr.dart
Normal file
71
lib/logic/calendar/entry/lidarr.dart
Normal file
@@ -0,0 +1,71 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/artist.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/logic/abstracts.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class CalendarLidarrEntry extends CalendarEntry {
|
||||
String albumTitle;
|
||||
int artistId;
|
||||
bool hasAllFiles;
|
||||
|
||||
CalendarLidarrEntry({
|
||||
@required int id,
|
||||
@required String title,
|
||||
@required this.albumTitle,
|
||||
@required this.artistId,
|
||||
@required this.hasAllFiles,
|
||||
}) : super(id, title);
|
||||
|
||||
@override
|
||||
String get bannerURI {
|
||||
List<dynamic> values = Values.lidarrValues;
|
||||
return '${values[1]}/api/v1/MediaCover/Artist/$artistId/banner.jpg?apikey=${values[2]}';
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan get subtitle => TextSpan(
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: albumTitle,
|
||||
style: TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
if(!hasAllFiles) TextSpan(
|
||||
text: '\nNot Downloaded',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
if(hasAllFiles) TextSpan(
|
||||
text: '\nDownloaded',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(Constants.ACCENT_COLOR),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
Future<void> enterContent(BuildContext context) async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LidarrArtistDetails(entry: null, artistID: artistId),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
IconButton get trailing => IconButton(
|
||||
icon: Elements.getIcon(Icons.arrow_forward_ios),
|
||||
onPressed: null,
|
||||
);
|
||||
}
|
||||
77
lib/logic/calendar/entry/radarr.dart
Normal file
77
lib/logic/calendar/entry/radarr.dart
Normal file
@@ -0,0 +1,77 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/routes/radarr/subpages/details/movie.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
import 'package:lunasea/logic/abstracts.dart';
|
||||
|
||||
class CalendarRadarrEntry extends CalendarEntry {
|
||||
bool hasFile;
|
||||
String fileQualityProfile;
|
||||
int year;
|
||||
int runtime;
|
||||
|
||||
CalendarRadarrEntry({
|
||||
@required int id,
|
||||
@required String title,
|
||||
@required this.hasFile,
|
||||
@required this.fileQualityProfile,
|
||||
@required this.year,
|
||||
@required this.runtime,
|
||||
}): super(id, title);
|
||||
|
||||
String get runtimeString {
|
||||
if(runtime == null || runtime == 0) {
|
||||
return '';
|
||||
}
|
||||
return Functions.runtimeReadable(runtime, withDot: true);
|
||||
}
|
||||
|
||||
@override
|
||||
TextSpan get subtitle => TextSpan(
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '$year$runtimeString',
|
||||
),
|
||||
if(!hasFile) TextSpan(
|
||||
text: '\nNot Downloaded',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
if(hasFile) TextSpan(
|
||||
text: '\nDownloaded ($fileQualityProfile)',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(Constants.ACCENT_COLOR),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
String get bannerURI {
|
||||
List values = Values.radarrValues;
|
||||
return '${values[1]}/api/MediaCover/$id/fanart-360.jpg?apikey=${values[2]}';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> enterContent(BuildContext context) async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => RadarrMovieDetails(entry: null, movieID: id),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
IconButton get trailing => IconButton(
|
||||
icon: Elements.getIcon(Icons.arrow_forward_ios),
|
||||
onPressed: null,
|
||||
);
|
||||
}
|
||||
101
lib/logic/calendar/entry/sonarr.dart
Normal file
101
lib/logic/calendar/entry/sonarr.dart
Normal file
@@ -0,0 +1,101 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/routes/sonarr/subpages/details/show.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/logic/abstracts.dart';
|
||||
|
||||
class CalendarSonarrEntry extends CalendarEntry {
|
||||
String episodeTitle;
|
||||
int seasonNumber;
|
||||
int episodeNumber;
|
||||
int seriesID;
|
||||
String airTime;
|
||||
bool hasFile;
|
||||
String fileQualityProfile;
|
||||
|
||||
CalendarSonarrEntry({
|
||||
@required int id,
|
||||
@required String title,
|
||||
@required this.episodeTitle,
|
||||
@required this.seasonNumber,
|
||||
@required this.episodeNumber,
|
||||
@required this.seriesID,
|
||||
@required this.airTime,
|
||||
@required this.hasFile,
|
||||
@required this.fileQualityProfile,
|
||||
}) : super(id, title);
|
||||
|
||||
@override
|
||||
TextSpan get subtitle => TextSpan(
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: 'Season $seasonNumber Episode $episodeNumber: ',
|
||||
),
|
||||
TextSpan(
|
||||
text: episodeTitle,
|
||||
style: TextStyle(
|
||||
fontStyle: FontStyle.italic,
|
||||
),
|
||||
),
|
||||
if(!hasFile) TextSpan(
|
||||
text: '\nNot Downloaded',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Colors.red,
|
||||
),
|
||||
),
|
||||
if(hasFile) TextSpan(
|
||||
text: '\nDownloaded ($fileQualityProfile)',
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.bold,
|
||||
color: Color(Constants.ACCENT_COLOR),
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
@override
|
||||
String get bannerURI {
|
||||
List values = Values.sonarrValues;
|
||||
return '${values[1]}/api/mediacover/$seriesID/banner-70.jpg?apikey=${values[2]}';
|
||||
}
|
||||
|
||||
@override
|
||||
Future<void> enterContent(BuildContext context) async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => SonarrShowDetails(entry: null, seriesID: seriesID),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@override
|
||||
IconButton get trailing => IconButton(
|
||||
icon: Text(
|
||||
airTimeString,
|
||||
textAlign: TextAlign.center,
|
||||
style: TextStyle(
|
||||
color: Colors.white,
|
||||
fontWeight: FontWeight.bold,
|
||||
fontSize: 10.0,
|
||||
),
|
||||
),
|
||||
onPressed: null,
|
||||
);
|
||||
|
||||
DateTime get airTimeObject {
|
||||
return DateTime.tryParse(airTime)?.toLocal();
|
||||
}
|
||||
|
||||
String get airTimeString {
|
||||
if(airTimeObject != null) {
|
||||
return DateFormat('KK:mm\na').format(airTimeObject);
|
||||
}
|
||||
return 'N/A';
|
||||
}
|
||||
}
|
||||
2
lib/logic/clients.dart
Normal file
2
lib/logic/clients.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'package:lunasea/logic/clients/nzbget.dart';
|
||||
export 'package:lunasea/logic/clients/sabnzbd.dart';
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget/entry.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/logger.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
|
||||
class NZBGetAPI {
|
||||
NZBGetAPI._();
|
||||
@@ -16,14 +15,10 @@ class NZBGetAPI {
|
||||
Logger.error('package:lunasea/logic/clients/nzbget/api.dart', methodName, 'NZBGet: $text', error, StackTrace.current);
|
||||
}
|
||||
|
||||
static String getURL(String uri) {
|
||||
return Uri.encodeFull('$uri/jsonrpc');
|
||||
}
|
||||
|
||||
static Map<String, String> getHeader(String username, String password) {
|
||||
return {
|
||||
'authorization': 'Basic ' + base64Encode(utf8.encode('$username:$password')),
|
||||
};
|
||||
static String getURL(String uri, String username, String password) {
|
||||
return (username != null && username != '' && password != null && password != '')
|
||||
? Uri.encodeFull('$uri/$username:$password/jsonrpc')
|
||||
: Uri.encodeFull('$uri/jsonrpc');
|
||||
}
|
||||
|
||||
static String getBody(String method, {List<dynamic> params = Constants.EMPTY_LIST}) {
|
||||
@@ -38,8 +33,7 @@ class NZBGetAPI {
|
||||
static Future<bool> testConnection(List<dynamic> values) async {
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('version'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -81,8 +75,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('status'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -114,8 +107,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('status'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -151,8 +143,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'log',
|
||||
params: [
|
||||
@@ -193,8 +184,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('listgroups'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -239,8 +229,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'history',
|
||||
params: [hidden],
|
||||
@@ -284,8 +273,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('pausedownload'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -312,8 +300,7 @@ class NZBGetAPI {
|
||||
try {
|
||||
if(await pauseQueue()) {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'scheduleresume',
|
||||
params: [minutes*60],
|
||||
@@ -343,8 +330,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('resumedownload'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -370,8 +356,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -404,8 +389,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -438,8 +422,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -472,8 +455,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -506,8 +488,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -540,8 +521,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -574,8 +554,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -608,8 +587,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -642,8 +620,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -676,8 +653,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -710,8 +686,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody('config'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
@@ -750,8 +725,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'editqueue',
|
||||
params: [
|
||||
@@ -784,8 +758,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'append',
|
||||
params: [
|
||||
@@ -826,8 +799,7 @@ class NZBGetAPI {
|
||||
try {
|
||||
String dataBase64 = utf8.fuse(base64).encode(data);
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'append',
|
||||
params: [
|
||||
@@ -867,8 +839,7 @@ class NZBGetAPI {
|
||||
}
|
||||
try {
|
||||
http.Response response = await http.post(
|
||||
getURL(values[1]),
|
||||
headers: getHeader(values[2], values[3]),
|
||||
getURL(values[1], values[2], values[3]),
|
||||
body: getBody(
|
||||
'rate',
|
||||
params: [limit],
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class NZBGetHistoryEntry {
|
||||
int id;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class NZBGetQueueEntry {
|
||||
int id;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class NZBGetStatisticsEntry {
|
||||
int freeSpaceHigh;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class NZBGetStatusEntry {
|
||||
bool paused;
|
||||
|
||||
@@ -1,8 +1,7 @@
|
||||
import 'dart:convert';
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/logic/clients/sabnzbd/entry.dart';
|
||||
import 'package:lunasea/system/logger.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/clients/sabnzbd.dart';
|
||||
|
||||
class SABnzbdAPI {
|
||||
SABnzbdAPI._();
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class SABnzbdHistoryEntry {
|
||||
String nzoId;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class SABnzbdStatisticsEntry {
|
||||
List<String> servers;
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class SABnzbdStatusEntry {
|
||||
bool paused;
|
||||
|
||||
1
lib/logic/system.dart
Normal file
1
lib/logic/system.dart
Normal file
@@ -0,0 +1 @@
|
||||
export 'package:lunasea/logic/system/version.dart';
|
||||
@@ -1,21 +1,9 @@
|
||||
import 'package:http/http.dart' as http;
|
||||
import 'dart:convert';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class System {
|
||||
System._();
|
||||
|
||||
static Future<Map> getLatestVersion() async {
|
||||
try {
|
||||
http.Response response = await http.get(
|
||||
Uri.encodeFull('https://www.lunasea.app/version.json'),
|
||||
);
|
||||
if(response.statusCode == 200) {
|
||||
return json.decode(response.body);
|
||||
}
|
||||
} catch (e) {}
|
||||
return Constants.LOWEST_VERSION;
|
||||
}
|
||||
|
||||
static Future<List> getChangelog() async {
|
||||
try {
|
||||
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'dart:async';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/pages/pages.dart';
|
||||
import 'package:lunasea/configuration/configuration.dart';
|
||||
import 'package:lunasea/system/logger.dart';
|
||||
import 'package:flutter_redux/flutter_redux.dart';
|
||||
import 'package:redux/redux.dart';
|
||||
import 'package:lunasea/routes.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
|
||||
void main() async {
|
||||
WidgetsFlutterBinding.ensureInitialized();
|
||||
@@ -17,17 +18,25 @@ void main() async {
|
||||
}
|
||||
|
||||
class _BIOS extends StatelessWidget {
|
||||
final Store<AppState> store = Store<AppState>(
|
||||
appReducer,
|
||||
initialState: AppState.initialState(),
|
||||
);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return MaterialApp(
|
||||
title: 'LunaSea',
|
||||
debugShowCheckedModeBanner: false,
|
||||
routes: _setRoute(),
|
||||
theme: _setTheme(),
|
||||
return StoreProvider(
|
||||
store: store,
|
||||
child: MaterialApp(
|
||||
title: 'LunaSea',
|
||||
debugShowCheckedModeBanner: false,
|
||||
routes: _setRoutes(),
|
||||
theme: _setTheme(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Map<String, WidgetBuilder> _setRoute() {
|
||||
Map<String, WidgetBuilder> _setRoutes() {
|
||||
return <String, WidgetBuilder> {
|
||||
'/': (BuildContext context) => Home(),
|
||||
'/settings': (BuildContext context) => Settings(),
|
||||
|
||||
@@ -1,2 +0,0 @@
|
||||
export 'package:lunasea/pages/home/sections/summary.dart';
|
||||
export 'package:lunasea/pages/home/sections/quickaccess.dart';
|
||||
@@ -1,3 +0,0 @@
|
||||
export 'package:lunasea/pages/lidarr/subpages/catalogue/catalogue.dart';
|
||||
export 'package:lunasea/pages/lidarr/subpages/history/history.dart';
|
||||
export 'package:lunasea/pages/lidarr/subpages/missing/missing.dart';
|
||||
@@ -1,2 +0,0 @@
|
||||
export 'package:lunasea/pages/nzbget/subpages/history/history.dart';
|
||||
export 'package:lunasea/pages/nzbget/subpages/queue/queue.dart';
|
||||
@@ -1,7 +0,0 @@
|
||||
export 'package:lunasea/pages/home/home.dart';
|
||||
export 'package:lunasea/pages/settings/settings.dart';
|
||||
export 'package:lunasea/pages/lidarr/lidarr.dart';
|
||||
export 'package:lunasea/pages/nzbget/nzbget.dart';
|
||||
export 'package:lunasea/pages/radarr/radarr.dart';
|
||||
export 'package:lunasea/pages/sonarr/sonarr.dart';
|
||||
export 'package:lunasea/pages/sabnzbd/sabnzbd.dart';
|
||||
@@ -1,4 +0,0 @@
|
||||
export 'package:lunasea/pages/radarr/subpages/catalogue/catalogue.dart';
|
||||
export 'package:lunasea/pages/radarr/subpages/history/history.dart';
|
||||
export 'package:lunasea/pages/radarr/subpages/missing/missing.dart';
|
||||
export 'package:lunasea/pages/radarr/subpages/details/movie.dart';
|
||||
@@ -1,3 +0,0 @@
|
||||
export 'package:lunasea/pages/radarr/subpages/details/tabs/files.dart';
|
||||
export 'package:lunasea/pages/radarr/subpages/details/tabs/overview.dart';
|
||||
export 'package:lunasea/pages/radarr/subpages/details/tabs/releases.dart';
|
||||
@@ -1,2 +0,0 @@
|
||||
export 'package:lunasea/pages/sabnzbd/subpages/history/history.dart';
|
||||
export 'package:lunasea/pages/sabnzbd/subpages/queue/queue.dart';
|
||||
@@ -1,4 +0,0 @@
|
||||
export 'package:lunasea/pages/settings/subpages/general/general.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/monitoring/monitoring.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/automation/automation.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/clients/clients.dart';
|
||||
@@ -1,3 +0,0 @@
|
||||
export 'package:lunasea/pages/settings/subpages/automation/tabs/lidarr.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/automation/tabs/radarr.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/automation/tabs/sonarr.dart';
|
||||
@@ -1,2 +0,0 @@
|
||||
export 'package:lunasea/pages/settings/subpages/clients/tabs/nzbget.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/clients/tabs/sabnzbd.dart';
|
||||
@@ -1,4 +0,0 @@
|
||||
export 'package:lunasea/pages/settings/subpages/general/tabs/backup_restore.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/general/tabs/logs.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/general/tabs/lunasea.dart';
|
||||
export 'package:lunasea/pages/settings/subpages/general/tabs/profile.dart';
|
||||
@@ -1,6 +0,0 @@
|
||||
export 'package:lunasea/pages/sonarr/subpages/catalogue/catalogue.dart';
|
||||
export 'package:lunasea/pages/sonarr/subpages/history/history.dart';
|
||||
export 'package:lunasea/pages/sonarr/subpages/missing/missing.dart';
|
||||
export 'package:lunasea/pages/sonarr/subpages/upcoming/upcoming.dart';
|
||||
export 'package:lunasea/pages/sonarr/subpages/details/season.dart';
|
||||
export 'package:lunasea/pages/sonarr/subpages/details/show.dart';
|
||||
7
lib/routes.dart
Normal file
7
lib/routes.dart
Normal file
@@ -0,0 +1,7 @@
|
||||
export 'package:lunasea/routes/home/home.dart';
|
||||
export 'package:lunasea/routes/settings/settings.dart';
|
||||
export 'package:lunasea/routes/lidarr/lidarr.dart';
|
||||
export 'package:lunasea/routes/nzbget/nzbget.dart';
|
||||
export 'package:lunasea/routes/radarr/radarr.dart';
|
||||
export 'package:lunasea/routes/sonarr/sonarr.dart';
|
||||
export 'package:lunasea/routes/sabnzbd/sabnzbd.dart';
|
||||
60
lib/routes/home/home.dart
Normal file
60
lib/routes/home/home.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
import 'package:lunasea/routes/home/subpages.dart';
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
@override
|
||||
State<Home> createState() {
|
||||
return _State();
|
||||
}
|
||||
}
|
||||
|
||||
class _State extends State<Home> {
|
||||
final _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
int _currIndex = 0;
|
||||
|
||||
final List<Widget> _children = [
|
||||
Summary(),
|
||||
Calendar(),
|
||||
];
|
||||
|
||||
final List<String> _titles = [
|
||||
'Summary',
|
||||
'Calendar',
|
||||
];
|
||||
|
||||
final List<Icon> _icons = [
|
||||
Icon(CustomIcons.home),
|
||||
Icon(CustomIcons.calendar)
|
||||
];
|
||||
|
||||
void _navOnTap(int index) {
|
||||
if(mounted) {
|
||||
setState(() {
|
||||
_currIndex = index;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
key: _scaffoldKey,
|
||||
body: Stack(
|
||||
children: <Widget>[
|
||||
for(int i=0; i < _children.length; i++)
|
||||
Offstage(
|
||||
offstage: _currIndex != i,
|
||||
child: TickerMode(
|
||||
enabled: _currIndex == i,
|
||||
child: _children[i],
|
||||
),
|
||||
)
|
||||
],
|
||||
),
|
||||
appBar: Navigation.getAppBar('LunaSea', context),
|
||||
drawer: Navigation.getDrawer('home', context),
|
||||
bottomNavigationBar: Navigation.getBottomNavigationBar(_currIndex, _icons, _titles, _navOnTap),
|
||||
);
|
||||
}
|
||||
}
|
||||
2
lib/routes/home/subpages.dart
Normal file
2
lib/routes/home/subpages.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'package:lunasea/routes/home/subpages/summary/summary.dart';
|
||||
export 'package:lunasea/routes/home/subpages/calendar/calendar.dart';
|
||||
60
lib/routes/home/subpages/calendar/calendar.dart
Normal file
60
lib/routes/home/subpages/calendar/calendar.dart
Normal file
@@ -0,0 +1,60 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/logic.dart';
|
||||
import 'package:lunasea/widgets/pages/home.dart';
|
||||
import 'package:lunasea/widgets/ui.dart' as UI;
|
||||
|
||||
class Calendar extends StatefulWidget {
|
||||
@override
|
||||
State<Calendar> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<Calendar> {
|
||||
final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
|
||||
DateTime _today;
|
||||
Map<DateTime, List> _events;
|
||||
bool _loading = true;
|
||||
|
||||
@override
|
||||
initState() {
|
||||
super.initState();
|
||||
Future.delayed(Duration(milliseconds: 200)).then((_) {
|
||||
if(mounted) {
|
||||
_refreshIndicatorKey?.currentState?.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _handleRefresh() async {
|
||||
if(mounted) setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
CalendarAPI api = CalendarAPI();
|
||||
_today = DateTime.now().round();
|
||||
_events = await api.getUpcoming(_today);
|
||||
if(mounted) setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
body: RefreshIndicator(
|
||||
key: _refreshIndicatorKey,
|
||||
onRefresh: _handleRefresh,
|
||||
backgroundColor: Color(Constants.SECONDARY_COLOR),
|
||||
child: _loading
|
||||
? UI.Loading()
|
||||
: _events == null
|
||||
? UI.ConnectionError(onTapHandler: () {
|
||||
_refreshIndicatorKey?.currentState?.show();
|
||||
})
|
||||
: CalendarWidget(
|
||||
events: _events,
|
||||
today: _today,
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
2
lib/routes/home/subpages/summary/sections.dart
Normal file
2
lib/routes/home/subpages/summary/sections.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'package:lunasea/routes/home/subpages/summary/sections/summary.dart';
|
||||
export 'package:lunasea/routes/home/subpages/summary/sections/quickaccess.dart';
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
List buildQuickAccess(BuildContext context, List<String> services) {
|
||||
List serviceList = [
|
||||
@@ -8,7 +8,7 @@ List buildQuickAccess(BuildContext context, List<String> services) {
|
||||
child: Card(
|
||||
child: InkWell(
|
||||
child: Padding(
|
||||
child: Elements.getIcon(Icons.music_note, color: Colors.blue),
|
||||
child: Elements.getIcon(CustomIcons.music, color: Colors.blue),
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
),
|
||||
onTap: () async {
|
||||
@@ -24,7 +24,7 @@ List buildQuickAccess(BuildContext context, List<String> services) {
|
||||
child: Card(
|
||||
child: InkWell(
|
||||
child: Padding(
|
||||
child: Elements.getIcon(Icons.movie, color: Color(Constants.ACCENT_COLOR)),
|
||||
child: Elements.getIcon(CustomIcons.movies, color: Color(Constants.ACCENT_COLOR)),
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
),
|
||||
onTap: () async {
|
||||
@@ -40,7 +40,7 @@ List buildQuickAccess(BuildContext context, List<String> services) {
|
||||
child: Card(
|
||||
child: InkWell(
|
||||
child: Padding(
|
||||
child: Elements.getIcon(Icons.live_tv, color: Colors.orange),
|
||||
child: Elements.getIcon(CustomIcons.television, color: Colors.orange),
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
),
|
||||
onTap: () async {
|
||||
@@ -88,7 +88,7 @@ List buildQuickAccess(BuildContext context, List<String> services) {
|
||||
child: Card(
|
||||
child: InkWell(
|
||||
child: Padding(
|
||||
child: Elements.getIcon(Icons.settings, color: Colors.red),
|
||||
child: Elements.getIcon(CustomIcons.settings, color: Colors.red),
|
||||
padding: EdgeInsets.symmetric(vertical: 16.0),
|
||||
),
|
||||
onTap: () async {
|
||||
@@ -102,7 +102,7 @@ List buildQuickAccess(BuildContext context, List<String> services) {
|
||||
),
|
||||
];
|
||||
List<Padding> chunkedList = [Elements.getHeader('Quick Access')];
|
||||
List<Padding> chunks = chunkifyServices(serviceList);
|
||||
List<Padding> chunks = chunkifyServices(serviceList, chunkSize: serviceList.length <= 4 ? 4 : (serviceList.length/2).ceil());
|
||||
chunkedList.addAll(chunks);
|
||||
return chunkedList;
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
List buildSummary(BuildContext context, List<String> services, int sonarr, int radarr, int lidarr) {
|
||||
return [
|
||||
@@ -1,20 +1,18 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/pages/home/sections.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/logic/automation/radarr.dart';
|
||||
import 'package:lunasea/logic/automation/sonarr.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/routes/home/subpages/summary/sections.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
import 'package:lunasea/logic/automation.dart';
|
||||
|
||||
class Home extends StatefulWidget {
|
||||
class Summary extends StatefulWidget {
|
||||
@override
|
||||
State<Home> createState() {
|
||||
State<Summary> createState() {
|
||||
return _State();
|
||||
}
|
||||
}
|
||||
|
||||
class _State extends State<Home> {
|
||||
class _State extends State<Summary> {
|
||||
final _refreshIndicatorKey = GlobalKey<RefreshIndicatorState>();
|
||||
List<String> _services = [];
|
||||
int _lidarrCount;
|
||||
@@ -108,10 +106,6 @@ class _State extends State<Home> {
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Scaffold(
|
||||
appBar: Navigation.getAppBar('LunaSea', context),
|
||||
drawer: Navigation.getDrawer('home', context),
|
||||
body: _buildBody(),
|
||||
);
|
||||
return _buildBody();
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr/api.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/catalogue/addartist/search.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/catalogue/addartist/search.dart';
|
||||
|
||||
class Lidarr extends StatefulWidget {
|
||||
@override
|
||||
@@ -36,9 +35,9 @@ class _State extends State<Lidarr> {
|
||||
];
|
||||
|
||||
final List<Icon> _icons = [
|
||||
Icon(Icons.music_note),
|
||||
Icon(Icons.event_busy),
|
||||
Icon(Icons.history)
|
||||
Icon(CustomIcons.music),
|
||||
Icon(CustomIcons.calendar_missing),
|
||||
Icon(CustomIcons.history)
|
||||
];
|
||||
|
||||
void _navOnTap(int index) {
|
||||
3
lib/routes/lidarr/subpages.dart
Normal file
3
lib/routes/lidarr/subpages.dart
Normal file
@@ -0,0 +1,3 @@
|
||||
export 'package:lunasea/routes/lidarr/subpages/catalogue/catalogue.dart';
|
||||
export 'package:lunasea/routes/lidarr/subpages/history/history.dart';
|
||||
export 'package:lunasea/routes/lidarr/subpages/missing/missing.dart';
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrArtistSearchDetails extends StatefulWidget {
|
||||
final LidarrSearchEntry entry;
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/catalogue/addartist/details.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/catalogue/addartist/details.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrArtistSearch extends StatefulWidget {
|
||||
@override
|
||||
@@ -2,10 +2,10 @@ import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/artist.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/edit.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/artist.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/edit.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class Catalogue extends StatefulWidget {
|
||||
final GlobalKey<RefreshIndicatorState> refreshIndicatorKey;
|
||||
@@ -167,7 +167,7 @@ class _State extends State<Catalogue> with TickerProviderStateMixin {
|
||||
_searchController.text = '';
|
||||
}
|
||||
}
|
||||
setState(() {});
|
||||
if(mounted) setState(() {});
|
||||
}
|
||||
|
||||
Widget _noEntries(String message) {
|
||||
@@ -343,12 +343,25 @@ class _State extends State<Catalogue> with TickerProviderStateMixin {
|
||||
case 'remove_artist': {
|
||||
values = await LidarrDialogs.showDeleteArtistPrompt(context);
|
||||
if(values[0]) {
|
||||
if(await LidarrAPI.removeArtist(entry.artistID)) {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Removed ${entry.title}');
|
||||
widget.refreshIndicatorKey?.currentState?.show();
|
||||
if(values[1]) {
|
||||
values = await SystemDialogs.showDeleteCatalogueWithFilesPrompt(context, entry.title);
|
||||
if(values[0]) {
|
||||
if(await LidarrAPI.removeArtist(entry.artistID, deleteFiles: true)) {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Removed ${entry.title}');
|
||||
widget.refreshIndicatorKey?.currentState?.show();
|
||||
} else {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Failed to remove ${entry.title}');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Failed to remove ${entry.title}');
|
||||
if(await LidarrAPI.removeArtist(entry.artistID)) {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Removed ${entry.title}');
|
||||
widget.refreshIndicatorKey?.currentState?.show();
|
||||
} else {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Failed to remove ${entry.title}');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -380,7 +393,7 @@ class _State extends State<Catalogue> with TickerProviderStateMixin {
|
||||
Future<void> _enterArtist(LidarrCatalogueEntry entry, int index) async {
|
||||
final result = await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LidarrArtistDetails(entry: entry),
|
||||
builder: (context) => LidarrArtistDetails(entry: entry, artistID: entry.artistID),
|
||||
),
|
||||
);
|
||||
//Handle the result
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/search.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/search.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrAlbumDetails extends StatefulWidget {
|
||||
final String title;
|
||||
@@ -1,18 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/album.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/edit.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/album.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/edit.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrArtistDetails extends StatefulWidget {
|
||||
final LidarrCatalogueEntry entry;
|
||||
final int artistID;
|
||||
|
||||
LidarrArtistDetails({
|
||||
Key key,
|
||||
this.entry,
|
||||
@required this.entry,
|
||||
@required this.artistID,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
@@ -29,6 +30,7 @@ class _State extends State<LidarrArtistDetails> {
|
||||
'Albums',
|
||||
];
|
||||
List<LidarrAlbumEntry> _albumEntries;
|
||||
bool _loading = false;
|
||||
bool _loadingAlbums = true;
|
||||
bool _hideUnmonitored = false;
|
||||
|
||||
@@ -40,7 +42,17 @@ class _State extends State<LidarrArtistDetails> {
|
||||
@override
|
||||
void initState() {
|
||||
super.initState();
|
||||
_refreshData();
|
||||
if(entry == null) {
|
||||
_needFetch();
|
||||
}
|
||||
_refreshArtist();
|
||||
_refreshAlbums();
|
||||
}
|
||||
|
||||
void _needFetch() {
|
||||
if(mounted) setState(() {
|
||||
_loading = true;
|
||||
});
|
||||
}
|
||||
|
||||
@override
|
||||
@@ -50,21 +62,31 @@ class _State extends State<LidarrArtistDetails> {
|
||||
initialIndex: 1,
|
||||
child: Scaffold(
|
||||
key: _scaffoldKey,
|
||||
body: _buildPage(),
|
||||
body: _loading ?
|
||||
Notifications.centeredMessage('Loading...') :
|
||||
entry == null ?
|
||||
Notifications.centeredMessage('Connection Error') :
|
||||
_buildPage(),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _refreshData() async {
|
||||
Future<void> _refreshArtist() async {
|
||||
LidarrCatalogueEntry _entry = await LidarrAPI.getArtist(widget.artistID);
|
||||
_entry ??= entry;
|
||||
entry = _entry;
|
||||
if(mounted) setState(() {
|
||||
_loading = false;
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> _refreshAlbums() async {
|
||||
if(mounted) {
|
||||
setState(() {
|
||||
_loadingAlbums = true;
|
||||
});
|
||||
}
|
||||
LidarrCatalogueEntry _entry = await LidarrAPI.getArtist(entry.artistID);
|
||||
_entry ??= entry;
|
||||
entry = _entry;
|
||||
_albumEntries = await LidarrAPI.getArtistAlbums(entry.artistID);
|
||||
_albumEntries = await LidarrAPI.getArtistAlbums(widget.artistID);
|
||||
if(mounted) {
|
||||
setState(() {
|
||||
_loadingAlbums = false;
|
||||
@@ -144,11 +166,23 @@ class _State extends State<LidarrArtistDetails> {
|
||||
case 'remove_artist': {
|
||||
values = await LidarrDialogs.showDeleteArtistPrompt(context);
|
||||
if(values[0]) {
|
||||
if(await LidarrAPI.removeArtist(entry.artistID)) {
|
||||
Navigator.of(context).pop('remove_artist');
|
||||
if(values[1]) {
|
||||
values = await SystemDialogs.showDeleteCatalogueWithFilesPrompt(context, entry.title);
|
||||
if(values[0]) {
|
||||
if(await LidarrAPI.removeArtist(entry.artistID, deleteFiles: true)) {
|
||||
Navigator.of(context).pop('remove_artist');
|
||||
} else {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Failed to remove ${entry.title}');
|
||||
}
|
||||
}
|
||||
} else {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Failed to remove ${entry.title}');
|
||||
if(await LidarrAPI.removeArtist(entry.artistID)) {
|
||||
Navigator.of(context).pop('remove_artist');
|
||||
} else {
|
||||
Notifications.showSnackBar(_scaffoldKey, 'Failed to remove ${entry.title}');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
break;
|
||||
}
|
||||
@@ -632,6 +666,6 @@ class _State extends State<LidarrArtistDetails> {
|
||||
}
|
||||
}
|
||||
}
|
||||
_refreshData();
|
||||
_refreshAlbums();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrEditArtist extends StatefulWidget {
|
||||
final LidarrCatalogueEntry entry;
|
||||
@@ -1,8 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrReleaseInfo extends StatefulWidget {
|
||||
final LidarrReleaseEntry entry;
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/release.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/release.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class LidarrAlbumSearch extends StatefulWidget {
|
||||
final int albumID;
|
||||
@@ -87,12 +86,38 @@ class _State extends State<LidarrAlbumSearch> {
|
||||
return Card(
|
||||
child: ListTile(
|
||||
title: Elements.getTitle(release.title),
|
||||
subtitle: Elements.getSubtitle(
|
||||
'${Functions.toCapitalize(release.protocol)}' +
|
||||
'${release.isTorrent ? "\t•\t${release.seeders}/${release.leechers}" : ''}' +
|
||||
'\t•\t${Functions.hoursReadable(release.ageHours) ?? 'Unknown'}\n' +
|
||||
'${release.quality ?? 'Unknown'}\t•\t'+
|
||||
'${Functions.bytesToReadable(release.size) ?? 'Unknown'}'
|
||||
subtitle: RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: 14.0,
|
||||
),
|
||||
children: <TextSpan>[
|
||||
TextSpan(
|
||||
text: '${Functions.toCapitalize(release.protocol)}',
|
||||
style: TextStyle(
|
||||
color: release.isTorrent ? Colors.orange : Color(Constants.ACCENT_COLOR),
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
if(release.isTorrent) TextSpan(
|
||||
text: '${release.isTorrent ? " (${release.seeders}/${release.leechers})" : ''}',
|
||||
style: TextStyle(
|
||||
color: Colors.orange,
|
||||
fontWeight: FontWeight.bold,
|
||||
),
|
||||
),
|
||||
TextSpan(
|
||||
text: '\t•\t${Functions.hoursReadable(release.ageHours) ?? 'Unknown'}\n',
|
||||
),
|
||||
TextSpan(
|
||||
text: '${release.quality ?? 'Unknown'}\t•\t',
|
||||
),
|
||||
TextSpan(
|
||||
text: '${Functions.bytesToReadable(release.size) ?? 'Unknown'}',
|
||||
),
|
||||
]
|
||||
),
|
||||
),
|
||||
trailing: InkWell(
|
||||
child: IconButton(
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class History extends StatefulWidget {
|
||||
final GlobalKey<RefreshIndicatorState> refreshIndicatorKey;
|
||||
@@ -1,9 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||
import 'package:lunasea/logic/automation/lidarr.dart';
|
||||
import 'package:lunasea/pages/lidarr/subpages/details/album.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/album.dart';
|
||||
import 'package:lunasea/routes/lidarr/subpages/details/artist.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class Missing extends StatefulWidget {
|
||||
final GlobalKey<RefreshIndicatorState> refreshIndicatorKey;
|
||||
@@ -127,6 +128,9 @@ class _State extends State<Missing> {
|
||||
onTap: () async {
|
||||
_enterAlbum(entry);
|
||||
},
|
||||
onLongPress: () async {
|
||||
_enterArtist(entry);
|
||||
},
|
||||
),
|
||||
decoration: BoxDecoration(
|
||||
image: DecorationImage(
|
||||
@@ -162,4 +166,12 @@ class _State extends State<Missing> {
|
||||
switch(result) {
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> _enterArtist(LidarrMissingEntry entry) async {
|
||||
await Navigator.of(context).push(
|
||||
MaterialPageRoute(
|
||||
builder: (context) => LidarrArtistDetails(entry: null, artistID: entry.artistID),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,12 @@
|
||||
import 'dart:io';
|
||||
import 'package:file_picker/file_picker.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
import 'package:lunasea/pages/nzbget/subpages.dart';
|
||||
import 'package:lunasea/pages/nzbget/subpages/statistics/statistics.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/nzbget/subpages.dart';
|
||||
import 'package:lunasea/routes/nzbget/subpages/statistics/statistics.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class NZBGet extends StatefulWidget {
|
||||
@override
|
||||
@@ -38,8 +37,8 @@ class _State extends State<NZBGet> {
|
||||
int _currIndex = 0;
|
||||
|
||||
final List<Icon> _icons = [
|
||||
Icon(Icons.queue),
|
||||
Icon(Icons.history),
|
||||
Icon(CustomIcons.queue),
|
||||
Icon(CustomIcons.history),
|
||||
];
|
||||
|
||||
void _navOnTap(int index) {
|
||||
@@ -107,7 +106,7 @@ class _State extends State<NZBGet> {
|
||||
),
|
||||
appBar: _buildAppBar(),
|
||||
drawer: Navigation.getDrawer('nzbget', context),
|
||||
bottomNavigationBar: _buildBottomNavigationBar(),
|
||||
bottomNavigationBar: Navigation.getBottomNavigationBar(_currIndex, _icons, _titles, _navOnTap),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -166,23 +165,6 @@ class _State extends State<NZBGet> {
|
||||
);
|
||||
}
|
||||
|
||||
BottomNavigationBar _buildBottomNavigationBar() {
|
||||
return BottomNavigationBar(
|
||||
currentIndex: _currIndex,
|
||||
type: BottomNavigationBarType.fixed,
|
||||
fixedColor: Color(Constants.ACCENT_COLOR),
|
||||
elevation: 0.0,
|
||||
onTap: _navOnTap,
|
||||
items: [
|
||||
for(int i =0; i<_icons.length; i++)
|
||||
BottomNavigationBarItem(
|
||||
icon: _icons[i],
|
||||
title: Text(_titles[i]),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> _handlePopup(BuildContext context) async {
|
||||
List<dynamic> values = await NZBGetDialogs.showSettingsPrompt(context);
|
||||
if(values[0]) {
|
||||
2
lib/routes/nzbget/subpages.dart
Normal file
2
lib/routes/nzbget/subpages.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'package:lunasea/routes/nzbget/subpages/history/history.dart';
|
||||
export 'package:lunasea/routes/nzbget/subpages/queue/queue.dart';
|
||||
@@ -1,6 +1,6 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class NZBGetHistoryDetails extends StatefulWidget {
|
||||
final NZBGetHistoryEntry entry;
|
||||
@@ -1,9 +1,9 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter/rendering.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
import 'package:lunasea/pages/nzbget/subpages/history/details.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/nzbget/subpages/history/details.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class NZBGetHistory extends StatefulWidget {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey;
|
||||
@@ -1,13 +1,10 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/flutter/reorderable_list.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/system/ui/dialog.dart';
|
||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class NZBGetQueue extends StatefulWidget {
|
||||
final GlobalKey<ScaffoldState> scaffoldKey;
|
||||
@@ -128,7 +125,7 @@ class _State extends State<NZBGetQueue> with TickerProviderStateMixin {
|
||||
if(_values[1] == -1) {
|
||||
_values = await NZBGetDialogs.showCustomPauseForPrompt(context);
|
||||
if(_values[0]) {
|
||||
if(await NZBGetAPI.pauseQueueFor(_values[1])) {
|
||||
if(await NZBGetAPI.pauseQueueFor(_values[1]) && mounted) {
|
||||
setState(() {
|
||||
_paused = true;
|
||||
});
|
||||
@@ -138,7 +135,7 @@ class _State extends State<NZBGetQueue> with TickerProviderStateMixin {
|
||||
}
|
||||
}
|
||||
} else {
|
||||
if(await NZBGetAPI.pauseQueueFor(_values[1])) {
|
||||
if(await NZBGetAPI.pauseQueueFor(_values[1]) && mounted) {
|
||||
setState(() {
|
||||
_paused = true;
|
||||
});
|
||||
@@ -1,7 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/clients/nzbget.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class NZBGetStatistics extends StatefulWidget {
|
||||
@override
|
||||
@@ -1,11 +1,10 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/configuration/values.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/system.dart';
|
||||
import 'package:lunasea/logic/automation/radarr/api.dart';
|
||||
import 'package:lunasea/pages/radarr/subpages/catalogue/addmovie/search.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/pages/radarr/subpages.dart';
|
||||
import 'package:lunasea/routes/radarr/subpages/catalogue/addmovie/search.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
import 'package:lunasea/routes/radarr/subpages.dart';
|
||||
|
||||
class Radarr extends StatefulWidget {
|
||||
@override
|
||||
@@ -19,26 +18,30 @@ class _State extends State<Radarr> {
|
||||
GlobalKey<RefreshIndicatorState>(),
|
||||
GlobalKey<RefreshIndicatorState>(),
|
||||
GlobalKey<RefreshIndicatorState>(),
|
||||
GlobalKey<RefreshIndicatorState>(),
|
||||
];
|
||||
final _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
int _currIndex = 0;
|
||||
|
||||
final List<Widget> _children = [
|
||||
Catalogue(refreshIndicatorKey: _refreshKeys[0]),
|
||||
Missing(refreshIndicatorKey: _refreshKeys[1]),
|
||||
History(refreshIndicatorKey: _refreshKeys[2]),
|
||||
Upcoming(refreshIndicatorKey: _refreshKeys[1]),
|
||||
Missing(refreshIndicatorKey: _refreshKeys[2]),
|
||||
History(refreshIndicatorKey: _refreshKeys[3]),
|
||||
];
|
||||
|
||||
final List<String> _titles = [
|
||||
'Catalogue',
|
||||
'Upcoming',
|
||||
'Missing',
|
||||
'History',
|
||||
];
|
||||
|
||||
final List<Icon> _icons = [
|
||||
Icon(Icons.movie),
|
||||
Icon(Icons.event_busy),
|
||||
Icon(Icons.history)
|
||||
Icon(CustomIcons.movies),
|
||||
Icon(CustomIcons.upcoming),
|
||||
Icon(CustomIcons.calendar_missing),
|
||||
Icon(CustomIcons.history)
|
||||
];
|
||||
|
||||
void _navOnTap(int index) {
|
||||
4
lib/routes/radarr/subpages.dart
Normal file
4
lib/routes/radarr/subpages.dart
Normal file
@@ -0,0 +1,4 @@
|
||||
export 'package:lunasea/routes/radarr/subpages/catalogue/catalogue.dart';
|
||||
export 'package:lunasea/routes/radarr/subpages/history/history.dart';
|
||||
export 'package:lunasea/routes/radarr/subpages/missing/missing.dart';
|
||||
export 'package:lunasea/routes/radarr/subpages/upcoming/upcoming.dart';
|
||||
@@ -1,9 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/radarr.dart';
|
||||
import 'package:flutter_advanced_networkimage/provider.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/functions.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class RadarrMovieSearchDetails extends StatefulWidget {
|
||||
final RadarrSearchEntry entry;
|
||||
@@ -1,8 +1,8 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/logic/automation/radarr.dart';
|
||||
import 'package:lunasea/pages/radarr/subpages/catalogue/addmovie/details.dart';
|
||||
import 'package:lunasea/system/constants.dart';
|
||||
import 'package:lunasea/system/ui.dart';
|
||||
import 'package:lunasea/routes/radarr/subpages/catalogue/addmovie/details.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/widgets/ui.dart';
|
||||
|
||||
class RadarrMovieSearch extends StatefulWidget {
|
||||
@override
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user