From aa6e33ed1a79f74930b36cdbdcd08e5cb470cc84 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 26 Jul 2024 15:37:07 -0400 Subject: [PATCH 01/31] Suggest subrooms by default --- lib/pages/chat_list/chat_list.dart | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 0897a28eb..8f5515fc4 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -863,7 +863,7 @@ class ChatListController extends State if (space.canSendDefaultStates) { for (final roomId in selectedRoomIds) { - await space.pangeaSetSpaceChild(roomId); + await space.pangeaSetSpaceChild(roomId, suggested: true); } } // Pangea# From 31213184a3b1c349b3c8176ae5ac181c05bf54e8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 26 Jul 2024 15:56:34 -0400 Subject: [PATCH 02/31] suggest rooms created by new in space view --- lib/pages/chat_list/space_view.dart | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index ccc9aa9c4..a90c0d094 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -579,7 +579,12 @@ class _SpaceViewState extends State { : null, ); } - await activeSpace.setSpaceChild(roomId); + await activeSpace.setSpaceChild( + roomId, + // #Pangea + suggested: true, + // Pangea# + ); }, ); if (result.error != null) return; From 24ccc538e16f9e535076ab5c25330b3f2b520793 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 29 Jul 2024 10:27:55 -0400 Subject: [PATCH 03/31] Ignores null timeline error --- lib/pages/chat/chat.dart | 6 ------ 1 file changed, 6 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index aa2b78d4d..50cb7ea9f 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -486,12 +486,6 @@ class ChatController extends State final timeline = this.timeline; if (timeline == null || timeline.events.isEmpty) { - // #Pangea - ErrorHandler.logError( - e: PangeaWarningError("Timeline is null or empty"), - s: StackTrace.current, - ); - // Pangea# return; } From 0670d5061d7bcf998659639f54c5c52136382513 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 29 Jul 2024 15:16:43 -0400 Subject: [PATCH 04/31] Avatar is no longer child of Hero --- lib/pages/chat_details/chat_details_view.dart | 23 ++++++++++--------- 1 file changed, 12 insertions(+), 11 deletions(-) diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 24db0f582..7bda65abf 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -138,17 +138,18 @@ class ChatDetailsView extends StatelessWidget { Avatar.defaultSize * 2.5, ), ), - child: Hero( - tag: controller.widget - .embeddedCloseButton != - null - ? 'embedded_content_banner' - : 'content_banner', - child: Avatar( - mxContent: room.avatar, - name: displayname, - size: Avatar.defaultSize * 2.5, - ), + // #Pangea + // child: Hero( + // tag: controller.widget + // .embeddedCloseButton != + // null + // ? 'embedded_content_banner' + // : 'content_banner', + // Pangea# + child: Avatar( + mxContent: room.avatar, + name: displayname, + size: Avatar.defaultSize * 2.5, ), ), if (!room.isDirectChat && From ecbe421611cecc0b93f91728b3a5de9395ff388e Mon Sep 17 00:00:00 2001 From: William Jordan-Cooley Date: Tue, 30 Jul 2024 11:34:14 -0400 Subject: [PATCH 05/31] if bot, don't invite people to your analytics room --- .../extensions/client_extension/client_analytics_extension.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pangea/extensions/client_extension/client_analytics_extension.dart b/lib/pangea/extensions/client_extension/client_analytics_extension.dart index 396e09f8d..797850662 100644 --- a/lib/pangea/extensions/client_extension/client_analytics_extension.dart +++ b/lib/pangea/extensions/client_extension/client_analytics_extension.dart @@ -100,6 +100,7 @@ extension AnalyticsClientExtension on Client { /// Handles case when students cannot add analytics room to space(s) /// so teacher is still able to get analytics data for this student void _inviteAllTeachersToAllAnalyticsRooms() { + if (userID == null || userID == BotName.byEnvironment) return; for (final Room room in allMyAnalyticsRooms) { room.inviteTeachersToAnalyticsRoom(); } From 1abbb8ee3f7ec6e9273bd574d6df5857dd523bf5 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 30 Jul 2024 12:45:31 -0400 Subject: [PATCH 06/31] on profile create, also create pangea profile. If there's no pangea profile when fetching access token, create one. --- lib/pangea/controllers/user_controller.dart | 27 ++++++++++++++++--- lib/pangea/repo/user_repo.dart | 29 +++++++++++++++++++++ 2 files changed, 53 insertions(+), 3 deletions(-) diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index 2ef0227e5..bf8ce3c11 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -83,6 +83,15 @@ class UserController extends BaseController { createdAt: DateTime.now(), ); final newProfile = Profile(userSettings: userSettings); + + // we don't use the pangea profile anymore, but we still need + // it to get access token for the choreographer, so create one + await PUserRepo.repoCreatePangeaUser( + userID: userId!, + dob: dob.toIso8601String(), + fullName: fullname!, + matrixAccessToken: _matrixAccessToken!, + ); await newProfile.saveProfileData(waitForDataInSync: true); } @@ -155,13 +164,25 @@ class UserController extends BaseController { _pangeaController.pStoreService.read(PLocalKey.access); if (localAccessToken == null || needNewJWT(localAccessToken)) { - final PangeaProfileResponse? userModel = - await PUserRepo.fetchPangeaUserInfo( + PangeaProfileResponse? userModel = await PUserRepo.fetchPangeaUserInfo( userID: userId!, matrixAccessToken: _matrixAccessToken!, ); + // Oops, some accounts were made without creating pangea profiles, so they + // don't have access to an access token yet. In that case, create a pangea profile. if (userModel?.access == null) { - throw ("Trying to get accessToken with null userModel"); + final dob = profile.userSettings.dateOfBirth; + if (dob != null) { + userModel = await PUserRepo.repoCreatePangeaUser( + userID: userId!, + dob: dob.toIso8601String(), + fullName: fullname!, + matrixAccessToken: _matrixAccessToken!, + ); + if (userModel?.access == null) { + throw ("Trying to get accessToken with null userModel"); + } + } } _pangeaController.pStoreService.save( PLocalKey.access, diff --git a/lib/pangea/repo/user_repo.dart b/lib/pangea/repo/user_repo.dart index 47caaab0b..244e21c54 100644 --- a/lib/pangea/repo/user_repo.dart +++ b/lib/pangea/repo/user_repo.dart @@ -2,6 +2,7 @@ import 'dart:convert'; import 'dart:developer'; import 'package:fluffychat/pangea/constants/model_keys.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:http/http.dart'; import '../models/user_model.dart'; @@ -10,6 +11,34 @@ import '../network/requests.dart'; import '../network/urls.dart'; class PUserRepo { + static Future repoCreatePangeaUser({ + required String userID, + required String dob, + required fullName, + required String matrixAccessToken, + }) async { + try { + final Requests req = Requests( + baseUrl: PApiUrls.baseAPI, + matrixAccessToken: matrixAccessToken, + ); + + final Map body = { + ModelKey.userFullName: fullName, + ModelKey.userPangeaUserId: userID, + ModelKey.userDateOfBirth: dob, + }; + final resp = await req.post( + url: PApiUrls.createUser, + body: body, + ); + return PangeaProfileResponse.fromJson(jsonDecode(resp.body)); + } catch (err, s) { + ErrorHandler.logError(e: err, s: s); + return null; + } + } + static Future fetchPangeaUserInfo({ required String userID, required String matrixAccessToken, From d9f272e38999d650883e2ac3f7e505c1946a55fc Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 30 Jul 2024 12:52:23 -0400 Subject: [PATCH 07/31] don't have analytics rooms for bot user --- lib/pangea/controllers/my_analytics_controller.dart | 8 ++++---- .../client_extension/client_analytics_extension.dart | 8 ++++++-- .../extensions/client_extension/client_extension.dart | 2 +- 3 files changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/pangea/controllers/my_analytics_controller.dart b/lib/pangea/controllers/my_analytics_controller.dart index 12baeb689..4c592a6fc 100644 --- a/lib/pangea/controllers/my_analytics_controller.dart +++ b/lib/pangea/controllers/my_analytics_controller.dart @@ -233,11 +233,11 @@ class MyAnalyticsController { if (userL2 == null || _client.userID == null) return; // analytics room for the user and current target language - final Room analyticsRoom = await _client.getMyAnalyticsRoom(userL2!); + final Room? analyticsRoom = await _client.getMyAnalyticsRoom(userL2!); // get the last time analytics were updated for this room final DateTime? l2AnalyticsLastUpdated = - await analyticsRoom.analyticsLastUpdated( + await analyticsRoom?.analyticsLastUpdated( PangeaEventTypes.summaryAnalytics, _client.userID!, ); @@ -307,7 +307,7 @@ class MyAnalyticsController { // if there's new content to be sent, or if lastUpdated hasn't been // set yet for this room, send the analytics events if (summaryContent.isNotEmpty || l2AnalyticsLastUpdated == null) { - await analyticsRoom.sendSummaryAnalyticsEvent( + await analyticsRoom?.sendSummaryAnalyticsEvent( summaryContent, ); } @@ -347,7 +347,7 @@ class MyAnalyticsController { // ); if (recentConstructUses.isNotEmpty) { - await analyticsRoom.sendConstructsEvent( + await analyticsRoom?.sendConstructsEvent( recentConstructUses, ); } diff --git a/lib/pangea/extensions/client_extension/client_analytics_extension.dart b/lib/pangea/extensions/client_extension/client_analytics_extension.dart index 396e09f8d..af43a7ba2 100644 --- a/lib/pangea/extensions/client_extension/client_analytics_extension.dart +++ b/lib/pangea/extensions/client_extension/client_analytics_extension.dart @@ -3,7 +3,7 @@ part of "client_extension.dart"; extension AnalyticsClientExtension on Client { /// Get the logged in user's analytics room matching /// a given langCode. If not present, create it. - Future _getMyAnalyticsRoom(String langCode) async { + Future _getMyAnalyticsRoom(String langCode) async { final Room? analyticsRoom = _analyticsRoomLocal(langCode); if (analyticsRoom != null) return analyticsRoom; return _makeAnalyticsRoom(langCode); @@ -35,7 +35,11 @@ extension AnalyticsClientExtension on Client { /// /// If the room does not appear immediately after creation, this method waits for it to appear in sync. /// Returns the created [Room] object. - Future _makeAnalyticsRoom(String langCode) async { + Future _makeAnalyticsRoom(String langCode) async { + if (userID == null || userID == BotName.byEnvironment) { + return null; + } + final String roomID = await createRoom( creationContent: { 'type': PangeaRoomTypes.analytics, diff --git a/lib/pangea/extensions/client_extension/client_extension.dart b/lib/pangea/extensions/client_extension/client_extension.dart index af66c7d1f..7af50d501 100644 --- a/lib/pangea/extensions/client_extension/client_extension.dart +++ b/lib/pangea/extensions/client_extension/client_extension.dart @@ -21,7 +21,7 @@ extension PangeaClient on Client { /// Get the logged in user's analytics room matching /// a given langCode. If not present, create it. - Future getMyAnalyticsRoom(String langCode) async => + Future getMyAnalyticsRoom(String langCode) async => await _getMyAnalyticsRoom(langCode); /// Get local analytics room for a given langCode and From 398cac35ffe095212ec92424c113e97fb6b31d81 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 30 Jul 2024 12:55:42 -0400 Subject: [PATCH 08/31] don't add analytics rooms to spaces if you are the bot --- .../extensions/client_extension/client_analytics_extension.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pangea/extensions/client_extension/client_analytics_extension.dart b/lib/pangea/extensions/client_extension/client_analytics_extension.dart index b694a02ca..381bbba4c 100644 --- a/lib/pangea/extensions/client_extension/client_analytics_extension.dart +++ b/lib/pangea/extensions/client_extension/client_analytics_extension.dart @@ -78,6 +78,7 @@ extension AnalyticsClientExtension on Client { // migration function to change analytics rooms' vsibility to public // so they will appear in the space hierarchy Future _updateAnalyticsRoomVisibility() async { + if (userID == null || userID == BotName.byEnvironment) return; await Future.wait( allMyAnalyticsRooms.map((room) async { final visability = await getRoomVisibilityOnDirectory(room.id); @@ -95,6 +96,7 @@ extension AnalyticsClientExtension on Client { /// so teachers can join them via space hierarchy. /// Allows teachers to join analytics rooms without being invited. void _addAnalyticsRoomsToAllSpaces() { + if (userID == null || userID == BotName.byEnvironment) return; for (final Room room in allMyAnalyticsRooms) { room.addAnalyticsRoomToSpaces(); } From bc913e4d7aad04f0a7e12610c74d3fc0b363743e Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 30 Jul 2024 13:54:05 -0400 Subject: [PATCH 09/31] bump version number --- pubspec.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.yaml b/pubspec.yaml index 1e75fc4b5..2f2d47699 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -6,7 +6,7 @@ description: Learn a language while texting your friends. # Pangea# publish_to: none # On version bump also increase the build number for F-Droid -version: 1.21.1+3533 +version: 1.21.2+3534 environment: sdk: ">=3.0.0 <4.0.0" From 347fa01ff8eeb6048e0a26cea88c6f75ed6abf2f Mon Sep 17 00:00:00 2001 From: Kelrap Date: Tue, 30 Jul 2024 14:01:11 -0400 Subject: [PATCH 10/31] Chat list is shown when rooms are loaded --- lib/pages/chat_list/chat_list.dart | 3 +++ lib/pages/chat_list/chat_list_body.dart | 12 ++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 8f5515fc4..e4ac86d36 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -909,6 +909,9 @@ class ChatListController extends State Future _waitForFirstSync() async { final client = Matrix.of(context).client; await client.roomsLoading; + // #Pangea + setState(() {}); + // Pangea# await client.accountDataLoading; await client.userDeviceKeysLoading; if (client.prevBatch == null) { diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index b9b388da9..11be0e097 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -187,7 +187,12 @@ class ChatListViewBody extends StatelessWidget { ], ), ), - if (client.prevBatch == null) + // #Pangea + // Only show loading screen if room list is empty + // because it is still loading + // if (client.prevBatch == null) + if (rooms.isEmpty && client.prevBatch == null) + // Pangea# SliverList( delegate: SliverChildBuilderDelegate( (context, i) => Opacity( @@ -245,7 +250,10 @@ class ChatListViewBody extends StatelessWidget { childCount: dummyChatCount, ), ), - if (client.prevBatch != null) + // #Pangea + // if (client.prevBatch != null) + if (rooms.isNotEmpty) + // Pangea# SliverList.builder( itemCount: rooms.length, itemBuilder: (BuildContext context, int i) { From 097417188df2c4aa848440df8b55ecaa163ef483 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Tue, 30 Jul 2024 14:26:26 -0400 Subject: [PATCH 11/31] Move less important syncs to own function --- lib/pages/chat_list/chat_list.dart | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index e4ac86d36..8d49c9478 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -933,8 +933,17 @@ class ChatListController extends State } // #Pangea + _lessImportantSyncs(client); + // Pangea# + if (!mounted) return; + setState(() { + waitForFirstSync = true; + }); + } + + // #Pangea + Future _lessImportantSyncs(Client client) async { if (mounted) { - // TODO try not to await so much GoogleAnalytics.analyticsUserUpdate(client.userID); await pangeaController.subscriptionController.initialize(); await pangeaController.myAnalytics.initialize(); @@ -946,14 +955,9 @@ class ChatListController extends State ErrorHandler.logError( m: "didn't run afterSyncAndFirstLoginInitialization because not mounted", ); - // debugger(when: kDebugMode); } - // Pangea# - if (!mounted) return; - setState(() { - waitForFirstSync = true; - }); } + // Pangea# void cancelAction() { if (selectMode == SelectMode.share) { From cd6a90473545794ffaaed1b392edb9f132ae266c Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 31 Jul 2024 13:36:36 -0400 Subject: [PATCH 12/31] prevent single character input from disapearing --- lib/pangea/models/igc_text_data_model.dart | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/lib/pangea/models/igc_text_data_model.dart b/lib/pangea/models/igc_text_data_model.dart index fe052a5ec..5f32f92d1 100644 --- a/lib/pangea/models/igc_text_data_model.dart +++ b/lib/pangea/models/igc_text_data_model.dart @@ -140,8 +140,6 @@ class IGCTextData { matches.removeAt(matchIndex); for (final match in matches) { - final matchOffset = match.match.offset; - final matchLength = match.match.length; match.match.fullText = originalInput; if (match.match.offset > pangeaMatch.match.offset) { match.match.offset += replacement.length - pangeaMatch.match.length; @@ -305,7 +303,7 @@ class IGCTextData { // create a pointer to the current index in the original input // and iterate until the pointer has reached the end of the input int currentIndex = 0; - while (currentIndex < originalInput.characters.length - 1) { + while (currentIndex < originalInput.characters.length) { // check if the pointer is at a match, and if so, get the index of the match final int matchIndex = matchRanges.indexWhere( (range) => currentIndex >= range[0] && currentIndex < range[1], From 9cc6a14734f6546fd6f2edde7a453dd18ebec288 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Wed, 31 Jul 2024 14:12:51 -0400 Subject: [PATCH 13/31] Enables activity tab on audio toolbar --- lib/pangea/enum/message_mode_enum.dart | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/lib/pangea/enum/message_mode_enum.dart b/lib/pangea/enum/message_mode_enum.dart index 58753e5b5..9faeb1d94 100644 --- a/lib/pangea/enum/message_mode_enum.dart +++ b/lib/pangea/enum/message_mode_enum.dart @@ -71,11 +71,13 @@ extension MessageModeExtension on MessageMode { switch (this) { case MessageMode.translation: case MessageMode.textToSpeech: - case MessageMode.practiceActivity: case MessageMode.definition: return event.messageType == MessageTypes.Text; case MessageMode.speechToText: return event.messageType == MessageTypes.Audio; + case MessageMode.practiceActivity: + return event.messageType == MessageTypes.Audio || + event.messageType == MessageTypes.Text; default: return true; } From 4b65b95060fb66c2b91e018265bc240a8ff4175b Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 31 Jul 2024 14:51:22 -0400 Subject: [PATCH 14/31] remove default for isValidMode switch statement, return true if practiceActivity --- lib/pangea/enum/message_mode_enum.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/pangea/enum/message_mode_enum.dart b/lib/pangea/enum/message_mode_enum.dart index 9faeb1d94..11c96e10e 100644 --- a/lib/pangea/enum/message_mode_enum.dart +++ b/lib/pangea/enum/message_mode_enum.dart @@ -76,9 +76,6 @@ extension MessageModeExtension on MessageMode { case MessageMode.speechToText: return event.messageType == MessageTypes.Audio; case MessageMode.practiceActivity: - return event.messageType == MessageTypes.Audio || - event.messageType == MessageTypes.Text; - default: return true; } } From b9c9332d28fb3e3cd3502a0815d42e21883624eb Mon Sep 17 00:00:00 2001 From: Kelrap Date: Wed, 31 Jul 2024 15:12:04 -0400 Subject: [PATCH 15/31] Remove unecessary setState --- lib/pages/chat_list/chat_list.dart | 3 --- 1 file changed, 3 deletions(-) diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 8d49c9478..8a588d1aa 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -909,9 +909,6 @@ class ChatListController extends State Future _waitForFirstSync() async { final client = Matrix.of(context).client; await client.roomsLoading; - // #Pangea - setState(() {}); - // Pangea# await client.accountDataLoading; await client.userDeviceKeysLoading; if (client.prevBatch == null) { From 0da6bb9cb5d35ce3a2a46bfb9113ef5e99488de3 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Wed, 31 Jul 2024 15:32:08 -0400 Subject: [PATCH 16/31] Add comment explaining rationale --- lib/pages/chat_details/chat_details_view.dart | 2 ++ 1 file changed, 2 insertions(+) diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 7bda65abf..0afa56086 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -139,6 +139,8 @@ class ChatDetailsView extends StatelessWidget { ), ), // #Pangea + // Hero animation is causing weird visual glitch + // Probably not worth keeping // child: Hero( // tag: controller.widget // .embeddedCloseButton != From 4de8530a7e357235713894f4a3f22fddba174112 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Thu, 1 Aug 2024 17:15:25 -0400 Subject: [PATCH 17/31] separate 2 components for bot settings in create group and chat details --- assets/l10n/intl_en.arb | 3 +- lib/pages/chat_details/chat_details.dart | 7 +- lib/pages/chat_details/chat_details_view.dart | 4 +- lib/pages/new_group/new_group.dart | 7 +- lib/pages/new_group/new_group_view.dart | 4 +- .../conversation_bot_settings.dart | 269 ------------------ ...onversation_bot_settings_chat_details.dart | 227 +++++++++++++++ ...onversation_bot_settings_create_group.dart | 237 +++++++++++++++ 8 files changed, 478 insertions(+), 280 deletions(-) delete mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 385009ff6..88c1e21f6 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3879,7 +3879,7 @@ "define": "Define", "listen": "Listen", "addConversationBot": "Enable Conversation Bot", - "addConversationBotDesc": "Add a bot to this group chat that will ask questions on a specific topic", + "addConversationBotDesc": "Add a bot to this group chat", "convoBotSettingsTitle": "Conversation Bot Settings", "convoBotSettingsDescription": "Edit conversation topic and difficulty", "enterAConversationTopic": "Enter a conversation topic", @@ -4004,6 +4004,7 @@ "conversationBotCustomZone_customSystemPromptLabel": "System prompt", "conversationBotCustomZone_customSystemPromptPlaceholder": "Set custom system prompt", "conversationBotCustomZone_customTriggerReactionEnabledLabel": "Responds on ⏩ reaction", + "botConfig": "Conversation Bot Settings", "addConversationBotDialogTitleInvite": "Confirm inviting conversation bot", "addConversationBotButtonInvite": "Invite", "addConversationBotDialogInviteConfirmation": "Invite", diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 7b7bbfd1c..383ffb5a5 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -6,7 +6,7 @@ import 'package:fluffychat/pages/settings/settings.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_description_button.dart'; import 'package:fluffychat/pangea/utils/set_class_name.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -43,8 +43,9 @@ class ChatDetailsController extends State { // #Pangea final GlobalKey addToSpaceKey = GlobalKey(); - final GlobalKey addConversationBotKey = - GlobalKey(); + final GlobalKey + addConversationBotKey = + GlobalKey(); bool displayAddStudentOptions = false; void toggleAddStudentOptions() => diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 0afa56086..dbc3b2152 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -11,7 +11,7 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_nam import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/utils/lock_room.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/widgets/avatar.dart'; @@ -452,7 +452,7 @@ class ChatDetailsView extends StatelessWidget { if (!room.isSpace && !room.isDirectChat && room.canInvite) - ConversationBotSettings( + ConversationBotSettingsChatDetails( key: controller.addConversationBotKey, room: room, ), diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 9c6e22f85..94684e442 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -11,7 +11,7 @@ import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/utils/class_chat_power_levels.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -51,8 +51,9 @@ class NewGroupController extends State { // #Pangea PangeaController pangeaController = MatrixState.pangeaController; final GlobalKey addToSpaceKey = GlobalKey(); - final GlobalKey addConversationBotKey = - GlobalKey(); + final GlobalKey + addConversationBotKey = + GlobalKey(); final GlobalKey addCapacityKey = GlobalKey(); diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index 84bfbfbc5..37061da3d 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -2,7 +2,7 @@ import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/new_group/new_group.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; @@ -99,7 +99,7 @@ class NewGroupView extends StatelessWidget { RoomCapacityButton( key: controller.addCapacityKey, ), - ConversationBotSettings( + ConversationBotSettingsCreateGroup( key: controller.addConversationBotKey, activeSpaceId: controller.activeSpaceId, ), diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart deleted file mode 100644 index 1c78fd030..000000000 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart +++ /dev/null @@ -1,269 +0,0 @@ -import 'dart:developer'; - -import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/utils/bot_name.dart'; -import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; -import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; -import 'package:flutter/foundation.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 '../../../widgets/matrix.dart'; -import '../../constants/pangea_event_types.dart'; -import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; -import '../../utils/error_handler.dart'; - -class ConversationBotSettings extends StatefulWidget { - final Room? room; - final bool startOpen; - final String? activeSpaceId; - - const ConversationBotSettings({ - super.key, - this.room, - this.startOpen = false, - this.activeSpaceId, - }); - - @override - ConversationBotSettingsState createState() => ConversationBotSettingsState(); -} - -class ConversationBotSettingsState extends State { - late BotOptionsModel botOptions; - late bool isOpen; - bool addBot = false; - Room? parentSpace; - - ConversationBotSettingsState({Key? key}); - - @override - void initState() { - super.initState(); - isOpen = widget.startOpen; - botOptions = widget.room?.botOptions != null - ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) - : BotOptionsModel(); - widget.room?.isBotRoom.then((bool isBotRoom) { - setState(() { - addBot = isBotRoom; - }); - }); - parentSpace = widget.activeSpaceId != null - ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) - : null; - } - - Future updateBotOption(void Function() makeLocalChange) async { - makeLocalChange(); - await showFutureLoadingDialog( - context: context, - future: () async { - try { - await setBotOption(); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - setState(() {}); - }, - ); - } - - Future setBotOption() async { - if (widget.room == null) return; - try { - await Matrix.of(context).client.setRoomStateWithKey( - widget.room!.id, - PangeaEventTypes.botOptions, - '', - botOptions.toJson(), - ); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - } - - @override - Widget build(BuildContext context) => Column( - children: [ - ListTile( - title: Text( - L10n.of(context)!.convoBotSettingsTitle, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text(L10n.of(context)!.convoBotSettingsDescription), - leading: CircleAvatar( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, - child: const Icon(Icons.psychology_outlined), - ), - trailing: Icon( - isOpen - ? Icons.keyboard_arrow_down_outlined - : Icons.keyboard_arrow_right_outlined, - ), - onTap: () => setState(() => isOpen = !isOpen), - ), - if (isOpen) - AnimatedContainer( - duration: const Duration(milliseconds: 300), - height: isOpen ? null : 0, - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16), - child: ListTile( - title: Text( - L10n.of(context)!.addConversationBot, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text(L10n.of(context)!.addConversationBotDesc), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: - Theme.of(context).textTheme.bodyLarge!.color, - child: const BotFace( - width: 30.0, - expression: BotExpression.idle, - ), - ), - trailing: ElevatedButton( - onPressed: () async { - final bool? confirm = await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: addBot - ? Text( - L10n.of(context)! - .addConversationBotButtonTitleRemove, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogTitleInvite, - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(L10n.of(context)!.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(!addBot); - }, - child: addBot - ? Text( - L10n.of(context)! - .addConversationBotDialogRemoveConfirmation, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogInviteConfirmation, - ), - ), - ], - ); - }, - ); - - if (confirm == true) { - setState(() => addBot = true); - widget.room?.invite(BotName.byEnvironment); - } else { - setState(() => addBot = false); - widget.room?.kick(BotName.byEnvironment); - } - }, - child: addBot - ? Text( - L10n.of(context)! - .addConversationBotButtonRemove, - ) - : Text( - L10n.of(context)! - .addConversationBotButtonInvite, - ), - ), - ), - ), - if (addBot) ...[ - Padding( - padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), - child: Text( - L10n.of(context)!.conversationLanguageLevel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: LanguageLevelDropdown( - initialLevel: botOptions.languageLevel, - onChanged: (int? newValue) => updateBotOption(() { - botOptions.languageLevel = newValue!; - }), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), - child: Text( - L10n.of(context)!.conversationBotModeSelectDescription, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: ConversationBotModeSelect( - initialMode: botOptions.mode, - onChanged: (String? mode) => updateBotOption( - () { - botOptions.mode = mode ?? "discussion"; - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), - child: ConversationBotModeDynamicZone( - initialBotOptions: botOptions, - onChanged: (BotOptionsModel? newOptions) { - updateBotOption(() { - if (newOptions != null) { - botOptions = newOptions; - } - }); - }, - ), - ), - const SizedBox(height: 16), - ], - ], - ), - ), - ], - ); -} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart new file mode 100644 index 000000000..59b35e3fe --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart @@ -0,0 +1,227 @@ +import 'dart:developer'; + +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/utils/bot_name.dart'; +import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; +import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:flutter/foundation.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 '../../../widgets/matrix.dart'; +import '../../constants/pangea_event_types.dart'; +import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; +import '../../utils/error_handler.dart'; + +class ConversationBotSettingsChatDetails extends StatefulWidget { + final Room? room; + final bool startOpen; + final String? activeSpaceId; + + const ConversationBotSettingsChatDetails({ + super.key, + this.room, + this.startOpen = false, + this.activeSpaceId, + }); + + @override + ConversationBotSettingsChatDetailsState createState() => + ConversationBotSettingsChatDetailsState(); +} + +class ConversationBotSettingsChatDetailsState + extends State { + late BotOptionsModel botOptions; + late bool isOpen; + bool addBot = false; + Room? parentSpace; + + ConversationBotSettingsChatDetailsState({Key? key}); + + @override + void initState() { + super.initState(); + isOpen = widget.startOpen; + botOptions = widget.room?.botOptions != null + ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) + : BotOptionsModel(); + widget.room?.isBotRoom.then((bool isBotRoom) { + setState(() { + addBot = isBotRoom; + }); + }); + parentSpace = widget.activeSpaceId != null + ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) + : null; + } + + Future updateBotOption(void Function() makeLocalChange) async { + makeLocalChange(); + await showFutureLoadingDialog( + context: context, + future: () async { + try { + await setBotOption(); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + setState(() {}); + }, + ); + } + + Future setBotOption() async { + if (widget.room == null) return; + try { + await Matrix.of(context).client.setRoomStateWithKey( + widget.room!.id, + PangeaEventTypes.botOptions, + '', + botOptions.toJson(), + ); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + } + + @override + Widget build(BuildContext context) => AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + title: Text( + L10n.of(context)!.botConfig, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + leading: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, + child: const BotFace( + width: 30.0, + expression: BotExpression.idle, + ), + ), + trailing: const Icon(Icons.settings), + onTap: () async { + final bool? confirm = await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: addBot + ? Text( + L10n.of(context)! + .addConversationBotButtonTitleRemove, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogTitleInvite, + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(L10n.of(context)!.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(!addBot); + }, + child: addBot + ? Text( + L10n.of(context)! + .addConversationBotDialogRemoveConfirmation, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogInviteConfirmation, + ), + ), + ], + ); + }, + ); + if (confirm == true) { + setState(() => addBot = true); + widget.room?.invite(BotName.byEnvironment); + } else { + setState(() => addBot = false); + widget.room?.kick(BotName.byEnvironment); + } + }, + ), + if (addBot) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), + child: Text( + L10n.of(context)!.conversationLanguageLevel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: LanguageLevelDropdown( + initialLevel: botOptions.languageLevel, + onChanged: (int? newValue) => updateBotOption(() { + botOptions.languageLevel = newValue!; + }), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), + child: Text( + L10n.of(context)!.conversationBotModeSelectDescription, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: ConversationBotModeSelect( + initialMode: botOptions.mode, + onChanged: (String? mode) => updateBotOption( + () { + botOptions.mode = mode ?? "discussion"; + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), + child: ConversationBotModeDynamicZone( + initialBotOptions: botOptions, + onChanged: (BotOptionsModel? newOptions) { + updateBotOption(() { + if (newOptions != null) { + botOptions = newOptions; + } + }); + }, + ), + ), + const SizedBox(height: 16), + ], + ], + ), + ); +} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart new file mode 100644 index 000000000..49d3df9c0 --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart @@ -0,0 +1,237 @@ +import 'dart:developer'; + +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/utils/bot_name.dart'; +import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; +import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:flutter/foundation.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 '../../../widgets/matrix.dart'; +import '../../constants/pangea_event_types.dart'; +import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; +import '../../utils/error_handler.dart'; + +class ConversationBotSettingsCreateGroup extends StatefulWidget { + final Room? room; + final bool startOpen; + final String? activeSpaceId; + + const ConversationBotSettingsCreateGroup({ + super.key, + this.room, + this.startOpen = false, + this.activeSpaceId, + }); + + @override + ConversationBotSettingsCreateGroupState createState() => + ConversationBotSettingsCreateGroupState(); +} + +class ConversationBotSettingsCreateGroupState + extends State { + late BotOptionsModel botOptions; + late bool isOpen; + bool addBot = false; + Room? parentSpace; + + ConversationBotSettingsCreateGroupState({Key? key}); + + @override + void initState() { + super.initState(); + isOpen = widget.startOpen; + botOptions = widget.room?.botOptions != null + ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) + : BotOptionsModel(); + widget.room?.isBotRoom.then((bool isBotRoom) { + setState(() { + addBot = isBotRoom; + }); + }); + parentSpace = widget.activeSpaceId != null + ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) + : null; + } + + Future updateBotOption(void Function() makeLocalChange) async { + makeLocalChange(); + await showFutureLoadingDialog( + context: context, + future: () async { + try { + await setBotOption(); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + setState(() {}); + }, + ); + } + + Future setBotOption() async { + if (widget.room == null) return; + try { + await Matrix.of(context).client.setRoomStateWithKey( + widget.room!.id, + PangeaEventTypes.botOptions, + '', + botOptions.toJson(), + ); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + } + + @override + Widget build(BuildContext context) => AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + title: Text( + L10n.of(context)!.addConversationBot, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text(L10n.of(context)!.addConversationBotDesc), + leading: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, + child: const BotFace( + width: 30.0, + expression: BotExpression.idle, + ), + ), + trailing: ElevatedButton( + onPressed: () async { + final bool? confirm = await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: addBot + ? Text( + L10n.of(context)! + .addConversationBotButtonTitleRemove, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogTitleInvite, + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(L10n.of(context)!.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(!addBot); + }, + child: addBot + ? Text( + L10n.of(context)! + .addConversationBotDialogRemoveConfirmation, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogInviteConfirmation, + ), + ), + ], + ); + }, + ); + + if (confirm == true) { + setState(() => addBot = true); + widget.room?.invite(BotName.byEnvironment); + } else { + setState(() => addBot = false); + widget.room?.kick(BotName.byEnvironment); + } + }, + child: addBot + ? Text( + L10n.of(context)!.addConversationBotButtonRemove, + ) + : Text( + L10n.of(context)!.addConversationBotButtonInvite, + ), + ), + ), + if (addBot) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), + child: Text( + L10n.of(context)!.conversationLanguageLevel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: LanguageLevelDropdown( + initialLevel: botOptions.languageLevel, + onChanged: (int? newValue) => updateBotOption(() { + botOptions.languageLevel = newValue!; + }), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), + child: Text( + L10n.of(context)!.conversationBotModeSelectDescription, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: ConversationBotModeSelect( + initialMode: botOptions.mode, + onChanged: (String? mode) => updateBotOption( + () { + botOptions.mode = mode ?? "discussion"; + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), + child: ConversationBotModeDynamicZone( + initialBotOptions: botOptions, + onChanged: (BotOptionsModel? newOptions) { + updateBotOption(() { + if (newOptions != null) { + botOptions = newOptions; + } + }); + }, + ), + ), + const SizedBox(height: 16), + ], + ], + ), + ); +} From 8294e1959c2c97caa5ea20e2616dec3aae2e4ffd Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 2 Aug 2024 13:32:23 -0400 Subject: [PATCH 18/31] Fixes input bar spacing issues --- lib/pages/chat/chat_view.dart | 425 ++++++++++++++++++---------------- 1 file changed, 220 insertions(+), 205 deletions(-) diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 9b12f9904..405e16418 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -14,7 +14,6 @@ import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/widgets/chat/chat_floating_action_button.dart'; import 'package:fluffychat/utils/account_config.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/chat_settings_popup_menu.dart'; import 'package:fluffychat/widgets/connection_status_header.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -299,216 +298,232 @@ class ChatView extends StatelessWidget { ), ), SafeArea( - child: Column( - children: [ - Expanded( - child: GestureDetector( - onTap: controller.clearSingleSelectedEvent, - child: Builder( - builder: (context) { - if (controller.timeline == null) { - return const Center( - child: CircularProgressIndicator.adaptive( - strokeWidth: 2, - ), - ); - } - return ChatEventList( - controller: controller, - ); - }, - ), - ), - ), - if (controller.room.canSendDefaultMessages && - controller.room.membership == Membership.join) - Container( - margin: EdgeInsets.only( - bottom: bottomSheetPadding, - left: bottomSheetPadding, - right: bottomSheetPadding, - ), - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 2.5, - ), - alignment: Alignment.center, - child: Material( - clipBehavior: Clip.hardEdge, - color: Theme.of(context) - .colorScheme - // ignore: deprecated_member_use - .surfaceVariant, - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), - child: controller.room.isAbandonedDMRoom == true - ? Row( - mainAxisAlignment: - MainAxisAlignment.spaceEvenly, - children: [ - // #Pangea - if (controller.room.isRoomAdmin) - TextButton.icon( - style: TextButton.styleFrom( - padding: const EdgeInsets.all( - 16, - ), - foregroundColor: Theme.of(context) - .colorScheme - .error, - ), - icon: const Icon( - Icons.archive_outlined, - ), - onPressed: controller.archiveChat, - label: Text( - L10n.of(context)!.archive, - ), - ), - // Pangea# - TextButton.icon( - style: TextButton.styleFrom( - padding: const EdgeInsets.all( - 16, - ), - foregroundColor: Theme.of(context) - .colorScheme - .error, - ), - icon: const Icon( - // #Pangea - // Icons.archive_outlined, - Icons.arrow_forward, - // Pangea# - ), - onPressed: controller.leaveChat, - label: Text( - L10n.of(context)!.leave, - ), - ), - TextButton.icon( - style: TextButton.styleFrom( - padding: const EdgeInsets.all( - 16, - ), - ), - icon: const Icon( - Icons.forum_outlined, - ), - onPressed: controller.recreateChat, - label: Text( - L10n.of(context)!.reopenChat, - ), - ), - ], - ) - : - // #Pangea - null, - // Column( - // mainAxisSize: MainAxisSize.min, - // children: [ - // const ConnectionStatusHeader(), - // ITBar( - // choreographer: - // controller.choreographer, - // ), - // ReactionsPicker(controller), - // ReplyDisplay(controller), - // ChatInputRow(controller), - // ChatEmojiPicker(controller), - // ], - // ), - // Pangea# - ), - ), + child: // #Pangea - // Keep messages above minimum input bar height - SizedBox( - height: (PlatformInfos.isMobile ? 30 : 60), + Stack( + children: [ + // Pangea# + Column( + children: [ + Expanded( + child: GestureDetector( + onTap: controller.clearSingleSelectedEvent, + child: Builder( + builder: (context) { + if (controller.timeline == null) { + return const Center( + child: + CircularProgressIndicator.adaptive( + strokeWidth: 2, + ), + ); + } + return ChatEventList( + controller: controller, + ); + }, + ), + ), + ), + if (controller.room.canSendDefaultMessages && + controller.room.membership == Membership.join) + Container( + margin: EdgeInsets.only( + bottom: bottomSheetPadding, + left: bottomSheetPadding, + right: bottomSheetPadding, + ), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth * 2.5, + ), + alignment: Alignment.center, + child: Material( + clipBehavior: Clip.hardEdge, + color: Theme.of(context) + .colorScheme + // ignore: deprecated_member_use + .surfaceVariant, + borderRadius: const BorderRadius.all( + Radius.circular(24), + ), + child: controller.room.isAbandonedDMRoom == + true + ? Row( + mainAxisAlignment: + MainAxisAlignment.spaceEvenly, + children: [ + // #Pangea + if (controller.room.isRoomAdmin) + TextButton.icon( + style: TextButton.styleFrom( + padding: const EdgeInsets.all( + 16, + ), + foregroundColor: + Theme.of(context) + .colorScheme + .error, + ), + icon: const Icon( + Icons.archive_outlined, + ), + onPressed: + controller.archiveChat, + label: Text( + L10n.of(context)!.archive, + ), + ), + // Pangea# + TextButton.icon( + style: TextButton.styleFrom( + padding: const EdgeInsets.all( + 16, + ), + foregroundColor: + Theme.of(context) + .colorScheme + .error, + ), + icon: const Icon( + // #Pangea + // Icons.archive_outlined, + Icons.arrow_forward, + // Pangea# + ), + onPressed: controller.leaveChat, + label: Text( + L10n.of(context)!.leave, + ), + ), + TextButton.icon( + style: TextButton.styleFrom( + padding: const EdgeInsets.all( + 16, + ), + ), + icon: const Icon( + Icons.forum_outlined, + ), + onPressed: + controller.recreateChat, + label: Text( + L10n.of(context)!.reopenChat, + ), + ), + ], + ) + : + // #Pangea + null, + // Column( + // mainAxisSize: MainAxisSize.min, + // children: [ + // const ConnectionStatusHeader(), + // ITBar( + // choreographer: + // controller.choreographer, + // ), + // ReactionsPicker(controller), + // ReplyDisplay(controller), + // ChatInputRow(controller), + // ChatEmojiPicker(controller), + // ], + // ), + // Pangea# + ), + ), + // #Pangea + // Keep messages above minimum input bar height + const SizedBox( + height: 60, + ), + // Pangea# + ], + ), + // #Pangea + Positioned( + left: 0, + right: 0, + bottom: 16, + child: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + if (!controller.selectMode) + Container( + margin: EdgeInsets.only( + bottom: 10, + left: bottomSheetPadding, + right: bottomSheetPadding, + ), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth * 2.4, + ), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + StartIGCButton( + controller: controller, + ), + ChatFloatingActionButton( + controller: controller, + ), + ], + ), + ), + Container( + margin: EdgeInsets.only( + bottom: bottomSheetPadding, + left: bottomSheetPadding, + right: bottomSheetPadding, + ), + constraints: const BoxConstraints( + maxWidth: FluffyThemes.columnWidth * 2.5, + ), + alignment: Alignment.center, + child: Material( + clipBehavior: Clip.hardEdge, + color: Theme.of(context) + .colorScheme + .surfaceContainerHighest, + borderRadius: const BorderRadius.all( + Radius.circular(24), + ), + child: Column( + children: [ + const ConnectionStatusHeader(), + ITBar( + choreographer: controller.choreographer, + ), + ReactionsPicker(controller), + ReplyDisplay(controller), + ChatInputRow(controller), + ChatEmojiPicker(controller), + ], + ), + ), + ), + ], + ), ), // Pangea# ], ), + // #Pangea + // if (controller.dragging) + // Container( + // color: Theme.of(context) + // .scaffoldBackgroundColor + // .withOpacity(0.9), + // alignment: Alignment.center, + // child: const Icon( + // Icons.upload_outlined, + // size: 100, + // ), + // ), + // Pangea# ), - // #Pangea - // if (controller.dragging) - // Container( - // color: Theme.of(context) - // .scaffoldBackgroundColor - // .withOpacity(0.9), - // alignment: Alignment.center, - // child: const Icon( - // Icons.upload_outlined, - // size: 100, - // ), - // ), - Positioned( - left: 0, - right: 0, - bottom: 16, - child: Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (!controller.selectMode) - Container( - margin: EdgeInsets.only( - bottom: 10, - left: bottomSheetPadding, - right: bottomSheetPadding, - ), - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 2.4, - ), - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - StartIGCButton( - controller: controller, - ), - ChatFloatingActionButton( - controller: controller, - ), - ], - ), - ), - Container( - margin: EdgeInsets.only( - bottom: bottomSheetPadding, - left: bottomSheetPadding, - right: bottomSheetPadding, - ), - constraints: const BoxConstraints( - maxWidth: FluffyThemes.columnWidth * 2.5, - ), - alignment: Alignment.center, - child: Material( - clipBehavior: Clip.hardEdge, - color: Theme.of(context) - .colorScheme - .surfaceContainerHighest, - borderRadius: const BorderRadius.all( - Radius.circular(24), - ), - child: Column( - children: [ - const ConnectionStatusHeader(), - ITBar( - choreographer: controller.choreographer, - ), - ReactionsPicker(controller), - ReplyDisplay(controller), - ChatInputRow(controller), - ChatEmojiPicker(controller), - ], - ), - ), - ), - ], - ), - ), - // Pangea# ], ), ); From 98732ec904f2c58a08382ac2fc80cc4ca4a8ee32 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Fri, 2 Aug 2024 14:34:39 -0400 Subject: [PATCH 19/31] Sets minimum width for toolbar content --- lib/pangea/widgets/chat/message_toolbar.dart | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index a638640e7..3c63c81fc 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -435,7 +435,11 @@ class MessageToolbarState extends State { child: Column( mainAxisSize: MainAxisSize.min, children: [ - Flexible( + Container( + constraints: const BoxConstraints( + minWidth: 300, + maxHeight: 228, + ), child: SingleChildScrollView( child: AnimatedSize( duration: FluffyThemes.animationDuration, From 6cc07d5c3858f8768afbb1875daffb92461c889d Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 5 Aug 2024 09:39:04 -0400 Subject: [PATCH 20/31] changed condition to wait for next sync in stream in waitforfirstsync to better reflect whether the first sync has come through or not --- lib/pages/chat_list/chat_list.dart | 14 ++++++++------ lib/pages/chat_list/chat_list_body.dart | 12 ++---------- 2 files changed, 10 insertions(+), 16 deletions(-) diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index 8a588d1aa..ec34a5b81 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -911,11 +911,12 @@ class ChatListController extends State await client.roomsLoading; await client.accountDataLoading; await client.userDeviceKeysLoading; - if (client.prevBatch == null) { + // #Pangea + // See here for explanation of this change: https://github.com/pangeachat/client/pull/539 + // if (client.prevBatch == null) { + if (client.onSync.value?.nextBatch == null) { + // Pangea# await client.onSync.stream.first; - // #Pangea - pangeaController.startChatWithBotIfNotPresent(); - //Pangea# // Display first login bootstrap if enabled // #Pangea @@ -930,7 +931,7 @@ class ChatListController extends State } // #Pangea - _lessImportantSyncs(client); + await _initPangeaControllers(client); // Pangea# if (!mounted) return; setState(() { @@ -939,9 +940,10 @@ class ChatListController extends State } // #Pangea - Future _lessImportantSyncs(Client client) async { + Future _initPangeaControllers(Client client) async { if (mounted) { GoogleAnalytics.analyticsUserUpdate(client.userID); + pangeaController.startChatWithBotIfNotPresent(); await pangeaController.subscriptionController.initialize(); await pangeaController.myAnalytics.initialize(); pangeaController.afterSyncAndFirstLoginInitialization(context); diff --git a/lib/pages/chat_list/chat_list_body.dart b/lib/pages/chat_list/chat_list_body.dart index 11be0e097..b9b388da9 100644 --- a/lib/pages/chat_list/chat_list_body.dart +++ b/lib/pages/chat_list/chat_list_body.dart @@ -187,12 +187,7 @@ class ChatListViewBody extends StatelessWidget { ], ), ), - // #Pangea - // Only show loading screen if room list is empty - // because it is still loading - // if (client.prevBatch == null) - if (rooms.isEmpty && client.prevBatch == null) - // Pangea# + if (client.prevBatch == null) SliverList( delegate: SliverChildBuilderDelegate( (context, i) => Opacity( @@ -250,10 +245,7 @@ class ChatListViewBody extends StatelessWidget { childCount: dummyChatCount, ), ), - // #Pangea - // if (client.prevBatch != null) - if (rooms.isNotEmpty) - // Pangea# + if (client.prevBatch != null) SliverList.builder( itemCount: rooms.length, itemBuilder: (BuildContext context, int i) { From 2f9446fb803130bdd9495d9486fa571ddf864853 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Mon, 5 Aug 2024 10:05:37 -0400 Subject: [PATCH 21/31] Scrolls to correct message --- lib/pages/chat/chat.dart | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 50cb7ea9f..f278cd7c2 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1109,7 +1109,13 @@ class ChatController extends State } void scrollToEventId(String eventId) async { - final eventIndex = timeline!.events.indexWhere((e) => e.eventId == eventId); + // #Pangea + // final eventIndex = timeline!.events.indexWhere((e) => e.eventId == eventId); + final eventIndex = timeline!.events + .where((event) => event.isVisibleInGui) + .toList() + .indexWhere((e) => e.eventId == eventId); + // Pangea# if (eventIndex == -1) { setState(() { timeline = null; From d86a9303d2689e4cf6c66f95f6daa431a5c62b55 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Mon, 5 Aug 2024 13:26:54 -0400 Subject: [PATCH 22/31] saving, bug at toggle not switching --- assets/l10n/intl_en.arb | 2 + .../conversation_bot_settings.dart | 269 ++++++++++++++++++ ...onversation_bot_settings_chat_details.dart | 57 ++-- 3 files changed, 302 insertions(+), 26 deletions(-) create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 88c1e21f6..981a36238 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4011,6 +4011,8 @@ "addConversationBotButtonTitleRemove": "Confirm removing conversation bot", "addConversationBotButtonRemove": "Remove", "addConversationBotDialogRemoveConfirmation": "Remove", + "conversationBotConfigConfirmChange": "Confirm", + "conversationBotStatus": "Bot Status", "studentAnalyticsNotAvailable": "Student data not currently available", "roomDataMissing": "Some data may be missing from rooms in which you are not a member.", "updatePhoneOS": "You may need to update your device's OS version.", diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart new file mode 100644 index 000000000..1c78fd030 --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart @@ -0,0 +1,269 @@ +import 'dart:developer'; + +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/utils/bot_name.dart'; +import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; +import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:flutter/foundation.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 '../../../widgets/matrix.dart'; +import '../../constants/pangea_event_types.dart'; +import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; +import '../../utils/error_handler.dart'; + +class ConversationBotSettings extends StatefulWidget { + final Room? room; + final bool startOpen; + final String? activeSpaceId; + + const ConversationBotSettings({ + super.key, + this.room, + this.startOpen = false, + this.activeSpaceId, + }); + + @override + ConversationBotSettingsState createState() => ConversationBotSettingsState(); +} + +class ConversationBotSettingsState extends State { + late BotOptionsModel botOptions; + late bool isOpen; + bool addBot = false; + Room? parentSpace; + + ConversationBotSettingsState({Key? key}); + + @override + void initState() { + super.initState(); + isOpen = widget.startOpen; + botOptions = widget.room?.botOptions != null + ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) + : BotOptionsModel(); + widget.room?.isBotRoom.then((bool isBotRoom) { + setState(() { + addBot = isBotRoom; + }); + }); + parentSpace = widget.activeSpaceId != null + ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) + : null; + } + + Future updateBotOption(void Function() makeLocalChange) async { + makeLocalChange(); + await showFutureLoadingDialog( + context: context, + future: () async { + try { + await setBotOption(); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + setState(() {}); + }, + ); + } + + Future setBotOption() async { + if (widget.room == null) return; + try { + await Matrix.of(context).client.setRoomStateWithKey( + widget.room!.id, + PangeaEventTypes.botOptions, + '', + botOptions.toJson(), + ); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + } + + @override + Widget build(BuildContext context) => Column( + children: [ + ListTile( + title: Text( + L10n.of(context)!.convoBotSettingsTitle, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text(L10n.of(context)!.convoBotSettingsDescription), + leading: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, + child: const Icon(Icons.psychology_outlined), + ), + trailing: Icon( + isOpen + ? Icons.keyboard_arrow_down_outlined + : Icons.keyboard_arrow_right_outlined, + ), + onTap: () => setState(() => isOpen = !isOpen), + ), + if (isOpen) + AnimatedContainer( + duration: const Duration(milliseconds: 300), + height: isOpen ? null : 0, + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + Padding( + padding: const EdgeInsets.only(left: 16), + child: ListTile( + title: Text( + L10n.of(context)!.addConversationBot, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + subtitle: Text(L10n.of(context)!.addConversationBotDesc), + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: + Theme.of(context).textTheme.bodyLarge!.color, + child: const BotFace( + width: 30.0, + expression: BotExpression.idle, + ), + ), + trailing: ElevatedButton( + onPressed: () async { + final bool? confirm = await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: addBot + ? Text( + L10n.of(context)! + .addConversationBotButtonTitleRemove, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogTitleInvite, + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(L10n.of(context)!.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(!addBot); + }, + child: addBot + ? Text( + L10n.of(context)! + .addConversationBotDialogRemoveConfirmation, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogInviteConfirmation, + ), + ), + ], + ); + }, + ); + + if (confirm == true) { + setState(() => addBot = true); + widget.room?.invite(BotName.byEnvironment); + } else { + setState(() => addBot = false); + widget.room?.kick(BotName.byEnvironment); + } + }, + child: addBot + ? Text( + L10n.of(context)! + .addConversationBotButtonRemove, + ) + : Text( + L10n.of(context)! + .addConversationBotButtonInvite, + ), + ), + ), + ), + if (addBot) ...[ + Padding( + padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), + child: Text( + L10n.of(context)!.conversationLanguageLevel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: LanguageLevelDropdown( + initialLevel: botOptions.languageLevel, + onChanged: (int? newValue) => updateBotOption(() { + botOptions.languageLevel = newValue!; + }), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), + child: Text( + L10n.of(context)!.conversationBotModeSelectDescription, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + Padding( + padding: const EdgeInsets.only(left: 16), + child: ConversationBotModeSelect( + initialMode: botOptions.mode, + onChanged: (String? mode) => updateBotOption( + () { + botOptions.mode = mode ?? "discussion"; + }, + ), + ), + ), + Padding( + padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), + child: ConversationBotModeDynamicZone( + initialBotOptions: botOptions, + onChanged: (BotOptionsModel? newOptions) { + updateBotOption(() { + if (newOptions != null) { + botOptions = newOptions; + } + }); + }, + ), + ), + const SizedBox(height: 16), + ], + ], + ), + ), + ], + ); +} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart index 59b35e3fe..36a965301 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart @@ -1,7 +1,6 @@ import 'dart:developer'; import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; @@ -120,15 +119,28 @@ class ConversationBotSettingsChatDetailsState context: context, builder: (BuildContext context) { return AlertDialog( - title: addBot - ? Text( - L10n.of(context)! - .addConversationBotButtonTitleRemove, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogTitleInvite, - ), + title: Text( + L10n.of(context)!.botConfig, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(L10n.of(context)!.conversationBotStatus), + Switch( + value: addBot, + onChanged: (value) { + setState( + () => addBot = value, + ); + }, + ), + ], + ), + ], + ), actions: [ TextButton( onPressed: () { @@ -137,29 +149,22 @@ class ConversationBotSettingsChatDetailsState child: Text(L10n.of(context)!.cancel), ), TextButton( - onPressed: () { - Navigator.of(context).pop(!addBot); - }, - child: addBot - ? Text( - L10n.of(context)! - .addConversationBotDialogRemoveConfirmation, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogInviteConfirmation, - ), + onPressed: () {}, + child: Text( + L10n.of(context)! + .conversationBotConfigConfirmChange, + ), ), ], ); }, ); if (confirm == true) { - setState(() => addBot = true); - widget.room?.invite(BotName.byEnvironment); + // setState(() => addBot = true); + // widget.room?.invite(BotName.byEnvironment); } else { - setState(() => addBot = false); - widget.room?.kick(BotName.byEnvironment); + // setState(() => addBot = false); + // widget.room?.kick(BotName.byEnvironment); } }, ), From 11dfa13a0bf48c6f4c1bb30415311e14396e33e0 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Mon, 5 Aug 2024 13:58:20 -0400 Subject: [PATCH 23/31] wrap stateful alert dialog in StatefulBuilder to enable toggle updates --- ...onversation_bot_settings_chat_details.dart | 72 ++++++++++--------- 1 file changed, 37 insertions(+), 35 deletions(-) diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart index 36a965301..32a6caf5d 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart @@ -118,44 +118,46 @@ class ConversationBotSettingsChatDetailsState final bool? confirm = await showDialog( context: context, builder: (BuildContext context) { - return AlertDialog( - title: Text( - L10n.of(context)!.botConfig, - ), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(L10n.of(context)!.conversationBotStatus), - Switch( - value: addBot, - onChanged: (value) { - setState( - () => addBot = value, - ); - }, - ), - ], + return StatefulBuilder( + builder: (context, setState) => AlertDialog( + title: Text( + L10n.of(context)!.botConfig, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + children: [ + Text(L10n.of(context)!.conversationBotStatus), + Switch( + value: addBot, + onChanged: (value) { + setState( + () => addBot = value, + ); + }, + ), + ], + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(L10n.of(context)!.cancel), + ), + TextButton( + onPressed: () {}, + child: Text( + L10n.of(context)! + .conversationBotConfigConfirmChange, + ), ), ], ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(L10n.of(context)!.cancel), - ), - TextButton( - onPressed: () {}, - child: Text( - L10n.of(context)! - .conversationBotConfigConfirmChange, - ), - ), - ], ); }, ); From e164e73bf414dd09a3f31a9ffc51e9a2e364be6f Mon Sep 17 00:00:00 2001 From: Kelrap Date: Tue, 6 Aug 2024 10:13:23 -0400 Subject: [PATCH 24/31] Remove option to report user --- .../user_bottom_sheet_view.dart | 20 ++++++++++--------- 1 file changed, 11 insertions(+), 9 deletions(-) diff --git a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart index 19e4a524d..ef79c0e31 100644 --- a/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart +++ b/lib/pages/user_bottom_sheet/user_bottom_sheet_view.dart @@ -370,15 +370,17 @@ class UserBottomSheetView extends StatelessWidget { onTap: () => controller .participantAction(UserBottomSheetAction.unban), ), - if (user != null && user.id != client.userID) - ListTile( - textColor: Theme.of(context).colorScheme.onErrorContainer, - iconColor: Theme.of(context).colorScheme.onErrorContainer, - title: Text(L10n.of(context)!.reportUser), - leading: const Icon(Icons.report_outlined), - onTap: () => controller - .participantAction(UserBottomSheetAction.report), - ), + // #Pangea + // if (user != null && user.id != client.userID) + // ListTile( + // textColor: Theme.of(context).colorScheme.onErrorContainer, + // iconColor: Theme.of(context).colorScheme.onErrorContainer, + // title: Text(L10n.of(context)!.reportUser), + // leading: const Icon(Icons.report_outlined), + // onTap: () => controller + // .participantAction(UserBottomSheetAction.report), + // ), + // Pangea# if (profileSearchError != null) ListTile( leading: const Icon( From 76c38a594e4a12718ecad5025d0ddbe75a08f08c Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 12:13:55 -0400 Subject: [PATCH 25/31] complete implementation of bot option dialog --- .../conversation_bot_settings.dart | 269 ------------------ ...onversation_bot_settings_chat_details.dart | 187 +++++++----- 2 files changed, 110 insertions(+), 346 deletions(-) delete mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart deleted file mode 100644 index 1c78fd030..000000000 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart +++ /dev/null @@ -1,269 +0,0 @@ -import 'dart:developer'; - -import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/utils/bot_name.dart'; -import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; -import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; -import 'package:flutter/foundation.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 '../../../widgets/matrix.dart'; -import '../../constants/pangea_event_types.dart'; -import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; -import '../../utils/error_handler.dart'; - -class ConversationBotSettings extends StatefulWidget { - final Room? room; - final bool startOpen; - final String? activeSpaceId; - - const ConversationBotSettings({ - super.key, - this.room, - this.startOpen = false, - this.activeSpaceId, - }); - - @override - ConversationBotSettingsState createState() => ConversationBotSettingsState(); -} - -class ConversationBotSettingsState extends State { - late BotOptionsModel botOptions; - late bool isOpen; - bool addBot = false; - Room? parentSpace; - - ConversationBotSettingsState({Key? key}); - - @override - void initState() { - super.initState(); - isOpen = widget.startOpen; - botOptions = widget.room?.botOptions != null - ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) - : BotOptionsModel(); - widget.room?.isBotRoom.then((bool isBotRoom) { - setState(() { - addBot = isBotRoom; - }); - }); - parentSpace = widget.activeSpaceId != null - ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) - : null; - } - - Future updateBotOption(void Function() makeLocalChange) async { - makeLocalChange(); - await showFutureLoadingDialog( - context: context, - future: () async { - try { - await setBotOption(); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - setState(() {}); - }, - ); - } - - Future setBotOption() async { - if (widget.room == null) return; - try { - await Matrix.of(context).client.setRoomStateWithKey( - widget.room!.id, - PangeaEventTypes.botOptions, - '', - botOptions.toJson(), - ); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - } - - @override - Widget build(BuildContext context) => Column( - children: [ - ListTile( - title: Text( - L10n.of(context)!.convoBotSettingsTitle, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text(L10n.of(context)!.convoBotSettingsDescription), - leading: CircleAvatar( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, - child: const Icon(Icons.psychology_outlined), - ), - trailing: Icon( - isOpen - ? Icons.keyboard_arrow_down_outlined - : Icons.keyboard_arrow_right_outlined, - ), - onTap: () => setState(() => isOpen = !isOpen), - ), - if (isOpen) - AnimatedContainer( - duration: const Duration(milliseconds: 300), - height: isOpen ? null : 0, - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Padding( - padding: const EdgeInsets.only(left: 16), - child: ListTile( - title: Text( - L10n.of(context)!.addConversationBot, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text(L10n.of(context)!.addConversationBotDesc), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: - Theme.of(context).textTheme.bodyLarge!.color, - child: const BotFace( - width: 30.0, - expression: BotExpression.idle, - ), - ), - trailing: ElevatedButton( - onPressed: () async { - final bool? confirm = await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: addBot - ? Text( - L10n.of(context)! - .addConversationBotButtonTitleRemove, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogTitleInvite, - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(L10n.of(context)!.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(!addBot); - }, - child: addBot - ? Text( - L10n.of(context)! - .addConversationBotDialogRemoveConfirmation, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogInviteConfirmation, - ), - ), - ], - ); - }, - ); - - if (confirm == true) { - setState(() => addBot = true); - widget.room?.invite(BotName.byEnvironment); - } else { - setState(() => addBot = false); - widget.room?.kick(BotName.byEnvironment); - } - }, - child: addBot - ? Text( - L10n.of(context)! - .addConversationBotButtonRemove, - ) - : Text( - L10n.of(context)! - .addConversationBotButtonInvite, - ), - ), - ), - ), - if (addBot) ...[ - Padding( - padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), - child: Text( - L10n.of(context)!.conversationLanguageLevel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: LanguageLevelDropdown( - initialLevel: botOptions.languageLevel, - onChanged: (int? newValue) => updateBotOption(() { - botOptions.languageLevel = newValue!; - }), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), - child: Text( - L10n.of(context)!.conversationBotModeSelectDescription, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: ConversationBotModeSelect( - initialMode: botOptions.mode, - onChanged: (String? mode) => updateBotOption( - () { - botOptions.mode = mode ?? "discussion"; - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), - child: ConversationBotModeDynamicZone( - initialBotOptions: botOptions, - onChanged: (BotOptionsModel? newOptions) { - updateBotOption(() { - if (newOptions != null) { - botOptions = newOptions; - } - }); - }, - ), - ), - const SizedBox(height: 16), - ], - ], - ), - ), - ], - ); -} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart index 32a6caf5d..a585922a7 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; @@ -126,20 +127,105 @@ class ConversationBotSettingsChatDetailsState content: Column( mainAxisSize: MainAxisSize.min, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - Text(L10n.of(context)!.conversationBotStatus), - Switch( - value: addBot, - onChanged: (value) { - setState( - () => addBot = value, - ); - }, - ), - ], + Padding( + padding: const EdgeInsets.fromLTRB(0, 0, 0, 12), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text(L10n.of(context)!.conversationBotStatus), + Switch( + value: addBot, + onChanged: (value) { + setState( + () => addBot = value, + ); + }, + ), + ], + ), ), + if (addBot) + Flexible( + child: SingleChildScrollView( + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context) + .colorScheme + .secondary, + width: 0.5, + ), + borderRadius: const BorderRadius.all( + Radius.circular(10), + ), + ), + child: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: const EdgeInsets.all(12.0), + child: Text( + L10n.of(context)! + .conversationLanguageLevel, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + LanguageLevelDropdown( + initialLevel: + botOptions.languageLevel, + onChanged: (int? newValue) => { + setState(() { + botOptions.languageLevel = + newValue!; + }), + }, + ), + Text( + L10n.of(context)! + .conversationBotModeSelectDescription, + style: TextStyle( + color: Theme.of(context) + .colorScheme + .secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ConversationBotModeSelect( + initialMode: botOptions.mode, + onChanged: (String? mode) => { + setState(() { + botOptions.mode = + mode ?? "discussion"; + }), + }, + ), + Padding( + padding: const EdgeInsets.all(12), + child: ConversationBotModeDynamicZone( + initialBotOptions: botOptions, + onChanged: + (BotOptionsModel? newOptions) { + if (newOptions != null) { + setState(() { + botOptions = newOptions; + }); + } + }, + ), + ), + ], + ), + ), + ), + ), ], ), actions: [ @@ -150,7 +236,9 @@ class ConversationBotSettingsChatDetailsState child: Text(L10n.of(context)!.cancel), ), TextButton( - onPressed: () {}, + onPressed: () { + Navigator.of(context).pop(true); + }, child: Text( L10n.of(context)! .conversationBotConfigConfirmChange, @@ -162,72 +250,17 @@ class ConversationBotSettingsChatDetailsState }, ); if (confirm == true) { - // setState(() => addBot = true); - // widget.room?.invite(BotName.byEnvironment); - } else { - // setState(() => addBot = false); - // widget.room?.kick(BotName.byEnvironment); + if (addBot) { + await widget.room?.invite(BotName.byEnvironment); + } else { + await widget.room?.kick(BotName.byEnvironment); + } + updateBotOption(() { + botOptions = botOptions; + }); } }, ), - if (addBot) ...[ - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), - child: Text( - L10n.of(context)!.conversationLanguageLevel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: LanguageLevelDropdown( - initialLevel: botOptions.languageLevel, - onChanged: (int? newValue) => updateBotOption(() { - botOptions.languageLevel = newValue!; - }), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), - child: Text( - L10n.of(context)!.conversationBotModeSelectDescription, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: ConversationBotModeSelect( - initialMode: botOptions.mode, - onChanged: (String? mode) => updateBotOption( - () { - botOptions.mode = mode ?? "discussion"; - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), - child: ConversationBotModeDynamicZone( - initialBotOptions: botOptions, - onChanged: (BotOptionsModel? newOptions) { - updateBotOption(() { - if (newOptions != null) { - botOptions = newOptions; - } - }); - }, - ), - ), - const SizedBox(height: 16), - ], ], ), ); From e2380685384de65263d76182712e588a5e442bbf Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 6 Aug 2024 12:32:31 -0400 Subject: [PATCH 26/31] replaced scrollToEventId with current version from fluffychat --- lib/pages/chat/chat.dart | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index f278cd7c2..b2cdc9f47 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1108,14 +1108,14 @@ class ChatController extends State inputFocus.requestFocus(); } - void scrollToEventId(String eventId) async { - // #Pangea - // final eventIndex = timeline!.events.indexWhere((e) => e.eventId == eventId); + void scrollToEventId( + String eventId, { + bool highlightEvent = true, + }) async { final eventIndex = timeline!.events .where((event) => event.isVisibleInGui) .toList() .indexWhere((e) => e.eventId == eventId); - // Pangea# if (eventIndex == -1) { setState(() { timeline = null; @@ -1131,11 +1131,14 @@ class ChatController extends State }); return; } - setState(() { - scrollToEventIdMarker = eventId; - }); + if (highlightEvent) { + setState(() { + scrollToEventIdMarker = eventId; + }); + } await scrollController.scrollToIndex( - eventIndex, + eventIndex + 1, + duration: FluffyThemes.animationDuration, preferPosition: AutoScrollPosition.middle, ); _updateScrollController(); From 0201aae91653818247bc3d0d7bc9b5b1acb53e2c Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 13:19:08 -0400 Subject: [PATCH 27/31] create shared component for create and detail --- .../conversation_bot_settings.dart | 89 +++++++++++++++ ...onversation_bot_settings_chat_details.dart | 108 ++++-------------- ...onversation_bot_settings_create_group.dart | 104 +---------------- 3 files changed, 118 insertions(+), 183 deletions(-) create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart new file mode 100644 index 000000000..a286258f2 --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart @@ -0,0 +1,89 @@ +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; +import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:matrix/matrix.dart'; + +class ConversationBotSettings extends StatefulWidget { + final Room? room; + final BotOptionsModel botOptions; + + const ConversationBotSettings({ + super.key, + this.room, + required this.botOptions, + }); + + @override + ConversationBotSettingsState createState() => ConversationBotSettingsState(); +} + +class ConversationBotSettingsState extends State { + late BotOptionsModel botOptions; + + ConversationBotSettingsState({Key? key}); + + @override + void initState() { + super.initState(); + botOptions = widget.botOptions; + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(12.0), + child: Text( + L10n.of(context)!.conversationLanguageLevel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + LanguageLevelDropdown( + initialLevel: botOptions.languageLevel, + onChanged: (int? newValue) => { + setState(() { + botOptions.languageLevel = newValue!; + }), + }, + ), + Text( + L10n.of(context)!.conversationBotModeSelectDescription, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ConversationBotModeSelect( + initialMode: botOptions.mode, + onChanged: (String? mode) => { + setState(() { + botOptions.mode = mode ?? "discussion"; + }), + }, + ), + Padding( + padding: const EdgeInsets.all(12), + child: ConversationBotModeDynamicZone( + initialBotOptions: botOptions, + onChanged: (BotOptionsModel? newOptions) { + if (newOptions != null) { + setState(() { + botOptions = newOptions; + }); + } + }, + ), + ), + ], + ); + } +} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart index a585922a7..e524f1430 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart @@ -1,22 +1,19 @@ import 'dart:developer'; +import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/bot_options_model.dart'; import 'package:fluffychat/pangea/utils/bot_name.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; -import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.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 '../../../widgets/matrix.dart'; -import '../../constants/pangea_event_types.dart'; -import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; -import '../../utils/error_handler.dart'; - class ConversationBotSettingsChatDetails extends StatefulWidget { final Room? room; final bool startOpen; @@ -60,6 +57,21 @@ class ConversationBotSettingsChatDetailsState : null; } + Future setBotOption() async { + if (widget.room == null) return; + try { + await Matrix.of(context).client.setRoomStateWithKey( + widget.room!.id, + PangeaEventTypes.botOptions, + '', + botOptions.toJson(), + ); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + } + Future updateBotOption(void Function() makeLocalChange) async { makeLocalChange(); await showFutureLoadingDialog( @@ -76,21 +88,6 @@ class ConversationBotSettingsChatDetailsState ); } - Future setBotOption() async { - if (widget.room == null) return; - try { - await Matrix.of(context).client.setRoomStateWithKey( - widget.room!.id, - PangeaEventTypes.botOptions, - '', - botOptions.toJson(), - ); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - } - @override Widget build(BuildContext context) => AnimatedContainer( duration: const Duration(milliseconds: 300), @@ -160,68 +157,9 @@ class ConversationBotSettingsChatDetailsState Radius.circular(10), ), ), - child: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.all(12.0), - child: Text( - L10n.of(context)! - .conversationLanguageLevel, - style: TextStyle( - color: Theme.of(context) - .colorScheme - .secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - LanguageLevelDropdown( - initialLevel: - botOptions.languageLevel, - onChanged: (int? newValue) => { - setState(() { - botOptions.languageLevel = - newValue!; - }), - }, - ), - Text( - L10n.of(context)! - .conversationBotModeSelectDescription, - style: TextStyle( - color: Theme.of(context) - .colorScheme - .secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ConversationBotModeSelect( - initialMode: botOptions.mode, - onChanged: (String? mode) => { - setState(() { - botOptions.mode = - mode ?? "discussion"; - }), - }, - ), - Padding( - padding: const EdgeInsets.all(12), - child: ConversationBotModeDynamicZone( - initialBotOptions: botOptions, - onChanged: - (BotOptionsModel? newOptions) { - if (newOptions != null) { - setState(() { - botOptions = newOptions; - }); - } - }, - ), - ), - ], + child: ConversationBotSettings( + room: widget.room, + botOptions: botOptions, ), ), ), diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart index 49d3df9c0..5542e3ec8 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart @@ -1,22 +1,13 @@ -import 'dart:developer'; - +import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/bot_options_model.dart'; import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; -import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; -import 'package:flutter/foundation.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.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 '../../../widgets/matrix.dart'; -import '../../constants/pangea_event_types.dart'; -import '../../extensions/pangea_room_extension/pangea_room_extension.dart'; -import '../../utils/error_handler.dart'; - class ConversationBotSettingsCreateGroup extends StatefulWidget { final Room? room; final bool startOpen; @@ -60,37 +51,6 @@ class ConversationBotSettingsCreateGroupState : null; } - Future updateBotOption(void Function() makeLocalChange) async { - makeLocalChange(); - await showFutureLoadingDialog( - context: context, - future: () async { - try { - await setBotOption(); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - setState(() {}); - }, - ); - } - - Future setBotOption() async { - if (widget.room == null) return; - try { - await Matrix.of(context).client.setRoomStateWithKey( - widget.room!.id, - PangeaEventTypes.botOptions, - '', - botOptions.toJson(), - ); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - } - @override Widget build(BuildContext context) => AnimatedContainer( duration: const Duration(milliseconds: 300), @@ -174,62 +134,10 @@ class ConversationBotSettingsCreateGroupState ), ), if (addBot) ...[ - Padding( - padding: const EdgeInsets.fromLTRB(16, 0, 0, 0), - child: Text( - L10n.of(context)!.conversationLanguageLevel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), + ConversationBotSettings( + room: widget.room, + botOptions: botOptions, ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: LanguageLevelDropdown( - initialLevel: botOptions.languageLevel, - onChanged: (int? newValue) => updateBotOption(() { - botOptions.languageLevel = newValue!; - }), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(32, 16, 0, 0), - child: Text( - L10n.of(context)!.conversationBotModeSelectDescription, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ), - Padding( - padding: const EdgeInsets.only(left: 16), - child: ConversationBotModeSelect( - initialMode: botOptions.mode, - onChanged: (String? mode) => updateBotOption( - () { - botOptions.mode = mode ?? "discussion"; - }, - ), - ), - ), - Padding( - padding: const EdgeInsets.fromLTRB(28, 0, 12, 0), - child: ConversationBotModeDynamicZone( - initialBotOptions: botOptions, - onChanged: (BotOptionsModel? newOptions) { - updateBotOption(() { - if (newOptions != null) { - botOptions = newOptions; - } - }); - }, - ), - ), - const SizedBox(height: 16), ], ], ), From 1ece90dad25a0831853d1c913f991b931cf7bd6a Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 15:48:58 -0400 Subject: [PATCH 28/31] refactor, group create group and chat details into one component --- lib/pages/chat_details/chat_details.dart | 5 +- lib/pages/chat_details/chat_details_view.dart | 4 +- lib/pages/new_group/new_group.dart | 7 +- lib/pages/new_group/new_group_view.dart | 4 +- .../conversation_bot_custom_zone.dart | 1 - .../conversation_bot_settings.dart | 299 ++++++++++++++---- ...onversation_bot_settings_chat_details.dart | 205 ------------ ...onversation_bot_settings_create_group.dart | 145 --------- .../conversation_bot_settings_form.dart | 88 ++++++ .../.gradle/6.7.1/fileHashes/fileHashes.lock | Bin 39 -> 17 bytes .../buildOutputCleanup.lock | Bin 39 -> 17 bytes .../android/.gradle/checksums/checksums.lock | Bin 39 -> 17 bytes 12 files changed, 341 insertions(+), 417 deletions(-) delete mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart delete mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_settings_form.dart diff --git a/lib/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 383ffb5a5..050a1b272 100644 --- a/lib/pages/chat_details/chat_details.dart +++ b/lib/pages/chat_details/chat_details.dart @@ -6,7 +6,6 @@ import 'package:fluffychat/pages/settings/settings.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_description_button.dart'; import 'package:fluffychat/pangea/utils/set_class_name.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -43,9 +42,9 @@ class ChatDetailsController extends State { // #Pangea final GlobalKey addToSpaceKey = GlobalKey(); - final GlobalKey + final GlobalKey addConversationBotKey = - GlobalKey(); + GlobalKey(); bool displayAddStudentOptions = false; void toggleAddStudentOptions() => diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index dbc3b2152..0afa56086 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -11,7 +11,7 @@ import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/class_nam import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/utils/lock_room.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/utils/fluffy_share.dart'; import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart'; import 'package:fluffychat/widgets/avatar.dart'; @@ -452,7 +452,7 @@ class ChatDetailsView extends StatelessWidget { if (!room.isSpace && !room.isDirectChat && room.canInvite) - ConversationBotSettingsChatDetails( + ConversationBotSettings( key: controller.addConversationBotKey, room: room, ), diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 94684e442..9c6e22f85 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -11,7 +11,7 @@ import 'package:fluffychat/pangea/utils/bot_name.dart'; import 'package:fluffychat/pangea/utils/class_chat_power_levels.dart'; import 'package:fluffychat/pangea/utils/firebase_analytics.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -51,9 +51,8 @@ class NewGroupController extends State { // #Pangea PangeaController pangeaController = MatrixState.pangeaController; final GlobalKey addToSpaceKey = GlobalKey(); - final GlobalKey - addConversationBotKey = - GlobalKey(); + final GlobalKey addConversationBotKey = + GlobalKey(); final GlobalKey addCapacityKey = GlobalKey(); diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart index 37061da3d..84bfbfbc5 100644 --- a/lib/pages/new_group/new_group_view.dart +++ b/lib/pages/new_group/new_group_view.dart @@ -2,7 +2,7 @@ import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/new_group/new_group.dart'; import 'package:fluffychat/pangea/pages/class_settings/p_class_widgets/room_capacity_button.dart'; import 'package:fluffychat/pangea/widgets/class/add_space_toggles.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; import 'package:fluffychat/utils/localized_exception_extension.dart'; import 'package:fluffychat/widgets/avatar.dart'; import 'package:fluffychat/widgets/layouts/max_width_body.dart'; @@ -99,7 +99,7 @@ class NewGroupView extends StatelessWidget { RoomCapacityButton( key: controller.addCapacityKey, ), - ConversationBotSettingsCreateGroup( + ConversationBotSettings( key: controller.addConversationBotKey, activeSpaceId: controller.activeSpaceId, ), diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart index 553de7182..d5002ce2f 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart @@ -16,7 +16,6 @@ class ConversationBotCustomZone extends StatelessWidget { @override Widget build(BuildContext context) { - print(initialBotOptions.toJson()); return Column( children: [ const SizedBox(height: 12), diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart index a286258f2..e4054f4e5 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart @@ -1,19 +1,29 @@ +import 'dart:developer'; + +import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; -import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:fluffychat/pangea/utils/bot_name.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings_form.dart'; +import 'package:fluffychat/widgets/matrix.dart'; +import 'package:flutter/foundation.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'; class ConversationBotSettings extends StatefulWidget { final Room? room; - final BotOptionsModel botOptions; + final bool startOpen; + final String? activeSpaceId; const ConversationBotSettings({ super.key, this.room, - required this.botOptions, + this.startOpen = false, + this.activeSpaceId, }); @override @@ -22,68 +32,247 @@ class ConversationBotSettings extends StatefulWidget { class ConversationBotSettingsState extends State { late BotOptionsModel botOptions; + late bool isOpen; + late bool isCreating; + bool addBot = false; + Room? parentSpace; ConversationBotSettingsState({Key? key}); @override void initState() { super.initState(); - botOptions = widget.botOptions; + isOpen = widget.startOpen; + botOptions = widget.room?.botOptions != null + ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) + : BotOptionsModel(); + widget.room?.isBotRoom.then((bool isBotRoom) { + setState(() { + addBot = isBotRoom; + }); + }); + parentSpace = widget.activeSpaceId != null + ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) + : null; + isCreating = widget.room == null; + } + + Future setBotOption() async { + if (widget.room == null) return; + try { + await Matrix.of(context).client.setRoomStateWithKey( + widget.room!.id, + PangeaEventTypes.botOptions, + '', + botOptions.toJson(), + ); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + } + + Future updateBotOption(void Function() makeLocalChange) async { + makeLocalChange(); + await showFutureLoadingDialog( + context: context, + future: () async { + try { + await setBotOption(); + } catch (err, stack) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: stack); + } + setState(() {}); + }, + ); } @override Widget build(BuildContext context) { - return Column( - children: [ - Padding( - padding: const EdgeInsets.all(12.0), - child: Text( - L10n.of(context)!.conversationLanguageLevel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + ListTile( + title: Text( + isCreating + ? L10n.of(context)!.addConversationBot + : L10n.of(context)!.botConfig, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), ), + subtitle: isCreating + ? Text(L10n.of(context)!.addConversationBotDesc) + : null, + leading: CircleAvatar( + backgroundColor: Theme.of(context).scaffoldBackgroundColor, + foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, + child: const BotFace( + width: 30.0, + expression: BotExpression.idle, + ), + ), + trailing: isCreating + ? ElevatedButton( + onPressed: () async { + final bool? confirm = await showDialog( + context: context, + builder: (BuildContext context) { + return AlertDialog( + title: addBot + ? Text( + L10n.of(context)! + .addConversationBotButtonTitleRemove, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogTitleInvite, + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(L10n.of(context)!.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(!addBot); + }, + child: addBot + ? Text( + L10n.of(context)! + .addConversationBotDialogRemoveConfirmation, + ) + : Text( + L10n.of(context)! + .addConversationBotDialogInviteConfirmation, + ), + ), + ], + ); + }, + ); + + if (confirm == true) { + setState(() => addBot = true); + widget.room?.invite(BotName.byEnvironment); + } else { + setState(() => addBot = false); + widget.room?.kick(BotName.byEnvironment); + } + }, + child: addBot + ? Text( + L10n.of(context)!.addConversationBotButtonRemove, + ) + : Text( + L10n.of(context)!.addConversationBotButtonInvite, + ), + ) + : const Icon(Icons.settings), + onTap: isCreating + ? null + : () async { + final bool? confirm = await showDialog( + context: context, + builder: (BuildContext context) { + return StatefulBuilder( + builder: (context, setState) => AlertDialog( + title: Text( + L10n.of(context)!.botConfig, + ), + content: Column( + mainAxisSize: MainAxisSize.min, + children: [ + Padding( + padding: + const EdgeInsets.fromLTRB(0, 0, 0, 12), + child: Row( + mainAxisAlignment: + MainAxisAlignment.spaceBetween, + children: [ + Text( + L10n.of(context)!.conversationBotStatus, + ), + Switch( + value: addBot, + onChanged: (value) { + setState( + () => addBot = value, + ); + }, + ), + ], + ), + ), + if (addBot) + Flexible( + child: SingleChildScrollView( + child: Container( + decoration: BoxDecoration( + border: Border.all( + color: Theme.of(context) + .colorScheme + .secondary, + width: 0.5, + ), + borderRadius: const BorderRadius.all( + Radius.circular(10), + ), + ), + child: ConversationBotSettingsForm( + botOptions: botOptions, + ), + ), + ), + ), + ], + ), + actions: [ + TextButton( + onPressed: () { + Navigator.of(context).pop(false); + }, + child: Text(L10n.of(context)!.cancel), + ), + TextButton( + onPressed: () { + Navigator.of(context).pop(true); + }, + child: Text( + L10n.of(context)! + .conversationBotConfigConfirmChange, + ), + ), + ], + ), + ); + }, + ); + if (confirm == true) { + if (addBot) { + await widget.room?.invite(BotName.byEnvironment); + } else { + await widget.room?.kick(BotName.byEnvironment); + } + updateBotOption(() { + botOptions = botOptions; + }); + } + }, ), - ), - LanguageLevelDropdown( - initialLevel: botOptions.languageLevel, - onChanged: (int? newValue) => { - setState(() { - botOptions.languageLevel = newValue!; - }), - }, - ), - Text( - L10n.of(context)!.conversationBotModeSelectDescription, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - fontSize: 16, - ), - ), - ConversationBotModeSelect( - initialMode: botOptions.mode, - onChanged: (String? mode) => { - setState(() { - botOptions.mode = mode ?? "discussion"; - }), - }, - ), - Padding( - padding: const EdgeInsets.all(12), - child: ConversationBotModeDynamicZone( - initialBotOptions: botOptions, - onChanged: (BotOptionsModel? newOptions) { - if (newOptions != null) { - setState(() { - botOptions = newOptions; - }); - } - }, - ), - ), - ], + if (isCreating && addBot) + ConversationBotSettingsForm( + botOptions: botOptions, + ), + ], + ), ); } } diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart deleted file mode 100644 index e524f1430..000000000 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_chat_details.dart +++ /dev/null @@ -1,205 +0,0 @@ -import 'dart:developer'; - -import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; -import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/utils/bot_name.dart'; -import 'package:fluffychat/pangea/utils/error_handler.dart'; -import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; -import 'package:fluffychat/widgets/matrix.dart'; -import 'package:flutter/foundation.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'; - -class ConversationBotSettingsChatDetails extends StatefulWidget { - final Room? room; - final bool startOpen; - final String? activeSpaceId; - - const ConversationBotSettingsChatDetails({ - super.key, - this.room, - this.startOpen = false, - this.activeSpaceId, - }); - - @override - ConversationBotSettingsChatDetailsState createState() => - ConversationBotSettingsChatDetailsState(); -} - -class ConversationBotSettingsChatDetailsState - extends State { - late BotOptionsModel botOptions; - late bool isOpen; - bool addBot = false; - Room? parentSpace; - - ConversationBotSettingsChatDetailsState({Key? key}); - - @override - void initState() { - super.initState(); - isOpen = widget.startOpen; - botOptions = widget.room?.botOptions != null - ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) - : BotOptionsModel(); - widget.room?.isBotRoom.then((bool isBotRoom) { - setState(() { - addBot = isBotRoom; - }); - }); - parentSpace = widget.activeSpaceId != null - ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) - : null; - } - - Future setBotOption() async { - if (widget.room == null) return; - try { - await Matrix.of(context).client.setRoomStateWithKey( - widget.room!.id, - PangeaEventTypes.botOptions, - '', - botOptions.toJson(), - ); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - } - - Future updateBotOption(void Function() makeLocalChange) async { - makeLocalChange(); - await showFutureLoadingDialog( - context: context, - future: () async { - try { - await setBotOption(); - } catch (err, stack) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: stack); - } - setState(() {}); - }, - ); - } - - @override - Widget build(BuildContext context) => AnimatedContainer( - duration: const Duration(milliseconds: 300), - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListTile( - title: Text( - L10n.of(context)!.botConfig, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - leading: CircleAvatar( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, - child: const BotFace( - width: 30.0, - expression: BotExpression.idle, - ), - ), - trailing: const Icon(Icons.settings), - onTap: () async { - final bool? confirm = await showDialog( - context: context, - builder: (BuildContext context) { - return StatefulBuilder( - builder: (context, setState) => AlertDialog( - title: Text( - L10n.of(context)!.botConfig, - ), - content: Column( - mainAxisSize: MainAxisSize.min, - children: [ - Padding( - padding: const EdgeInsets.fromLTRB(0, 0, 0, 12), - child: Row( - mainAxisAlignment: - MainAxisAlignment.spaceBetween, - children: [ - Text(L10n.of(context)!.conversationBotStatus), - Switch( - value: addBot, - onChanged: (value) { - setState( - () => addBot = value, - ); - }, - ), - ], - ), - ), - if (addBot) - Flexible( - child: SingleChildScrollView( - child: Container( - decoration: BoxDecoration( - border: Border.all( - color: Theme.of(context) - .colorScheme - .secondary, - width: 0.5, - ), - borderRadius: const BorderRadius.all( - Radius.circular(10), - ), - ), - child: ConversationBotSettings( - room: widget.room, - botOptions: botOptions, - ), - ), - ), - ), - ], - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(L10n.of(context)!.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(true); - }, - child: Text( - L10n.of(context)! - .conversationBotConfigConfirmChange, - ), - ), - ], - ), - ); - }, - ); - if (confirm == true) { - if (addBot) { - await widget.room?.invite(BotName.byEnvironment); - } else { - await widget.room?.kick(BotName.byEnvironment); - } - updateBotOption(() { - botOptions = botOptions; - }); - } - }, - ), - ], - ), - ); -} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart deleted file mode 100644 index 5542e3ec8..000000000 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_create_group.dart +++ /dev/null @@ -1,145 +0,0 @@ -import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; -import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/utils/bot_name.dart'; -import 'package:fluffychat/pangea/widgets/common/bot_face_svg.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_settings.dart'; -import 'package:fluffychat/widgets/matrix.dart'; -import 'package:flutter/material.dart'; -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:matrix/matrix.dart'; - -class ConversationBotSettingsCreateGroup extends StatefulWidget { - final Room? room; - final bool startOpen; - final String? activeSpaceId; - - const ConversationBotSettingsCreateGroup({ - super.key, - this.room, - this.startOpen = false, - this.activeSpaceId, - }); - - @override - ConversationBotSettingsCreateGroupState createState() => - ConversationBotSettingsCreateGroupState(); -} - -class ConversationBotSettingsCreateGroupState - extends State { - late BotOptionsModel botOptions; - late bool isOpen; - bool addBot = false; - Room? parentSpace; - - ConversationBotSettingsCreateGroupState({Key? key}); - - @override - void initState() { - super.initState(); - isOpen = widget.startOpen; - botOptions = widget.room?.botOptions != null - ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) - : BotOptionsModel(); - widget.room?.isBotRoom.then((bool isBotRoom) { - setState(() { - addBot = isBotRoom; - }); - }); - parentSpace = widget.activeSpaceId != null - ? Matrix.of(context).client.getRoomById(widget.activeSpaceId!) - : null; - } - - @override - Widget build(BuildContext context) => AnimatedContainer( - duration: const Duration(milliseconds: 300), - width: double.infinity, - child: Column( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - ListTile( - title: Text( - L10n.of(context)!.addConversationBot, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - subtitle: Text(L10n.of(context)!.addConversationBotDesc), - leading: CircleAvatar( - backgroundColor: Theme.of(context).scaffoldBackgroundColor, - foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, - child: const BotFace( - width: 30.0, - expression: BotExpression.idle, - ), - ), - trailing: ElevatedButton( - onPressed: () async { - final bool? confirm = await showDialog( - context: context, - builder: (BuildContext context) { - return AlertDialog( - title: addBot - ? Text( - L10n.of(context)! - .addConversationBotButtonTitleRemove, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogTitleInvite, - ), - actions: [ - TextButton( - onPressed: () { - Navigator.of(context).pop(false); - }, - child: Text(L10n.of(context)!.cancel), - ), - TextButton( - onPressed: () { - Navigator.of(context).pop(!addBot); - }, - child: addBot - ? Text( - L10n.of(context)! - .addConversationBotDialogRemoveConfirmation, - ) - : Text( - L10n.of(context)! - .addConversationBotDialogInviteConfirmation, - ), - ), - ], - ); - }, - ); - - if (confirm == true) { - setState(() => addBot = true); - widget.room?.invite(BotName.byEnvironment); - } else { - setState(() => addBot = false); - widget.room?.kick(BotName.byEnvironment); - } - }, - child: addBot - ? Text( - L10n.of(context)!.addConversationBotButtonRemove, - ) - : Text( - L10n.of(context)!.addConversationBotButtonInvite, - ), - ), - ), - if (addBot) ...[ - ConversationBotSettings( - room: widget.room, - botOptions: botOptions, - ), - ], - ], - ), - ); -} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings_form.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_form.dart new file mode 100644 index 000000000..519245303 --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings_form.dart @@ -0,0 +1,88 @@ +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart'; +import 'package:fluffychat/pangea/widgets/space/language_level_dropdown.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +class ConversationBotSettingsForm extends StatefulWidget { + final BotOptionsModel botOptions; + + const ConversationBotSettingsForm({ + super.key, + required this.botOptions, + }); + + @override + ConversationBotSettingsFormState createState() => + ConversationBotSettingsFormState(); +} + +class ConversationBotSettingsFormState + extends State { + final formKey = GlobalKey(); + + late BotOptionsModel botOptions; + + @override + void initState() { + super.initState(); + botOptions = widget.botOptions; + } + + @override + Widget build(BuildContext context) { + return Column( + children: [ + Padding( + padding: const EdgeInsets.all(12.0), + child: Text( + L10n.of(context)!.conversationLanguageLevel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ), + LanguageLevelDropdown( + initialLevel: botOptions.languageLevel, + onChanged: (int? newValue) => { + setState(() { + botOptions.languageLevel = newValue!; + }), + }, + ), + Text( + L10n.of(context)!.conversationBotModeSelectDescription, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + fontSize: 16, + ), + ), + ConversationBotModeSelect( + initialMode: botOptions.mode, + onChanged: (String? mode) => { + setState(() { + botOptions.mode = mode ?? "discussion"; + }), + }, + ), + Padding( + padding: const EdgeInsets.all(12), + child: ConversationBotModeDynamicZone( + initialBotOptions: botOptions, + onChanged: (BotOptionsModel? newOptions) { + if (newOptions != null) { + setState(() { + botOptions = newOptions; + }); + } + }, + ), + ), + ], + ); + } +} diff --git a/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock b/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock index f1facd8351bcedf036c6985ed1ac7b5c21ff1f87..7cb52b3f842396598d593e360f52c43265089f07 100644 GIT binary patch literal 17 UcmZQ(pPrsFC-<%*0|YPw04fjzcK`qY literal 39 qcmZQ(pPrsFC-<%*0|YQLGcepv|Nb(2y-ILJJp-$ufrX_x0|Nlj?+P*i diff --git a/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock index ea7da199a9aab10e1551a086bd1892ebf1cea816..487a88833085c25d183c663046ee06e3b9888272 100644 GIT binary patch literal 17 TcmZQ}bn=zC_JSdv0Rm(IB}W4( literal 39 qcmZQ}bn=zC_JSdv0Rm*085nM-N1x~La=fsziGkJ7z{1j;fdK%xu?aK) diff --git a/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock b/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock index a148f5b0ee85072228e5cdc5e1edaa30a4ae84ab..b99989c33f39a2bacad6d6ee7ad3244b27d3a856 100644 GIT binary patch literal 17 VcmZSnAb4*|_KHR73}C?S3jjDZ1g8K1 literal 39 scmZSnAb4*|_KHR73}C?S%gn%VJ6-3|)`{1Oo98gF8X8zwnlmr}0Q(>dwg3PC From 5015f2e3d49ac88d954d4e9aa7295172501254e7 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 15:52:04 -0400 Subject: [PATCH 29/31] remove lock files --- .../.gradle/6.7.1/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .../buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 0 bytes .../android/.gradle/checksums/checksums.lock | Bin 17 -> 0 bytes 3 files changed, 0 insertions(+), 0 deletions(-) delete mode 100644 pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock delete mode 100644 pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock diff --git a/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock b/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock deleted file mode 100644 index 7cb52b3f842396598d593e360f52c43265089f07..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQ(pPrsFC-<%*0|YPw04fjzcK`qY diff --git a/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index 487a88833085c25d183c663046ee06e3b9888272..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZQ}bn=zC_JSdv0Rm(IB}W4( diff --git a/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock b/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock deleted file mode 100644 index b99989c33f39a2bacad6d6ee7ad3244b27d3a856..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZSnAb4*|_KHR73}C?S3jjDZ1g8K1 From 959172fcfe265355056c794f0ee3ce288f94a598 Mon Sep 17 00:00:00 2001 From: Kelrap Date: Tue, 6 Aug 2024 16:40:11 -0400 Subject: [PATCH 30/31] Hide public profile toggle in learning settings --- .../settings_learning_view.dart | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/lib/pangea/pages/settings_learning/settings_learning_view.dart b/lib/pangea/pages/settings_learning/settings_learning_view.dart index 4182ab2d6..1a6576770 100644 --- a/lib/pangea/pages/settings_learning/settings_learning_view.dart +++ b/lib/pangea/pages/settings_learning/settings_learning_view.dart @@ -1,4 +1,3 @@ -import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/models/space_model.dart'; import 'package:fluffychat/pangea/pages/settings_learning/settings_learning.dart'; import 'package:fluffychat/pangea/widgets/user_settings/country_picker_tile.dart'; @@ -32,15 +31,15 @@ class SettingsLearningView extends StatelessWidget { const SizedBox(height: 8), const Divider(height: 1), const SizedBox(height: 8), - if (controller.pangeaController.permissionsController.isUser18()) - SwitchListTile.adaptive( - activeColor: AppConfig.activeToggleColor, - title: Text(L10n.of(context)!.publicProfileTitle), - subtitle: Text(L10n.of(context)!.publicProfileDesc), - value: controller.pangeaController.userController.isPublic, - onChanged: (bool isPublicProfile) => - controller.setPublicProfile(isPublicProfile), - ), + // if (controller.pangeaController.permissionsController.isUser18()) + // SwitchListTile.adaptive( + // activeColor: AppConfig.activeToggleColor, + // title: Text(L10n.of(context)!.publicProfileTitle), + // subtitle: Text(L10n.of(context)!.publicProfileDesc), + // value: controller.pangeaController.userController.isPublic, + // onChanged: (bool isPublicProfile) => + // controller.setPublicProfile(isPublicProfile), + // ), ListTile( subtitle: Text(L10n.of(context)!.toggleToolSettingsDescription), ), From 71650600411b1486d843ff42bbe6b819f76dbbe8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 7 Aug 2024 09:59:01 -0400 Subject: [PATCH 31/31] choreographer pulls roomID from chat so input bar key does not change after setting choreo roomID, resolving issues with input bar auto-focus --- lib/pages/chat/chat.dart | 1 - lib/pages/chat/input_bar.dart | 6 +++--- lib/pangea/choreographer/controllers/choreographer.dart | 6 +----- lib/pangea/widgets/igc/pangea_text_controller.dart | 2 +- 4 files changed, 5 insertions(+), 10 deletions(-) diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index b2cdc9f47..3e0413230 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -328,7 +328,6 @@ class ChatController extends State ); } await Matrix.of(context).client.roomsLoading; - choreographer.setRoomId(roomId); }); // Pangea# _tryLoadTimeline(); diff --git a/lib/pages/chat/input_bar.dart b/lib/pages/chat/input_bar.dart index 84a802e54..61ce641fc 100644 --- a/lib/pages/chat/input_bar.dart +++ b/lib/pages/chat/input_bar.dart @@ -463,7 +463,7 @@ class InputBar extends StatelessWidget { debounceDuration: const Duration(milliseconds: 50), // show suggestions after 50ms idle time (default is 300) // #Pangea - key: controller!.choreographer.inputLayerLinkAndKey.key, + key: controller?.choreographer.inputLayerLinkAndKey.key, // builder: (context, controller, focusNode) => TextField( builder: (context, _, focusNode) => TextField( // Pangea# @@ -504,11 +504,11 @@ class InputBar extends StatelessWidget { onSubmitted!(text); }, // #Pangea - style: controller?.isMaxLength ?? false + style: controller?.exceededMaxLength ?? false ? const TextStyle(color: Colors.red) : null, onTap: () { - controller!.onInputTap( + controller?.onInputTap( context, fNode: focusNode, ); diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index dd2078fa2..c3cd0ab09 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -42,7 +42,6 @@ class Choreographer { bool isFetching = false; Timer? debounceTimer; - String? _roomId; ChoreoRecord choreoRecord = ChoreoRecord.newRecord; // last checked by IGC or translation String? _lastChecked; @@ -464,10 +463,7 @@ class Choreographer { setState(); } - get roomId => _roomId; - void setRoomId(String? roomId) { - _roomId = roomId ?? ''; - } + get roomId => chatController.roomId; bool get _useCustomInput => [ EditType.keyboard, diff --git a/lib/pangea/widgets/igc/pangea_text_controller.dart b/lib/pangea/widgets/igc/pangea_text_controller.dart index 8fc136edd..63c5b3f94 100644 --- a/lib/pangea/widgets/igc/pangea_text_controller.dart +++ b/lib/pangea/widgets/igc/pangea_text_controller.dart @@ -27,7 +27,7 @@ class PangeaTextController extends TextEditingController { } static const int maxLength = 1000; - bool get isMaxLength => text.length == 1000; + bool get exceededMaxLength => text.length >= maxLength; bool forceKeepOpen = false;