mirror of
https://github.com/jagandeepbrar/lunasea.git
synced 2026-08-31 12:42:34 +00:00
[Release] v4.0.0+400101 (#258)
NEW - Nothing TWEAKS - [Settings] Added headers to all customization pages - [Tautulli] Cleanup code, improve routing - [State] Improve resetting of state when switching profiles FIXES - [Settings] Fix default page prompt not dismissing correctly
This commit is contained in:
@@ -19,12 +19,12 @@ class Providers {
|
||||
Providers._();
|
||||
|
||||
static void reset(BuildContext context) {
|
||||
Provider.of<LunaSeaState>(context, listen: false).reset(initialize: true);
|
||||
Provider.of<LunaSeaState>(context, listen: false).reset();
|
||||
// General
|
||||
Provider.of<HomeState>(context, listen: false).reset(initialize: true);
|
||||
Provider.of<SettingsState>(context, listen: false).reset(initialize: true);
|
||||
Provider.of<HomeState>(context, listen: false).reset();
|
||||
Provider.of<SettingsState>(context, listen: false).reset();
|
||||
// Monitoring
|
||||
Provider.of<TautulliState>(context, listen: false).reset(initialize: true);
|
||||
Provider.of<TautulliState>(context, listen: false).reset();
|
||||
}
|
||||
|
||||
static MultiProvider providers({ @required Widget child }) => MultiProvider(
|
||||
|
||||
@@ -21,4 +21,5 @@ export 'ui/rive.dart';
|
||||
export 'ui/shape.dart';
|
||||
export 'ui/snackbar.dart';
|
||||
export 'ui/sticky_header.dart';
|
||||
export 'ui/table.dart';
|
||||
export 'ui/text.dart';
|
||||
|
||||
2
lib/core/ui/table.dart
Normal file
2
lib/core/ui/table.dart
Normal file
@@ -0,0 +1,2 @@
|
||||
export 'table/block.dart';
|
||||
export 'table/content.dart';
|
||||
35
lib/core/ui/table/block.dart
Normal file
35
lib/core/ui/table/block.dart
Normal file
@@ -0,0 +1,35 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LSTableBlock extends StatelessWidget {
|
||||
final String title;
|
||||
final List<LSTableContent> children;
|
||||
|
||||
LSTableBlock({
|
||||
Key key,
|
||||
this.title,
|
||||
@required this.children,
|
||||
}) : super(key: key);
|
||||
|
||||
List<Widget> _block({
|
||||
String title,
|
||||
@required List<LSTableContent> children,
|
||||
}) => [
|
||||
if(title != null) LSHeader(text: title),
|
||||
LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Column(
|
||||
children: _block(title: title, children: children),
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
mainAxisAlignment: MainAxisAlignment.start,
|
||||
);
|
||||
}
|
||||
45
lib/core/ui/table/content.dart
Normal file
45
lib/core/ui/table/content.dart
Normal file
@@ -0,0 +1,45 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
class LSTableContent extends StatelessWidget {
|
||||
final String title;
|
||||
final String body;
|
||||
|
||||
LSTableContent({
|
||||
Key key,
|
||||
@required this.title,
|
||||
@required this.body,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
title.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
);
|
||||
}
|
||||
@@ -12,7 +12,7 @@ class HomeDialogs {
|
||||
void _setValues(bool flag, int index) {
|
||||
_flag = flag;
|
||||
_index = index;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
|
||||
@@ -15,6 +15,7 @@ class HomeState extends ChangeNotifier {
|
||||
_navigationIndex = HomeDatabaseValue.NAVIGATION_INDEX.data;
|
||||
_calendarStartingType = HomeDatabaseValue.CALENDAR_STARTING_TYPE.data;
|
||||
}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
int _navigationIndex;
|
||||
|
||||
@@ -12,7 +12,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, LidarrQualityProfile quality) {
|
||||
_flag = flag;
|
||||
_quality = quality;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -39,7 +39,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, LidarrMetadataProfile metadata) {
|
||||
_flag = flag;
|
||||
_metadata = metadata;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -66,7 +66,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, bool files) {
|
||||
_flag = flag;
|
||||
_files = files;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -97,7 +97,7 @@ class LidarrDialogs {
|
||||
|
||||
void _setValues(bool flag) {
|
||||
_flag = flag;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -122,7 +122,7 @@ class LidarrDialogs {
|
||||
|
||||
void _setValues(bool flag) {
|
||||
_flag = flag;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -154,7 +154,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, String value) {
|
||||
_flag = flag;
|
||||
_value = value;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -181,7 +181,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, LidarrRootFolder folder) {
|
||||
_flag = flag;
|
||||
_folder = folder;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -220,7 +220,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, String value) {
|
||||
_flag = flag;
|
||||
_value = value;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
@@ -247,7 +247,7 @@ class LidarrDialogs {
|
||||
void _setValues(bool flag, int index) {
|
||||
_flag = flag;
|
||||
_index = index;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
|
||||
@@ -573,7 +573,7 @@ class NZBGetDialogs {
|
||||
void _setValues(bool flag, int index) {
|
||||
_flag = flag;
|
||||
_index = index;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
|
||||
@@ -298,7 +298,7 @@ class RadarrDialogs {
|
||||
void _setValues(bool flag, int index) {
|
||||
_flag = flag;
|
||||
_index = index;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
|
||||
@@ -661,7 +661,7 @@ class SABnzbdDialogs {
|
||||
void _setValues(bool flag, int index) {
|
||||
_flag = flag;
|
||||
_index = index;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
|
||||
@@ -1,28 +1 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsState extends ChangeNotifier {
|
||||
SettingsState() {
|
||||
reset(initialize: true);
|
||||
}
|
||||
|
||||
/// Reset the state of Home back to the default
|
||||
///
|
||||
/// If `initialize` is true, resets everything.
|
||||
/// If false, the navigation index, etc. are not reset.
|
||||
void reset({ bool initialize = false }) {
|
||||
if(initialize) {
|
||||
_navigationIndex = 0;
|
||||
}
|
||||
}
|
||||
|
||||
GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
|
||||
GlobalKey<ScaffoldState> rootScaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
int _navigationIndex;
|
||||
int get navigationIndex => _navigationIndex;
|
||||
set navigationIndex(int navigationIndex) {
|
||||
assert(navigationIndex != null);
|
||||
_navigationIndex = navigationIndex;
|
||||
notifyListeners();
|
||||
}
|
||||
}
|
||||
export 'state/global.dart';
|
||||
|
||||
19
lib/modules/settings/core/state/global.dart
Normal file
19
lib/modules/settings/core/state/global.dart
Normal file
@@ -0,0 +1,19 @@
|
||||
import 'package:flutter/material.dart';
|
||||
|
||||
class SettingsState extends ChangeNotifier {
|
||||
SettingsState() {
|
||||
reset(initialize: true);
|
||||
}
|
||||
|
||||
/// Reset the state of Home back to the default
|
||||
///
|
||||
/// If `initialize` is true, resets everything.
|
||||
/// If false, the navigation index, etc. are not reset.
|
||||
void reset({ bool initialize = false }) {
|
||||
if(initialize) {}
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
GlobalKey<NavigatorState> rootNavigatorKey = GlobalKey<NavigatorState>();
|
||||
GlobalKey<ScaffoldState> rootScaffoldKey = GlobalKey<ScaffoldState>();
|
||||
}
|
||||
@@ -30,9 +30,25 @@ class _State extends State<SettingsCustomizationAppearanceRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
SettingsCustomizationAppearanceAMOLEDTile(),
|
||||
SettingsCustomizationAppearanceAMOLEDBorderTile(),
|
||||
SettingsCustomizationAppearance24HourTimeTile(),
|
||||
..._theme,
|
||||
..._localization,
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _theme => [
|
||||
LSHeader(
|
||||
text: 'Theme',
|
||||
subtitle: 'Customize the colour theme of LunaSea',
|
||||
),
|
||||
SettingsCustomizationAppearanceAMOLEDTile(),
|
||||
SettingsCustomizationAppearanceAMOLEDBorderTile(),
|
||||
];
|
||||
|
||||
List<Widget> get _localization => [
|
||||
LSHeader(
|
||||
text: 'Localization',
|
||||
subtitle: 'Customizable options for localization',
|
||||
),
|
||||
SettingsCustomizationAppearance24HourTimeTile(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -30,10 +30,18 @@ class _State extends State<SettingsCustomizationDrawerRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
SettingsCustomizationDrawerUseCategoriesTile(),
|
||||
SettingsCustomizationDrawerExpandAutomationTile(),
|
||||
SettingsCustomizationDrawerExpandClientsTile(),
|
||||
SettingsCustomizationDrawerExpandMonitoringTile(),
|
||||
..._folders,
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _folders => [
|
||||
LSHeader(
|
||||
text: 'Folders',
|
||||
subtitle: 'Customizable options related to grouping modules into folders',
|
||||
),
|
||||
SettingsCustomizationDrawerUseCategoriesTile(),
|
||||
SettingsCustomizationDrawerExpandAutomationTile(),
|
||||
SettingsCustomizationDrawerExpandClientsTile(),
|
||||
SettingsCustomizationDrawerExpandMonitoringTile(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -10,7 +10,7 @@ class SettingsCustomizationDrawerExpandAutomationTile extends StatelessWidget {
|
||||
]),
|
||||
builder: (context, box, widget) => LSCardTile(
|
||||
title: LSTitle(text: 'Expand Automation'),
|
||||
subtitle: LSSubtitle(text: 'Expand Automation Category Initially'),
|
||||
subtitle: LSSubtitle(text: 'Expand Automation Folder Initially'),
|
||||
trailing: Switch(
|
||||
value: LunaSeaDatabaseValue.DRAWER_EXPAND_AUTOMATION.data,
|
||||
onChanged: LunaSeaDatabaseValue.DRAWER_GROUP_MODULES.data
|
||||
|
||||
@@ -10,7 +10,7 @@ class SettingsCustomizationDrawerExpandClientsTile extends StatelessWidget {
|
||||
]),
|
||||
builder: (context, box, widget) => LSCardTile(
|
||||
title: LSTitle(text: 'Expand Clients'),
|
||||
subtitle: LSSubtitle(text: 'Expand Clients Category Initially'),
|
||||
subtitle: LSSubtitle(text: 'Expand Clients Folder Initially'),
|
||||
trailing: Switch(
|
||||
value: LunaSeaDatabaseValue.DRAWER_EXPAND_CLIENTS.data,
|
||||
onChanged: LunaSeaDatabaseValue.DRAWER_GROUP_MODULES.data
|
||||
|
||||
@@ -10,7 +10,7 @@ class SettingsCustomizationDrawerExpandMonitoringTile extends StatelessWidget {
|
||||
]),
|
||||
builder: (context, box, widget) => LSCardTile(
|
||||
title: LSTitle(text: 'Expand Monitoring'),
|
||||
subtitle: LSSubtitle(text: 'Expand Monitoring Category Initially'),
|
||||
subtitle: LSSubtitle(text: 'Expand Monitoring Folder Initially'),
|
||||
trailing: Switch(
|
||||
value: LunaSeaDatabaseValue.DRAWER_EXPAND_MONITORING.data,
|
||||
onChanged: LunaSeaDatabaseValue.DRAWER_GROUP_MODULES.data
|
||||
|
||||
@@ -6,7 +6,7 @@ class SettingsCustomizationDrawerUseCategoriesTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [LunaSeaDatabaseValue.DRAWER_GROUP_MODULES.key]),
|
||||
builder: (context, box, widget) => LSCardTile(
|
||||
title: LSTitle(text: 'Group by Category'),
|
||||
title: LSTitle(text: 'Use Folders'),
|
||||
subtitle: LSSubtitle(text: 'Group Modules into Categories'),
|
||||
trailing: Switch(
|
||||
value: LunaSeaDatabaseValue.DRAWER_GROUP_MODULES.data,
|
||||
|
||||
@@ -30,8 +30,24 @@ class _State extends State<SettingsCustomizationHomeRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
SettingsCustomizationHomeDefaultPageTile(),
|
||||
SettingsCustomizationHomeBrandColoursTile(),
|
||||
..._defaultPages,
|
||||
..._modules,
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _defaultPages => [
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationHomeDefaultPageTile(),
|
||||
];
|
||||
|
||||
List<Widget> get _modules => [
|
||||
LSHeader(
|
||||
text: 'Modules',
|
||||
subtitle: 'Customizable options related to the module list',
|
||||
),
|
||||
SettingsCustomizationHomeBrandColoursTile(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationHomeDefaultPageTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [HomeDatabaseValue.NAVIGATION_INDEX.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Default Page'),
|
||||
title: LSTitle(text: 'Home'),
|
||||
subtitle: LSSubtitle(text: HomeNavigationBar.titles[HomeDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
trailing: LSIconButton(icon: HomeNavigationBar.icons[HomeDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
onTap: () async => _defaultPage(context),
|
||||
|
||||
@@ -38,6 +38,10 @@ class _State extends State<SettingsCustomizationLidarrRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationLidarrDefaultPageTile(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -38,6 +38,10 @@ class _State extends State<SettingsCustomizationNZBGetRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationNZBGetDefaultPageTile(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationNZBGetDefaultPageTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [NZBGetDatabaseValue.NAVIGATION_INDEX.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Default Page'),
|
||||
title: LSTitle(text: 'Home'),
|
||||
subtitle: LSSubtitle(text: NZBGetNavigationBar.titles[NZBGetDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
trailing: LSIconButton(icon: NZBGetNavigationBar.icons[NZBGetDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
onTap: () async => _defaultPage(context),
|
||||
|
||||
@@ -38,6 +38,10 @@ class _State extends State<SettingsCustomizationRadarrRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationRadarrDefaultPageTile(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationRadarrDefaultPageTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [RadarrDatabaseValue.NAVIGATION_INDEX.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Default Page'),
|
||||
title: LSTitle(text: 'Home'),
|
||||
subtitle: LSSubtitle(text: RadarrNavigationBar.titles[RadarrDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
trailing: LSIconButton(icon: RadarrNavigationBar.icons[RadarrDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
onTap: () async => _defaultPage(context),
|
||||
|
||||
@@ -38,6 +38,10 @@ class _State extends State<SettingsCustomizationSABnzbdRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationSABnzbdDefaultPageTile(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationSABnzbdDefaultPageTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [SABnzbdDatabaseValue.NAVIGATION_INDEX.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Default Page'),
|
||||
title: LSTitle(text: 'Home'),
|
||||
subtitle: LSSubtitle(text: SABnzbdNavigationBar.titles[SABnzbdDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
trailing: LSIconButton(icon: SABnzbdNavigationBar.icons[SABnzbdDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
onTap: () async => _defaultPage(context),
|
||||
|
||||
@@ -38,7 +38,15 @@ class _State extends State<SettingsCustomizationSearchRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
SettingsCustomizationSearchHideAdultCategoriesTile(),
|
||||
..._categories,
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _categories => [
|
||||
LSHeader(
|
||||
text: 'Categories',
|
||||
subtitle: 'Customizable options related to the category lists',
|
||||
),
|
||||
SettingsCustomizationSearchHideAdultCategoriesTile(),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -38,6 +38,10 @@ class _State extends State<SettingsCustomizationSonarrRoute> {
|
||||
|
||||
Widget get _body => LSListView(
|
||||
children: [
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationSonarrDefaultPageTile(),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -7,7 +7,7 @@ class SettingsCustomizationSonarrDefaultPageTile extends StatelessWidget {
|
||||
Widget build(BuildContext context) => ValueListenableBuilder(
|
||||
valueListenable: Database.lunaSeaBox.listenable(keys: [SonarrDatabaseValue.NAVIGATION_INDEX.key]),
|
||||
builder: (context, box, _) => LSCardTile(
|
||||
title: LSTitle(text: 'Default Page'),
|
||||
title: LSTitle(text: 'Home'),
|
||||
subtitle: LSSubtitle(text: SonarrNavigationBar.titles[SonarrDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
trailing: LSIconButton(icon: SonarrNavigationBar.icons[SonarrDatabaseValue.NAVIGATION_INDEX.data]),
|
||||
onTap: () async => _defaultPage(context),
|
||||
|
||||
@@ -47,7 +47,7 @@ class _State extends State<SettingsCustomizationTautulliRoute> {
|
||||
List<Widget> get _defaultPages => <Widget>[
|
||||
LSHeader(
|
||||
text: 'Default Pages',
|
||||
subtitle: 'Choose the default/initial page when opening pages with navigation bars',
|
||||
subtitle: 'Choose the default page when opening routes with navigation bars',
|
||||
),
|
||||
SettingsCustomizationTautulliDefaultPageHomeTile(),
|
||||
SettingsCustomizationTautulliDefaultPageGraphsTile(),
|
||||
|
||||
@@ -365,7 +365,7 @@ class SonarrDialogs {
|
||||
void _setValues(bool flag, int index) {
|
||||
_flag = flag;
|
||||
_index = index;
|
||||
Navigator.of(context).pop();
|
||||
Navigator.of(context, rootNavigator: true).pop();
|
||||
}
|
||||
|
||||
await LSDialog.dialog(
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
export 'extensions/tautulli_history_record.dart';
|
||||
export 'extensions/tautulli_session.dart';
|
||||
export 'extensions/tautulli_table_library.dart';
|
||||
|
||||
@@ -1,12 +1,49 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
|
||||
extension TautulliHistoryRecordExtension on TautulliHistoryRecord {
|
||||
/// Returns a the header that should be used for titles, appbars, etc.
|
||||
String get header => this.grandparentTitle == null || this.grandparentTitle.isEmpty
|
||||
String get lsFullTitle => [
|
||||
if(this.title != null && this.title.isNotEmpty) '${this.title}',
|
||||
if(this.parentTitle != null && this.parentTitle.isNotEmpty) '\n${this.parentTitle}',
|
||||
if(this.grandparentTitle != null && this.grandparentTitle.isNotEmpty) '\n${this.grandparentTitle}',
|
||||
].join();
|
||||
|
||||
String get lsTitle => this.grandparentTitle == null || this.grandparentTitle.isEmpty
|
||||
? this.parentTitle == null || this.parentTitle.isEmpty
|
||||
? this.title == null || this.title.isEmpty
|
||||
? 'Unknown Title'
|
||||
: this.title
|
||||
: this.parentTitle
|
||||
? this.title == null || this.title.isEmpty
|
||||
? 'Unknown Title'
|
||||
: this.title
|
||||
: this.parentTitle
|
||||
: this.grandparentTitle;
|
||||
}
|
||||
|
||||
IconData get lsWatchStatusIcon {
|
||||
switch(this.watchedStatus) {
|
||||
case TautulliWatchedStatus.PARTIALLY_WATCHED: return Icons.radio_button_checked;
|
||||
case TautulliWatchedStatus.WATCHED: return Icons.check_circle;
|
||||
case TautulliWatchedStatus.UNWATCHED:
|
||||
default: return Icons.radio_button_unchecked;
|
||||
}
|
||||
}
|
||||
|
||||
String get lsDate => DateTime.now().lsDateTime_ageString(this.date);
|
||||
|
||||
String get lsStatus {
|
||||
switch(this.watchedStatus) {
|
||||
case TautulliWatchedStatus.UNWATCHED: return 'Incompleted';
|
||||
case TautulliWatchedStatus.PARTIALLY_WATCHED: return 'Partially Completed';
|
||||
case TautulliWatchedStatus.WATCHED: return 'Completed';
|
||||
default: return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
String get lsState {
|
||||
switch(this.state) {
|
||||
case TautulliSessionState.PLAYING: return 'Playing';
|
||||
case TautulliSessionState.PAUSED: return 'Paused';
|
||||
case TautulliSessionState.BUFFERING: return 'Buffering';
|
||||
case TautulliSessionState.NULL:
|
||||
default: return 'Finished';
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
110
lib/modules/tautulli/core/extensions/tautulli_session.dart
Normal file
110
lib/modules/tautulli/core/extensions/tautulli_session.dart
Normal file
@@ -0,0 +1,110 @@
|
||||
import 'dart:math';
|
||||
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
extension TautulliSessionExtension on TautulliSession {
|
||||
String get lsFullTitle => [
|
||||
if(this.title != null && this.title.isNotEmpty) '${this.title}',
|
||||
if(this.parentTitle != null && this.parentTitle.isNotEmpty) '\n${this.parentTitle}',
|
||||
if(this.grandparentTitle != null && this.grandparentTitle.isNotEmpty) '\n${this.grandparentTitle}',
|
||||
].join();
|
||||
|
||||
String get lsTitle => this.grandparentTitle == null || this.grandparentTitle.isEmpty
|
||||
? this.parentTitle == null || this.parentTitle.isEmpty
|
||||
? this.title == null || this.title.isEmpty
|
||||
? 'Unknown Title'
|
||||
: this.title
|
||||
: this.parentTitle
|
||||
: this.grandparentTitle;
|
||||
|
||||
String get lsDuration {
|
||||
double _percent = this.progressPercent/100;
|
||||
String _progress = Duration(seconds: (this.streamDuration.inSeconds*_percent).floor()).lsDuration_timestamp();
|
||||
String _total = this.streamDuration.lsDuration_timestamp();
|
||||
return '$_progress/$_total (${this.progressPercent}%)';
|
||||
}
|
||||
|
||||
String get lsBandwidth => '${this.bandwidth.lsBytes_KilobytesToString(bytes: false, decimals: 1)}ps';
|
||||
|
||||
String get lsQuality => '${this.qualityProfile} (${this.streamBitrate.lsBytes_KilobytesToString(bytes: false, decimals: 1)}ps)';
|
||||
|
||||
String get lsStream {
|
||||
switch(this.transcodeDecision) {
|
||||
case TautulliTranscodeDecision.TRANSCODE:
|
||||
String _transcodeStatus = this.transcodeThrottled ? 'Throttled' : '${this.transcodeSpeed ?? 0.0}x';
|
||||
return 'Transcode ($_transcodeStatus)';
|
||||
case TautulliTranscodeDecision.COPY: return 'Direct Stream';
|
||||
case TautulliTranscodeDecision.DIRECT_PLAY: return 'Direct Play';
|
||||
case TautulliTranscodeDecision.NULL:
|
||||
default: return 'Unknown Transcode Decision';
|
||||
}
|
||||
}
|
||||
|
||||
String get lsContainer => [
|
||||
this.streamContainerDecision.name,
|
||||
' (',
|
||||
this.container.toUpperCase(),
|
||||
if(this.streamContainerDecision != null && this.streamContainerDecision != TautulliTranscodeDecision.DIRECT_PLAY)
|
||||
' ${Constants.TEXT_RARROW} ${this.streamContainer.toUpperCase()}',
|
||||
')',
|
||||
].join();
|
||||
|
||||
String get lsVideo => [
|
||||
this.videoDecision.name,
|
||||
' (',
|
||||
this.videoCodec.toUpperCase(),
|
||||
' ',
|
||||
this.videoFullResolution,
|
||||
if(this.transcodeVideoCodec.isNotEmpty) ' ${Constants.TEXT_RARROW} ',
|
||||
if(this.transcodeVideoCodec.isNotEmpty) this.transcodeVideoCodec.toUpperCase(),
|
||||
if(this.transcodeVideoCodec.isNotEmpty) ' ${this.streamVideoFullResolution}',
|
||||
')',
|
||||
].join();
|
||||
|
||||
String get lsAudio => [
|
||||
this.audioDecision.name,
|
||||
' (',
|
||||
this.audioCodec.toUpperCase(),
|
||||
if(this.transcodeAudioCodec.isNotEmpty) ' ${Constants.TEXT_RARROW} ',
|
||||
if(this.transcodeAudioCodec.isNotEmpty) this.transcodeAudioCodec.toUpperCase(),
|
||||
')',
|
||||
].join();
|
||||
|
||||
String lsArtworkPath(BuildContext context) {
|
||||
TautulliState _state = Provider.of<TautulliState>(context, listen: false);
|
||||
switch(this.mediaType) {
|
||||
case TautulliMediaType.EPISODE: return _state.getImageURLFromRatingKey(this.grandparentRatingKey);
|
||||
case TautulliMediaType.TRACK: return _state.getImageURLFromRatingKey(this.parentRatingKey);
|
||||
case TautulliMediaType.MOVIE:
|
||||
case TautulliMediaType.LIVE:
|
||||
default: return _state.getImageURLFromRatingKey(this.ratingKey);
|
||||
}
|
||||
}
|
||||
|
||||
double get lsTranscodeProgress => min(1.0, max(0, this.transcodeProgress/100));
|
||||
double get lsProgressPercent => min(1.0, max(0, this.progressPercent/100));
|
||||
|
||||
IconData get lsStateIcon {
|
||||
switch(this.state) {
|
||||
case TautulliSessionState.PAUSED: return Icons.pause;
|
||||
case TautulliSessionState.PLAYING: return Icons.play_arrow;
|
||||
case TautulliSessionState.BUFFERING:
|
||||
default: return Icons.compare_arrows;
|
||||
}
|
||||
}
|
||||
|
||||
String get lsTranscodeDecision {
|
||||
switch(this.transcodeDecision) {
|
||||
case TautulliTranscodeDecision.TRANSCODE:
|
||||
String _transcodeStatus = this.transcodeThrottled ? 'Throttled' : '${this.transcodeSpeed ?? 0.0}x';
|
||||
return 'Transcoding ($_transcodeStatus)';
|
||||
case TautulliTranscodeDecision.DIRECT_PLAY:
|
||||
case TautulliTranscodeDecision.COPY:
|
||||
case TautulliTranscodeDecision.NULL:
|
||||
default: return this.transcodeDecision.name ?? 'Unknown';
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -7,29 +7,29 @@ class TautulliRouter {
|
||||
TautulliRouter._();
|
||||
|
||||
static void initialize() {
|
||||
TautulliRoute.defineRoute(router);
|
||||
TautulliHomeRouter.defineRoutes(router);
|
||||
// Details
|
||||
TautulliActivityDetailsRoute.defineRoute(router);
|
||||
TautulliHistoryDetailsRoute.defineRoute(router);
|
||||
TautulliActivityDetailsRouter.defineRoutes(router);
|
||||
TautulliIPAddressDetailsRouter.defineRoutes(router);
|
||||
TautulliLibrariesDetailsRouter.defineRoutes(router);
|
||||
TautulliMediaDetailsRoute.defineRoute(router);
|
||||
TautulliUserDetailsRoute.defineRoute(router);
|
||||
// Logs
|
||||
TautulliLogsRoute.defineRoute(router);
|
||||
TautulliLogsLoginsRoute.defineRoute(router);
|
||||
TautulliLogsNewslettersRoute.defineRoute(router);
|
||||
TautulliLogsNotificationsRoute.defineRoute(router);
|
||||
TautulliLogsPlexMediaScannerRoute.defineRoute(router);
|
||||
TautulliLogsPlexMediaServerRoute.defineRoute(router);
|
||||
TautulliLogsTautulliRoute.defineRoute(router);
|
||||
// Other
|
||||
TautulliCheckForUpdatesRoute.defineRoute(router);
|
||||
TautulliGraphsRoute.defineRoute(router);
|
||||
TautulliLibrariesRoute.defineRoute(router);
|
||||
TautulliHistoryDetailsRouter.defineRoutes(router);
|
||||
TautulliUserDetailsRouter.defineRoutes(router);
|
||||
TautulliMediaDetailsRouter.defineRoutes(router);
|
||||
// More/*
|
||||
TautulliCheckForUpdatesRouter.defineRoutes(router);
|
||||
TautulliSearchRouter.defineRoutes(router);
|
||||
TautulliStatisticsRoute.defineRoute(router);
|
||||
TautulliSyncedItemsRoute.defineRoute(router);
|
||||
TautulliRecentlyAddedRoute.defineRoute(router);
|
||||
TautulliGraphsRouter.defineRoutes(router);
|
||||
TautulliLibrariesRouter.defineRoutes(router);
|
||||
TautulliSyncedItemsRouter.defineRoutes(router);
|
||||
TautulliStatisticsRouter.defineRoutes(router);
|
||||
TautulliRecentlyAddedRouter.defineRoutes(router);
|
||||
// Logs
|
||||
TautulliLogsRouter.defineRoutes(router);
|
||||
TautulliLogsLoginsRouter.defineRoutes(router);
|
||||
TautulliLogsNewslettersRouter.defineRoutes(router);
|
||||
TautulliLogsNotificationsRouter.defineRoutes(router);
|
||||
TautulliLogsPlexMediaScannerRouter.defineRoutes(router);
|
||||
TautulliLogsPlexMediaServerRouter.defineRoutes(router);
|
||||
TautulliLogsTautulliRouter.defineRoutes(router);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,6 +22,8 @@ class TautulliState extends ChangeNotifier {
|
||||
}
|
||||
resetProfile();
|
||||
resetActivity();
|
||||
resetUsers();
|
||||
resetHistory();
|
||||
notifyListeners();
|
||||
}
|
||||
|
||||
|
||||
@@ -34,8 +34,5 @@ extension TautulliMediaDetailsSwitcherTypeExtension on TautulliMediaDetailsSwitc
|
||||
@required BuildContext context,
|
||||
@required TautulliMediaType mediaType,
|
||||
@required int ratingKey
|
||||
}) => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(ratingKey: ratingKey, mediaType: mediaType),
|
||||
);
|
||||
}) => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: ratingKey, mediaType: mediaType);
|
||||
}
|
||||
|
||||
@@ -23,7 +23,7 @@ class _State extends State<TautulliModule> {
|
||||
onWillPop: _onWillPop,
|
||||
child: Navigator(
|
||||
key: Provider.of<TautulliState>(context, listen: false).rootNavigatorKey,
|
||||
initialRoute: TautulliRoute.route(profile: widget.profile),
|
||||
initialRoute: TautulliHomeRouter.route(profile: widget.profile),
|
||||
onGenerateRoute: TautulliRouter.router.generator,
|
||||
),
|
||||
),
|
||||
|
||||
@@ -80,4 +80,4 @@ class _State extends State<TautulliActivityRoute> with AutomaticKeepAliveClientM
|
||||
buttonText: 'Refresh',
|
||||
onTapHandler: () async => _refreshKey.currentState.show(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,4 +1,3 @@
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
import 'package:percent_indicator/linear_percent_indicator.dart';
|
||||
@@ -48,24 +47,13 @@ class TautulliActivityTile extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
);
|
||||
|
||||
String _artworkPath(BuildContext context) {
|
||||
TautulliState _state = Provider.of<TautulliState>(context, listen: false);
|
||||
switch(session.mediaType) {
|
||||
case TautulliMediaType.EPISODE: return _state.getImageURLFromRatingKey(session.grandparentRatingKey);
|
||||
case TautulliMediaType.TRACK: return _state.getImageURLFromRatingKey(session.parentRatingKey);
|
||||
case TautulliMediaType.MOVIE:
|
||||
case TautulliMediaType.LIVE:
|
||||
default: return _state.getImageURLFromRatingKey(session.ratingKey);
|
||||
}
|
||||
}
|
||||
|
||||
Widget get _mediaInfo => Padding(
|
||||
child: Container(
|
||||
child: Column(
|
||||
children: [
|
||||
_title,
|
||||
LSTitle(text: session.lsTitle, maxLines: 1),
|
||||
_subtitle,
|
||||
_transcodeDecision,
|
||||
LSSubtitle(text: session.lsTranscodeDecision, maxLines: 1),
|
||||
_user,
|
||||
_progressBar,
|
||||
],
|
||||
@@ -78,17 +66,6 @@ class TautulliActivityTile extends StatelessWidget {
|
||||
padding: EdgeInsets.all(_padding),
|
||||
);
|
||||
|
||||
Widget get _title => LSTitle(
|
||||
text: session.grandparentTitle == null || session.grandparentTitle.isEmpty
|
||||
? session.parentTitle == null || session.parentTitle.isEmpty
|
||||
? session.title == null || session.title.isEmpty
|
||||
? 'Unknown Title'
|
||||
: session.title
|
||||
: session.parentTitle
|
||||
: session.grandparentTitle,
|
||||
maxLines: 1,
|
||||
);
|
||||
|
||||
Widget get _subtitle => RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
@@ -113,60 +90,37 @@ class TautulliActivityTile extends StatelessWidget {
|
||||
overflow: TextOverflow.fade,
|
||||
);
|
||||
|
||||
Widget get _transcodeDecision {
|
||||
String _value = '';
|
||||
switch(session.transcodeDecision) {
|
||||
case TautulliTranscodeDecision.TRANSCODE:
|
||||
String _transcodeStatus = session.transcodeThrottled ? 'Throttled' : '${session.transcodeSpeed ?? 0.0}x';
|
||||
_value = 'Transcoding ($_transcodeStatus)';
|
||||
break;
|
||||
case TautulliTranscodeDecision.DIRECT_PLAY:
|
||||
case TautulliTranscodeDecision.COPY:
|
||||
case TautulliTranscodeDecision.NULL: _value = session.transcodeDecision.name ?? 'Unknown'; break;
|
||||
}
|
||||
return LSSubtitle(text: _value, maxLines: 1);
|
||||
}
|
||||
|
||||
Widget _poster(BuildContext context) => LSNetworkImage(
|
||||
url: _artworkPath(context),
|
||||
url: session.lsArtworkPath(context),
|
||||
placeholder: 'assets/images/sonarr/noseriesposter.png',
|
||||
height: _height,
|
||||
width: _width,
|
||||
headers: Provider.of<TautulliState>(context, listen: false).headers.cast<String, String>(),
|
||||
);
|
||||
|
||||
Widget get _user {
|
||||
IconData _icon;
|
||||
switch(session.state) {
|
||||
case TautulliSessionState.PAUSED: _icon = Icons.pause; break;
|
||||
case TautulliSessionState.PLAYING: _icon = Icons.play_arrow; break;
|
||||
case TautulliSessionState.BUFFERING:
|
||||
default: _icon = Icons.compare_arrows; break;
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
LSIcon(
|
||||
icon: _icon,
|
||||
size: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
color: Colors.white70,
|
||||
),
|
||||
LSSubtitle(text: '\t${session.friendlyName}'),
|
||||
],
|
||||
);
|
||||
}
|
||||
Widget get _user => Row(
|
||||
children: [
|
||||
LSIcon(
|
||||
icon: session.lsStateIcon,
|
||||
size: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
color: Colors.white70,
|
||||
),
|
||||
LSSubtitle(text: '\t${session.friendlyName}'),
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _progressBar => Padding(
|
||||
child: Stack(
|
||||
children: [
|
||||
LinearPercentIndicator(
|
||||
percent: min(1.0, max(0, session.transcodeProgress/100)),
|
||||
percent: session.lsTranscodeProgress,
|
||||
padding: EdgeInsets.symmetric(horizontal: 2.0),
|
||||
progressColor: LSColors.splash.withOpacity(0.30),
|
||||
backgroundColor: Colors.transparent,
|
||||
lineHeight: 4.0,
|
||||
),
|
||||
LinearPercentIndicator(
|
||||
percent: min(1.0, max(0, session.progressPercent/100)),
|
||||
percent: session.lsProgressPercent,
|
||||
padding: EdgeInsets.symmetric(horizontal: 2.0),
|
||||
progressColor: LSColors.accent,
|
||||
backgroundColor: LSColors.accent.withOpacity(0.15),
|
||||
@@ -177,8 +131,5 @@ class TautulliActivityTile extends StatelessWidget {
|
||||
padding: EdgeInsets.only(top: _padding),
|
||||
);
|
||||
|
||||
Future<void> _enterDetails(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliActivityDetailsRoute.route(sessionId: session.sessionId),
|
||||
);
|
||||
Future<void> _enterDetails(BuildContext context) async => TautulliActivityDetailsRouter.navigateTo(context, sessionId: session.sessionId);
|
||||
}
|
||||
|
||||
@@ -4,25 +4,61 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliActivityDetailsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/activity/details/:sessionid/:profile';
|
||||
final String sessionId;
|
||||
class TautulliActivityDetailsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/activity/details/:sessionid';
|
||||
|
||||
static String route({ String profile, @required String sessionId }) {
|
||||
if(profile == null) return '/tautulli/activity/details/$sessionId/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/activity/details/$sessionId/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliActivityDetailsRoute(
|
||||
sessionId: params['sessionid'][0]),
|
||||
),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
static Future<void> navigateTo(BuildContext context, {
|
||||
@required String sessionId,
|
||||
}) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(sessionId: sessionId),
|
||||
);
|
||||
|
||||
TautulliActivityDetailsRoute({
|
||||
static String route({
|
||||
String profile,
|
||||
@required String sessionId,
|
||||
}) => [
|
||||
ROUTE_NAME.replaceFirst(':sessionid', sessionId ?? '0'),
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
/// With profile defined
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliActivityDetailsRoute(
|
||||
sessionId: params['sessionid'] != null && params['sessionid'].length != 0
|
||||
? params['sessionid'][0] ?? '-1'
|
||||
: '-1',
|
||||
profile: params['profile'] != null && params['profile'].length != 0
|
||||
? params['profile'][0]
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
/// Without profile defined
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliActivityDetailsRoute(
|
||||
sessionId: params['sessionid'] != null && params['sessionid'].length != 0
|
||||
? params['sessionid'][0] ?? '-1'
|
||||
: '-1',
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliActivityDetailsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliActivityDetailsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
final String sessionId;
|
||||
|
||||
_TautulliActivityDetailsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
@required this.sessionId,
|
||||
}): super(key: key);
|
||||
|
||||
@@ -30,7 +66,7 @@ class TautulliActivityDetailsRoute extends StatefulWidget {
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliActivityDetailsRoute> {
|
||||
class _State extends State<_TautulliActivityDetailsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -66,7 +102,7 @@ class _State extends State<TautulliActivityDetailsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliActivityDetailsRoute',
|
||||
'_TautulliActivityDetailsRoute',
|
||||
'_body',
|
||||
'Unable to pull Tautulli activity session',
|
||||
snapshot.error,
|
||||
|
||||
@@ -16,167 +16,48 @@ class TautulliActivityDetailsInformation extends StatelessWidget {
|
||||
children: [
|
||||
TautulliActivityTile(session: session, disableOnTap: true),
|
||||
TautulliActivityDetailsTerminateSession(session: session),
|
||||
..._metadataBlock,
|
||||
..._playerBlock,
|
||||
..._streamBlock,
|
||||
_metadataBlock,
|
||||
_playerBlock,
|
||||
_streamBlock,
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _metadataBlock => _block(
|
||||
Widget get _metadataBlock => LSTableBlock(
|
||||
title: 'Metadata',
|
||||
children: [
|
||||
_title,
|
||||
_content('year', session.year.toString()),
|
||||
_duration,
|
||||
_content('library', session.libraryName),
|
||||
_content('user', session.friendlyName),
|
||||
LSTableContent(title: 'title', body: session.lsFullTitle),
|
||||
LSTableContent(title: 'year', body: session.year.toString()),
|
||||
LSTableContent(title: 'duration', body: session.lsDuration),
|
||||
LSTableContent(title: 'library', body: session.libraryName),
|
||||
LSTableContent(title: 'user', body: session.friendlyName),
|
||||
]
|
||||
);
|
||||
|
||||
Widget get _title => _content(
|
||||
'title',
|
||||
[
|
||||
if(session.title != null && session.title.isNotEmpty) '${session.title}',
|
||||
if(session.parentTitle != null && session.parentTitle.isNotEmpty) '\n${session.parentTitle}',
|
||||
if(session.grandparentTitle != null && session.grandparentTitle.isNotEmpty) '\n${session.grandparentTitle}',
|
||||
].join()
|
||||
);
|
||||
|
||||
Widget get _duration {
|
||||
double _percent = session.progressPercent/100;
|
||||
String _progress = Duration(seconds: (session.streamDuration.inSeconds*_percent).floor()).lsDuration_timestamp();
|
||||
String _total = session.streamDuration.lsDuration_timestamp();
|
||||
return _content('duration', '$_progress/$_total (${session.progressPercent}%)');
|
||||
}
|
||||
|
||||
List<Widget> get _playerBlock => _block(
|
||||
Widget get _playerBlock => LSTableBlock(
|
||||
title: 'Player',
|
||||
children: [
|
||||
_content('location', session.ipAddress),
|
||||
_content('device', session.device),
|
||||
_content('platform', session.platform),
|
||||
_content('product', session.product),
|
||||
_content('player', session.player),
|
||||
_content('version', session.platformVersion),
|
||||
LSTableContent(title: 'location', body: session.ipAddress),
|
||||
LSTableContent(title: 'device', body: session.device),
|
||||
LSTableContent(title: 'platform', body: session.platform),
|
||||
LSTableContent(title: 'product', body: session.product),
|
||||
LSTableContent(title: 'player', body: session.player),
|
||||
LSTableContent(title: 'version', body: session.platformVersion),
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _streamBlock => _block(
|
||||
Widget get _streamBlock => LSTableBlock(
|
||||
title: 'Stream',
|
||||
children: [
|
||||
_bandwidth,
|
||||
_quality,
|
||||
_stream,
|
||||
_container,
|
||||
_video,
|
||||
_audio,
|
||||
LSTableContent(title: 'bandwidth', body: session.lsBandwidth),
|
||||
LSTableContent(title: 'quality', body: session.lsQuality),
|
||||
LSTableContent(title: 'stream', body: session.lsStream),
|
||||
LSTableContent(title: 'container', body: session.lsContainer),
|
||||
session.streamVideoDecision != null && session.streamVideoDecision != TautulliTranscodeDecision.NULL
|
||||
? LSTableContent(title: 'video', body: session.lsVideo)
|
||||
: Container(),
|
||||
session.streamAudioDecision != null && session.streamAudioDecision != TautulliTranscodeDecision.NULL
|
||||
? LSTableContent(title: 'audio', body: session.lsAudio)
|
||||
: Container(),
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _bandwidth => _content('bandwidth', '${session.bandwidth.lsBytes_KilobytesToString(bytes: false, decimals: 1)}ps');
|
||||
|
||||
Widget get _quality => _content('quality', '${session.qualityProfile} (${session.streamBitrate.lsBytes_KilobytesToString(bytes: false, decimals: 1)}ps)');
|
||||
|
||||
Widget get _stream {
|
||||
String _value = '';
|
||||
switch(session.transcodeDecision) {
|
||||
case TautulliTranscodeDecision.TRANSCODE:
|
||||
String _transcodeStatus = session.transcodeThrottled ? 'Throttled' : '${session.transcodeSpeed ?? 0.0}x';
|
||||
_value = 'Transcode ($_transcodeStatus)';
|
||||
break;
|
||||
case TautulliTranscodeDecision.COPY: _value = 'Direct Stream'; break;
|
||||
case TautulliTranscodeDecision.DIRECT_PLAY: _value = 'Direct Play'; break;
|
||||
case TautulliTranscodeDecision.NULL: _value = 'Unknown Transcode Decision'; break;
|
||||
}
|
||||
return _content('stream', _value);
|
||||
}
|
||||
|
||||
Widget get _container => _content(
|
||||
'container',
|
||||
[
|
||||
session.streamContainerDecision.name,
|
||||
' (',
|
||||
session.container.toUpperCase(),
|
||||
if(session.streamContainerDecision != null && session.streamContainerDecision != TautulliTranscodeDecision.DIRECT_PLAY)
|
||||
' ${Constants.TEXT_RARROW} ${session.streamContainer.toUpperCase()}',
|
||||
')',
|
||||
].join(),
|
||||
);
|
||||
|
||||
Widget get _video => session.streamVideoDecision != null && session.streamVideoDecision != TautulliTranscodeDecision.NULL
|
||||
? _content(
|
||||
'video',
|
||||
[
|
||||
session.videoDecision.name,
|
||||
' (',
|
||||
session.videoCodec.toUpperCase(),
|
||||
' ',
|
||||
session.videoFullResolution,
|
||||
if(session.transcodeVideoCodec.isNotEmpty) ' ${Constants.TEXT_RARROW} ',
|
||||
if(session.transcodeVideoCodec.isNotEmpty) session.transcodeVideoCodec.toUpperCase(),
|
||||
if(session.transcodeVideoCodec.isNotEmpty) ' ${session.streamVideoFullResolution}',
|
||||
')',
|
||||
].join(),
|
||||
)
|
||||
: Container();
|
||||
|
||||
Widget get _audio => session.streamAudioDecision != null && session.streamAudioDecision != TautulliTranscodeDecision.NULL
|
||||
? _content(
|
||||
'audio',
|
||||
[
|
||||
session.audioDecision.name,
|
||||
' (',
|
||||
session.audioCodec.toUpperCase(),
|
||||
if(session.transcodeAudioCodec.isNotEmpty) ' ${Constants.TEXT_RARROW} ',
|
||||
if(session.transcodeAudioCodec.isNotEmpty) session.transcodeAudioCodec.toUpperCase(),
|
||||
')',
|
||||
].join(),
|
||||
)
|
||||
: Container();
|
||||
|
||||
List<Widget> _block({
|
||||
@required String title,
|
||||
@required List<Widget> children,
|
||||
}) => [
|
||||
LSHeader(text: title),
|
||||
LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
Widget _content(String header, String body) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
header.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -21,7 +21,7 @@ class TautulliActivityDetailsMetadata extends StatelessWidget {
|
||||
if(snapshot.hasData) {
|
||||
TautulliSession session = snapshot.data.sessions.firstWhere((element) => element.sessionId == sessionId, orElse: () => null);
|
||||
if(session != null) return LSIconButton(
|
||||
icon: Icons.info,
|
||||
icon: Icons.info_outline,
|
||||
onPressed: () async => _onPressed(context, session),
|
||||
);
|
||||
}
|
||||
@@ -30,11 +30,5 @@ class TautulliActivityDetailsMetadata extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> _onPressed(BuildContext context, TautulliSession session) => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: session.ratingKey,
|
||||
mediaType: session.mediaType,
|
||||
),
|
||||
);
|
||||
Future<void> _onPressed(BuildContext context, TautulliSession session) => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: session.ratingKey, mediaType: session.mediaType);
|
||||
}
|
||||
|
||||
@@ -50,4 +50,4 @@ class TautulliActivityDetailsTerminateSession extends StatelessWidget {
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,8 +30,8 @@ class TautulliActivityDetailsUser extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> _onPressed(BuildContext context, int userId) => TautulliRouter.router.navigateTo(
|
||||
Future<void> _onPressed(BuildContext context, int userId) => TautulliUserDetailsRouter.navigateTo(
|
||||
context,
|
||||
TautulliUserDetailsRoute.route(userId: userId),
|
||||
userId: userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,29 +5,56 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliCheckForUpdatesRoute extends StatefulWidget {
|
||||
static const ROUTE_NAME = '/tautulli/checkforupdates/:profile';
|
||||
class TautulliCheckForUpdatesRouter {
|
||||
static const ROUTE_NAME = '/tautulli/more/checkforupdates';
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/checkforupdates/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/checkforupdates/$profile';
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliCheckForUpdatesRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0
|
||||
? params['profile'][0]
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliCheckForUpdatesRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliCheckForUpdatesRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
TautulliCheckForUpdatesRouter._();
|
||||
}
|
||||
|
||||
class _TautulliCheckForUpdatesRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliCheckForUpdatesRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliCheckForUpdatesRoute> {
|
||||
class _State extends State<_TautulliCheckForUpdatesRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
// Tracks the initial load to ensure the futures have been initialized
|
||||
bool _initialLoad = false;
|
||||
|
||||
Future<void> _refresh() async {
|
||||
@@ -67,7 +94,7 @@ class _State extends State<TautulliCheckForUpdatesRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliCheckForUpdatesRoute',
|
||||
'_TautulliCheckForUpdatesRoute',
|
||||
'_body',
|
||||
'Unable to fetch updates',
|
||||
snapshot.error,
|
||||
|
||||
@@ -3,29 +3,54 @@ import 'package:flutter/material.dart' hide Router;
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
|
||||
class TautulliGraphsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/graphs/:profile';
|
||||
class TautulliGraphsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/more/graphs';
|
||||
|
||||
TautulliGraphsRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliGraphsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0
|
||||
? params['profile'][0]
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliGraphsRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliGraphsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliGraphsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliGraphsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TautulliGraphsRoute> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/graphs/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/graphs/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliGraphsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliGraphsRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
State<_TautulliGraphsRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliGraphsRoute> {
|
||||
class _State extends State<_TautulliGraphsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
PageController _pageController;
|
||||
|
||||
|
||||
@@ -34,4 +34,4 @@ class TautulliGraphsTypeButton extends StatelessWidget {
|
||||
)
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,9 +50,9 @@ class TautulliHistoryTile extends StatelessWidget {
|
||||
child: Container(
|
||||
child: Column(
|
||||
children: [
|
||||
_title,
|
||||
LSTitle(text: history.lsTitle, maxLines: 1),
|
||||
_subtitle,
|
||||
_date,
|
||||
LSSubtitle(text: history.lsDate),
|
||||
_userInfo,
|
||||
],
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
@@ -65,11 +65,6 @@ class TautulliHistoryTile extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _title => LSTitle(
|
||||
text: history.header,
|
||||
maxLines: 1,
|
||||
);
|
||||
|
||||
Widget get _subtitle => RichText(
|
||||
text: TextSpan(
|
||||
style: TextStyle(
|
||||
@@ -94,41 +89,28 @@ class TautulliHistoryTile extends StatelessWidget {
|
||||
overflow: TextOverflow.fade,
|
||||
);
|
||||
|
||||
Widget get _userInfo {
|
||||
IconData _icon;
|
||||
switch(history.watchedStatus) {
|
||||
case TautulliWatchedStatus.UNWATCHED: _icon = Icons.radio_button_unchecked; break;
|
||||
case TautulliWatchedStatus.PARTIALLY_WATCHED: _icon = Icons.radio_button_checked; break;
|
||||
case TautulliWatchedStatus.WATCHED: _icon = Icons.check_circle; break;
|
||||
}
|
||||
return Row(
|
||||
children: [
|
||||
Padding(
|
||||
child: LSIcon(
|
||||
icon: _icon,
|
||||
size: Constants.UI_FONT_SIZE_SUBHEADER,
|
||||
),
|
||||
padding: EdgeInsets.only(right: 6.0),
|
||||
Widget get _userInfo => Row(
|
||||
children: [
|
||||
Padding(
|
||||
child: LSIcon(
|
||||
icon: history.lsWatchStatusIcon,
|
||||
size: Constants.UI_FONT_SIZE_SUBHEADER,
|
||||
),
|
||||
Expanded(
|
||||
child: LSSubtitle(
|
||||
text: history.friendlyName ?? 'Unknown User',
|
||||
maxLines: 1,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
}
|
||||
padding: EdgeInsets.only(right: 6.0),
|
||||
),
|
||||
Expanded(
|
||||
child: LSSubtitle(
|
||||
text: history.friendlyName ?? 'Unknown User',
|
||||
maxLines: 1,
|
||||
),
|
||||
)
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _date => LSSubtitle(text: DateTime.now().lsDateTime_ageString(history.date));
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
Future<void> _onTap(BuildContext context) async => TautulliHistoryDetailsRouter.navigateTo(
|
||||
context,
|
||||
TautulliHistoryDetailsRoute.route(
|
||||
profile: LunaSeaDatabaseValue.ENABLED_PROFILE.data,
|
||||
ratingKey: history.ratingKey,
|
||||
sessionKey: history.sessionKey,
|
||||
referenceId: history.referenceId,
|
||||
),
|
||||
ratingKey: history.ratingKey,
|
||||
sessionKey: history.sessionKey,
|
||||
referenceId: history.referenceId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -5,14 +5,65 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliHistoryDetailsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/history/details/:ratingkey/:key/:value/:profile';
|
||||
class TautulliHistoryDetailsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/history/details/:ratingkey/:key/:value';
|
||||
|
||||
static Future<void> navigateTo(BuildContext context, {
|
||||
@required int ratingKey,
|
||||
int referenceId,
|
||||
int sessionKey,
|
||||
}) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(ratingKey: ratingKey, referenceId: referenceId, sessionKey: sessionKey),
|
||||
);
|
||||
|
||||
static String route({
|
||||
String profile,
|
||||
@required int ratingKey,
|
||||
int referenceId,
|
||||
int sessionKey,
|
||||
}) {
|
||||
String _route = '/tautulli';
|
||||
if(referenceId != null) _route = '/tautulli/history/details/$ratingKey/referenceid/$referenceId';
|
||||
if(sessionKey != null) _route = '/tautulli/history/details/$ratingKey/sessionkey/$sessionKey';
|
||||
return profile != null ? _route + '/$profile' : _route;
|
||||
}
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliHistoryDetailsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
ratingKey: int.tryParse(params['ratingkey'][0]),
|
||||
sessionKey: params['key'][0] == 'sessionkey' ? int.tryParse(params['value'][0]) : null,
|
||||
referenceId: params['key'][0] == 'referenceid' ? int.tryParse(params['value'][0]) : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliHistoryDetailsRoute(
|
||||
profile: null,
|
||||
ratingKey: int.tryParse(params['ratingkey'][0]),
|
||||
sessionKey: params['key'][0] == 'sessionkey' ? int.tryParse(params['value'][0]) : null,
|
||||
referenceId: params['key'][0] == 'referenceid' ? int.tryParse(params['value'][0]) : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliHistoryDetailsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliHistoryDetailsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
final int ratingKey;
|
||||
final int sessionKey;
|
||||
final int referenceId;
|
||||
|
||||
TautulliHistoryDetailsRoute({
|
||||
_TautulliHistoryDetailsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
@required this.ratingKey,
|
||||
this.sessionKey,
|
||||
this.referenceId,
|
||||
@@ -20,31 +71,9 @@ class TautulliHistoryDetailsRoute extends StatefulWidget {
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({
|
||||
@required String profile,
|
||||
@required int ratingKey,
|
||||
int referenceId,
|
||||
int sessionKey,
|
||||
}) {
|
||||
String _route = '/tautulli/$profile';
|
||||
if(referenceId != null) _route = '/tautulli/history/details/$ratingKey/referenceid/$referenceId/$profile';
|
||||
if(sessionKey != null) _route = '/tautulli/history/details/$ratingKey/sessionkey/$sessionKey/$profile';
|
||||
return _route;
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliHistoryDetailsRoute(
|
||||
ratingKey: int.tryParse(params['ratingkey'][0]),
|
||||
sessionKey: params['key'][0] == 'sessionkey' ? int.tryParse(params['value'][0]) : null,
|
||||
referenceId: params['key'][0] == 'referenceid' ? int.tryParse(params['value'][0]) : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliHistoryDetailsRoute> {
|
||||
class _State extends State<_TautulliHistoryDetailsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -91,7 +120,7 @@ class _State extends State<TautulliHistoryDetailsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliHistoryDetailsRoute',
|
||||
'_TautulliHistoryDetailsRoute',
|
||||
'_shared',
|
||||
'Unable to pull Tautulli history session',
|
||||
snapshot.error,
|
||||
@@ -114,5 +143,5 @@ class _State extends State<TautulliHistoryDetailsRoute> {
|
||||
),
|
||||
);
|
||||
|
||||
Widget get _unknown => LSGenericMessage(text: 'History Record Not Found');
|
||||
Widget get _unknown => LSGenericMessage(text: 'History Not Found');
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliHistoryDetailsInformation extends StatelessWidget {
|
||||
@@ -14,123 +15,40 @@ class TautulliHistoryDetailsInformation extends StatelessWidget {
|
||||
@override
|
||||
Widget build(BuildContext context) => LSListView(
|
||||
children: [
|
||||
..._metadataBlock,
|
||||
..._sessionBlock,
|
||||
..._playerBlock,
|
||||
_metadataBlock,
|
||||
_sessionBlock,
|
||||
_playerBlock,
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _metadataBlock => _block(
|
||||
Widget get _metadataBlock => LSTableBlock(
|
||||
title: 'Metadata',
|
||||
children: <Widget>[
|
||||
_status,
|
||||
_title,
|
||||
_content('year', history.year.toString()),
|
||||
_content('user', history.friendlyName),
|
||||
children: [
|
||||
LSTableContent(title: 'status', body: history.lsStatus),
|
||||
LSTableContent(title: 'title', body: history.lsFullTitle),
|
||||
LSTableContent(title: 'year', body: history.year.toString()),
|
||||
LSTableContent(title: 'user', body: history.friendlyName),
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _sessionBlock => _block(
|
||||
Widget get _sessionBlock => LSTableBlock(
|
||||
title: 'Session',
|
||||
children: <Widget>[
|
||||
_state,
|
||||
_content('date', DateFormat('yyyy-MM-dd').format(history.date)),
|
||||
_content('started', history.date.lsDateTime_time),
|
||||
_content('stopped', history.state == null ? history.stopped.lsDateTime_time : Constants.TEXT_EMDASH),
|
||||
_content('paused', history.pausedCounter.lsDuration_fullTimestamp()),
|
||||
children: [
|
||||
LSTableContent(title: 'state', body: history.lsState),
|
||||
LSTableContent(title: 'date', body: DateFormat('yyyy-MM-dd').format(history.date)),
|
||||
LSTableContent(title: 'started', body: history.date.lsDateTime_time),
|
||||
LSTableContent(title: 'stopped', body: history.state == null ? history.stopped.lsDateTime_time : Constants.TEXT_EMDASH),
|
||||
LSTableContent(title: 'paused', body: history.pausedCounter.lsDuration_fullTimestamp()),
|
||||
],
|
||||
);
|
||||
|
||||
List<Widget> get _playerBlock => _block(
|
||||
Widget get _playerBlock => LSTableBlock(
|
||||
title: 'Player',
|
||||
children: <Widget>[
|
||||
_content('location', history.ipAddress),
|
||||
_content('platform', history.platform),
|
||||
_content('product', history.product),
|
||||
_content('player', history.player),
|
||||
//_content('quality', history.)
|
||||
children: [
|
||||
LSTableContent(title: 'location', body: history.ipAddress),
|
||||
LSTableContent(title: 'platform', body: history.platform),
|
||||
LSTableContent(title: 'product', body: history.product),
|
||||
LSTableContent(title: 'player', body: history.player),
|
||||
],
|
||||
);
|
||||
|
||||
Widget get _status {
|
||||
String _progress = 'Unknown';
|
||||
if(history.watchedStatus != null) switch(history.watchedStatus) {
|
||||
case TautulliWatchedStatus.UNWATCHED: _progress = 'Incompleted'; break;
|
||||
case TautulliWatchedStatus.PARTIALLY_WATCHED: _progress = 'Partially Completed'; break;
|
||||
case TautulliWatchedStatus.WATCHED: _progress = 'Completed'; break;
|
||||
}
|
||||
return _content(
|
||||
'status',
|
||||
_progress,
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _state {
|
||||
String _status = 'Finished';
|
||||
if(history.state != null) switch(history.state) {
|
||||
case TautulliSessionState.PLAYING: _status = 'Playing'; break;
|
||||
case TautulliSessionState.PAUSED: _status = 'Paused'; break;
|
||||
case TautulliSessionState.BUFFERING: _status = 'Buffering'; break;
|
||||
case TautulliSessionState.NULL: _status = 'Finished'; break;
|
||||
}
|
||||
return _content(
|
||||
'state',
|
||||
_status,
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _title => _content(
|
||||
'title',
|
||||
[
|
||||
if(history.title != null && history.title.isNotEmpty) '${history.title}',
|
||||
if(history.parentTitle != null && history.parentTitle.isNotEmpty) '\n${history.parentTitle}',
|
||||
if(history.grandparentTitle != null && history.grandparentTitle.isNotEmpty) '\n${history.grandparentTitle}',
|
||||
].join()
|
||||
);
|
||||
|
||||
List<Widget> _block({
|
||||
@required String title,
|
||||
@required List<Widget> children,
|
||||
}) => [
|
||||
LSHeader(text: title),
|
||||
LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: children,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
),
|
||||
];
|
||||
|
||||
Widget _content(String header, String body) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
header.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
);
|
||||
}
|
||||
|
||||
@@ -26,7 +26,7 @@ class TautulliHistoryDetailsMetadata extends StatelessWidget {
|
||||
return false;
|
||||
}, orElse: () => null);
|
||||
if(_record != null) return LSIconButton(
|
||||
icon: Icons.info,
|
||||
icon: Icons.info_outline,
|
||||
onPressed: () async => _onPressed(context, _record),
|
||||
);
|
||||
}
|
||||
@@ -34,11 +34,5 @@ class TautulliHistoryDetailsMetadata extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
|
||||
Future<void> _onPressed(BuildContext context, TautulliHistoryRecord record) => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: record.ratingKey,
|
||||
mediaType: record.mediaType,
|
||||
),
|
||||
);
|
||||
Future<void> _onPressed(BuildContext context, TautulliHistoryRecord record) => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: record.ratingKey, mediaType: record.mediaType);
|
||||
}
|
||||
|
||||
@@ -34,8 +34,8 @@ class TautulliHistoryDetailsUser extends StatelessWidget {
|
||||
},
|
||||
);
|
||||
|
||||
Future<void> _onPressed(BuildContext context, int userId) => TautulliRouter.router.navigateTo(
|
||||
Future<void> _onPressed(BuildContext context, int userId) => TautulliUserDetailsRouter.navigateTo(
|
||||
context,
|
||||
TautulliUserDetailsRoute.route(userId: userId),
|
||||
userId: userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -8,8 +8,7 @@ import 'package:tautulli/tautulli.dart';
|
||||
class TautulliIPAddressDetailsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/ipaddress/:ipaddress';
|
||||
|
||||
static Future<void> navigateTo({
|
||||
@required BuildContext context,
|
||||
static Future<void> navigateTo(BuildContext context, {
|
||||
@required String ip,
|
||||
}) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
@@ -117,9 +116,7 @@ class _State extends State<_TautulliIPAddressRoute> {
|
||||
|
||||
Widget _list(TautulliGeolocationInfo geolocation, TautulliWHOISInfo whois) => LSListView(
|
||||
children: [
|
||||
LSHeader(text: 'Location Details'),
|
||||
TautulliIPAddressDetailsGeolocationTile(geolocation: geolocation),
|
||||
LSHeader(text: 'Connection Details'),
|
||||
TautulliIPAddressDetailsWHOISTile(whois: whois),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -11,51 +11,16 @@ class TautulliIPAddressDetailsGeolocationTile extends StatelessWidget {
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: [
|
||||
_content('country', geolocation.country),
|
||||
_content('region', geolocation.region),
|
||||
_content('city', geolocation.city),
|
||||
_content('postal', geolocation.postalCode),
|
||||
_content('timezone', geolocation.timezone),
|
||||
_content('latitude', '${geolocation.latitude}'),
|
||||
_content('longitude', '${geolocation.longitude}'),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
);
|
||||
|
||||
Widget _content(String header, String body) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
header.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
Widget build(BuildContext context) => LSTableBlock(
|
||||
title: 'Location Details',
|
||||
children: [
|
||||
LSTableContent(title: 'country', body: geolocation.country),
|
||||
LSTableContent(title: 'region', body: geolocation.region),
|
||||
LSTableContent(title: 'city', body: geolocation.city),
|
||||
LSTableContent(title: 'postal', body: geolocation.postalCode),
|
||||
LSTableContent(title: 'timezone', body: geolocation.timezone),
|
||||
LSTableContent(title: 'latitude', body: '${geolocation.latitude}'),
|
||||
LSTableContent(title: 'longitude', body: '${geolocation.longitude}'),
|
||||
],
|
||||
);
|
||||
}
|
||||
@@ -11,55 +11,23 @@ class TautulliIPAddressDetailsWHOISTile extends StatelessWidget {
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: [
|
||||
_content('host', whois.host),
|
||||
...whois.subnets.fold<List<Widget>>([], (list, subnet) {
|
||||
list.add(_content('isp', [
|
||||
subnet.description,
|
||||
'\n\n${subnet.address}',
|
||||
'\n${subnet.city}, ${subnet.state}',
|
||||
'\n${subnet.postalCode}',
|
||||
'\n${subnet.country}',
|
||||
].join()));
|
||||
return list;
|
||||
}),
|
||||
],
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
Widget build(BuildContext context) => LSTableBlock(
|
||||
title: 'Connection Details',
|
||||
children: [
|
||||
LSTableContent(title: 'host', body: whois.host),
|
||||
...whois.subnets.fold<List<LSTableContent>>([], (list, subnet) {
|
||||
list.add(LSTableContent(
|
||||
title: 'isp',
|
||||
body: [
|
||||
subnet.description,
|
||||
'\n\n${subnet.address}',
|
||||
'\n${subnet.city}, ${subnet.state}',
|
||||
'\n${subnet.postalCode}',
|
||||
'\n${subnet.country}',
|
||||
].join(),
|
||||
));
|
||||
return list;
|
||||
}),
|
||||
],
|
||||
);
|
||||
|
||||
Widget _content(String header, String body) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
header.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLibrariesRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/libraries/:profile';
|
||||
class TautulliLibrariesRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/libraries/list';
|
||||
|
||||
TautulliLibrariesRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLibrariesRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLibrariesRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLibrariesRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLibrariesRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLibrariesRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TautulliLibrariesRoute> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/libraries/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/libraries/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLibrariesRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLibrariesRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
State<_TautulliLibrariesRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLibrariesRoute> {
|
||||
class _State extends State<_TautulliLibrariesRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLibrariesRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLibrariesRoute',
|
||||
'_TautulliLibrariesRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli libraries table',
|
||||
snapshot.error,
|
||||
|
||||
@@ -48,8 +48,5 @@ class TautulliLibrariesLibraryTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) => TautulliLibrariesDetailsRouter.navigateTo(
|
||||
context: context,
|
||||
sectionId: library.sectionId,
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) => TautulliLibrariesDetailsRouter.navigateTo(context, sectionId: library.sectionId);
|
||||
}
|
||||
|
||||
@@ -6,16 +6,13 @@ import 'package:lunasea/modules/tautulli.dart';
|
||||
class TautulliLibrariesDetailsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/libraries/details/:sectionid';
|
||||
|
||||
/// Static function to navigate to this route
|
||||
static Future<void> navigateTo({
|
||||
@required BuildContext context,
|
||||
static Future<void> navigateTo(BuildContext context, {
|
||||
@required int sectionId,
|
||||
}) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(sectionId: sectionId),
|
||||
);
|
||||
|
||||
/// Given the parameters, generates a String for routing to the route
|
||||
static String route({
|
||||
String profile,
|
||||
@required int sectionId,
|
||||
@@ -24,9 +21,7 @@ class TautulliLibrariesDetailsRouter {
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
/// Given a Fluro router, defines the routes and handlers
|
||||
static void defineRoutes(Router router) {
|
||||
/// With profile defined
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLibrariesDetailsRoute(
|
||||
@@ -39,7 +34,6 @@ class TautulliLibrariesDetailsRouter {
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
/// Without profile defined
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLibrariesDetailsRoute(
|
||||
|
||||
@@ -83,21 +83,11 @@ class _State extends State<TautulliLibrariesDetailsInformation> with AutomaticKe
|
||||
}) {
|
||||
return LSListView(
|
||||
children: [
|
||||
..._details(library),
|
||||
..._watchTimeStats(watchTimeStats),
|
||||
TautulliLibrariesDetailsInformationDetails(library: library),
|
||||
TautulliLibrariesDetailsInformationGlobalStats(watchtime: watchTimeStats),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _unknown => LSGenericMessage(text: 'Library Not Found');
|
||||
|
||||
List<Widget> _details(TautulliTableLibrary library) => <Widget>[
|
||||
LSHeader(text: 'Details'),
|
||||
TautulliLibrariesDetailsInformationDetails(library: library),
|
||||
];
|
||||
|
||||
List<Widget> _watchTimeStats(List<TautulliLibraryWatchTimeStats> watchTimeStats) => <Widget>[
|
||||
LSHeader(text: 'Global Stats'),
|
||||
TautulliLibrariesDetailsInformationGlobalStats(watchtime: watchTimeStats),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -11,20 +11,16 @@ class TautulliLibrariesDetailsInformationDetails extends StatelessWidget {
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: [
|
||||
_content('name', library.sectionName),
|
||||
if(library.count != null) _content(_count(library.count), '${library.count} ${_count(library.count)}'),
|
||||
if(library.parentCount != null) _content(_parentCount(library.parentCount), '${library.parentCount} ${_parentCount(library.parentCount)}'),
|
||||
if(library.childCount != null) _content(_childCount(library.childCount), '${library.childCount} ${_childCount(library.childCount)}'),
|
||||
_content('last played', library.lastPlayed),
|
||||
_content('', DateTime.now().lsDateTime_ageString(library.lastAccessed)),
|
||||
]
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
Widget build(BuildContext context) => LSTableBlock(
|
||||
title: 'Details',
|
||||
children: [
|
||||
LSTableContent(title: 'name', body: library.sectionName),
|
||||
if(library.count != null) LSTableContent(title: _count(library.count), body: '${library.count} ${_count(library.count)}'),
|
||||
if(library.parentCount != null) LSTableContent(title: _parentCount(library.parentCount), body: '${library.parentCount} ${_parentCount(library.parentCount)}'),
|
||||
if(library.childCount != null) LSTableContent(title: _childCount(library.childCount), body: '${library.childCount} ${_childCount(library.childCount)}'),
|
||||
LSTableContent(title: 'last played', body: library.lastPlayed),
|
||||
LSTableContent(title: '', body: DateTime.now().lsDateTime_ageString(library.lastAccessed)),
|
||||
],
|
||||
);
|
||||
|
||||
String _count(int value) {
|
||||
@@ -59,35 +55,4 @@ class TautulliLibrariesDetailsInformationDetails extends StatelessWidget {
|
||||
default: return 'Unknown';
|
||||
}
|
||||
}
|
||||
|
||||
Widget _content(String header, String body) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
header.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
);
|
||||
}
|
||||
@@ -9,62 +9,29 @@ class TautulliLibrariesDetailsInformationGlobalStats extends StatelessWidget {
|
||||
Key key,
|
||||
@required this.watchtime,
|
||||
}) : super(key: key);
|
||||
|
||||
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => LSCard(
|
||||
child: Padding(
|
||||
child: Column(
|
||||
children: List.generate(
|
||||
watchtime.length,
|
||||
(index) => _content(
|
||||
_globalStatsTitle(watchtime[index].queryDays),
|
||||
_globalStatsContent(watchtime[index].totalPlays, watchtime[index].totalTime),
|
||||
),
|
||||
),
|
||||
Widget build(BuildContext context) => LSTableBlock(
|
||||
title: 'Global Stats',
|
||||
children: List.generate(
|
||||
watchtime.length,
|
||||
(index) => LSTableContent(
|
||||
title: _title(watchtime[index].queryDays),
|
||||
body: _body(watchtime[index].totalPlays, watchtime[index].totalTime),
|
||||
),
|
||||
padding: EdgeInsets.symmetric(vertical: 8.0),
|
||||
),
|
||||
);
|
||||
|
||||
String _globalStatsTitle(int days) {
|
||||
String _title(int days) {
|
||||
if(days == 0) return 'All Time';
|
||||
if(days == 1) return '24 Hours';
|
||||
return '$days Days';
|
||||
}
|
||||
|
||||
String _globalStatsContent(int plays, Duration duration) {
|
||||
String _body(int plays, Duration duration) {
|
||||
String _plays = plays == 1 ? '1 Play': '$plays Plays';
|
||||
return '$_plays\n${duration.lsDuration_fullTimestamp()}';
|
||||
}
|
||||
|
||||
Widget _content(String header, String body) => Padding(
|
||||
child: Row(
|
||||
children: [
|
||||
Expanded(
|
||||
child: Text(
|
||||
header.toUpperCase(),
|
||||
textAlign: TextAlign.end,
|
||||
style: TextStyle(
|
||||
color: Colors.white70,
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 2,
|
||||
),
|
||||
Container(width: 16.0, height: 0.0),
|
||||
Expanded(
|
||||
child: Text(
|
||||
body,
|
||||
textAlign: TextAlign.start,
|
||||
style: TextStyle(
|
||||
fontSize: Constants.UI_FONT_SIZE_SUBTITLE,
|
||||
),
|
||||
),
|
||||
flex: 5,
|
||||
),
|
||||
],
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
padding: EdgeInsets.symmetric(horizontal: 12.0, vertical: 4.0),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,5 +66,5 @@ class _State extends State<TautulliLibrariesDetailsUserStats> with AutomaticKeep
|
||||
);
|
||||
}
|
||||
|
||||
Widget get _noStatsFound => LSGenericMessage(text: 'No User Stats Found');
|
||||
Widget get _noStatsFound => LSGenericMessage(text: 'No User Found');
|
||||
}
|
||||
|
||||
@@ -25,7 +25,7 @@ class TautulliLibrariesDetailsUserStatsTile extends StatelessWidget {
|
||||
mainAxisAlignment: MainAxisAlignment.spaceBetween,
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
),
|
||||
onTap: () async => _enterDetails(context),
|
||||
onTap: () async => _onPressed(context),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -94,8 +94,8 @@ class TautulliLibrariesDetailsUserStatsTile extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
Future<void> _enterDetails(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
Future<void> _onPressed(BuildContext context) => TautulliUserDetailsRouter.navigateTo(
|
||||
context,
|
||||
TautulliUserDetailsRoute.route(userId: user.userId),
|
||||
userId: user.userId,
|
||||
);
|
||||
}
|
||||
|
||||
@@ -3,30 +3,54 @@ import 'package:flutter/material.dart' hide Router;
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
|
||||
class TautulliLogsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/:profile';
|
||||
class TautulliLogsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/list';
|
||||
|
||||
TautulliLogsRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsRoute> {
|
||||
class _State extends State<_TautulliLogsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
|
||||
@override
|
||||
Widget build(BuildContext context) => Scaffold(
|
||||
key: _scaffoldKey,
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliLogsLoginsTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsLoginsRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsLoginsRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliLogsNewslettersTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsNewslettersRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsNewslettersRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliLogsNotificationsTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsNotificationsRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsNotificationsRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliLogsPlexMediaScannerTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsPlexMediaScannerRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsPlexMediaScannerRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliLogsPlexMediaServerTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsPlexMediaServerRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsPlexMediaServerRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliLogsTautulliTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsTautulliRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsTautulliRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLogsLoginsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/logins/:profile';
|
||||
class TautulliLogsLoginsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/logins';
|
||||
|
||||
TautulliLogsLoginsRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsLoginsRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsLoginsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsLoginsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsLoginsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsLoginsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/logins/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/logins/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsLoginsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsLoginsRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsLoginsRoute> {
|
||||
class _State extends State<_TautulliLogsLoginsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLogsLoginsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLogsLoginsRoute',
|
||||
'_TautulliLogsLoginsRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli login logs',
|
||||
snapshot.error,
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLogsNewslettersRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/newsletters/:profile';
|
||||
class TautulliLogsNewslettersRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/newsletters';
|
||||
|
||||
TautulliLogsNewslettersRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsNewslettersRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsNewslettersRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsNewslettersRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsNewslettersRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsNewslettersRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/newsletters/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/newsletters/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsNewslettersRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsNewslettersRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsNewslettersRoute> {
|
||||
class _State extends State<_TautulliLogsNewslettersRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLogsNewslettersRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLogsNewslettersRoute',
|
||||
'_TautulliLogsNewslettersRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli newsletter logs',
|
||||
snapshot.error,
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLogsNotificationsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/notifications/:profile';
|
||||
class TautulliLogsNotificationsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/notifications';
|
||||
|
||||
TautulliLogsNotificationsRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsNotificationsRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsNotificationsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsNotificationsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsNotificationsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsNotificationsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/notifications/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/notifications/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsNotificationsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsNotificationsRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsNotificationsRoute> {
|
||||
class _State extends State<_TautulliLogsNotificationsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLogsNotificationsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLogsNotificationsRoute',
|
||||
'_TautulliLogsNotificationsRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli notification logs',
|
||||
snapshot.error,
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLogsPlexMediaScannerRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/plexmediascanner/:profile';
|
||||
class TautulliLogsPlexMediaScannerRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/plexmediascanner';
|
||||
|
||||
TautulliLogsPlexMediaScannerRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsPlexMediaScannerRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsPlexMediaScannerRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsPlexMediaScannerRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsPlexMediaScannerRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsPlexMediaScannerRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/plexmediascanner/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/plexmediascanner/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsPlexMediaScannerRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsPlexMediaScannerRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsPlexMediaScannerRoute> {
|
||||
class _State extends State<_TautulliLogsPlexMediaScannerRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLogsPlexMediaScannerRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLogsPlexMediaScannerRoute',
|
||||
'_TautulliLogsPlexMediaScannerRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli plex media scanner logs',
|
||||
snapshot.error,
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLogsPlexMediaServerRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/plexmediaserver/:profile';
|
||||
class TautulliLogsPlexMediaServerRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/plexmediaserver';
|
||||
|
||||
TautulliLogsPlexMediaServerRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsPlexMediaServerRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsPlexMediaServerRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsPlexMediaServerRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsPlexMediaServerRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsPlexMediaServerRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/plexmediaserver/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/plexmediaserver/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsPlexMediaServerRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsPlexMediaServerRoute()),
|
||||
transitionType: LunaRouter.transitionType
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsPlexMediaServerRoute> {
|
||||
class _State extends State<_TautulliLogsPlexMediaServerRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLogsPlexMediaServerRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLogsPlexMediaServerRoute',
|
||||
'_TautulliLogsPlexMediaServerRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli plex media server logs',
|
||||
snapshot.error,
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliLogsTautulliRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/tautulli/:profile';
|
||||
class TautulliLogsTautulliRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/logs/tautulli';
|
||||
|
||||
TautulliLogsTautulliRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsTautulliRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliLogsTautulliRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliLogsTautulliRouter._();
|
||||
}
|
||||
|
||||
class _TautulliLogsTautulliRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliLogsTautulliRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/logs/tautulli/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/logs/tautulli/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliLogsTautulliRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliLogsTautulliRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliLogsTautulliRoute> {
|
||||
class _State extends State<_TautulliLogsTautulliRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliLogsTautulliRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliLogsTautulliRoute',
|
||||
'_TautulliLogsTautulliRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli Tautulli logs',
|
||||
snapshot.error,
|
||||
|
||||
@@ -4,40 +4,79 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliMediaDetailsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/media/details/:type/:ratingkey/:profile';
|
||||
class TautulliMediaDetailsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/media/details/:mediatype/:ratingkey';
|
||||
|
||||
static Future<void> navigateTo(BuildContext context, {
|
||||
@required int ratingKey,
|
||||
@required TautulliMediaType mediaType,
|
||||
}) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(ratingKey: ratingKey, mediaType: mediaType),
|
||||
);
|
||||
|
||||
static String route({
|
||||
@required int ratingKey,
|
||||
@required TautulliMediaType mediaType,
|
||||
String profile,
|
||||
}) => [
|
||||
ROUTE_NAME
|
||||
.replaceFirst(':mediatype', mediaType?.value ?? 'mediatype')
|
||||
.replaceFirst(':ratingkey', ratingKey.toString()),
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliMediaDetailsRoute(
|
||||
profile: null,
|
||||
ratingKey: params['ratingkey'] != null && params['ratingkey'].length != 0
|
||||
? int.tryParse(params['ratingkey'][0])
|
||||
: null,
|
||||
mediaType: params['mediatype'] != null && params['mediatype'].length != 0
|
||||
? TautulliMediaType.NULL.from(params['mediatype'][0])
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliMediaDetailsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0
|
||||
? params['profile'][0]
|
||||
: null,
|
||||
ratingKey: params['ratingkey'] != null && params['ratingkey'].length != 0
|
||||
? int.tryParse(params['ratingkey'][0])
|
||||
: null,
|
||||
mediaType: params['mediatype'] != null && params['mediatype'].length != 0
|
||||
? TautulliMediaType.NULL.from(params['mediatype'][0])
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliMediaDetailsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliMediaDetailsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
final int ratingKey;
|
||||
final TautulliMediaType mediaType;
|
||||
|
||||
TautulliMediaDetailsRoute({
|
||||
_TautulliMediaDetailsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
@required this.ratingKey,
|
||||
@required this.mediaType,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TautulliMediaDetailsRoute> createState() => _State();
|
||||
|
||||
static String route({
|
||||
String profile,
|
||||
@required int ratingKey,
|
||||
@required TautulliMediaType mediaType,
|
||||
}) {
|
||||
if(profile == null) return '/tautulli/media/details/${mediaType.value}/$ratingKey/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/media/details/${mediaType.value}/$ratingKey/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliMediaDetailsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliMediaDetailsRoute(
|
||||
ratingKey: int.tryParse(params['ratingkey'][0]),
|
||||
mediaType: TautulliMediaType.NULL.from(params['type'][0]),
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
State<_TautulliMediaDetailsRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliMediaDetailsRoute> {
|
||||
class _State extends State<_TautulliMediaDetailsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
PageController _pageController;
|
||||
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreCheckForUpdatesTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliCheckForUpdatesRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliCheckForUpdatesRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreGraphsTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliGraphsRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliGraphsRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreLibrariesTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLibrariesRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLibrariesRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreLogsTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliLogsRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliLogsRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreRecentlyAddedTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliRecentlyAddedRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRecentlyAddedRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreStatisticsTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliStatisticsRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliStatisticsRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -14,8 +14,5 @@ class TautulliMoreSyncedItemsTile extends StatelessWidget {
|
||||
onTap: () async => _onTap(context),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliSyncedItemsRoute.route(),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliSyncedItemsRouter.navigateTo(context);
|
||||
}
|
||||
|
||||
@@ -5,29 +5,54 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliRecentlyAddedRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/recentlyadded/:profile';
|
||||
class TautulliRecentlyAddedRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/recentlyadded/list';
|
||||
|
||||
TautulliRecentlyAddedRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({
|
||||
String profile,
|
||||
}) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliRecentlyAddedRoute(profile: null)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliRecentlyAddedRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0
|
||||
? params['profile'][0]
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliRecentlyAddedRouter._();
|
||||
}
|
||||
|
||||
class _TautulliRecentlyAddedRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliRecentlyAddedRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TautulliRecentlyAddedRoute> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/recentlyadded/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/recentlyadded/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliRecentlyAddedRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliRecentlyAddedRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
State<_TautulliRecentlyAddedRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliRecentlyAddedRoute> {
|
||||
class _State extends State<_TautulliRecentlyAddedRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +88,7 @@ class _State extends State<TautulliRecentlyAddedRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliRecentlyAddedRoute',
|
||||
'_TautulliRecentlyAddedRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli recently added',
|
||||
snapshot.error,
|
||||
|
||||
@@ -127,11 +127,5 @@ class TautulliRecentlyAddedContentTile extends StatelessWidget {
|
||||
|
||||
Widget get _library => LSSubtitle(text: recentlyAdded.libraryName);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: recentlyAdded.ratingKey,
|
||||
mediaType: recentlyAdded.mediaType,
|
||||
),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: recentlyAdded.ratingKey, mediaType: recentlyAdded.mediaType);
|
||||
}
|
||||
|
||||
@@ -96,11 +96,5 @@ class TautulliSearchResultTile extends StatelessWidget {
|
||||
),
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: result.ratingKey,
|
||||
mediaType: mediaType,
|
||||
),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: result.ratingKey, mediaType: mediaType);
|
||||
}
|
||||
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliStatisticsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/statistics/:profile';
|
||||
class TautulliStatisticsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/statistics/list';
|
||||
|
||||
TautulliStatisticsRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliStatisticsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliStatisticsRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliStatisticsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliStatisticsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliStatisticsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<TautulliStatisticsRoute> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/statistics/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/statistics/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliStatisticsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliStatisticsRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
State<_TautulliStatisticsRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliStatisticsRoute> {
|
||||
class _State extends State<_TautulliStatisticsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -69,7 +92,7 @@ class _State extends State<TautulliStatisticsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliStatisticsRoute',
|
||||
'_TautulliStatisticsRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli statistics',
|
||||
snapshot.error,
|
||||
|
||||
@@ -116,11 +116,5 @@ class TautulliStatisticsMediaTile extends StatelessWidget {
|
||||
overflow: TextOverflow.fade,
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: data['rating_key'],
|
||||
mediaType: mediaType,
|
||||
),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: data['rating_key'], mediaType: mediaType);
|
||||
}
|
||||
@@ -94,11 +94,5 @@ class TautulliStatisticsRecentlyWatchedTile extends StatelessWidget {
|
||||
overflow: TextOverflow.fade,
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: data['rating_key'],
|
||||
mediaType: TautulliMediaType.NULL.from(data['media_type']),
|
||||
),
|
||||
);
|
||||
}
|
||||
Future<void> _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: data['rating_key'], mediaType: TautulliMediaType.NULL.from(data['media_type']));
|
||||
}
|
||||
|
||||
@@ -119,10 +119,7 @@ class TautulliStatisticsUserTile extends StatelessWidget {
|
||||
type: SNACKBAR_TYPE.failure,
|
||||
);
|
||||
} else {
|
||||
TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliUserDetailsRoute.route(userId: _user.userId),
|
||||
);
|
||||
TautulliUserDetailsRouter.navigateTo(context, userId: _user.userId);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,29 +5,52 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliSyncedItemsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/synceditems/:profile';
|
||||
class TautulliSyncedItemsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/synceditems/list';
|
||||
|
||||
TautulliSyncedItemsRoute({
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliSyncedItemsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliSyncedItemsRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliSyncedItemsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliSyncedItemsRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliSyncedItemsRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}): super(key: key);
|
||||
|
||||
@override
|
||||
State<TautulliSyncedItemsRoute> createState() => _State();
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/synceditems/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/synceditems/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliSyncedItemsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliSyncedItemsRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
State<_TautulliSyncedItemsRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliSyncedItemsRoute> {
|
||||
class _State extends State<_TautulliSyncedItemsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
final GlobalKey<RefreshIndicatorState> _refreshKey = GlobalKey<RefreshIndicatorState>();
|
||||
|
||||
@@ -63,7 +86,7 @@ class _State extends State<TautulliSyncedItemsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliSyncedItemsRoute',
|
||||
'_TautulliSyncedItemsRoute',
|
||||
'_body',
|
||||
'Unable to fetch Tautulli synced items',
|
||||
snapshot.error,
|
||||
|
||||
@@ -60,11 +60,5 @@ class TautulliSyncedItemTile extends StatelessWidget {
|
||||
padContent: true,
|
||||
);
|
||||
|
||||
Future<void> _onTap(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliMediaDetailsRoute.route(
|
||||
ratingKey: syncedItem.ratingKey,
|
||||
mediaType: TautulliMediaType.NULL.from(syncedItem.metadataType),
|
||||
),
|
||||
);
|
||||
Future<void> _onTap(BuildContext context) async => TautulliMediaDetailsRouter.navigateTo(context, ratingKey: syncedItem.ratingKey, mediaType: TautulliMediaType.NULL.from(syncedItem.metadataType));
|
||||
}
|
||||
|
||||
@@ -3,25 +3,56 @@ import 'package:flutter/material.dart' hide Router;
|
||||
import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
|
||||
class TautulliRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/:profile';
|
||||
class TautulliHomeRouter {
|
||||
static const ROUTE_NAME = '/tautulli';
|
||||
|
||||
@override
|
||||
State<TautulliRoute> createState() => _State();
|
||||
static Future<void> navigateTo(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(),
|
||||
);
|
||||
|
||||
static String route({ String profile }) {
|
||||
if(profile == null) return '/tautulli/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/$profile';
|
||||
static String route({ String profile }) => [
|
||||
ROUTE_NAME,
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
/// With profile defined
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliHomeRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0
|
||||
? params['profile'][0]
|
||||
: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
/// Without profile defined
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliHomeRoute(
|
||||
profile: null,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliRoute()),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
TautulliHomeRouter._();
|
||||
}
|
||||
|
||||
class _State extends State<TautulliRoute> {
|
||||
class _TautulliHomeRoute extends StatefulWidget {
|
||||
final String profile;
|
||||
|
||||
_TautulliHomeRoute({
|
||||
Key key,
|
||||
@required this.profile,
|
||||
}) : super(key: key);
|
||||
|
||||
@override
|
||||
State<_TautulliHomeRoute> createState() => _State();
|
||||
}
|
||||
|
||||
class _State extends State<_TautulliHomeRoute> {
|
||||
PageController _pageController;
|
||||
|
||||
@override
|
||||
|
||||
@@ -87,7 +87,7 @@ class _State extends State<TautulliNavigationBar> {
|
||||
? LSColors.accent
|
||||
: Colors.white,
|
||||
),
|
||||
showBadge: state.navigationIndex != 0 && snapshot.hasData && snapshot.data.streamCount > 0,
|
||||
showBadge: state.enabled && state.navigationIndex != 0 && snapshot.hasData && snapshot.data.streamCount > 0,
|
||||
),
|
||||
),
|
||||
),
|
||||
|
||||
@@ -104,8 +104,5 @@ class TautulliUserTile extends StatelessWidget {
|
||||
],
|
||||
);
|
||||
|
||||
Future<void> _enterDetails(BuildContext context) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
TautulliUserDetailsRoute.route(userId: user.userId),
|
||||
);
|
||||
Future<void> _enterDetails(BuildContext context) async => TautulliUserDetailsRouter.navigateTo(context, userId: user.userId);
|
||||
}
|
||||
|
||||
@@ -5,33 +5,61 @@ import 'package:lunasea/core.dart';
|
||||
import 'package:lunasea/modules/tautulli.dart';
|
||||
import 'package:tautulli/tautulli.dart';
|
||||
|
||||
class TautulliUserDetailsRoute extends StatefulWidget {
|
||||
static const String ROUTE_NAME = '/tautulli/users/details/:userid/:profile';
|
||||
final int userId;
|
||||
class TautulliUserDetailsRouter {
|
||||
static const String ROUTE_NAME = '/tautulli/users/details/:userid';
|
||||
|
||||
TautulliUserDetailsRoute({
|
||||
static Future<void> navigateTo(BuildContext context, {
|
||||
@required int userId,
|
||||
}) async => TautulliRouter.router.navigateTo(
|
||||
context,
|
||||
route(userId: userId),
|
||||
);
|
||||
|
||||
static String route({
|
||||
String profile,
|
||||
@required int userId,
|
||||
}) => [
|
||||
ROUTE_NAME.replaceFirst(':userid', userId.toString()),
|
||||
if(profile != null) '/$profile',
|
||||
].join();
|
||||
|
||||
static void defineRoutes(Router router) {
|
||||
router.define(
|
||||
ROUTE_NAME + '/:profile',
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliUserDetailsRoute(
|
||||
profile: params['profile'] != null && params['profile'].length != 0 ? params['profile'][0] : null,
|
||||
userId: int.tryParse(params['userid'][0]) ?? -1,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
router.define(
|
||||
ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => _TautulliUserDetailsRoute(
|
||||
profile: null,
|
||||
userId: int.tryParse(params['userid'][0]) ?? -1,
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
TautulliUserDetailsRouter._();
|
||||
}
|
||||
|
||||
class _TautulliUserDetailsRoute extends StatefulWidget {
|
||||
final int userId;
|
||||
final String profile;
|
||||
|
||||
_TautulliUserDetailsRoute({
|
||||
Key key,
|
||||
@required this.userId,
|
||||
@required this.profile,
|
||||
}): super(key: key);
|
||||
|
||||
@override
|
||||
State<StatefulWidget> createState() => _State();
|
||||
|
||||
static String route({ String profile, @required int userId }) {
|
||||
if(profile == null) return '/tautulli/users/details/$userId/${LunaSeaDatabaseValue.ENABLED_PROFILE.data}';
|
||||
return '/tautulli/users/details/$userId/$profile';
|
||||
}
|
||||
|
||||
static void defineRoute(Router router) => router.define(
|
||||
TautulliUserDetailsRoute.ROUTE_NAME,
|
||||
handler: Handler(handlerFunc: (context, params) => TautulliUserDetailsRoute(
|
||||
userId: int.tryParse(params['userid'][0]),
|
||||
)),
|
||||
transitionType: LunaRouter.transitionType,
|
||||
);
|
||||
}
|
||||
|
||||
class _State extends State<TautulliUserDetailsRoute> {
|
||||
class _State extends State<_TautulliUserDetailsRoute> {
|
||||
final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
|
||||
PageController _pageController;
|
||||
|
||||
@@ -82,7 +110,7 @@ class _State extends State<TautulliUserDetailsRoute> {
|
||||
if(snapshot.hasError) {
|
||||
if(snapshot.connectionState != ConnectionState.waiting) {
|
||||
Logger.error(
|
||||
'TautulliUserDetailsRoute',
|
||||
'_TautulliUserDetailsRoute',
|
||||
'_body',
|
||||
'Unable to pull Tautulli user table',
|
||||
snapshot.error,
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user