From 183247035dce1bc407f8677cd07c34d692d06454 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 1 Jul 2024 15:06:11 -0400 Subject: [PATCH] removed view selection page in analytics --- assets/l10n/intl_en.arb | 3 +- lib/config/routes.dart | 53 +-- lib/pangea/enum/bar_chart_view_enum.dart | 11 - .../analytics/analytics_language_button.dart | 4 +- .../pages/analytics/analytics_list_tile.dart | 5 +- .../analytics/analytics_view_button.dart | 49 +++ .../pages/analytics/base_analytics.dart | 12 +- .../pages/analytics/base_analytics_view.dart | 379 +++++++----------- .../space_analytics/space_analytics.dart | 4 +- .../student_analytics/student_analytics.dart | 4 +- 10 files changed, 222 insertions(+), 302 deletions(-) create mode 100644 lib/pangea/pages/analytics/analytics_view_button.dart diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 964107cf8..7f44188a6 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4084,5 +4084,6 @@ "@interactiveTranslatorAutoPlayDesc": { "type": "text", "placeholders": {} - } + }, + "changeAnalyticsView": "Change Analytics View" } \ No newline at end of file diff --git a/lib/config/routes.dart b/lib/config/routes.dart index eba1ae511..51c631ff3 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -170,31 +170,11 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - const StudentAnalyticsPage(), + const StudentAnalyticsPage( + selectedView: BarChartViewSelection.messages, + ), ), redirect: loggedOutRedirect, - routes: [ - GoRoute( - path: 'messages', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const StudentAnalyticsPage( - selectedView: BarChartViewSelection.messages, - ), - ), - ), - GoRoute( - path: 'errors', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const StudentAnalyticsPage( - selectedView: BarChartViewSelection.grammar, - ), - ), - ), - ], ), GoRoute( path: 'analytics', @@ -207,34 +187,13 @@ abstract class AppRoutes { routes: [ GoRoute( path: ':spaceid', - redirect: loggedOutRedirect, pageBuilder: (context, state) => defaultPageBuilder( context, state, - const SpaceAnalyticsPage(), - ), - routes: [ - GoRoute( - path: 'messages', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const SpaceAnalyticsPage( - selectedView: BarChartViewSelection.messages, - ), - ), - ), - GoRoute( - path: 'errors', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const SpaceAnalyticsPage( - selectedView: BarChartViewSelection.grammar, - ), - ), + const SpaceAnalyticsPage( + selectedView: BarChartViewSelection.messages, ), - ], + ), ), ], ), diff --git a/lib/pangea/enum/bar_chart_view_enum.dart b/lib/pangea/enum/bar_chart_view_enum.dart index 3fe812634..aba0652af 100644 --- a/lib/pangea/enum/bar_chart_view_enum.dart +++ b/lib/pangea/enum/bar_chart_view_enum.dart @@ -29,15 +29,4 @@ extension BarChartViewSelectionExtension on BarChartViewSelection { return Icons.spellcheck_outlined; } } - - String get route { - switch (this) { - case BarChartViewSelection.messages: - return 'messages'; - // case BarChartViewSelection.vocab: - // return 'vocab'; - case BarChartViewSelection.grammar: - return 'errors'; - } - } } diff --git a/lib/pangea/pages/analytics/analytics_language_button.dart b/lib/pangea/pages/analytics/analytics_language_button.dart index 2c3923fb4..08b3220b0 100644 --- a/lib/pangea/pages/analytics/analytics_language_button.dart +++ b/lib/pangea/pages/analytics/analytics_language_button.dart @@ -34,9 +34,7 @@ class AnalyticsLanguageButton extends StatelessWidget { }).toList(), child: TextButton.icon( label: Text( - L10n.of(context)!.languageButtonLabel( - value.getDisplayName(context) ?? value.langCode, - ), + value.getDisplayName(context) ?? value.langCode, style: TextStyle( color: Theme.of(context).colorScheme.onSurface, ), diff --git a/lib/pangea/pages/analytics/analytics_list_tile.dart b/lib/pangea/pages/analytics/analytics_list_tile.dart index 8b1e1ba49..a49ef4cb4 100644 --- a/lib/pangea/pages/analytics/analytics_list_tile.dart +++ b/lib/pangea/pages/analytics/analytics_list_tile.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; -import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -141,9 +140,7 @@ class AnalyticsListTileState extends State { return; } if ((room?.isSpace ?? false) && widget.allowNavigateOnSelect) { - final String selectedView = - widget.controller!.widget.selectedView!.route; - context.go('/rooms/analytics/${room!.id}/$selectedView'); + context.go('/rooms/analytics/${room!.id}'); return; } widget.onTap(widget.selected); diff --git a/lib/pangea/pages/analytics/analytics_view_button.dart b/lib/pangea/pages/analytics/analytics_view_button.dart new file mode 100644 index 000000000..c98bf47fc --- /dev/null +++ b/lib/pangea/pages/analytics/analytics_view_button.dart @@ -0,0 +1,49 @@ +import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +class AnalyticsViewButton extends StatelessWidget { + final BarChartViewSelection value; + final void Function(BarChartViewSelection) onChange; + const AnalyticsViewButton({ + super.key, + required this.value, + required this.onChange, + }); + + @override + Widget build(BuildContext context) { + return PopupMenuButton( + tooltip: L10n.of(context)!.changeAnalyticsView, + initialValue: value, + onSelected: (BarChartViewSelection? view) { + if (view == null) { + debugPrint("when is view null?"); + return; + } + onChange(view); + }, + itemBuilder: (BuildContext context) => BarChartViewSelection.values + .map>( + (BarChartViewSelection view) { + return PopupMenuItem( + value: view, + child: Text(view.string(context)), + ); + }).toList(), + child: TextButton.icon( + label: Text( + value.string(context), + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + icon: Icon( + value.icon, + color: Theme.of(context).colorScheme.onSurface, + ), + onPressed: null, + ), + ); + } +} diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart index 146a5ac70..cd41d2312 100644 --- a/lib/pangea/pages/analytics/base_analytics.dart +++ b/lib/pangea/pages/analytics/base_analytics.dart @@ -20,7 +20,7 @@ import '../../models/analytics/chart_analytics_model.dart'; class BaseAnalyticsPage extends StatefulWidget { final String pageTitle; final List tabs; - final BarChartViewSelection? selectedView; + final BarChartViewSelection selectedView; final AnalyticsSelected defaultSelected; final AnalyticsSelected? alwaysSelected; @@ -33,7 +33,7 @@ class BaseAnalyticsPage extends StatefulWidget { required this.tabs, required this.alwaysSelected, required this.defaultSelected, - this.selectedView, + required this.selectedView, this.myAnalyticsController, targetLanguages, }) : targetLanguages = (targetLanguages?.isNotEmpty ?? false) @@ -50,6 +50,7 @@ class BaseAnalyticsController extends State { String? currentLemma; ChartAnalyticsModel? chartData; StreamController refreshStream = StreamController.broadcast(); + BarChartViewSelection currentView = BarChartViewSelection.messages; bool isSelected(String chatOrStudentId) => chatOrStudentId == selected?.id; @@ -63,6 +64,7 @@ class BaseAnalyticsController extends State { @override void initState() { super.initState(); + currentView = widget.selectedView; if (widget.defaultSelected.type == AnalyticsEntryType.student) { runFirstRefresh(); } @@ -168,6 +170,12 @@ class BaseAnalyticsController extends State { refreshStream.add(false); } + Future toggleView(BarChartViewSelection view) async { + currentView = view; + await setChartData(); + refreshStream.add(false); + } + void setCurrentLemma(String? lemma) { currentLemma = lemma; setState(() {}); diff --git a/lib/pangea/pages/analytics/base_analytics_view.dart b/lib/pangea/pages/analytics/base_analytics_view.dart index cca0c7f4e..13e49aa38 100644 --- a/lib/pangea/pages/analytics/base_analytics_view.dart +++ b/lib/pangea/pages/analytics/base_analytics_view.dart @@ -5,6 +5,7 @@ import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; import 'package:fluffychat/pangea/enum/time_span.dart'; import 'package:fluffychat/pangea/pages/analytics/analytics_language_button.dart'; import 'package:fluffychat/pangea/pages/analytics/analytics_list_tile.dart'; +import 'package:fluffychat/pangea/pages/analytics/analytics_view_button.dart'; import 'package:fluffychat/pangea/pages/analytics/base_analytics.dart'; import 'package:fluffychat/pangea/pages/analytics/construct_list.dart'; import 'package:fluffychat/pangea/pages/analytics/messages_bar_chart.dart'; @@ -24,11 +25,7 @@ class BaseAnalyticsView extends StatelessWidget { final BaseAnalyticsController controller; Widget chartView(BuildContext context) { - if (controller.widget.selectedView == null) { - return const SizedBox(); - } - - switch (controller.widget.selectedView!) { + switch (controller.currentView) { case BarChartViewSelection.messages: return MessagesBarChart( chartAnalytics: controller.chartData, @@ -75,27 +72,13 @@ class BaseAnalyticsView extends StatelessWidget { if (controller.activeSpace != null) TextSpan( text: controller.activeSpace!.getLocalizedDisplayname(), - style: const TextStyle(decoration: TextDecoration.underline), - recognizer: TapGestureRecognizer() - ..onTap = () { - if (controller.widget.selectedView == null) return; - String route = - "/rooms/${controller.widget.defaultSelected.type.route}"; - if (controller.widget.defaultSelected.type == - AnalyticsEntryType.space) { - route += "/${controller.widget.defaultSelected.id}"; - } - context.go(route); - }, - ), - if (controller.widget.selectedView != null) - const TextSpan( - text: " > ", - ), - if (controller.widget.selectedView != null) - TextSpan( - text: controller.widget.selectedView!.string(context), ), + const TextSpan( + text: " > ", + ), + TextSpan( + text: controller.currentView.string(context), + ), ], ), overflow: TextOverflow.ellipsis, @@ -104,220 +87,156 @@ class BaseAnalyticsView extends StatelessWidget { ), body: MaxWidthBody( withScrolling: false, - child: controller.widget.selectedView != null - ? Column( - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceEvenly, - children: [ - // if (controller.widget.defaultSelected.type == - // AnalyticsEntryType.student) - // IconButton( - // icon: const Icon(Icons.refresh), - // onPressed: controller.onRefresh, - // tooltip: L10n.of(context)!.refresh, - // ), - TimeSpanMenuButton( - value: controller.currentTimeSpan, - onChange: (TimeSpan value) => - controller.toggleTimeSpan(context, value), - ), - AnalyticsLanguageButton( - value: controller - .pangeaController.analytics.currentAnalyticsLang, - onChange: (lang) => controller.toggleSpaceLang(lang), - languages: controller.widget.targetLanguages, - ), - ], - ), - Expanded( - flex: 1, - child: chartView(context), - ), - Expanded( - flex: 1, - child: DefaultTabController( - length: 2, - child: Column( - children: [ - TabBar( - tabs: [ - ...controller.widget.tabs.map( - (tab) => Tab( - icon: Icon( - tab.icon, - color: Theme.of(context) - .colorScheme - .onSurfaceVariant, - ), - ), - ), - ], + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + TimeSpanMenuButton( + value: controller.currentTimeSpan, + onChange: (TimeSpan value) => + controller.toggleTimeSpan(context, value), + ), + AnalyticsViewButton( + value: controller.currentView, + onChange: controller.toggleView, + ), + AnalyticsLanguageButton( + value: controller + .pangeaController.analytics.currentAnalyticsLang, + onChange: (lang) => controller.toggleSpaceLang(lang), + languages: controller.widget.targetLanguages, + ), + ], + ), + const SizedBox( + height: 10, + ), + Expanded( + flex: 1, + child: chartView(context), + ), + Expanded( + flex: 1, + child: DefaultTabController( + length: 2, + child: Column( + children: [ + TabBar( + tabs: [ + ...controller.widget.tabs.map( + (tab) => Tab( + icon: Icon( + tab.icon, + color: Theme.of(context) + .colorScheme + .onSurfaceVariant, + ), ), - Expanded( - child: SingleChildScrollView( - child: SizedBox( - height: max( - controller.widget.tabs[0].items.length + - 1, - controller.widget.tabs[1].items.length, - ) * - 72, - child: TabBarView( - physics: const NeverScrollableScrollPhysics(), - children: [ - Column( - crossAxisAlignment: - CrossAxisAlignment.stretch, - children: [ - ...controller.widget.tabs[0].items.map( - (item) => AnalyticsListTile( - refreshStream: - controller.refreshStream, - avatar: item.avatar, - defaultSelected: controller - .widget.defaultSelected, - selected: AnalyticsSelected( - item.id, - controller.widget.tabs[0].type, - item.displayName, - ), - isSelected: - controller.isSelected(item.id), - onTap: (_) => - controller.toggleSelection( - AnalyticsSelected( - item.id, - controller.widget.tabs[0].type, - item.displayName, - ), - ), - allowNavigateOnSelect: controller - .widget - .tabs[0] - .allowNavigateOnSelect, - pangeaController: - controller.pangeaController, - controller: controller, - ), + ), + ], + ), + Expanded( + child: SingleChildScrollView( + child: SizedBox( + height: max( + controller.widget.tabs[0].items.length + 1, + controller.widget.tabs[1].items.length, + ) * + 72, + child: TabBarView( + physics: const NeverScrollableScrollPhysics(), + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ...controller.widget.tabs[0].items.map( + (item) => AnalyticsListTile( + refreshStream: controller.refreshStream, + avatar: item.avatar, + defaultSelected: + controller.widget.defaultSelected, + selected: AnalyticsSelected( + item.id, + controller.widget.tabs[0].type, + item.displayName, + ), + isSelected: + controller.isSelected(item.id), + onTap: (_) => controller.toggleSelection( + AnalyticsSelected( + item.id, + controller.widget.tabs[0].type, + item.displayName, ), - if (controller - .widget.defaultSelected.type == - AnalyticsEntryType.space) - AnalyticsListTile( - refreshStream: - controller.refreshStream, - defaultSelected: controller - .widget.defaultSelected, - avatar: null, - selected: AnalyticsSelected( - controller - .widget.defaultSelected.id, - AnalyticsEntryType.privateChats, - L10n.of(context)!.allPrivateChats, - ), - allowNavigateOnSelect: false, - isSelected: controller.isSelected( - controller - .widget.defaultSelected.id, - ), - onTap: controller.toggleSelection, - pangeaController: - controller.pangeaController, - controller: controller, - ), - ], + ), + allowNavigateOnSelect: controller + .widget.tabs[0].allowNavigateOnSelect, + pangeaController: + controller.pangeaController, + controller: controller, ), - Column( - crossAxisAlignment: - CrossAxisAlignment.stretch, - children: controller.widget.tabs[1].items - .map( - (item) => AnalyticsListTile( - refreshStream: - controller.refreshStream, - avatar: item.avatar, - defaultSelected: controller - .widget.defaultSelected, - selected: AnalyticsSelected( - item.id, - controller.widget.tabs[1].type, - item.displayName, - ), - isSelected: controller - .isSelected(item.id), - onTap: controller.toggleSelection, - allowNavigateOnSelect: controller - .widget - .tabs[1] - .allowNavigateOnSelect, - pangeaController: - controller.pangeaController, - controller: controller, - ), - ) - .toList(), + ), + if (controller.widget.defaultSelected.type == + AnalyticsEntryType.space) + AnalyticsListTile( + refreshStream: controller.refreshStream, + defaultSelected: + controller.widget.defaultSelected, + avatar: null, + selected: AnalyticsSelected( + controller.widget.defaultSelected.id, + AnalyticsEntryType.privateChats, + L10n.of(context)!.allPrivateChats, + ), + allowNavigateOnSelect: false, + isSelected: controller.isSelected( + controller.widget.defaultSelected.id, + ), + onTap: controller.toggleSelection, + pangeaController: + controller.pangeaController, + controller: controller, ), - ], - ), + ], ), - ), + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: controller.widget.tabs[1].items + .map( + (item) => AnalyticsListTile( + refreshStream: controller.refreshStream, + avatar: item.avatar, + defaultSelected: + controller.widget.defaultSelected, + selected: AnalyticsSelected( + item.id, + controller.widget.tabs[1].type, + item.displayName, + ), + isSelected: + controller.isSelected(item.id), + onTap: controller.toggleSelection, + allowNavigateOnSelect: controller.widget + .tabs[1].allowNavigateOnSelect, + pangeaController: + controller.pangeaController, + controller: controller, + ), + ) + .toList(), + ), + ], ), - ], + ), ), ), - ), - ], - ) - : Column( - children: [ - const Divider(height: 1), - ListTile( - title: Text(L10n.of(context)!.grammarAnalytics), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: - Theme.of(context).textTheme.bodyLarge!.color, - child: Icon(BarChartViewSelection.grammar.icon), - ), - trailing: const Icon(Icons.chevron_right), - onTap: () { - String route = - "/rooms/${controller.widget.defaultSelected.type.route}"; - if (controller.widget.defaultSelected.type == - AnalyticsEntryType.space) { - route += "/${controller.widget.defaultSelected.id}"; - } - route += "/${BarChartViewSelection.grammar.route}"; - context.go(route); - }, - ), - const Divider(height: 1), - ListTile( - title: Text(L10n.of(context)!.messageAnalytics), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: - Theme.of(context).textTheme.bodyLarge!.color, - child: Icon(BarChartViewSelection.messages.icon), - ), - trailing: const Icon(Icons.chevron_right), - onTap: () { - String route = - "/rooms/${controller.widget.defaultSelected.type.route}"; - if (controller.widget.defaultSelected.type == - AnalyticsEntryType.space) { - route += "/${controller.widget.defaultSelected.id}"; - } - route += "/${BarChartViewSelection.messages.route}"; - context.go(route); - }, - ), - const Divider(height: 1), - ], + ], + ), ), + ), + ], + ), ), ); } diff --git a/lib/pangea/pages/analytics/space_analytics/space_analytics.dart b/lib/pangea/pages/analytics/space_analytics/space_analytics.dart index b32780761..2db1acb4c 100644 --- a/lib/pangea/pages/analytics/space_analytics/space_analytics.dart +++ b/lib/pangea/pages/analytics/space_analytics/space_analytics.dart @@ -18,8 +18,8 @@ import '../../../utils/sync_status_util_v2.dart'; import 'space_analytics_view.dart'; class SpaceAnalyticsPage extends StatefulWidget { - final BarChartViewSelection? selectedView; - const SpaceAnalyticsPage({super.key, this.selectedView}); + final BarChartViewSelection selectedView; + const SpaceAnalyticsPage({super.key, required this.selectedView}); @override State createState() => SpaceAnalyticsV2Controller(); diff --git a/lib/pangea/pages/analytics/student_analytics/student_analytics.dart b/lib/pangea/pages/analytics/student_analytics/student_analytics.dart index 5c694b6ca..e06c6d0ba 100644 --- a/lib/pangea/pages/analytics/student_analytics/student_analytics.dart +++ b/lib/pangea/pages/analytics/student_analytics/student_analytics.dart @@ -18,8 +18,8 @@ import '../base_analytics.dart'; import 'student_analytics_view.dart'; class StudentAnalyticsPage extends StatefulWidget { - final BarChartViewSelection? selectedView; - const StudentAnalyticsPage({super.key, this.selectedView}); + final BarChartViewSelection selectedView; + const StudentAnalyticsPage({super.key, required this.selectedView}); @override State createState() => StudentAnalyticsController();