From 19809a6f2deff8ab206b0d4f40b36616b099ab20 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 17 May 2024 12:10:36 -0400 Subject: [PATCH 01/20] When a user creates a new group from inside a class, the space ID will be stored via query --- lib/config/routes.dart | 30 +++++++++++++++---------- lib/pages/chat_list/start_chat_fab.dart | 6 +++-- lib/pages/new_group/new_group.dart | 9 +++++++- 3 files changed, 30 insertions(+), 15 deletions(-) diff --git a/lib/config/routes.dart b/lib/config/routes.dart index 8d4d4f181..e6ab37967 100644 --- a/lib/config/routes.dart +++ b/lib/config/routes.dart @@ -232,20 +232,26 @@ abstract class AppRoutes { pageBuilder: (context, state) => defaultPageBuilder( context, state, - const NewGroup(), + NewGroup( + // #Pangea + spaceId: state.uri.queryParameters['spaceId'], + // Pangea# + ), ), redirect: loggedOutRedirect, - routes: [ - GoRoute( - path: ':spaceid', - pageBuilder: (context, state) => defaultPageBuilder( - context, - state, - const NewGroup(), - ), - redirect: loggedOutRedirect, - ), - ], + // #Pangea + // routes: [ + // GoRoute( + // path: ':spaceid', + // pageBuilder: (context, state) => defaultPageBuilder( + // context, + // state, + // const NewGroup(), + // ), + // redirect: loggedOutRedirect, + // ), + // ], + // Pangea# ), GoRoute( path: 'newspace', diff --git a/lib/pages/chat_list/start_chat_fab.dart b/lib/pages/chat_list/start_chat_fab.dart index 2bea8537e..c9175b8d6 100644 --- a/lib/pages/chat_list/start_chat_fab.dart +++ b/lib/pages/chat_list/start_chat_fab.dart @@ -30,7 +30,8 @@ class StartChatFloatingActionButton extends StatelessWidget { void _onPressed(BuildContext context) async { //#Pangea if (controller.activeSpaceId != null) { - context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); + // context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); + context.go('/rooms/newgroup?spaceId=${controller.activeSpaceId ?? ''}'); return; } //Pangea# @@ -44,7 +45,8 @@ class StartChatFloatingActionButton extends StatelessWidget { case ActiveFilter.groups: // #Pangea // context.go('/rooms/newgroup'); - context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); + // context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); + context.go('/rooms/newgroup?spaceId=${controller.activeSpaceId ?? ''}'); // Pangea# break; case ActiveFilter.spaces: diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 16d4e2cdb..90c658a45 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -17,7 +17,14 @@ import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart' as sdk; class NewGroup extends StatefulWidget { - const NewGroup({super.key}); + // #Pangea + final String? spaceId; + + const NewGroup({ + super.key, + this.spaceId, + }); + // Pangea# @override NewGroupController createState() => NewGroupController(); From f27c5981e86e5c53a5430322f959d2e93023d8c4 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 17 May 2024 14:06:22 -0400 Subject: [PATCH 02/20] Checks the user is member of room and admin before showing option to remove room from space --- lib/pages/chat_list/space_view.dart | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 856bed7d1..348550c65 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -237,6 +237,10 @@ class _SpaceViewState extends State { icon: Icons.send_outlined, ), if (spaceChild != null && + // #Pangea + room != null && + room.ownPowerLevel >= ClassDefaultValues.powerLevelOfAdmin && + // Pangea# (activeSpace?.canChangeStateEvent(EventTypes.spaceChild) ?? false)) SheetAction( key: SpaceChildContextAction.removeFromSpace, From c74b2c290a7ec6318f76a404e85075a813b20755 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 17 May 2024 14:35:21 -0400 Subject: [PATCH 03/20] Non-text messages cannot be edited --- lib/pages/chat/chat.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 0b9078ebb..460de198c 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1078,6 +1078,9 @@ class ChatController extends State bool get canEditSelectedEvents { if (isArchived || selectedEvents.length != 1 || + // #Pangea + selectedEvents.single.messageType != MessageTypes.Text || + // Pangea# !selectedEvents.first.status.isSent) { return false; } From c03ca24efe8ebfd71dfd84e7446bd6b600c8bf4e Mon Sep 17 00:00:00 2001 From: Kelrap <99418823+Kelrap@users.noreply.github.com> Date: Fri, 17 May 2024 15:42:37 -0400 Subject: [PATCH 04/20] limit new group name length to 32 --- lib/pages/new_group/new_group_view.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index ac3d9dacc..523f3002e 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -57,6 +57,9 @@ class NewGroupView extends StatelessWidget { const SizedBox(width: 16), Expanded( child: TextField( + // #Pangea + maxLength: 32, + // Pangea# controller: controller.nameController, autocorrect: false, readOnly: controller.loading, From f84e92d9d09c6c30613634faa6d20460e9882de7 Mon Sep 17 00:00:00 2001 From: Kelrap <99418823+Kelrap@users.noreply.github.com> Date: Fri, 17 May 2024 15:43:36 -0400 Subject: [PATCH 05/20] limit new space name length to 32 --- lib/pages/new_space/new_space_view.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pages/new_space/new_space_view.dart b/lib/pages/new_space/new_space_view.dart index e550d0019..23f81b7ab 100644 --- a/lib/pages/new_space/new_space_view.dart +++ b/lib/pages/new_space/new_space_view.dart @@ -95,6 +95,9 @@ class NewSpaceView extends StatelessWidget { const SizedBox(width: 16), Expanded( child: TextField( + // #Pangea + maxLength: 32, + // Pangea# controller: controller.nameController, autocorrect: false, readOnly: controller.loading, From 09f26fb91faa3f9f3cfe7ab1abf8d69e47a28042 Mon Sep 17 00:00:00 2001 From: Kelrap <99418823+Kelrap@users.noreply.github.com> Date: Fri, 17 May 2024 15:45:14 -0400 Subject: [PATCH 06/20] Limit display name length to 32 --- lib/pages/settings/settings.dart | 3 +++ 1 file changed, 3 insertions(+) diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 988ec3ff4..0e32fe478 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -42,6 +42,9 @@ class SettingsController extends State { cancelLabel: L10n.of(context)!.cancel, textFields: [ DialogTextField( + // #Pangea + maxLength: 32, + // Pangea# initialText: profile?.displayName ?? Matrix.of(context).client.userID!.localpart, ), From d247abb320c0a425e9098ff3139652620c8674cc Mon Sep 17 00:00:00 2001 From: Kelrap <99418823+Kelrap@users.noreply.github.com> Date: Fri, 17 May 2024 15:46:27 -0400 Subject: [PATCH 07/20] Limited edited class name length to 32 --- lib/pangea/utils/set_class_name.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pangea/utils/set_class_name.dart b/lib/pangea/utils/set_class_name.dart index 92909034a..1fd2ab66d 100644 --- a/lib/pangea/utils/set_class_name.dart +++ b/lib/pangea/utils/set_class_name.dart @@ -27,6 +27,7 @@ void setClassDisplayname(BuildContext context, String? roomId) async { : L10n.of(context)!.changeTheNameOfTheChat, ), content: TextField( + maxLength: 32, controller: textFieldController, ), actions: [ From b2166906c37be52a963005345ca79b96a2d11041 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 17 May 2024 16:26:04 -0400 Subject: [PATCH 08/20] Use query parameter to autoselect class --- lib/pages/new_group/new_group.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 90c658a45..2ada80dfa 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -57,7 +57,7 @@ class NewGroupController extends State { void setVocab(List vocab) => setState(() => chatTopic.vocab = vocab); String? get activeSpaceId => - GoRouterState.of(context).pathParameters['spaceid']; + GoRouterState.of(context).uri.queryParameters['spaceId']; // Pangea# void setPublicGroup(bool b) => setState(() => publicGroup = b); From c88970d8598c4a686bbba6646e314a835f9da9b9 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 17 May 2024 16:37:39 -0400 Subject: [PATCH 09/20] removed unused comments --- lib/pages/chat_list/start_chat_fab.dart | 2 -- 1 file changed, 2 deletions(-) diff --git a/lib/pages/chat_list/start_chat_fab.dart b/lib/pages/chat_list/start_chat_fab.dart index c9175b8d6..117833ff0 100644 --- a/lib/pages/chat_list/start_chat_fab.dart +++ b/lib/pages/chat_list/start_chat_fab.dart @@ -30,7 +30,6 @@ class StartChatFloatingActionButton extends StatelessWidget { void _onPressed(BuildContext context) async { //#Pangea if (controller.activeSpaceId != null) { - // context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); context.go('/rooms/newgroup?spaceId=${controller.activeSpaceId ?? ''}'); return; } @@ -45,7 +44,6 @@ class StartChatFloatingActionButton extends StatelessWidget { case ActiveFilter.groups: // #Pangea // context.go('/rooms/newgroup'); - // context.go('/rooms/newgroup/${controller.activeSpaceId ?? ''}'); context.go('/rooms/newgroup?spaceId=${controller.activeSpaceId ?? ''}'); // Pangea# break; From f797cdbb4afadb211a0b83efe1420ba2eb314831 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 20 May 2024 12:34:36 -0400 Subject: [PATCH 10/20] ensure speech_to_text endpoint is only called once, round words for per minute string, always auto-speech-to-text for audio message toolbar --- lib/pangea/enum/message_mode_enum.dart | 14 +++++++++++ .../pangea_message_event.dart | 13 ++++++++++ .../pangea_representation_event.dart | 5 ---- .../chat/message_speech_to_text_card.dart | 2 +- lib/pangea/widgets/chat/message_toolbar.dart | 25 +++++++++++++++---- 5 files changed, 48 insertions(+), 11 deletions(-) diff --git a/lib/pangea/enum/message_mode_enum.dart b/lib/pangea/enum/message_mode_enum.dart index c64861dc0..25948d23b 100644 --- a/lib/pangea/enum/message_mode_enum.dart +++ b/lib/pangea/enum/message_mode_enum.dart @@ -1,6 +1,7 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:material_symbols_icons/symbols.dart'; +import 'package:matrix/matrix.dart'; enum MessageMode { translation, definition, speechToText, textToSpeech } @@ -52,4 +53,17 @@ extension MessageModeExtension on MessageMode { .oopsSomethingWentWrong; // Title to indicate an error or unsupported mode } } + + bool isValidMode(Event event) { + switch (this) { + case MessageMode.translation: + case MessageMode.textToSpeech: + case MessageMode.definition: + return event.messageType == MessageTypes.Text; + case MessageMode.speechToText: + return event.messageType == MessageTypes.Audio; + default: + return true; + } + } } diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index cb7cba52a..db5c7902a 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -346,6 +346,19 @@ class PangeaMessageEvent { ), ); + _representations?.add( + RepresentationEvent( + timeline: timeline, + content: PangeaRepresentation( + langCode: response.langCode, + text: response.transcript.text, + originalSent: false, + originalWritten: false, + speechToText: response, + ), + ), + ); + return response; } diff --git a/lib/pangea/matrix_event_wrappers/pangea_representation_event.dart b/lib/pangea/matrix_event_wrappers/pangea_representation_event.dart index 0796f7f5d..e774dc4f2 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_representation_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_representation_event.dart @@ -3,7 +3,6 @@ import 'dart:developer'; import 'package:fluffychat/pangea/extensions/pangea_event_extension.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_choreo_event.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; -import 'package:fluffychat/pangea/models/speech_to_text_models.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/repo/tokens_repo.dart'; import 'package:flutter/foundation.dart'; @@ -27,15 +26,12 @@ class RepresentationEvent { ChoreoRecord? _choreo; Timeline timeline; - SpeechToTextModel? _speechToTextResponse; - RepresentationEvent({ required this.timeline, Event? event, PangeaRepresentation? content, PangeaMessageTokens? tokens, ChoreoRecord? choreo, - SpeechToTextModel? speechToTextResponse, }) { if (event != null && event.type != PangeaEventTypes.representation) { throw Exception( @@ -46,7 +42,6 @@ class RepresentationEvent { _content = content; _tokens = tokens; _choreo = choreo; - _speechToTextResponse = speechToTextResponse; } Event? get event => _event; diff --git a/lib/pangea/widgets/chat/message_speech_to_text_card.dart b/lib/pangea/widgets/chat/message_speech_to_text_card.dart index bc2cf3327..37b013b53 100644 --- a/lib/pangea/widgets/chat/message_speech_to_text_card.dart +++ b/lib/pangea/widgets/chat/message_speech_to_text_card.dart @@ -138,7 +138,7 @@ class MessageSpeechToTextCardState extends State { } String? get wordsPerMinuteString => - speechToTextResponse?.transcript.wordsPerMinute?.toString(); + speechToTextResponse?.transcript.wordsPerMinute?.toStringAsFixed(2); @override Widget build(BuildContext context) { diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index b2c61a354..81884ffca 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -172,6 +172,19 @@ class MessageToolbarState extends State { debugPrint("updating toolbar mode"); final bool subscribed = MatrixState.pangeaController.subscriptionController.isSubscribed; + + if (!newMode.isValidMode(widget.pangeaMessageEvent.event)) { + ErrorHandler.logError( + e: "Invalid mode for event", + s: StackTrace.current, + data: { + "newMode": newMode, + "event": widget.pangeaMessageEvent.event, + }, + ); + return; + } + setState(() { currentMode = newMode; updatingMode = true; @@ -274,12 +287,14 @@ class MessageToolbarState extends State { PLocalKey.autoPlayMessages, ) ?? true; + + if (widget.pangeaMessageEvent.isAudioMessage) { + updateMode(MessageMode.speechToText); + return; + } + autoplay - ? updateMode( - widget.pangeaMessageEvent.isAudioMessage - ? MessageMode.speechToText - : MessageMode.textToSpeech, - ) + ? updateMode(MessageMode.textToSpeech) : updateMode(MessageMode.translation); }); From 39c8012137740463d1c30c725092ac1b8919f50a Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 20 May 2024 13:52:14 -0400 Subject: [PATCH 11/20] Archive list does not show spaces/analytics rooms --- lib/pages/archive/archive.dart | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/lib/pages/archive/archive.dart b/lib/pages/archive/archive.dart index a3c35c347..06d80b7df 100644 --- a/lib/pages/archive/archive.dart +++ b/lib/pages/archive/archive.dart @@ -1,13 +1,12 @@ -import 'package:flutter/material.dart'; - import 'package:adaptive_dialog/adaptive_dialog.dart'; +import 'package:fluffychat/pages/archive/archive_view.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension.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:matrix/matrix.dart'; -import 'package:fluffychat/pages/archive/archive_view.dart'; -import 'package:fluffychat/widgets/matrix.dart'; - class Archive extends StatefulWidget { const Archive({super.key}); @@ -20,7 +19,11 @@ class ArchiveController extends State { Future> getArchive(BuildContext context) async { if (archive.isNotEmpty) return archive; - return archive = await Matrix.of(context).client.loadArchive(); + // #Pangea + return archive = (await Matrix.of(context).client.loadArchive()) + .where((e) => (!e.isSpace && !e.isAnalyticsRoom)) + .toList(); + // Pangea# } void forgetRoomAction(int i) async { From 5f839555440df8c33ef5af771457263fbc7ef37d Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 20 May 2024 14:26:18 -0400 Subject: [PATCH 12/20] Archived chats don't show Chat Details or Leave --- lib/pages/archive/archive.dart | 1 + lib/pages/chat/chat_view.dart | 3 +- lib/widgets/chat_settings_popup_menu.dart | 39 ++++++++++++++++------- 3 files changed, 30 insertions(+), 13 deletions(-) diff --git a/lib/pages/archive/archive.dart b/lib/pages/archive/archive.dart index 06d80b7df..78e735d05 100644 --- a/lib/pages/archive/archive.dart +++ b/lib/pages/archive/archive.dart @@ -20,6 +20,7 @@ class ArchiveController extends State { Future> getArchive(BuildContext context) async { if (archive.isNotEmpty) return archive; // #Pangea + //return archive = await Matrix.of(context).client.loadArchive(); return archive = (await Matrix.of(context).client.loadArchive()) .where((e) => (!e.isSpace && !e.isAnalyticsRoom)) .toList(); diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 57255ffc9..21789f527 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -116,7 +116,8 @@ class ChatView extends StatelessWidget { // #Pangea } else { return [ - ChatSettingsPopupMenu(controller.room, !controller.room.isDirectChat), + ChatSettingsPopupMenu(controller.room, + (!controller.room.isDirectChat && !controller.room.isArchived)), ]; } diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index f10f08ff7..1feadc459 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -83,19 +83,34 @@ class ChatSettingsPopupMenuState extends State { ], ), ), - PopupMenuItem( - value: 'leave', - child: Row( - children: [ - // #Pangea - // const Icon(Icons.delete_outlined), - const Icon(Icons.arrow_forward), - // Pangea# - const SizedBox(width: 12), - Text(L10n.of(context)!.leave), - ], + // #Pangea + // PopupMenuItem( + // value: 'leave', + // child: Row( + // children: [ + // // #Pangea + // // const Icon(Icons.delete_outlined), + // const Icon(Icons.arrow_forward), + // // Pangea# + // const SizedBox(width: 12), + // Text(L10n.of(context)!.leave), + // ], + // ), + // ), + if (!widget.room.isArchived) + PopupMenuItem( + value: 'leave', + child: Row( + children: [ + // #Pangea + // const Icon(Icons.delete_outlined), + const Icon(Icons.arrow_forward), + // Pangea# + const SizedBox(width: 12), + Text(L10n.of(context)!.leave), + ], + ), ), - ), // #Pangea if (classSettings != null) PopupMenuItem( From 8c421d80cc82427e4d1579366d0c115c97bfc3b9 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 20 May 2024 14:38:17 -0400 Subject: [PATCH 13/20] adjusted pangea comments --- lib/widgets/chat_settings_popup_menu.dart | 14 +------------- 1 file changed, 1 insertion(+), 13 deletions(-) diff --git a/lib/widgets/chat_settings_popup_menu.dart b/lib/widgets/chat_settings_popup_menu.dart index 1feadc459..781b8ab61 100644 --- a/lib/widgets/chat_settings_popup_menu.dart +++ b/lib/widgets/chat_settings_popup_menu.dart @@ -84,20 +84,8 @@ class ChatSettingsPopupMenuState extends State { ), ), // #Pangea - // PopupMenuItem( - // value: 'leave', - // child: Row( - // children: [ - // // #Pangea - // // const Icon(Icons.delete_outlined), - // const Icon(Icons.arrow_forward), - // // Pangea# - // const SizedBox(width: 12), - // Text(L10n.of(context)!.leave), - // ], - // ), - // ), if (!widget.room.isArchived) + // Pangea# PopupMenuItem( value: 'leave', child: Row( From 9a6a58e53cb6ea54daffaff01382ddc1fe609149 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 20 May 2024 16:33:33 -0400 Subject: [PATCH 14/20] Prevent non-admins of room from toggling class membership --- lib/pangea/extensions/pangea_room_extension.dart | 3 +++ lib/pangea/widgets/class/add_space_toggles.dart | 9 +++++++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart index bf152012a..febd17fa8 100644 --- a/lib/pangea/extensions/pangea_room_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension.dart @@ -815,6 +815,9 @@ extension PangeaRoom on Room { ); return false; } + if (room != null && !room.isRoomAdmin) { + return false; + } if (!pangeaCanSendEvent(EventTypes.spaceChild) && !isRoomAdmin) { return false; } diff --git a/lib/pangea/widgets/class/add_space_toggles.dart b/lib/pangea/widgets/class/add_space_toggles.dart index cd875cd95..eb06cd26a 100644 --- a/lib/pangea/widgets/class/add_space_toggles.dart +++ b/lib/pangea/widgets/class/add_space_toggles.dart @@ -235,8 +235,13 @@ class AddToSpaceState extends State { ), activeColor: AppConfig.activeToggleColor, value: isSuggestedInSpace(possibleParent), - onChanged: (bool suggest) => - setSuggested(suggest, possibleParent), + onChanged: (bool suggest) => canAdd + ? setSuggested(suggest, possibleParent) + : ScaffoldMessenger.of(context).showSnackBar( + SnackBar( + content: Text(L10n.of(context)!.noPermission), + ), + ), ) : Container(), ), From 0aacd6407cb3d5f926aa1a4308a77c9bdf9be4bd Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 20 May 2024 16:52:56 -0400 Subject: [PATCH 15/20] don't add spaceId query parameter if activeSpaceId is null --- lib/pages/chat_list/start_chat_fab.dart | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/lib/pages/chat_list/start_chat_fab.dart b/lib/pages/chat_list/start_chat_fab.dart index 117833ff0..f25374f4e 100644 --- a/lib/pages/chat_list/start_chat_fab.dart +++ b/lib/pages/chat_list/start_chat_fab.dart @@ -30,7 +30,9 @@ class StartChatFloatingActionButton extends StatelessWidget { void _onPressed(BuildContext context) async { //#Pangea if (controller.activeSpaceId != null) { - context.go('/rooms/newgroup?spaceId=${controller.activeSpaceId ?? ''}'); + context.go( + '/rooms/newgroup${controller.activeSpaceId != null ? '?spaceId=${controller.activeSpaceId}' : ''}', + ); return; } //Pangea# @@ -44,7 +46,9 @@ class StartChatFloatingActionButton extends StatelessWidget { case ActiveFilter.groups: // #Pangea // context.go('/rooms/newgroup'); - context.go('/rooms/newgroup?spaceId=${controller.activeSpaceId ?? ''}'); + context.go( + '/rooms/newgroup${controller.activeSpaceId != null ? '?spaceId=${controller.activeSpaceId}' : ''}', + ); // Pangea# break; case ActiveFilter.spaces: From 733f37717cffcdf83da6a3ae61848656a2fd6134 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Tue, 21 May 2024 11:11:55 -0400 Subject: [PATCH 16/20] When user changes languages, updates learning settings --- .../settings_learning/settings_learning.dart | 7 +++++-- .../settings_learning_view.dart | 2 +- .../widgets/user_settings/language_tile.dart | 16 ++++++++++------ .../widgets/user_settings/p_language_dialog.dart | 2 +- 4 files changed, 17 insertions(+), 10 deletions(-) diff --git a/lib/pangea/pages/settings_learning/settings_learning.dart b/lib/pangea/pages/settings_learning/settings_learning.dart index f699fc7b5..0785f3407 100644 --- a/lib/pangea/pages/settings_learning/settings_learning.dart +++ b/lib/pangea/pages/settings_learning/settings_learning.dart @@ -1,10 +1,9 @@ import 'dart:async'; -import 'package:flutter/material.dart'; - import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/pages/settings_learning/settings_learning_view.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/material.dart'; class SettingsLearning extends StatefulWidget { const SettingsLearning({super.key}); @@ -32,6 +31,10 @@ class SettingsLearningController extends State { }); } + Future refresh() async { + setState(() {}); + } + @override void dispose() { super.dispose(); diff --git a/lib/pangea/pages/settings_learning/settings_learning_view.dart b/lib/pangea/pages/settings_learning/settings_learning_view.dart index d878dcb42..6c3a87f00 100644 --- a/lib/pangea/pages/settings_learning/settings_learning_view.dart +++ b/lib/pangea/pages/settings_learning/settings_learning_view.dart @@ -31,7 +31,7 @@ class SettingsLearningView extends StatelessWidget { withScrolling: true, child: Column( children: [ - LanguageTile(), + LanguageTile(controller), CountryPickerTile(), const SizedBox(height: 8), const Divider(height: 1), diff --git a/lib/pangea/widgets/user_settings/language_tile.dart b/lib/pangea/widgets/user_settings/language_tile.dart index 085779781..95ff42f86 100644 --- a/lib/pangea/widgets/user_settings/language_tile.dart +++ b/lib/pangea/widgets/user_settings/language_tile.dart @@ -1,19 +1,20 @@ -import 'package:flutter/material.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; - import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/models/language_model.dart'; +import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart'; import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + import '../flag.dart'; import 'p_language_dialog.dart'; //PTODO - move this to settings_learning_view.dart and make callback a setState class LanguageTile extends StatelessWidget { + final SettingsLearningController learningController; final PangeaController pangeaController = MatrixState.pangeaController; - LanguageTile({super.key}); + LanguageTile(this.learningController, {super.key}); @override Widget build(BuildContext context) { @@ -81,7 +82,10 @@ class LanguageTile extends StatelessWidget { ], ), trailing: const Icon(Icons.edit_outlined), - onTap: () => pLanguageDialog(context, () {}), + onTap: () async { + await pLanguageDialog(context, () {}); + learningController.refresh(); + }, ); } } diff --git a/lib/pangea/widgets/user_settings/p_language_dialog.dart b/lib/pangea/widgets/user_settings/p_language_dialog.dart index 077959ead..4d09b506e 100644 --- a/lib/pangea/widgets/user_settings/p_language_dialog.dart +++ b/lib/pangea/widgets/user_settings/p_language_dialog.dart @@ -15,7 +15,7 @@ import '../../../widgets/matrix.dart'; import 'p_language_dropdown.dart'; import 'p_question_container.dart'; -pLanguageDialog(BuildContext parentContext, Function callback) { +pLanguageDialog(BuildContext parentContext, Function callback) async { final PangeaController pangeaController = MatrixState.pangeaController; //PTODO: if source language not set by user, default to languge from device settings final LanguageModel? userL1 = pangeaController.languageController.userL1; From 8b0104db06da84a2ea3a184030b1485cacad0467 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Tue, 21 May 2024 11:51:30 -0400 Subject: [PATCH 17/20] Moved state-related functionality to controller --- lib/pangea/pages/settings_learning/settings_learning.dart | 4 +++- lib/pangea/widgets/user_settings/language_tile.dart | 4 +--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/lib/pangea/pages/settings_learning/settings_learning.dart b/lib/pangea/pages/settings_learning/settings_learning.dart index 0785f3407..c560fef57 100644 --- a/lib/pangea/pages/settings_learning/settings_learning.dart +++ b/lib/pangea/pages/settings_learning/settings_learning.dart @@ -2,6 +2,7 @@ import 'dart:async'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/pages/settings_learning/settings_learning_view.dart'; +import 'package:fluffychat/pangea/widgets/user_settings/p_language_dialog.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; @@ -31,7 +32,8 @@ class SettingsLearningController extends State { }); } - Future refresh() async { + Future changeLanguage() async { + await pLanguageDialog(context, () {}); setState(() {}); } diff --git a/lib/pangea/widgets/user_settings/language_tile.dart b/lib/pangea/widgets/user_settings/language_tile.dart index 95ff42f86..d66335300 100644 --- a/lib/pangea/widgets/user_settings/language_tile.dart +++ b/lib/pangea/widgets/user_settings/language_tile.dart @@ -6,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import '../flag.dart'; -import 'p_language_dialog.dart'; //PTODO - move this to settings_learning_view.dart and make callback a setState @@ -83,8 +82,7 @@ class LanguageTile extends StatelessWidget { ), trailing: const Icon(Icons.edit_outlined), onTap: () async { - await pLanguageDialog(context, () {}); - learningController.refresh(); + learningController.changeLanguage(); }, ); } From 38634b8dc7351846bad1fa2bb8cc1ebadae70697 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 22 May 2024 10:05:33 -0400 Subject: [PATCH 18/20] fix for empty data returned from wordnet --- lib/pangea/models/word_data_model.dart | 6 +- lib/pangea/widgets/igc/word_data_card.dart | 89 ++++++++++++---------- 2 files changed, 53 insertions(+), 42 deletions(-) diff --git a/lib/pangea/models/word_data_model.dart b/lib/pangea/models/word_data_model.dart index 838240725..c4c059241 100644 --- a/lib/pangea/models/word_data_model.dart +++ b/lib/pangea/models/word_data_model.dart @@ -1,9 +1,8 @@ import 'dart:developer'; -import 'package:flutter/foundation.dart'; - import 'package:fluffychat/pangea/constants/model_keys.dart'; import 'package:fluffychat/pangea/widgets/igc/word_data_card.dart'; +import 'package:flutter/foundation.dart'; class WordData { final String word; @@ -102,10 +101,11 @@ class WordData { }) => word == w && userL1 == l1 && userL2 == l2 && fullText == f; - String formattedPartOfSpeech(LanguageType languageType) { + String? formattedPartOfSpeech(LanguageType languageType) { final String pos = languageType == LanguageType.base ? basePartOfSpeech : targetPartOfSpeech; + if (pos.isEmpty) return null; return pos[0].toUpperCase() + pos.substring(1); } diff --git a/lib/pangea/widgets/igc/word_data_card.dart b/lib/pangea/widgets/igc/word_data_card.dart index a6ef7b511..4b8445417 100644 --- a/lib/pangea/widgets/igc/word_data_card.dart +++ b/lib/pangea/widgets/igc/word_data_card.dart @@ -314,6 +314,23 @@ class PartOfSpeechBlock extends StatelessWidget { required this.languageType, }); + String get exampleSentence => languageType == LanguageType.target + ? wordData.targetExampleSentence + : wordData.baseExampleSentence; + + String get definition => languageType == LanguageType.target + ? wordData.targetDefinition + : wordData.baseDefinition; + + String formattedTitle(BuildContext context) { + final String word = languageType == LanguageType.target + ? wordData.targetWord + : wordData.baseWord; + String? pos = wordData.formattedPartOfSpeech(languageType); + if (pos == null || pos.isEmpty) pos = L10n.of(context)!.unkDisplayName; + return "$word (${wordData.formattedPartOfSpeech(languageType)})"; + } + @override Widget build(BuildContext context) { return Padding( @@ -324,9 +341,7 @@ class PartOfSpeechBlock extends StatelessWidget { Align( alignment: Alignment.centerLeft, child: Text( - languageType == LanguageType.target - ? "${wordData.targetWord} (${wordData.formattedPartOfSpeech(languageType)})" - : "${wordData.baseWord} (${wordData.formattedPartOfSpeech(languageType)})", + formattedTitle(context), style: BotStyle.text(context, italics: true, bold: false), ), ), @@ -337,47 +352,43 @@ class PartOfSpeechBlock extends StatelessWidget { alignment: Alignment.centerLeft, child: Column( children: [ - RichText( - text: TextSpan( - style: BotStyle.text( - context, - italics: false, - bold: false, - ), - children: [ - TextSpan( - text: "${L10n.of(context)!.definition}: ", - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: languageType == LanguageType.target - ? wordData.targetDefinition - : wordData.baseDefinition, + if (definition.isNotEmpty) + RichText( + text: TextSpan( + style: BotStyle.text( + context, + italics: false, + bold: false, ), - ], + children: [ + TextSpan( + text: "${L10n.of(context)!.definition}: ", + style: const TextStyle(fontWeight: FontWeight.bold), + ), + TextSpan(text: definition), + ], + ), ), - ), const SizedBox(height: 10), - RichText( - text: TextSpan( - style: BotStyle.text( - context, - italics: false, - bold: false, - ), - children: [ - TextSpan( - text: "${L10n.of(context)!.exampleSentence}: ", - style: const TextStyle(fontWeight: FontWeight.bold), + if (exampleSentence.isNotEmpty) + RichText( + text: TextSpan( + style: BotStyle.text( + context, + italics: false, + bold: false, ), - TextSpan( - text: languageType == LanguageType.target - ? wordData.targetExampleSentence - : wordData.baseExampleSentence, - ), - ], + children: [ + TextSpan( + text: "${L10n.of(context)!.exampleSentence}: ", + style: const TextStyle( + fontWeight: FontWeight.bold, + ), + ), + TextSpan(text: exampleSentence), + ], + ), ), - ), ], ), ), From ab33ec2b3f0ed9356d40777abc16f47351142bee Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 22 May 2024 12:58:35 -0400 Subject: [PATCH 19/20] don't show rich text for own messages if they're not overlay --- lib/pages/chat/events/message_content.dart | 8 +++- .../pangea_message_event.dart | 11 ++++- lib/pangea/widgets/chat/message_toolbar.dart | 7 ++- lib/pangea/widgets/chat/overlay_message.dart | 1 + lib/pangea/widgets/igc/pangea_rich_text.dart | 47 ++++++++++--------- 5 files changed, 45 insertions(+), 29 deletions(-) diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 9866ddb2d..f04296d38 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -38,6 +38,7 @@ class MessageContent extends StatelessWidget { //further down in the chain is also using pangeaController so its not constant final bool immersionMode; final ToolbarDisplayController? toolbarController; + final bool isOverlay; // Pangea# const MessageContent( @@ -50,6 +51,7 @@ class MessageContent extends StatelessWidget { this.pangeaMessageEvent, required this.immersionMode, required this.toolbarController, + this.isOverlay = false, // Pangea# required this.borderRadius, }); @@ -203,7 +205,8 @@ class MessageContent extends StatelessWidget { && !(pangeaMessageEvent?.showRichText( selected, - toolbarController?.highlighted ?? false, + isOverlay: isOverlay, + highlighted: toolbarController?.highlighted ?? false, ) ?? false) // Pangea# @@ -305,7 +308,8 @@ class MessageContent extends StatelessWidget { ); if (pangeaMessageEvent?.showRichText( selected, - toolbarController?.highlighted ?? false, + isOverlay: isOverlay, + highlighted: toolbarController?.highlighted ?? false, ) ?? false) { return PangeaRichText( diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index db5c7902a..fd669f6ec 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -80,7 +80,11 @@ class PangeaMessageEvent { return _latestEdit; } - bool showRichText(bool selected, bool highlighted) { + bool showRichText( + bool selected, { + bool highlighted = false, + bool isOverlay = false, + }) { if (!_isValidPangeaMessageEvent) { return false; } @@ -90,8 +94,11 @@ class PangeaMessageEvent { if ([EventStatus.error, EventStatus.sending].contains(_event.status)) { return false; } - if (ownMessage && !selected && !highlighted) return false; + if (isOverlay) return true; + if (ownMessage && !selected && !highlighted) { + return false; + } return true; } diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index 81884ffca..2f6d82ef1 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -134,8 +134,11 @@ class ToolbarDisplayController { }); } - bool get highlighted => - MatrixState.pAnyState.overlay.hashCode.toString() == overlayId; + bool get highlighted { + if (overlayId == null) return false; + if (MatrixState.pAnyState.overlay == null) overlayId = null; + return MatrixState.pAnyState.overlay.hashCode.toString() == overlayId; + } } class MessageToolbar extends StatefulWidget { diff --git a/lib/pangea/widgets/chat/overlay_message.dart b/lib/pangea/widgets/chat/overlay_message.dart index 5c7ccdef0..e8143b376 100644 --- a/lib/pangea/widgets/chat/overlay_message.dart +++ b/lib/pangea/widgets/chat/overlay_message.dart @@ -141,6 +141,7 @@ class OverlayMessage extends StatelessWidget { pangeaMessageEvent: pangeaMessageEvent, immersionMode: immersionMode, toolbarController: toolbarController, + isOverlay: true, ), if (event.hasAggregatedEvents( timeline, diff --git a/lib/pangea/widgets/igc/pangea_rich_text.dart b/lib/pangea/widgets/igc/pangea_rich_text.dart index 779955f82..43416e006 100644 --- a/lib/pangea/widgets/igc/pangea_rich_text.dart +++ b/lib/pangea/widgets/igc/pangea_rich_text.dart @@ -48,28 +48,33 @@ class PangeaRichTextState extends State { @override void initState() { super.initState(); - updateTextSpan(); - } - - void updateTextSpan() { - setState(() { - textSpan = getTextSpan(); - }); + setTextSpan(); } @override void didUpdateWidget(PangeaRichText oldWidget) { super.didUpdateWidget(oldWidget); - updateTextSpan(); + setTextSpan(); + } + + void _setTextSpan(String newTextSpan) { + widget.toolbarController?.toolbar?.textSelection.setMessageText( + newTextSpan, + ); + setState(() { + textSpan = newTextSpan; + }); } - String getTextSpan() { + void setTextSpan() { if (_fetchingRepresentation == true) { - return widget.pangeaMessageEvent.body; + _setTextSpan(textSpan = widget.pangeaMessageEvent.body); + return; } if (repEvent != null) { - return repEvent!.text; + _setTextSpan(repEvent!.text); + return; } if (widget.pangeaMessageEvent.eventId.contains("webdebug")) { @@ -84,7 +89,6 @@ class PangeaRichTextState extends State { if (repEvent == null) { setState(() => _fetchingRepresentation = true); - widget.pangeaMessageEvent .representationByLanguageGlobal( langCode: widget.pangeaMessageEvent.messageDisplayLangCode, @@ -95,23 +99,17 @@ class PangeaRichTextState extends State { ) .then((event) { repEvent = event; - widget.toolbarController?.toolbar?.textSelection.setMessageText( - repEvent?.text ?? widget.pangeaMessageEvent.body, - ); + _setTextSpan(repEvent?.text ?? widget.pangeaMessageEvent.body); }).whenComplete(() { if (mounted) { setState(() => _fetchingRepresentation = false); } }); - return widget.pangeaMessageEvent.body; + + _setTextSpan(widget.pangeaMessageEvent.body); } else { - widget.toolbarController?.toolbar?.textSelection.setMessageText( - repEvent!.text, - ); - setState(() {}); + _setTextSpan(repEvent!.text); } - - return repEvent!.text; } @override @@ -190,7 +188,10 @@ class PangeaRichTextState extends State { return blur > 0 ? ImageFiltered( - imageFilter: ImageFilter.blur(sigmaX: blur, sigmaY: blur), + imageFilter: ImageFilter.blur( + sigmaX: blur, + sigmaY: blur, + ), child: richText, ) : richText; From 087c0d05e9004b12c47c8b05aaa18a40008c73c1 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 22 May 2024 13:04:23 -0400 Subject: [PATCH 20/20] fix for showRichText function --- .../matrix_event_wrappers/pangea_message_event.dart | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index fd669f6ec..91f19f6e7 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -88,15 +88,16 @@ class PangeaMessageEvent { if (!_isValidPangeaMessageEvent) { return false; } - // if (URLFinder.getMatches(event.body).isNotEmpty) { - // return false; - // } + if ([EventStatus.error, EventStatus.sending].contains(_event.status)) { return false; } if (isOverlay) return true; - if (ownMessage && !selected && !highlighted) { + + // if ownMessage, don't show rich text if not selected or highlighted + // and don't show is the message is not an overlay + if (ownMessage && ((!selected && !highlighted) || !isOverlay)) { return false; } return true;