diff --git a/lib/core/ui/appbar.dart b/lib/core/ui/appbar.dart index 45b2970b..8fc8c118 100644 --- a/lib/core/ui/appbar.dart +++ b/lib/core/ui/appbar.dart @@ -3,7 +3,7 @@ import 'package:flutter/material.dart'; import 'package:flutter/services.dart'; import 'package:lunasea/core.dart'; -enum _APPBAR_TYPE { +enum _AppBarType { DEFAULT, EMPTY, DROPDOWN, @@ -12,7 +12,7 @@ enum _APPBAR_TYPE { class LunaAppBar extends StatefulWidget implements PreferredSizeWidget { static const APPBAR_HEIGHT = kToolbarHeight; - final _APPBAR_TYPE type; + final _AppBarType type; final String? title; final List? actions; final PreferredSizeWidget? bottom; @@ -76,7 +76,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget { scrollControllers: scrollControllers, hideLeading: hideLeading, backgroundColor: backgroundColor, - type: _APPBAR_TYPE.DEFAULT, + type: _AppBarType.DEFAULT, ); } @@ -102,7 +102,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget { height: height, useDrawer: false, backgroundColor: backgroundColor, - type: _APPBAR_TYPE.EMPTY, + type: _AppBarType.EMPTY, ); } @@ -137,7 +137,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget { pageController: pageController, scrollControllers: scrollControllers, backgroundColor: backgroundColor, - type: _APPBAR_TYPE.DEFAULT, + type: _AppBarType.DEFAULT, ); return LunaAppBar._internal( title: title, @@ -149,7 +149,7 @@ class LunaAppBar extends StatefulWidget implements PreferredSizeWidget { pageController: pageController, scrollControllers: scrollControllers, backgroundColor: backgroundColor, - type: _APPBAR_TYPE.DROPDOWN, + type: _AppBarType.DROPDOWN, ); } @@ -196,13 +196,13 @@ class _State extends State { Widget build(BuildContext context) { Widget child; switch (widget.type) { - case _APPBAR_TYPE.DEFAULT: + case _AppBarType.DEFAULT: child = _default(context); break; - case _APPBAR_TYPE.EMPTY: + case _AppBarType.EMPTY: child = _empty(context); break; - case _APPBAR_TYPE.DROPDOWN: + case _AppBarType.DROPDOWN: child = _dropdown(context); break; default: diff --git a/lib/core/ui/block/block.dart b/lib/core/ui/block/block.dart index 0fbdb149..a8619f5e 100644 --- a/lib/core/ui/block/block.dart +++ b/lib/core/ui/block/block.dart @@ -274,7 +274,7 @@ class LunaBlock extends StatelessWidget { context: context, title: _scrollableText( child: LunaText.title( - text: title!, + text: title ?? LunaUI.TEXT_EMDASH, color: titleColor, overflow: TextOverflow.visible, maxLines: 1, diff --git a/lib/modules/settings/core/router.dart b/lib/modules/settings/core/router.dart index 38953a4e..d96ca0ea 100644 --- a/lib/modules/settings/core/router.dart +++ b/lib/modules/settings/core/router.dart @@ -69,8 +69,10 @@ class SettingsRouter extends LunaModuleRouter { SettingsConfigurationTautulliHeadersRouter().defineRoute(router); // Configuration/Wake-on-LAN SettingsConfigurationWakeOnLANRouter().defineRoute(router); - // Other + // Debug Menu SettingsDebugMenuRouter().defineRoute(router); + SettingsSystemDebugMenuUIRouter().defineRoute(router); + // Other SettingsDonationsRouter().defineRoute(router); SettingsDonationsThankYouRouter().defineRoute(router); SettingsNotificationsRouter().defineRoute(router); diff --git a/lib/modules/settings/routes/debug_menu.dart b/lib/modules/settings/routes/debug_menu.dart index cc445150..29b72d9b 100644 --- a/lib/modules/settings/routes/debug_menu.dart +++ b/lib/modules/settings/routes/debug_menu.dart @@ -1 +1,2 @@ +export 'debug_menu/pages.dart'; export 'debug_menu/route.dart'; diff --git a/lib/modules/settings/routes/debug_menu/pages.dart b/lib/modules/settings/routes/debug_menu/pages.dart new file mode 100644 index 00000000..885658ef --- /dev/null +++ b/lib/modules/settings/routes/debug_menu/pages.dart @@ -0,0 +1 @@ +export 'pages/ui.dart'; diff --git a/lib/modules/settings/routes/debug_menu/pages/ui.dart b/lib/modules/settings/routes/debug_menu/pages/ui.dart new file mode 100644 index 00000000..b236ec49 --- /dev/null +++ b/lib/modules/settings/routes/debug_menu/pages/ui.dart @@ -0,0 +1,243 @@ +import 'package:fl_chart/fl_chart.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter/rendering.dart'; +import 'package:flutter/services.dart'; +import 'package:lunasea/core.dart'; +import 'package:lunasea/modules/settings.dart'; +import 'package:lunasea/modules/tautulli.dart'; + +class SettingsSystemDebugMenuUIRouter extends SettingsPageRouter { + SettingsSystemDebugMenuUIRouter() : super('/settings/debug_menu/ui'); + + @override + _Widget widget() => _Widget(); + + @override + void defineRoute(FluroRouter router) { + super.noParameterRouteDefinition(router); + } +} + +class _Widget extends StatefulWidget { + @override + State<_Widget> createState() => _State(); +} + +class _State extends State<_Widget> + with LunaScrollControllerMixin, TickerProviderStateMixin { + final GlobalKey _scaffoldKey = GlobalKey(); + late AnimationController _iconController; + late AnimationController _hideController; + bool _isFabVisible = true; + bool _isFabPaused = false; + + @override + void initState() { + super.initState(); + _setupIconController(); + _setupHideController(); + } + + @override + void dispose() { + _iconController.dispose(); + _hideController.dispose(); + scrollController.removeListener(scrollControllerListener); + super.dispose(); + } + + void scrollControllerListener() { + if (!scrollController.hasClients) return; + switch (scrollController.position.userScrollDirection) { + case ScrollDirection.forward: + if (!_isFabVisible) { + _hideController.forward(); + _isFabVisible = true; + } + break; + case ScrollDirection.reverse: + if (_isFabVisible) { + _hideController.reverse(); + _isFabVisible = false; + } + break; + case ScrollDirection.idle: + break; + } + } + + void _setupIconController() { + _iconController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: LunaUI.ANIMATION_SPEED), + ); + } + + void _setupHideController() { + _hideController = AnimationController( + vsync: this, + duration: const Duration(milliseconds: LunaUI.ANIMATION_SPEED), + ); + _hideController.forward(); + scrollController.addListener(scrollControllerListener); + } + + Future _toggle(BuildContext context) async { + HapticFeedback.lightImpact(); + _isFabPaused ? _iconController.reverse() : _iconController.forward(); + setState(() => _isFabPaused = !_isFabPaused); + } + + @override + Widget build(BuildContext context) { + return LunaScaffold( + scaffoldKey: _scaffoldKey, + appBar: _appBar() as PreferredSizeWidget?, + body: _body(), + floatingActionButton: _floatingActionButton(), + ); + } + + Widget _appBar() { + return LunaAppBar( + title: 'settings.DebugMenu'.tr(), + scrollControllers: [scrollController], + ); + } + + Widget _floatingActionButton() { + return ScaleTransition( + scale: _hideController, + child: InkWell( + child: LunaFloatingActionButtonAnimated( + controller: _iconController, + icon: AnimatedIcons.pause_play, + onPressed: () => _toggle(context), + ), + borderRadius: BorderRadius.circular(28.0), + ), + ); + } + + Widget _body() { + return LunaListView( + controller: scrollController, + children: [ + ..._lunaBlock(), + ..._tableContents(), + ..._graphs(), + ], + ); + } + + List _generateBody(int l) => + List.generate(l, (i) => TextSpan(text: 'Body ${i + 1}')); + + List _generateTableContent(int l) => List.generate(l, + (i) => LunaTableContent(title: 'Title ${i + 1}', body: 'Body ${i + 1}')); + + List _tableContents() { + return [ + LunaExpandableListTile( + title: 'Expandable 1', + collapsedSubtitles: _generateBody(2), + expandedTableContent: _generateTableContent(4), + collapsedTrailing: const LunaIconButton(icon: LunaIcons.ARROW_RIGHT), + ), + LunaTableCard(content: _generateTableContent(4)), + ]; + } + + List _lunaBlock() { + return [ + LunaBlock( + title: 'Title 1', + body: _generateBody(1), + bodyLeadingIcons: const [LunaIcons.DOWNLOAD], + leading: const LunaIconButton(icon: LunaIcons.ARROW_RIGHT), + trailing: const LunaIconButton(icon: LunaIcons.ARROW_RIGHT), + ), + LunaBlock( + disabled: true, + title: 'Title 1', + body: _generateBody(1), + bodyLeadingIcons: const [LunaIcons.DOWNLOAD], + leading: const LunaIconButton(icon: LunaIcons.ARROW_RIGHT), + trailing: const LunaIconButton(icon: LunaIcons.ARROW_RIGHT), + ), + const LunaBlock( + skeletonEnabled: true, + skeletonPoster: true, + skeletonSubtitles: 2, + ), + LunaBlock( + title: 'Title 1', + body: _generateBody(2), + posterPlaceholderIcon: LunaIcons.VIDEO_CAM, + posterUrl: TheMovieDB.getPosterURL('/qLX91FhHWCVrxDVsw0g2UD5c3Zk.jpg'), + backgroundUrl: + TheMovieDB.getPosterURL('/wR3ZbCWM55qbJBcIO7rHm0MB68j.jpg'), + onTap: () {}, + ), + ]; + } + + List _graphs() { + TautulliGraphData data = TautulliGraphData.fromJson(json.decode( + '{"categories":["2022-02-05","2022-02-06","2022-02-07","2022-02-08","2022-02-09","2022-02-10","2022-02-11","2022-02-12","2022-02-13","2022-02-14","2022-02-15","2022-02-16","2022-02-17","2022-02-18"],"series":[{"name":"Direct Play","data":[65,27,38,33,31,48,60,33,32,33,20,22,28,68]},{"name":"Direct Stream","data":[0,0,0,0,0,2,0,4,0,0,2,1,0,2]},{"name":"Transcode","data":[9,12,23,12,20,20,9,7,8,5,21,19,23,33]}]}', + )); + return [ + LunaCard( + context: context, + child: Column( + children: [ + SizedBox( + height: TautulliGraphHelper.GRAPH_HEIGHT, + width: MediaQuery.of(context).size.width, + child: Padding( + child: LineChart( + LineChartData( + gridData: TautulliGraphHelper().gridData(), + titlesData: TautulliLineGraphHelper.titlesData(data), + borderData: TautulliGraphHelper().borderData(), + lineBarsData: TautulliLineGraphHelper.lineBarsData(data), + lineTouchData: + TautulliLineGraphHelper.lineTouchData(context, data), + ), + ), + padding: LunaUI.MARGIN_DEFAULT, + ), + ), + TautulliGraphHelper().createLegend(data.series!), + ], + ), + ), + LunaCard( + context: context, + child: Column( + children: [ + SizedBox( + height: TautulliGraphHelper.GRAPH_HEIGHT, + width: MediaQuery.of(context).size.width, + child: Padding( + child: BarChart( + BarChartData( + alignment: TautulliGraphHelper().chartAlignment(), + gridData: TautulliGraphHelper().gridData(), + titlesData: TautulliGraphHelper().titlesData(data), + borderData: TautulliGraphHelper().borderData(), + barGroups: TautulliBarGraphHelper.barGroups(context, data), + barTouchData: + TautulliBarGraphHelper.barTouchData(context, data), + ), + ), + padding: LunaUI.MARGIN_DEFAULT, + ), + ), + TautulliGraphHelper().createLegend(data.series!), + ], + ), + ), + ]; + } +} diff --git a/lib/modules/settings/routes/debug_menu/route.dart b/lib/modules/settings/routes/debug_menu/route.dart index 89b0f284..e1469bd5 100644 --- a/lib/modules/settings/routes/debug_menu/route.dart +++ b/lib/modules/settings/routes/debug_menu/route.dart @@ -3,7 +3,7 @@ import 'package:lunasea/core.dart'; import 'package:lunasea/modules/settings.dart'; class SettingsDebugMenuRouter extends SettingsPageRouter { - SettingsDebugMenuRouter() : super('/settings/debugmenu'); + SettingsDebugMenuRouter() : super('/settings/debug_menu'); @override Widget widget() => _Widget(); @@ -33,7 +33,7 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { PreferredSizeWidget _appBar() { return LunaAppBar( - title: 'Debug Menu', + title: 'settings.DebugMenu'.tr(), scrollControllers: [scrollController], ); } @@ -42,6 +42,13 @@ class _State extends State<_Widget> with LunaScrollControllerMixin { return LunaListView( controller: scrollController, children: [ + LunaBlock( + title: 'UI', + trailing: const LunaIconButton(icon: LunaIcons.ARROW_RIGHT), + onTap: () async => + SettingsSystemDebugMenuUIRouter().navigateTo(context), + ), + const LunaHeader(text: 'Boxes'), LunaBlock( title: 'Clear Alerts Box', onTap: () async { diff --git a/pubspec.lock b/pubspec.lock index e8da7ad9..4efa0a07 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -687,7 +687,7 @@ packages: name: js url: "https://pub.dartlang.org" source: hosted - version: "0.6.4" + version: "0.6.3" json_annotation: dependency: "direct main" description: @@ -841,7 +841,7 @@ packages: name: path url: "https://pub.dartlang.org" source: hosted - version: "1.8.1" + version: "1.8.0" path_provider: dependency: "direct main" description: @@ -1492,5 +1492,5 @@ packages: source: hosted version: "3.1.0" sdks: - dart: ">=2.16.0-100.0.dev <3.0.0" + dart: ">=2.15.1 <3.0.0" flutter: ">=2.5.0"