From a781b8c78c0e233755f48f4b10db1cec6039582e Mon Sep 17 00:00:00 2001 From: Gabby Gurdin Date: Wed, 6 Mar 2024 10:58:35 -0500 Subject: [PATCH 1/6] removed reference to google auth key in environment.dart --- lib/pangea/config/environment.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/pangea/config/environment.dart b/lib/pangea/config/environment.dart index c4a6a028d..a95b3db3d 100644 --- a/lib/pangea/config/environment.dart +++ b/lib/pangea/config/environment.dart @@ -35,12 +35,6 @@ class Environment { 'e6fa9fa97031ba0c852efe78457922f278a2fbc109752fe18e465337699e9873'; } - //Question for Jordan - does the client ever pass this to the server? - static String get googleAuthKey { - return dotenv.env['GOOGLE_AUTH_KEY'] ?? - '466850640825-qegdiq3mpj3h5e0e79ud5hnnq2c22mi3.apps.googleusercontent.com'; - } - static String get sentryDsn { return dotenv.env["SENTRY_DSN"] ?? 'https://c2fd19ab2cdc4ebb939a32d01c0e9fa1@o225078.ingest.sentry.io/1376295'; From 1623bdf00539ae0f26bdf4aafed5798dd1447caa Mon Sep 17 00:00:00 2001 From: Gabby Gurdin Date: Mon, 11 Mar 2024 12:07:10 -0400 Subject: [PATCH 2/6] refresh button tooltip + message explaining archive, direct chat with support on help button click, ability to purchase subscription if in trial --- assets/l10n/intl_en.arb | 5 +- assets/l10n/intl_es.arb | 5 +- lib/pages/chat_details/chat_details_view.dart | 40 +++++--- lib/pages/chat_list/space_view.dart | 23 ++++- lib/pages/settings/settings_view.dart | 31 ++++-- lib/pangea/config/environment.dart | 4 + lib/pangea/controllers/user_controller.dart | 1 + .../settings_subscription.dart | 11 ++- .../settings_subscription_view.dart | 96 ++++++++++--------- lib/pangea/repo/user_repo.dart | 2 + .../subscription/subscription_buttons.dart | 3 +- 11 files changed, 143 insertions(+), 78 deletions(-) diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 0a636a566..9b9204947 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3790,7 +3790,7 @@ } }, "freeTrialDesc": "New users recieve a one week free trial of Pangea Chat", - "activateTrial": "Activate Trial", + "activateTrial": "Activate Free Trial", "inNoSpaces": "You are not a member of any classes or exchanges", "successfullySubscribed": "You have successfully subscribed!", "clickToManageSubscription": "Click here to manage your subscription.", @@ -3948,5 +3948,6 @@ "age": {} } }, - "kickBotWarning": "Kicking Pangea Bot will remove the conversation bot from this chat." + "kickBotWarning": "Kicking Pangea Bot will remove the conversation bot from this chat.", + "refresh": "Refresh" } \ No newline at end of file diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index 791a07069..4f6ba040e 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -4469,7 +4469,6 @@ } }, "freeTrialDesc": "Los nuevos usuarios reciben una semana de prueba gratuita de Pangea Chat", - "activateTrial": "Activar prueba", "successfullySubscribed": "Se ha suscrito correctamente.", "clickToManageSubscription": "Haga clic aquí para gestionar su suscripción.", "emptyInviteWarning": "Añade este chat a una clase o intercambio para invitar a otros usuarios.", @@ -4582,5 +4581,7 @@ } }, "selectToDefine": "Haga doble clic en una palabra para ver su definición.", - "kickBotWarning": "Patear Pangea Bot eliminará el bot de conversación de este chat." + "kickBotWarning": "Patear Pangea Bot eliminará el bot de conversación de este chat.", + "activateTrial": "Activar prueba gratuita", + "refresh": "Actualizar" } diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index ca4816da0..434e1e41d 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -1,3 +1,4 @@ +import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat_details/chat_details.dart'; import 'package:fluffychat/pages/chat_details/participant_list_item.dart'; @@ -531,18 +532,33 @@ class ChatDetailsView extends StatelessWidget { Icons.archive_outlined, ), ), - onTap: () => showFutureLoadingDialog( - context: context, - future: () async { - room.isSpace - ? await archiveSpace( - room, - Matrix.of(context).client, - ) - : await room.leave(); - context.go('/rooms'); - }, - ), + onTap: () async { + final confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: + L10n.of(context)!.archiveRoomDescription, + ); + if (confirmed == OkCancelResult.ok) { + final success = await showFutureLoadingDialog( + context: context, + future: () async { + room.isSpace + ? await archiveSpace( + room, + Matrix.of(context).client, + ) + : await room.leave(); + }, + ); + if (success.error == null) { + context.go('/rooms'); + } + } + }, ), if (room.isRoomAdmin && !room.isDirectChat) SwitchListTile.adaptive( diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 417e1165c..906c3af71 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -523,12 +523,25 @@ class _SpaceViewState extends State { MatrixLocals(L10n.of(context)!), ), ), - trailing: IconButton( - icon: loading - ? const CircularProgressIndicator.adaptive(strokeWidth: 2) - : const Icon(Icons.refresh_outlined), - onPressed: loading ? null : _refresh, + // #Pangea + // trailing: IconButton( + // icon: loading + // ? const CircularProgressIndicator.adaptive(strokeWidth: 2) + // : const Icon(Icons.refresh_outlined), + // onPressed: loading ? null : _refresh, + // ), + trailing: Tooltip( + message: L10n.of(context)!.refresh, + child: IconButton( + icon: loading + ? const CircularProgressIndicator.adaptive( + strokeWidth: 2, + ) + : const Icon(Icons.refresh_outlined), + onPressed: loading ? null : _refresh, + ), ), + // Pangea# ), ), Builder( diff --git a/lib/pages/settings/settings_view.dart b/lib/pages/settings/settings_view.dart index 6025e480b..36766ea65 100644 --- a/lib/pages/settings/settings_view.dart +++ b/lib/pages/settings/settings_view.dart @@ -1,15 +1,15 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:go_router/go_router.dart'; -import 'package:matrix/matrix.dart'; -import 'package:url_launcher/url_launcher_string.dart'; - import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:future_loading_dialog/future_loading_dialog.dart'; +import 'package:go_router/go_router.dart'; +import 'package:matrix/matrix.dart'; +import 'package:url_launcher/url_launcher_string.dart'; + import 'settings.dart'; class SettingsView extends StatelessWidget { @@ -208,7 +208,22 @@ class SettingsView extends StatelessWidget { ListTile( leading: const Icon(Icons.help_outline_outlined), title: Text(L10n.of(context)!.help), - onTap: () => launchUrlString(AppConfig.supportUrl), + // #Pangea + // onTap: () => launchUrlString(AppConfig.supportUrl), + onTap: () async { + await showFutureLoadingDialog( + context: context, + future: () async { + final String roomId = + await Matrix.of(context).client.startDirectChat( + Environment.supportUserId, + enableEncryption: false, + ); + context.go('/rooms/$roomId'); + }, + ); + }, + // Pangea# trailing: const Icon(Icons.open_in_new_outlined), ), ListTile( diff --git a/lib/pangea/config/environment.dart b/lib/pangea/config/environment.dart index a95b3db3d..4d4378999 100644 --- a/lib/pangea/config/environment.dart +++ b/lib/pangea/config/environment.dart @@ -68,4 +68,8 @@ class Environment { return dotenv.env["STRIPE_MANAGEMENT_LINK"] ?? 'https://billing.stripe.com/p/login/dR6dSkf5p6rBc4EcMM'; } + + static String get supportUserId { + return isStaging ? '@support:staging.pangea.chat' : '@support:pangea.chat'; + } } diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index cff86c9de..e1b326eab 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -260,6 +260,7 @@ class UserController extends BaseController { final PUserModel newUserModel = await PUserRepo.repoCreatePangeaUser( userID: userId!, fullName: fullname, + dob: dob, matrixAccessToken: _matrixAccessToken!, ); await _savePUserModel(newUserModel); diff --git a/lib/pangea/pages/settings_subscription/settings_subscription.dart b/lib/pangea/pages/settings_subscription/settings_subscription.dart index b517d32a2..86c43ff47 100644 --- a/lib/pangea/pages/settings_subscription/settings_subscription.dart +++ b/lib/pangea/pages/settings_subscription/settings_subscription.dart @@ -85,7 +85,7 @@ class SubscriptionManagementController extends State { ""; bool get showManagementOptions { - if (!currentSubscriptionAvailable) { + if (!currentSubscriptionAvailable || isNewUserTrial) { return false; } if (subscriptionController.subscription!.purchasedOnWeb) { @@ -102,7 +102,9 @@ class SubscriptionManagementController extends State { context, isPromo: isPromo, ); - setState(() {}); + setState(() { + selectedSubscription = null; + }); } catch (err) { showOkAlertDialog( context: context, @@ -164,6 +166,11 @@ class SubscriptionManagementController extends State { setState(() => selectedSubscription = subscription); } + bool isCurrentSubscription(SubscriptionDetails subscription) => + subscriptionController.subscription?.currentSubscription == + subscription || + isNewUserTrial && subscription.isTrial; + @override Widget build(BuildContext context) => SettingsSubscriptionView(this); } diff --git a/lib/pangea/pages/settings_subscription/settings_subscription_view.dart b/lib/pangea/pages/settings_subscription/settings_subscription_view.dart index 5e0d1da3a..9d9f21bf7 100644 --- a/lib/pangea/pages/settings_subscription/settings_subscription_view.dart +++ b/lib/pangea/pages/settings_subscription/settings_subscription_view.dart @@ -13,6 +13,44 @@ class SettingsSubscriptionView extends StatelessWidget { @override Widget build(BuildContext context) { + final List managementButtons = [ + if (controller.currentSubscriptionAvailable) + ListTile( + title: Text(L10n.of(context)!.currentSubscription), + subtitle: Text(controller.currentSubscriptionTitle), + trailing: Text(controller.currentSubscriptionPrice), + ), + Column( + children: [ + ListTile( + title: Text(L10n.of(context)!.cancelSubscription), + enabled: controller.showManagementOptions, + onTap: () => controller.launchMangementUrl( + ManagementOption.cancel, + ), + trailing: const Icon(Icons.cancel_outlined), + ), + const Divider(height: 1), + ListTile( + title: Text(L10n.of(context)!.paymentMethod), + trailing: const Icon(Icons.credit_card), + onTap: () => controller.launchMangementUrl( + ManagementOption.paymentMethod, + ), + enabled: controller.showManagementOptions, + ), + ListTile( + title: Text(L10n.of(context)!.paymentHistory), + trailing: const Icon(Icons.keyboard_arrow_right_outlined), + onTap: () => controller.launchMangementUrl( + ManagementOption.history, + ), + enabled: controller.showManagementOptions, + ), + ], + ), + ]; + return Scaffold( appBar: AppBar( centerTitle: true, @@ -23,53 +61,19 @@ class SettingsSubscriptionView extends StatelessWidget { body: ListTileTheme( iconColor: Theme.of(context).textTheme.bodyLarge!.color, child: MaxWidthBody( - child: !(controller.subscriptionController.isSubscribed) - ? ChangeSubscription(controller: controller) - : Column( - children: [ - if (controller.currentSubscriptionAvailable) - ListTile( - title: Text(L10n.of(context)!.currentSubscription), - subtitle: Text(controller.currentSubscriptionTitle), - trailing: Text(controller.currentSubscriptionPrice), - ), - Column( - children: [ - ListTile( - title: Text(L10n.of(context)!.cancelSubscription), - enabled: controller.showManagementOptions, - onTap: () => controller.launchMangementUrl( - ManagementOption.cancel, - ), - trailing: const Icon(Icons.cancel_outlined), - ), - const Divider(height: 1), - ListTile( - title: Text(L10n.of(context)!.paymentMethod), - trailing: const Icon(Icons.credit_card), - onTap: () => controller.launchMangementUrl( - ManagementOption.paymentMethod, - ), - enabled: controller.showManagementOptions, - ), - ListTile( - title: Text(L10n.of(context)!.paymentHistory), - trailing: - const Icon(Icons.keyboard_arrow_right_outlined), - onTap: () => controller.launchMangementUrl( - ManagementOption.history, - ), - enabled: controller.showManagementOptions, - ), - ], - ), - const SizedBox(height: 50), - if (!(controller.showManagementOptions)) - ManagementNotAvailableWarning( - controller: controller, - ), - ], + child: Column( + children: [ + if (controller.subscriptionController.isSubscribed && + !controller.showManagementOptions) + ManagementNotAvailableWarning( + controller: controller, ), + if (!(controller.subscriptionController.isSubscribed) || + controller.isNewUserTrial) + ChangeSubscription(controller: controller), + if (controller.showManagementOptions) ...managementButtons, + ], + ), ), ), ); diff --git a/lib/pangea/repo/user_repo.dart b/lib/pangea/repo/user_repo.dart index 70ab06704..8f3b5a67f 100644 --- a/lib/pangea/repo/user_repo.dart +++ b/lib/pangea/repo/user_repo.dart @@ -13,6 +13,7 @@ import '../network/urls.dart'; class PUserRepo { static Future repoCreatePangeaUser({ required String userID, + required String dob, required fullName, required String matrixAccessToken, }) async { @@ -24,6 +25,7 @@ class PUserRepo { final Map body = { ModelKey.userFullName: fullName, ModelKey.userPangeaUserId: userID, + ModelKey.userDateOfBirth: dob, }; final Response res = await req.post( url: PApiUrls.createUser, diff --git a/lib/pangea/widgets/subscription/subscription_buttons.dart b/lib/pangea/widgets/subscription/subscription_buttons.dart index 9292e41a4..2af95056a 100644 --- a/lib/pangea/widgets/subscription/subscription_buttons.dart +++ b/lib/pangea/widgets/subscription/subscription_buttons.dart @@ -40,7 +40,8 @@ class SubscriptionButtons extends StatelessWidget { selected: controller.selectedSubscription == subscription, selectedTileColor: Theme.of(context).colorScheme.secondary.withAlpha(16), - enabled: !subscription.isTrial || inTrialWindow, + enabled: (!subscription.isTrial || inTrialWindow) && + !controller.isCurrentSubscription(subscription), onTap: () { controller.selectSubscription(subscription); }, From 64c502b6fa3438ac8c7e8f850301fae534997f22 Mon Sep 17 00:00:00 2001 From: Gabby Gurdin Date: Mon, 18 Mar 2024 11:08:38 -0400 Subject: [PATCH 3/6] temp fix for iOS database build errors --- .../pages/analytics/base_analytics.dart | 177 ++++++++++++++ .../pages/analytics/base_analytics_view.dart | 227 ++++++++++++++++++ lib/utils/client_manager.dart | 5 +- .../flutter_matrix_sdk_database_builder.dart | 42 ++-- 4 files changed, 427 insertions(+), 24 deletions(-) create mode 100644 lib/pangea/pages/analytics/base_analytics.dart create mode 100644 lib/pangea/pages/analytics/base_analytics_view.dart diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart new file mode 100644 index 000000000..32f17ca0b --- /dev/null +++ b/lib/pangea/pages/analytics/base_analytics.dart @@ -0,0 +1,177 @@ +import 'dart:async'; + +import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; +import 'package:fluffychat/pangea/pages/analytics/base_analytics_view.dart'; +import 'package:fluffychat/pangea/pages/analytics/student_analytics/student_analytics.dart'; +import 'package:flutter/material.dart'; +import 'package:matrix/matrix.dart'; + +import '../../../widgets/matrix.dart'; +import '../../controllers/pangea_controller.dart'; +import '../../enum/bar_chart_view_enum.dart'; +import '../../enum/time_span.dart'; +import '../../models/chart_analytics_model.dart'; + +class BaseAnalyticsPage extends StatefulWidget { + final String pageTitle; + final List tabs; + final Future Function(BuildContext) refreshData; + + final AnalyticsSelected defaultSelected; + final AnalyticsSelected? alwaysSelected; + final StudentAnalyticsController? myAnalyticsController; + + const BaseAnalyticsPage({ + super.key, + required this.pageTitle, + required this.tabs, + required this.refreshData, + required this.alwaysSelected, + required this.defaultSelected, + this.myAnalyticsController, + }); + + @override + State createState() => BaseAnalyticsController(); +} + +class BaseAnalyticsController extends State { + final PangeaController pangeaController = MatrixState.pangeaController; + BarChartViewSelection selectedView = BarChartViewSelection.grammar; + AnalyticsSelected? selected; + String? currentLemma; + + bool isSelected(String chatOrStudentId) => chatOrStudentId == selected?.id; + + ChartAnalyticsModel? chartData( + BuildContext context, + AnalyticsSelected? selectedParam, + ) { + final AnalyticsSelected analyticsSelected = + selectedParam ?? widget.defaultSelected; + + if (analyticsSelected.type == AnalyticsEntryType.privateChats) { + return pangeaController.analytics.getAnalyticsLocal( + classId: analyticsSelected.id, + chatId: AnalyticsEntryType.privateChats.toString(), + ); + } + + String? chatId = analyticsSelected.type == AnalyticsEntryType.room + ? analyticsSelected.id + : null; + chatId ??= widget.alwaysSelected?.type == AnalyticsEntryType.room + ? widget.alwaysSelected?.id + : null; + + String? studentId = analyticsSelected.type == AnalyticsEntryType.student + ? analyticsSelected.id + : null; + studentId ??= widget.alwaysSelected?.type == AnalyticsEntryType.student + ? widget.alwaysSelected?.id + : null; + + String? classId = analyticsSelected.type == AnalyticsEntryType.space + ? analyticsSelected.id + : null; + classId ??= widget.alwaysSelected?.type == AnalyticsEntryType.space + ? widget.alwaysSelected?.id + : null; + + final data = pangeaController.analytics.getAnalyticsLocal( + classId: classId, + chatId: chatId, + studentId: studentId, + ); + + return data; + } + + String get barTitle => + "${selectedView.string(context)}: ${selected == null ? widget.defaultSelected.displayName : selected!.displayName}${currentLemma != null ? ' - $currentLemma' : ''}"; + + TimeSpan get currentTimeSpan => + pangeaController.analytics.currentAnalyticsTimeSpan; + + void navigate() { + currentLemma == null + ? Navigator.of(context).pop() + : setState(() => currentLemma = null); + } + + void toggleSelection(AnalyticsSelected selectedParam) { + setState(() { + debugPrint("selectedParam.id is ${selectedParam.id}"); + selected = isSelected(selectedParam.id) ? null : selectedParam; + }); + pangeaController.analytics.setConstructs( + constructType: ConstructType.grammar, + defaultSelected: widget.defaultSelected, + selected: selected, + removeIT: true, + ); + Future.delayed(Duration.zero, () => setState(() {})); + } + + void toggleTimeSpan(BuildContext context, TimeSpan timeSpan) { + pangeaController.analytics.setCurrentAnalyticsTimeSpan(timeSpan); + setState(() {}); + widget.refreshData(context).then((value) => setState(() {})); + } + + void toggleSelectedView(BarChartViewSelection view) { + selectedView = view; + if (!enableSelection(selected)) { + toggleSelection(selected!); + } + setState(() {}); + } + + bool enableSelection(AnalyticsSelected? selectedParam) { + return selectedView == BarChartViewSelection.grammar && + selectedParam?.type == AnalyticsEntryType.room + ? Matrix.of(context) + .client + .getRoomById(selectedParam!.id) + ?.membership == + Membership.join + : true; + } + + @override + Widget build(BuildContext context) { + return BaseAnalyticsView(controller: this); + } +} + +class TabData { + AnalyticsEntryType type; + IconData icon; + List items; + bool allowNavigateOnSelect; + + TabData({ + required this.type, + required this.items, + required this.icon, + this.allowNavigateOnSelect = true, + }); +} + +class TabItem { + Uri? avatar; + String displayName; + String id; + + TabItem({required this.avatar, required this.displayName, required this.id}); +} + +enum AnalyticsEntryType { student, room, space, privateChats } + +class AnalyticsSelected { + String id; + AnalyticsEntryType type; + String displayName; + + AnalyticsSelected(this.id, this.type, this.displayName); +} diff --git a/lib/pangea/pages/analytics/base_analytics_view.dart b/lib/pangea/pages/analytics/base_analytics_view.dart new file mode 100644 index 000000000..7b98df66e --- /dev/null +++ b/lib/pangea/pages/analytics/base_analytics_view.dart @@ -0,0 +1,227 @@ +import 'dart:math'; + +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart'; +import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; +import 'package:fluffychat/pangea/enum/time_span.dart'; +import 'package:fluffychat/pangea/pages/analytics/analytics_list_tile.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'; +import 'package:fluffychat/pangea/pages/analytics/time_span_menu_button.dart'; +import 'package:fluffychat/widgets/layouts/max_width_body.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +class BaseAnalyticsView extends StatelessWidget { + const BaseAnalyticsView({ + super.key, + required this.controller, + }); + + final BaseAnalyticsController controller; + + Widget chartView(BuildContext context) { + switch (controller.selectedView) { + case BarChartViewSelection.messages: + return MessagesBarChart( + chartAnalytics: controller.chartData( + context, + controller.selected, + ), + barChartTitle: controller.barTitle, + ); + case BarChartViewSelection.grammar: + return ConstructList( + constructType: ConstructType.grammar, + title: controller.barTitle, + defaultSelected: controller.widget.defaultSelected, + selected: controller.selected, + controller: controller, + pangeaController: controller.pangeaController, + ); + } + } + + @override + Widget build(BuildContext context) { + return Scaffold( + appBar: AppBar( + centerTitle: true, + title: Text( + controller.widget.pageTitle, + style: TextStyle( + color: Theme.of(context).textTheme.bodyLarge!.color, + fontSize: 18, + fontWeight: FontWeight.w700, + ), + overflow: TextOverflow.clip, + textAlign: TextAlign.center, + ), + leading: IconButton( + icon: const Icon(Icons.arrow_back), + onPressed: controller.navigate, + ), + actions: [ + for (final view in BarChartViewSelection.values) + Container( + decoration: BoxDecoration( + shape: BoxShape.circle, + color: controller.selectedView == view + ? AppConfig.primaryColor + : null, + ), + child: IconButton( + isSelected: controller.selectedView == view, + icon: Icon(view.icon), + tooltip: view.string(context), + onPressed: () => controller.toggleSelectedView(view), + ), + ), + TimeSpanMenuButton( + value: controller.currentTimeSpan, + onChange: (TimeSpan value) => + controller.toggleTimeSpan(context, value), + ), + ], + ), + body: MaxWidthBody( + withScrolling: false, + child: Column( + children: [ + 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( + children: [ + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + ...controller.widget.tabs[0].items.map( + (item) => AnalyticsListTile( + avatar: item.avatar, + model: controller.chartData( + context, + AnalyticsSelected( + item.id, + controller.widget.tabs[0].type, + "", + ), + ), + displayName: item.displayName, + id: item.id, + type: controller.widget.tabs[0].type, + selected: controller.isSelected(item.id), + enabled: controller.enableSelection( + AnalyticsSelected( + item.id, + controller.widget.tabs[0].type, + "", + ), + ), + showSpaceAnalytics: false, + onTap: (_) => controller.toggleSelection( + AnalyticsSelected( + item.id, + controller.widget.tabs[0].type, + item.displayName, + ), + ), + allowNavigateOnSelect: controller + .widget.tabs[0].allowNavigateOnSelect, + ), + ), + if (controller.widget.defaultSelected.type == + AnalyticsEntryType.space) + AnalyticsListTile( + avatar: null, + model: controller.chartData( + context, + AnalyticsSelected( + controller.widget.defaultSelected.id, + AnalyticsEntryType.privateChats, + L10n.of(context)!.allPrivateChats, + ), + ), + displayName: + L10n.of(context)!.allPrivateChats, + id: controller.widget.defaultSelected.id, + type: AnalyticsEntryType.privateChats, + allowNavigateOnSelect: false, + selected: controller.isSelected( + controller.widget.defaultSelected.id, + ), + onTap: controller.toggleSelection, + ), + ], + ), + Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: controller.widget.tabs[1].items + .map( + (item) => AnalyticsListTile( + avatar: item.avatar, + model: controller.chartData( + context, + AnalyticsSelected( + item.id, + controller.widget.tabs[1].type, + "", + ), + ), + displayName: item.displayName, + id: item.id, + type: controller.widget.tabs[1].type, + selected: + controller.isSelected(item.id), + onTap: controller.toggleSelection, + allowNavigateOnSelect: controller.widget + .tabs[1].allowNavigateOnSelect, + ), + ) + .toList(), + ), + ], + ), + ), + ), + ), + ], + ), + ), + ), + ], + ), + ), + ); + } +} diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart index 52f6a968c..0d9cbee90 100644 --- a/lib/utils/client_manager.dart +++ b/lib/utils/client_manager.dart @@ -6,7 +6,6 @@ import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/utils/custom_http_client.dart'; import 'package:fluffychat/utils/custom_image_resizer.dart'; import 'package:fluffychat/utils/init_with_restore.dart'; -import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter_local_notifications/flutter_local_notifications.dart'; @@ -122,7 +121,9 @@ abstract class ClientManager { }, logLevel: kReleaseMode ? Level.warning : Level.verbose, databaseBuilder: flutterMatrixSdkDatabaseBuilder, - legacyDatabaseBuilder: FlutterHiveCollectionsDatabase.databaseBuilder, + // #Pangea + // legacyDatabaseBuilder: FlutterHiveCollectionsDatabase.databaseBuilder, + // Pangea# supportedLoginTypes: { AuthenticationTypes.password, AuthenticationTypes.sso, diff --git a/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart b/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart index 3cc80e82e..447a3e45a 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart @@ -1,10 +1,10 @@ import 'dart:convert'; import 'dart:math'; +import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:flutter_secure_storage/flutter_secure_storage.dart'; import 'package:matrix/matrix.dart'; import 'package:path_provider/path_provider.dart'; @@ -12,36 +12,34 @@ import 'package:sqflite_common_ffi/sqflite_ffi.dart' as ffi; import 'package:sqflite_sqlcipher/sqflite.dart'; import 'package:universal_html/html.dart' as html; -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/utils/client_manager.dart'; -import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; - Future flutterMatrixSdkDatabaseBuilder(Client client) async { MatrixSdkDatabase? database; try { database = await _constructDatabase(client); + // throw "error"; await database.open(); return database; } catch (e) { + // #Pangea // Try to delete database so that it can created again on next init: - database?.delete().catchError( - (e, s) => Logs().w( - 'Unable to delete database, after failed construction', - e, - s, - ), - ); + // database?.delete().catchError( + // (e, s) => Logs().w( + // 'Unable to delete database, after failed construction', + // e, + // s, + // ), + // ); // Send error notification: - final l10n = lookupL10n(PlatformDispatcher.instance.locale); - ClientManager.sendInitNotification( - l10n.initAppError, - l10n.databaseBuildErrorBody( - AppConfig.newIssueUrl.toString(), - e.toString(), - ), - ); + // final l10n = lookupL10n(PlatformDispatcher.instance.locale); + // ClientManager.sendInitNotification( + // l10n.initAppError, + // l10n.databaseBuildErrorBody( + // AppConfig.newIssueUrl.toString(), + // e.toString(), + // ), + // ); + // Pangea# return FlutterHiveCollectionsDatabase.databaseBuilder(client); } From ee3a92b9c04458eafbbbcfb2a2e543e6d88d9c5a Mon Sep 17 00:00:00 2001 From: Gabby Gurdin Date: Mon, 18 Mar 2024 11:14:54 -0400 Subject: [PATCH 4/6] removed accidently commited code files --- .../pages/analytics/base_analytics.dart | 177 -------------- .../pages/analytics/base_analytics_view.dart | 227 ------------------ 2 files changed, 404 deletions(-) delete mode 100644 lib/pangea/pages/analytics/base_analytics.dart delete mode 100644 lib/pangea/pages/analytics/base_analytics_view.dart diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart deleted file mode 100644 index 32f17ca0b..000000000 --- a/lib/pangea/pages/analytics/base_analytics.dart +++ /dev/null @@ -1,177 +0,0 @@ -import 'dart:async'; - -import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; -import 'package:fluffychat/pangea/pages/analytics/base_analytics_view.dart'; -import 'package:fluffychat/pangea/pages/analytics/student_analytics/student_analytics.dart'; -import 'package:flutter/material.dart'; -import 'package:matrix/matrix.dart'; - -import '../../../widgets/matrix.dart'; -import '../../controllers/pangea_controller.dart'; -import '../../enum/bar_chart_view_enum.dart'; -import '../../enum/time_span.dart'; -import '../../models/chart_analytics_model.dart'; - -class BaseAnalyticsPage extends StatefulWidget { - final String pageTitle; - final List tabs; - final Future Function(BuildContext) refreshData; - - final AnalyticsSelected defaultSelected; - final AnalyticsSelected? alwaysSelected; - final StudentAnalyticsController? myAnalyticsController; - - const BaseAnalyticsPage({ - super.key, - required this.pageTitle, - required this.tabs, - required this.refreshData, - required this.alwaysSelected, - required this.defaultSelected, - this.myAnalyticsController, - }); - - @override - State createState() => BaseAnalyticsController(); -} - -class BaseAnalyticsController extends State { - final PangeaController pangeaController = MatrixState.pangeaController; - BarChartViewSelection selectedView = BarChartViewSelection.grammar; - AnalyticsSelected? selected; - String? currentLemma; - - bool isSelected(String chatOrStudentId) => chatOrStudentId == selected?.id; - - ChartAnalyticsModel? chartData( - BuildContext context, - AnalyticsSelected? selectedParam, - ) { - final AnalyticsSelected analyticsSelected = - selectedParam ?? widget.defaultSelected; - - if (analyticsSelected.type == AnalyticsEntryType.privateChats) { - return pangeaController.analytics.getAnalyticsLocal( - classId: analyticsSelected.id, - chatId: AnalyticsEntryType.privateChats.toString(), - ); - } - - String? chatId = analyticsSelected.type == AnalyticsEntryType.room - ? analyticsSelected.id - : null; - chatId ??= widget.alwaysSelected?.type == AnalyticsEntryType.room - ? widget.alwaysSelected?.id - : null; - - String? studentId = analyticsSelected.type == AnalyticsEntryType.student - ? analyticsSelected.id - : null; - studentId ??= widget.alwaysSelected?.type == AnalyticsEntryType.student - ? widget.alwaysSelected?.id - : null; - - String? classId = analyticsSelected.type == AnalyticsEntryType.space - ? analyticsSelected.id - : null; - classId ??= widget.alwaysSelected?.type == AnalyticsEntryType.space - ? widget.alwaysSelected?.id - : null; - - final data = pangeaController.analytics.getAnalyticsLocal( - classId: classId, - chatId: chatId, - studentId: studentId, - ); - - return data; - } - - String get barTitle => - "${selectedView.string(context)}: ${selected == null ? widget.defaultSelected.displayName : selected!.displayName}${currentLemma != null ? ' - $currentLemma' : ''}"; - - TimeSpan get currentTimeSpan => - pangeaController.analytics.currentAnalyticsTimeSpan; - - void navigate() { - currentLemma == null - ? Navigator.of(context).pop() - : setState(() => currentLemma = null); - } - - void toggleSelection(AnalyticsSelected selectedParam) { - setState(() { - debugPrint("selectedParam.id is ${selectedParam.id}"); - selected = isSelected(selectedParam.id) ? null : selectedParam; - }); - pangeaController.analytics.setConstructs( - constructType: ConstructType.grammar, - defaultSelected: widget.defaultSelected, - selected: selected, - removeIT: true, - ); - Future.delayed(Duration.zero, () => setState(() {})); - } - - void toggleTimeSpan(BuildContext context, TimeSpan timeSpan) { - pangeaController.analytics.setCurrentAnalyticsTimeSpan(timeSpan); - setState(() {}); - widget.refreshData(context).then((value) => setState(() {})); - } - - void toggleSelectedView(BarChartViewSelection view) { - selectedView = view; - if (!enableSelection(selected)) { - toggleSelection(selected!); - } - setState(() {}); - } - - bool enableSelection(AnalyticsSelected? selectedParam) { - return selectedView == BarChartViewSelection.grammar && - selectedParam?.type == AnalyticsEntryType.room - ? Matrix.of(context) - .client - .getRoomById(selectedParam!.id) - ?.membership == - Membership.join - : true; - } - - @override - Widget build(BuildContext context) { - return BaseAnalyticsView(controller: this); - } -} - -class TabData { - AnalyticsEntryType type; - IconData icon; - List items; - bool allowNavigateOnSelect; - - TabData({ - required this.type, - required this.items, - required this.icon, - this.allowNavigateOnSelect = true, - }); -} - -class TabItem { - Uri? avatar; - String displayName; - String id; - - TabItem({required this.avatar, required this.displayName, required this.id}); -} - -enum AnalyticsEntryType { student, room, space, privateChats } - -class AnalyticsSelected { - String id; - AnalyticsEntryType type; - String displayName; - - AnalyticsSelected(this.id, this.type, this.displayName); -} diff --git a/lib/pangea/pages/analytics/base_analytics_view.dart b/lib/pangea/pages/analytics/base_analytics_view.dart deleted file mode 100644 index 7b98df66e..000000000 --- a/lib/pangea/pages/analytics/base_analytics_view.dart +++ /dev/null @@ -1,227 +0,0 @@ -import 'dart:math'; - -import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart'; -import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; -import 'package:fluffychat/pangea/enum/time_span.dart'; -import 'package:fluffychat/pangea/pages/analytics/analytics_list_tile.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'; -import 'package:fluffychat/pangea/pages/analytics/time_span_menu_button.dart'; -import 'package:fluffychat/widgets/layouts/max_width_body.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; - -class BaseAnalyticsView extends StatelessWidget { - const BaseAnalyticsView({ - super.key, - required this.controller, - }); - - final BaseAnalyticsController controller; - - Widget chartView(BuildContext context) { - switch (controller.selectedView) { - case BarChartViewSelection.messages: - return MessagesBarChart( - chartAnalytics: controller.chartData( - context, - controller.selected, - ), - barChartTitle: controller.barTitle, - ); - case BarChartViewSelection.grammar: - return ConstructList( - constructType: ConstructType.grammar, - title: controller.barTitle, - defaultSelected: controller.widget.defaultSelected, - selected: controller.selected, - controller: controller, - pangeaController: controller.pangeaController, - ); - } - } - - @override - Widget build(BuildContext context) { - return Scaffold( - appBar: AppBar( - centerTitle: true, - title: Text( - controller.widget.pageTitle, - style: TextStyle( - color: Theme.of(context).textTheme.bodyLarge!.color, - fontSize: 18, - fontWeight: FontWeight.w700, - ), - overflow: TextOverflow.clip, - textAlign: TextAlign.center, - ), - leading: IconButton( - icon: const Icon(Icons.arrow_back), - onPressed: controller.navigate, - ), - actions: [ - for (final view in BarChartViewSelection.values) - Container( - decoration: BoxDecoration( - shape: BoxShape.circle, - color: controller.selectedView == view - ? AppConfig.primaryColor - : null, - ), - child: IconButton( - isSelected: controller.selectedView == view, - icon: Icon(view.icon), - tooltip: view.string(context), - onPressed: () => controller.toggleSelectedView(view), - ), - ), - TimeSpanMenuButton( - value: controller.currentTimeSpan, - onChange: (TimeSpan value) => - controller.toggleTimeSpan(context, value), - ), - ], - ), - body: MaxWidthBody( - withScrolling: false, - child: Column( - children: [ - 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( - children: [ - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - ...controller.widget.tabs[0].items.map( - (item) => AnalyticsListTile( - avatar: item.avatar, - model: controller.chartData( - context, - AnalyticsSelected( - item.id, - controller.widget.tabs[0].type, - "", - ), - ), - displayName: item.displayName, - id: item.id, - type: controller.widget.tabs[0].type, - selected: controller.isSelected(item.id), - enabled: controller.enableSelection( - AnalyticsSelected( - item.id, - controller.widget.tabs[0].type, - "", - ), - ), - showSpaceAnalytics: false, - onTap: (_) => controller.toggleSelection( - AnalyticsSelected( - item.id, - controller.widget.tabs[0].type, - item.displayName, - ), - ), - allowNavigateOnSelect: controller - .widget.tabs[0].allowNavigateOnSelect, - ), - ), - if (controller.widget.defaultSelected.type == - AnalyticsEntryType.space) - AnalyticsListTile( - avatar: null, - model: controller.chartData( - context, - AnalyticsSelected( - controller.widget.defaultSelected.id, - AnalyticsEntryType.privateChats, - L10n.of(context)!.allPrivateChats, - ), - ), - displayName: - L10n.of(context)!.allPrivateChats, - id: controller.widget.defaultSelected.id, - type: AnalyticsEntryType.privateChats, - allowNavigateOnSelect: false, - selected: controller.isSelected( - controller.widget.defaultSelected.id, - ), - onTap: controller.toggleSelection, - ), - ], - ), - Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: controller.widget.tabs[1].items - .map( - (item) => AnalyticsListTile( - avatar: item.avatar, - model: controller.chartData( - context, - AnalyticsSelected( - item.id, - controller.widget.tabs[1].type, - "", - ), - ), - displayName: item.displayName, - id: item.id, - type: controller.widget.tabs[1].type, - selected: - controller.isSelected(item.id), - onTap: controller.toggleSelection, - allowNavigateOnSelect: controller.widget - .tabs[1].allowNavigateOnSelect, - ), - ) - .toList(), - ), - ], - ), - ), - ), - ), - ], - ), - ), - ), - ], - ), - ), - ); - } -} From 97fc7a176d0306c86b52ac408aceef4ee11db49b Mon Sep 17 00:00:00 2001 From: Gabby Gurdin Date: Mon, 18 Mar 2024 11:16:19 -0400 Subject: [PATCH 5/6] error logging --- .../flutter_matrix_sdk_database_builder.dart | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart b/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart index 447a3e45a..555cec635 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart @@ -1,6 +1,7 @@ import 'dart:convert'; import 'dart:math'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/flutter_hive_collections_database.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/foundation.dart'; @@ -21,6 +22,11 @@ Future flutterMatrixSdkDatabaseBuilder(Client client) async { return database; } catch (e) { // #Pangea + ErrorHandler.logError( + e: e, + m: 'Unable to init database', + s: StackTrace.current, + ); // Try to delete database so that it can created again on next init: // database?.delete().catchError( // (e, s) => Logs().w( From a673372d649635c0296977bab53814040a98ff12 Mon Sep 17 00:00:00 2001 From: Gabby Gurdin Date: Mon, 18 Mar 2024 11:18:44 -0400 Subject: [PATCH 6/6] remove commented out test code --- .../flutter_matrix_sdk_database_builder.dart | 1 - 1 file changed, 1 deletion(-) diff --git a/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart b/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart index 555cec635..ff22abf5c 100644 --- a/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart +++ b/lib/utils/matrix_sdk_extensions/flutter_matrix_sdk_database_builder.dart @@ -17,7 +17,6 @@ Future flutterMatrixSdkDatabaseBuilder(Client client) async { MatrixSdkDatabase? database; try { database = await _constructDatabase(client); - // throw "error"; await database.open(); return database; } catch (e) {