From c34306ea31402f02156147c4ae02ac00f5d425ac Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Wed, 24 Jul 2024 09:42:29 -0400 Subject: [PATCH 01/18] bump matrix sdk version, fixes timeline memory issue --- pubspec.lock | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pubspec.lock b/pubspec.lock index ae95fb892..d8e1587b8 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1434,7 +1434,7 @@ packages: description: path: "." ref: main - resolved-ref: "0a95cd8f3cfac8c9b0b59d6ee7fdbdb159949ca3" + resolved-ref: "3bafe47e6d1b958b795f1c78edb6f5f2da3093c5" url: "https://github.com/pangeachat/matrix-dart-sdk.git" source: git version: "0.30.0" From 421a6e9eddfa6f7d2e9c19c545a593ba3d20a3bb Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Wed, 24 Jul 2024 13:57:21 -0400 Subject: [PATCH 02/18] bump to newer version of matrix sdk that fixes outdated events --- .../.gradle/6.7.1/fileHashes/fileHashes.lock | Bin 39 -> 39 bytes .../buildOutputCleanup/buildOutputCleanup.lock | Bin 39 -> 39 bytes .../android/.gradle/checksums/checksums.lock | Bin 39 -> 39 bytes pubspec.lock | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) 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..be611af26c2ebbbdbdb127baca6a52afe87af17a 100644 GIT binary patch delta 24 gcmY#apCBT9>$AI9+~JCMkGC+|wCtvj7_t8O!}T9}%em@_Z{0D6E3YXATM delta 24 fcmY#apCBT9J3ab5hnM4pl}!w+h6Wav<_rt~WMc;o 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..5a4f57d7b1c552d1d74e126c633cc7fc36acf3cf 100644 GIT binary patch delta 24 gcmY#apCBT9>+{|4{K@xDItDPXT9}%em@_Z{0D86vQvd(} delta 24 gcmY#apCBT9J6-3|)`{1Oo98gF8X8zwnlmr}0CNxs5&!@I diff --git a/pubspec.lock b/pubspec.lock index d8e1587b8..bd9a05993 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1434,7 +1434,7 @@ packages: description: path: "." ref: main - resolved-ref: "3bafe47e6d1b958b795f1c78edb6f5f2da3093c5" + resolved-ref: "e812b69daae0149458b858cc613c26923ba53bdb" url: "https://github.com/pangeachat/matrix-dart-sdk.git" source: git version: "0.30.0" From e46b09f8361ad21abe77a9ad18607f909b696685 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Wed, 24 Jul 2024 15:42:24 -0400 Subject: [PATCH 03/18] upgrade matrix resolved ref --- .../.gradle/6.7.1/fileHashes/fileHashes.lock | Bin 39 -> 0 bytes .../buildOutputCleanup/buildOutputCleanup.lock | Bin 39 -> 0 bytes .../android/.gradle/checksums/checksums.lock | Bin 39 -> 0 bytes pubspec.lock | 2 +- 4 files changed, 1 insertion(+), 1 deletion(-) 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 be611af26c2ebbbdbdb127baca6a52afe87af17a..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39 qcmZQ(pPrsFC-<%*0|YQLGcerx>@F5}xZ>U8Z49gyrluz53=9C(oC?+e 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 4743266b3cd7afe1cf881b4f6049c2fe13cb0b89..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39 qcmZQ}bn=zC_JSdv0Rm*085nMTUOuOFr*m%AZ3b2gQ&SUj1_l7m&I*wL 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 5a4f57d7b1c552d1d74e126c633cc7fc36acf3cf..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39 scmZSnAb4*|_KHR73}C?S%gn%V>+{|4{K@xDItDPXT9}%em@_Z{00Pwu_W%F@ diff --git a/pubspec.lock b/pubspec.lock index bd9a05993..648cb96fe 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -1434,7 +1434,7 @@ packages: description: path: "." ref: main - resolved-ref: "e812b69daae0149458b858cc613c26923ba53bdb" + resolved-ref: "0e27bd767a7f0faa7c25ea5f68292fb0b4f59a97" url: "https://github.com/pangeachat/matrix-dart-sdk.git" source: git version: "0.30.0" From 68ca0e770e7e103d8e014b13443d3cf63a50d45b Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Thu, 25 Jul 2024 11:59:21 -0400 Subject: [PATCH 04/18] change the way getTimeline is used, bump matrix sdk version --- .../controllers/my_analytics_controller.dart | 6 +- .../general_info_extension.dart | 4 +- .../events_extension.dart | 4 +- .../pages/analytics/construct_list.dart | 2 +- .../utils/get_chat_list_item_subtitle.dart | 8 ++- pubspec.lock | 66 +------------------ 6 files changed, 16 insertions(+), 74 deletions(-) diff --git a/lib/pangea/controllers/my_analytics_controller.dart b/lib/pangea/controllers/my_analytics_controller.dart index 12baeb689..5960fab11 100644 --- a/lib/pangea/controllers/my_analytics_controller.dart +++ b/lib/pangea/controllers/my_analytics_controller.dart @@ -277,7 +277,11 @@ class MyAnalyticsController { // get the timelines for each chat final List> timelineFutures = []; for (final chat in chats) { - timelineFutures.add(chat.getTimeline()); + timelineFutures.add( + chat.timeline == null + ? chat.getTimeline() + : Future.value(chat.timeline), + ); } final List timelines = await Future.wait(timelineFutures); final Map timelineMap = diff --git a/lib/pangea/extensions/client_extension/general_info_extension.dart b/lib/pangea/extensions/client_extension/general_info_extension.dart index ca5df40cc..41f81442e 100644 --- a/lib/pangea/extensions/client_extension/general_info_extension.dart +++ b/lib/pangea/extensions/client_extension/general_info_extension.dart @@ -3,7 +3,7 @@ part of "client_extension.dart"; extension GeneralInfoClientExtension on Client { Future> get _teacherRoomIds async { final List adminRoomIds = []; - for (final Room adminSpace in (await _spacesImTeaching)) { + for (final Room adminSpace in (_spacesImTeaching)) { adminRoomIds.add(adminSpace.id); final List adminSpaceRooms = adminSpace.allSpaceChildRoomIds; adminRoomIds.addAll(adminSpaceRooms); @@ -59,7 +59,7 @@ extension GeneralInfoClientExtension on Client { final Event? originalEvent = await room!.getEventById(edittedEventId); if (originalEvent == null) return []; - final Timeline timeline = await room.getTimeline(); + final Timeline timeline = room.timeline ?? await room.getTimeline(); final List editEvents = originalEvent .aggregatedEvents( timeline, diff --git a/lib/pangea/extensions/pangea_room_extension/events_extension.dart b/lib/pangea/extensions/pangea_room_extension/events_extension.dart index bc820998c..182779853 100644 --- a/lib/pangea/extensions/pangea_room_extension/events_extension.dart +++ b/lib/pangea/extensions/pangea_room_extension/events_extension.dart @@ -320,7 +320,7 @@ extension EventsRoomExtension on Room { "In messageListForChat with room that is not a chat", ); } - final Timeline timeline = await getTimeline(); + final Timeline timeline = this.timeline ?? await getTimeline(); while (timeline.canRequestHistory && numberOfSearches < 50) { await timeline.requestHistory(historyCount: 100); @@ -433,7 +433,7 @@ extension EventsRoomExtension on Room { }) async { try { int numberOfSearches = 0; - final Timeline timeline = await getTimeline(); + final Timeline timeline = this.timeline ?? await getTimeline(); List relevantEvents() => timeline.events .where((event) => event.senderId == sender && event.type == type) diff --git a/lib/pangea/pages/analytics/construct_list.dart b/lib/pangea/pages/analytics/construct_list.dart index d46936c86..1848e7ada 100644 --- a/lib/pangea/pages/analytics/construct_list.dart +++ b/lib/pangea/pages/analytics/construct_list.dart @@ -166,7 +166,7 @@ class ConstructListViewState extends State { if (_timelinesCache.containsKey(use.chatId)) { timeline = _timelinesCache[use.chatId]; } else { - timeline = await msgRoom.getTimeline(); + timeline = msgRoom.timeline ?? await msgRoom.getTimeline(); _timelinesCache[use.chatId] = timeline; } diff --git a/lib/pangea/utils/get_chat_list_item_subtitle.dart b/lib/pangea/utils/get_chat_list_item_subtitle.dart index 76bd453b6..f09679444 100644 --- a/lib/pangea/utils/get_chat_list_item_subtitle.dart +++ b/lib/pangea/utils/get_chat_list_item_subtitle.dart @@ -36,9 +36,11 @@ class GetChatListItemSubtitle { eventContextId = null; } - final Timeline timeline = await event.room.getTimeline( - eventContextId: eventContextId, - ); + final Timeline timeline = event.room.timeline != null && + event.room.timeline!.events + .any((event) => event.eventId == eventContextId) + ? event.room.timeline! + : await event.room.getTimeline(eventContextId: eventContextId); if (moveBackInTimeline(event)) { event = timeline.events.firstWhereOrNull((e) => !moveBackInTimeline(e)); diff --git a/pubspec.lock b/pubspec.lock index 648cb96fe..c9559e143 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,14 +105,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0" - base58check: - dependency: transitive - description: - name: base58check - sha256: "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5" - url: "https://pub.dev" - source: hosted - version: "2.0.0" blurhash_dart: dependency: "direct main" description: @@ -145,14 +137,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.3" - canonical_json: - dependency: transitive - description: - name: canonical_json - sha256: d6be1dd66b420c6ac9f42e3693e09edf4ff6edfee26cb4c28c1c019fdb8c0c15 - url: "https://pub.dev" - source: hosted - version: "1.1.2" characters: dependency: transitive description: @@ -369,14 +353,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.9" - enhanced_enum: - dependency: transitive - description: - name: enhanced_enum - sha256: "074c5a8b9664799ca91e1e8b68003b8694cb19998671cbafd9c7779c13fcdecf" - url: "https://pub.dev" - source: hosted - version: "0.2.4" equatable: dependency: transitive description: @@ -1039,14 +1015,6 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.4" - html_unescape: - dependency: transitive - description: - name: html_unescape - sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" - url: "https://pub.dev" - source: hosted - version: "2.0.0" http: dependency: "direct main" description: @@ -1434,7 +1402,7 @@ packages: description: path: "." ref: main - resolved-ref: "0e27bd767a7f0faa7c25ea5f68292fb0b4f59a97" + resolved-ref: "40b095825f2cefeac548009e96376110e72c76ff" url: "https://github.com/pangeachat/matrix-dart-sdk.git" source: git version: "0.30.0" @@ -1494,14 +1462,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" - olm: - dependency: transitive - description: - name: olm - sha256: "37948a6576949256f3ee1d0063d5b408634ff7e452b9a5c2f6410f9d7ced1c20" - url: "https://pub.dev" - source: hosted - version: "2.0.3" open_file: dependency: "direct main" description: @@ -1846,14 +1806,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" - random_string: - dependency: transitive - description: - name: random_string - sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02" - url: "https://pub.dev" - source: hosted - version: "2.3.1" receive_sharing_intent: dependency: "direct main" description: @@ -1974,14 +1926,6 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" - sdp_transform: - dependency: transitive - description: - name: sdp_transform - sha256: "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45" - url: "https://pub.dev" - source: hosted - version: "0.3.2" sentiment_dart: dependency: transitive description: @@ -2459,14 +2403,6 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" - unorm_dart: - dependency: transitive - description: - name: unorm_dart - sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b" - url: "https://pub.dev" - source: hosted - version: "0.2.0" url_launcher: dependency: "direct main" description: From 1924b3e2d1aefc617588bc10549f7033bdaceac1 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Thu, 25 Jul 2024 16:52:55 -0400 Subject: [PATCH 05/18] use chunk eventMaps to check if event exists --- .../utils/get_chat_list_item_subtitle.dart | 3 +- pubspec.lock | 66 ++++++++++++++++++- 2 files changed, 66 insertions(+), 3 deletions(-) diff --git a/lib/pangea/utils/get_chat_list_item_subtitle.dart b/lib/pangea/utils/get_chat_list_item_subtitle.dart index f09679444..d02ac7088 100644 --- a/lib/pangea/utils/get_chat_list_item_subtitle.dart +++ b/lib/pangea/utils/get_chat_list_item_subtitle.dart @@ -37,8 +37,7 @@ class GetChatListItemSubtitle { } final Timeline timeline = event.room.timeline != null && - event.room.timeline!.events - .any((event) => event.eventId == eventContextId) + event.room.timeline!.chunk.eventsMap.containsKey(eventContextId) ? event.room.timeline! : await event.room.getTimeline(eventContextId: eventContextId); diff --git a/pubspec.lock b/pubspec.lock index c9559e143..a0affbe48 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -105,6 +105,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.4.0" + base58check: + dependency: transitive + description: + name: base58check + sha256: "6c300dfc33e598d2fe26319e13f6243fea81eaf8204cb4c6b69ef20a625319a5" + url: "https://pub.dev" + source: hosted + version: "2.0.0" blurhash_dart: dependency: "direct main" description: @@ -137,6 +145,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.3.3" + canonical_json: + dependency: transitive + description: + name: canonical_json + sha256: d6be1dd66b420c6ac9f42e3693e09edf4ff6edfee26cb4c28c1c019fdb8c0c15 + url: "https://pub.dev" + source: hosted + version: "1.1.2" characters: dependency: transitive description: @@ -353,6 +369,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.9.9" + enhanced_enum: + dependency: transitive + description: + name: enhanced_enum + sha256: "074c5a8b9664799ca91e1e8b68003b8694cb19998671cbafd9c7779c13fcdecf" + url: "https://pub.dev" + source: hosted + version: "0.2.4" equatable: dependency: transitive description: @@ -1015,6 +1039,14 @@ packages: url: "https://pub.dev" source: hosted version: "0.15.4" + html_unescape: + dependency: transitive + description: + name: html_unescape + sha256: "15362d7a18f19d7b742ef8dcb811f5fd2a2df98db9f80ea393c075189e0b61e3" + url: "https://pub.dev" + source: hosted + version: "2.0.0" http: dependency: "direct main" description: @@ -1402,7 +1434,7 @@ packages: description: path: "." ref: main - resolved-ref: "40b095825f2cefeac548009e96376110e72c76ff" + resolved-ref: "5f22d0e9aed99f3044a208bb69f446d470eaa464" url: "https://github.com/pangeachat/matrix-dart-sdk.git" source: git version: "0.30.0" @@ -1462,6 +1494,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.0.2" + olm: + dependency: transitive + description: + name: olm + sha256: "37948a6576949256f3ee1d0063d5b408634ff7e452b9a5c2f6410f9d7ced1c20" + url: "https://pub.dev" + source: hosted + version: "2.0.3" open_file: dependency: "direct main" description: @@ -1806,6 +1846,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.2.1" + random_string: + dependency: transitive + description: + name: random_string + sha256: "03b52435aae8cbdd1056cf91bfc5bf845e9706724dd35ae2e99fa14a1ef79d02" + url: "https://pub.dev" + source: hosted + version: "2.3.1" receive_sharing_intent: dependency: "direct main" description: @@ -1926,6 +1974,14 @@ packages: url: "https://pub.dev" source: hosted version: "3.0.1" + sdp_transform: + dependency: transitive + description: + name: sdp_transform + sha256: "73e412a5279a5c2de74001535208e20fff88f225c9a4571af0f7146202755e45" + url: "https://pub.dev" + source: hosted + version: "0.3.2" sentiment_dart: dependency: transitive description: @@ -2403,6 +2459,14 @@ packages: url: "https://pub.dev" source: hosted version: "2.2.2" + unorm_dart: + dependency: transitive + description: + name: unorm_dart + sha256: "5b35bff83fce4d76467641438f9e867dc9bcfdb8c1694854f230579d68cd8f4b" + url: "https://pub.dev" + source: hosted + version: "0.2.0" url_launcher: dependency: "direct main" description: From 4de8530a7e357235713894f4a3f22fddba174112 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Thu, 1 Aug 2024 17:15:25 -0400 Subject: [PATCH 06/18] 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 d86a9303d2689e4cf6c66f95f6daa431a5c62b55 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Mon, 5 Aug 2024 13:26:54 -0400 Subject: [PATCH 07/18] 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 08/18] 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 76c38a594e4a12718ecad5025d0ddbe75a08f08c Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 12:13:55 -0400 Subject: [PATCH 09/18] 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 0201aae91653818247bc3d0d7bc9b5b1acb53e2c Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 13:19:08 -0400 Subject: [PATCH 10/18] 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 bd4d9e43ed314c2f37db41b264be79dabd787892 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 14:41:50 -0400 Subject: [PATCH 11/18] add create group chat validation for custom and game master instructions --- assets/l10n/intl_en.arb | 5 + lib/pages/new_group/new_group.dart | 28 ++++++ lib/pangea/constants/model_keys.dart | 3 + lib/pangea/models/bot_options_model.dart | 17 ++++ ...sation_bot_custom_system_prompt_input.dart | 48 +++++++--- .../conversation_bot_custom_zone.dart | 1 - .../conversation_bot_mode_dynamic_zone.dart | 6 +- .../conversation_bot_mode_select.dart | 4 +- ...venture_game_master_instruction_input.dart | 91 +++++++++++++++++++ .../conversation_bot_text_adventure_zone.dart | 45 ++++++++- 10 files changed, 229 insertions(+), 19 deletions(-) create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 981a36238..b8ad9121b 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -4003,6 +4003,7 @@ "conversationBotCustomZone_title": "Custom Settings", "conversationBotCustomZone_customSystemPromptLabel": "System prompt", "conversationBotCustomZone_customSystemPromptPlaceholder": "Set custom system prompt", + "conversationBotCustomZone_customSystemPromptEmptyError": "Missing custom system prompt", "conversationBotCustomZone_customTriggerReactionEnabledLabel": "Responds on ⏩ reaction", "botConfig": "Conversation Bot Settings", "addConversationBotDialogTitleInvite": "Confirm inviting conversation bot", @@ -4013,6 +4014,10 @@ "addConversationBotDialogRemoveConfirmation": "Remove", "conversationBotConfigConfirmChange": "Confirm", "conversationBotStatus": "Bot Status", + "conversationBotTextAdventureZone_title": "Text Adventure", + "conversationBotTextAdventureZone_instructionLabel": "Game Master Instructions", + "conversationBotTextAdventureZone_instructionPlaceholder": "Set game master instructions", + "conversationBotCustomZone_instructionSystemPromptEmptyError": "Missing game master instructions", "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/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart index 94684e442..cb16a83a7 100644 --- a/lib/pages/new_group/new_group.dart +++ b/lib/pages/new_group/new_group.dart @@ -106,6 +106,34 @@ class NewGroupController extends State { if (!mounted) return; + // #Pangea + // validate init bot options + final addBot = addConversationBotKey.currentState?.addBot ?? false; + if (addBot) { + final botOptions = addConversationBotKey.currentState!.botOptions; + if (botOptions.mode == "custom") { + if (botOptions.customSystemPrompt == null || + botOptions.customSystemPrompt!.isEmpty) { + setState(() { + error = L10n.of(context)! + .conversationBotCustomZone_customSystemPromptEmptyError; + loading = false; + }); + return; + } + } else if (botOptions.mode == "text_adventure") { + if (botOptions.textAdventureGameMasterInstructions == null || + botOptions.textAdventureGameMasterInstructions!.isEmpty) { + setState(() { + error = L10n.of(context)! + .conversationBotCustomZone_instructionSystemPromptEmptyError; + loading = false; + }); + return; + } + } + } + final roomId = await client.createGroupChat( // #Pangea // visibility: diff --git a/lib/pangea/constants/model_keys.dart b/lib/pangea/constants/model_keys.dart index 7c60b98d7..b42061446 100644 --- a/lib/pangea/constants/model_keys.dart +++ b/lib/pangea/constants/model_keys.dart @@ -114,6 +114,9 @@ class ModelKey { "custom_trigger_reaction_enabled"; static const String customTriggerReactionKey = "custom_trigger_reaction_key"; + static const String textAdventureGameMasterInstructions = + "text_adventure_game_master_instructions"; + static const String prevEventId = "prev_event_id"; static const String prevLastUpdated = "prev_last_updated"; } diff --git a/lib/pangea/models/bot_options_model.dart b/lib/pangea/models/bot_options_model.dart index 179461a34..5c61eef5a 100644 --- a/lib/pangea/models/bot_options_model.dart +++ b/lib/pangea/models/bot_options_model.dart @@ -20,6 +20,7 @@ class BotOptionsModel { String? customSystemPrompt; bool? customTriggerReactionEnabled; String? customTriggerReactionKey; + String? textAdventureGameMasterInstructions; BotOptionsModel({ //////////////////////////////////////////////////////////////////////////// @@ -45,6 +46,11 @@ class BotOptionsModel { this.customSystemPrompt, this.customTriggerReactionEnabled = true, this.customTriggerReactionKey = "⏩", + + //////////////////////////////////////////////////////////////////////////// + // Text Adventure Mode Options + //////////////////////////////////////////////////////////////////////////// + this.textAdventureGameMasterInstructions, }); factory BotOptionsModel.fromJson(json) { @@ -73,6 +79,12 @@ class BotOptionsModel { customTriggerReactionEnabled: json[ModelKey.customTriggerReactionEnabled] ?? true, customTriggerReactionKey: json[ModelKey.customTriggerReactionKey] ?? "⏩", + + ////////////////////////////////////////////////////////////////////////// + // Text Adventure Mode Options + ////////////////////////////////////////////////////////////////////////// + textAdventureGameMasterInstructions: + json[ModelKey.textAdventureGameMasterInstructions], ); } @@ -93,6 +105,8 @@ class BotOptionsModel { data[ModelKey.customTriggerReactionEnabled] = customTriggerReactionEnabled ?? true; data[ModelKey.customTriggerReactionKey] = customTriggerReactionKey ?? "⏩"; + data[ModelKey.textAdventureGameMasterInstructions] = + textAdventureGameMasterInstructions; return data; } catch (e, s) { debugger(when: kDebugMode); @@ -134,6 +148,9 @@ class BotOptionsModel { case ModelKey.customTriggerReactionKey: customTriggerReactionKey = value; break; + case ModelKey.textAdventureGameMasterInstructions: + textAdventureGameMasterInstructions = value; + break; default: throw Exception('Invalid key for bot options - $key'); } diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart index 55ec1493d..2e79e0677 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart @@ -20,6 +20,9 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget { final TextEditingController textFieldController = TextEditingController(text: customSystemPrompt); + final GlobalKey customSystemPromptFormKey = + GlobalKey(); + void setBotCustomSystemPromptAction() async { showDialog( context: context, @@ -28,14 +31,25 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget { title: Text( L10n.of(context)!.conversationBotCustomZone_customSystemPromptLabel, ), - content: TextField( - minLines: 1, - maxLines: 10, - maxLength: 1000, - controller: textFieldController, - onChanged: (value) { - customSystemPrompt = value; - }, + content: Form( + key: customSystemPromptFormKey, + child: TextFormField( + minLines: 1, + maxLines: 10, + maxLength: 1000, + controller: textFieldController, + onChanged: (value) { + if (value.isNotEmpty) { + customSystemPrompt = value; + } + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'This field cannot be empty'; + } + return null; + }, + ), ), actions: [ TextButton( @@ -47,11 +61,12 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget { TextButton( child: Text(L10n.of(context)!.ok), onPressed: () { - if (customSystemPrompt == "") return; - if (customSystemPrompt != - initialBotOptions.customSystemPrompt) { - initialBotOptions.customSystemPrompt = customSystemPrompt; - onChanged.call(initialBotOptions); + if (customSystemPromptFormKey.currentState!.validate()) { + if (customSystemPrompt != + initialBotOptions.customSystemPrompt) { + initialBotOptions.customSystemPrompt = customSystemPrompt; + onChanged.call(initialBotOptions); + } Navigator.of(context).pop(); } }, @@ -68,6 +83,13 @@ class ConversationBotCustomSystemPromptInput extends StatelessWidget { L10n.of(context)! .conversationBotCustomZone_customSystemPromptPlaceholder, ), + subtitle: customSystemPrompt.isEmpty + ? Text( + L10n.of(context)! + .conversationBotCustomZone_customSystemPromptEmptyError, + style: const TextStyle(color: Colors.red), + ) + : null, ); } } 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_mode_dynamic_zone.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart index b15689357..e7d8f55a9 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_mode_dynamic_zone.dart @@ -1,5 +1,6 @@ import 'package:fluffychat/pangea/models/bot_options_model.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart'; import 'package:flutter/material.dart'; import 'conversation_bot_discussion_zone.dart'; @@ -26,7 +27,10 @@ class ConversationBotModeDynamicZone extends StatelessWidget { onChanged: onChanged, ), // "conversation": const ConversationBotConversationZone(), - // "text_adventure": const ConversationBotTextAdventureZone(), + "text_adventure": ConversationBotTextAdventureZone( + initialBotOptions: initialBotOptions, + onChanged: onChanged, + ), }; return Container( decoration: BoxDecoration( diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart index ba60f038c..5ec435112 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart @@ -19,8 +19,8 @@ class ConversationBotModeSelect extends StatelessWidget { "custom": L10n.of(context)!.conversationBotModeSelectOption_custom, // "conversation": // L10n.of(context)!.conversationBotModeSelectOption_conversation, - // "text_adventure": - // L10n.of(context)!.conversationBotModeSelectOption_textAdventure, + "text_adventure": + L10n.of(context)!.conversationBotModeSelectOption_textAdventure, }; return Padding( diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart new file mode 100644 index 000000000..fc5aa0a08 --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart @@ -0,0 +1,91 @@ +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +class ConversationBotGameMasterInstructionsInput extends StatelessWidget { + final BotOptionsModel initialBotOptions; + // call this to update propagate changes to parents + final void Function(BotOptionsModel) onChanged; + + const ConversationBotGameMasterInstructionsInput({ + super.key, + required this.initialBotOptions, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + String gameMasterInstructions = + initialBotOptions.textAdventureGameMasterInstructions ?? ""; + + final TextEditingController textFieldController = + TextEditingController(text: gameMasterInstructions); + + final GlobalKey gameMasterInstructionsFormKey = + GlobalKey(); + + void setBotTextAdventureGameMasterInstructionsAction() async { + showDialog( + context: context, + useRootNavigator: false, + builder: (BuildContext context) => AlertDialog( + title: Text( + L10n.of(context)! + .conversationBotTextAdventureZone_instructionPlaceholder, + ), + content: Form( + key: gameMasterInstructionsFormKey, + child: TextFormField( + minLines: 1, + maxLines: 10, + maxLength: 1000, + controller: textFieldController, + onChanged: (value) { + if (value.isNotEmpty) { + gameMasterInstructions = value; + } + }, + validator: (value) { + if (value == null || value.isEmpty) { + return 'This field cannot be empty'; + } + return null; + }, + ), + ), + actions: [ + TextButton( + child: Text(L10n.of(context)!.cancel), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text(L10n.of(context)!.ok), + onPressed: () { + if (gameMasterInstructionsFormKey.currentState!.validate()) { + if (gameMasterInstructions != + initialBotOptions.textAdventureGameMasterInstructions) { + initialBotOptions.textAdventureGameMasterInstructions = + gameMasterInstructions; + onChanged.call(initialBotOptions); + } + Navigator.of(context).pop(); + } + }, + ), + ], + ), + ); + } + + return ListTile( + onTap: setBotTextAdventureGameMasterInstructionsAction, + title: Text( + initialBotOptions.textAdventureGameMasterInstructions ?? + L10n.of(context)! + .conversationBotTextAdventureZone_instructionPlaceholder, + ), + ); + } +} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart index 2f65348cf..7f47bd018 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart @@ -1,15 +1,56 @@ +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart'; import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; class ConversationBotTextAdventureZone extends StatelessWidget { + final BotOptionsModel initialBotOptions; + // call this to update propagate changes to parents + + final void Function(BotOptionsModel) onChanged; const ConversationBotTextAdventureZone({ super.key, + required this.initialBotOptions, + required this.onChanged, }); @override Widget build(BuildContext context) { - return const Column( + return Column( children: [ - Text('Text Adventure Zone'), + Text( + L10n.of(context)!.conversationBotTextAdventureZone_title, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + const Divider( + color: Colors.grey, + thickness: 1, + ), + const SizedBox(height: 12), + Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.fromLTRB(12, 0, 0, 0), + child: Text( + L10n.of(context)! + .conversationBotTextAdventureZone_instructionLabel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8), + child: ConversationBotGameMasterInstructionsInput( + initialBotOptions: initialBotOptions, + onChanged: onChanged, + ), + ), ], ); } From 1ece90dad25a0831853d1c913f991b931cf7bd6a Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Tue, 6 Aug 2024 15:48:58 -0400 Subject: [PATCH 12/18] 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 13/18] 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 14/18] 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 15/18] 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; From 62d71285a47889aaa50e942083ade67f5855f24b Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Wed, 7 Aug 2024 10:59:43 -0400 Subject: [PATCH 16/18] fix text adventure title padding --- .../conversation_bot/conversation_bot_text_adventure_zone.dart | 1 + 1 file changed, 1 insertion(+) diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart index 7f47bd018..0792295e9 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart @@ -18,6 +18,7 @@ class ConversationBotTextAdventureZone extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ + const SizedBox(height: 12), Text( L10n.of(context)!.conversationBotTextAdventureZone_title, style: TextStyle( From c193c928a1b8ff4169e61ae02af1629f7b5084eb Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Wed, 7 Aug 2024 11:27:22 -0400 Subject: [PATCH 17/18] implement dynamic zone label and title shared component --- .../conversation_bot_custom_zone.dart | 32 +++---------- .../conversation_bot_discussion_zone.dart | 48 ++++--------------- .../conversation_bot_dynamic_zone_label.dart | 27 +++++++++++ .../conversation_bot_dynamic_zone_title.dart | 31 ++++++++++++ .../conversation_bot_text_adventure_zone.dart | 32 +++---------- 5 files changed, 82 insertions(+), 88 deletions(-) create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart create mode 100644 lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart 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 d5002ce2f..14b05dc90 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart @@ -1,5 +1,7 @@ import 'package:fluffychat/pangea/models/bot_options_model.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -18,32 +20,12 @@ class ConversationBotCustomZone extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ - const SizedBox(height: 12), - Text( - L10n.of(context)!.conversationBotCustomZone_title, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), + ConversationBotDynamicZoneTitle( + title: L10n.of(context)!.conversationBotCustomZone_title, ), - const Divider( - color: Colors.grey, - thickness: 1, - ), - const SizedBox(height: 12), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.fromLTRB(12, 0, 0, 0), - child: Text( - L10n.of(context)! - .conversationBotCustomZone_customSystemPromptLabel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - ), + ConversationBotDynamicZoneLabel( + label: L10n.of(context)! + .conversationBotCustomZone_customSystemPromptLabel, ), Padding( padding: const EdgeInsets.all(8), diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_discussion_zone.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_discussion_zone.dart index 2bb4d7a76..6035faf4d 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_discussion_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_discussion_zone.dart @@ -1,6 +1,8 @@ import 'package:fluffychat/pangea/models/bot_options_model.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_discussion_keywords_input.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_discussion_topic_input.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -19,32 +21,12 @@ class ConversationBotDiscussionZone extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ - const SizedBox(height: 12), - Text( - L10n.of(context)!.conversationBotDiscussionZone_title, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), + ConversationBotDynamicZoneTitle( + title: L10n.of(context)!.conversationBotDiscussionZone_title, ), - const Divider( - color: Colors.grey, - thickness: 1, - ), - const SizedBox(height: 12), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.fromLTRB(12, 0, 0, 0), - child: Text( - L10n.of(context)! - .conversationBotDiscussionZone_discussionTopicLabel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - ), + ConversationBotDynamicZoneLabel( + label: L10n.of(context)! + .conversationBotDiscussionZone_discussionTopicLabel, ), Padding( padding: const EdgeInsets.all(8), @@ -54,19 +36,9 @@ class ConversationBotDiscussionZone extends StatelessWidget { ), ), const SizedBox(height: 12), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.fromLTRB(12, 0, 0, 0), - child: Text( - L10n.of(context)! - .conversationBotDiscussionZone_discussionKeywordsLabel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - ), + ConversationBotDynamicZoneLabel( + label: L10n.of(context)! + .conversationBotDiscussionZone_discussionKeywordsLabel, ), Padding( padding: const EdgeInsets.all(8), diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart new file mode 100644 index 000000000..6c2043dcd --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart @@ -0,0 +1,27 @@ +import 'package:flutter/material.dart'; + +class ConversationBotDynamicZoneLabel extends StatelessWidget { + final String label; + + const ConversationBotDynamicZoneLabel({ + super.key, + required this.label, + }); + + @override + Widget build(BuildContext context) { + return Align( + alignment: Alignment.centerLeft, + child: Padding( + padding: const EdgeInsets.fromLTRB(12, 0, 0, 0), + child: Text( + label, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + ), + ); + } +} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart new file mode 100644 index 000000000..dbfbb00dc --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart @@ -0,0 +1,31 @@ +import 'package:flutter/material.dart'; + +class ConversationBotDynamicZoneTitle extends StatelessWidget { + final String title; + + const ConversationBotDynamicZoneTitle({ + super.key, + required this.title, + }); + + @override + Widget build(BuildContext context) { + return Column( + children: [ + const SizedBox(height: 12), + Text( + title, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + const Divider( + color: Colors.grey, + thickness: 1, + ), + const SizedBox(height: 12), + ], + ); + } +} diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart index 0792295e9..effbf70ee 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_text_adventure_zone.dart @@ -1,4 +1,6 @@ import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_label.dart'; +import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_dynamic_zone_title.dart'; import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_text_adventure_game_master_instruction_input.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -18,32 +20,12 @@ class ConversationBotTextAdventureZone extends StatelessWidget { Widget build(BuildContext context) { return Column( children: [ - const SizedBox(height: 12), - Text( - L10n.of(context)!.conversationBotTextAdventureZone_title, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), + ConversationBotDynamicZoneTitle( + title: L10n.of(context)!.conversationBotTextAdventureZone_title, ), - const Divider( - color: Colors.grey, - thickness: 1, - ), - const SizedBox(height: 12), - Align( - alignment: Alignment.centerLeft, - child: Padding( - padding: const EdgeInsets.fromLTRB(12, 0, 0, 0), - child: Text( - L10n.of(context)! - .conversationBotTextAdventureZone_instructionLabel, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - ), + ConversationBotDynamicZoneLabel( + label: L10n.of(context)! + .conversationBotTextAdventureZone_instructionLabel, ), Padding( padding: const EdgeInsets.all(8), From b8bd90a44da8870dd5c8a240715a469826cbb73e Mon Sep 17 00:00:00 2001 From: ggurdin Date: Wed, 7 Aug 2024 12:48:28 -0400 Subject: [PATCH 18/18] replace accessToken with matrix access token --- .../controllers/alternative_translator.dart | 4 +- .../controllers/choreographer.dart | 2 +- .../controllers/igc_controller.dart | 2 +- .../controllers/span_data_controller.dart | 2 +- .../widgets/it_feedback_card.dart | 2 +- .../contextual_definition_controller.dart | 2 +- .../controllers/it_feedback_controller.dart | 2 +- .../language_detection_controller.dart | 2 +- .../controllers/message_data_controller.dart | 4 +- .../speech_to_text_controller.dart | 2 +- .../text_to_speech_controller.dart | 2 +- lib/pangea/controllers/user_controller.dart | 50 +++-------------- .../controllers/word_net_controller.dart | 2 +- .../pages/find_partner/find_partner.dart | 3 +- lib/pangea/repo/user_repo.dart | 53 +++++++++---------- .../chat/message_translation_card.dart | 2 +- lib/pangea/widgets/new_group/vocab_list.dart | 4 +- 17 files changed, 50 insertions(+), 90 deletions(-) diff --git a/lib/pangea/choreographer/controllers/alternative_translator.dart b/lib/pangea/choreographer/controllers/alternative_translator.dart index 5771d7f90..7ac564087 100644 --- a/lib/pangea/choreographer/controllers/alternative_translator.dart +++ b/lib/pangea/choreographer/controllers/alternative_translator.dart @@ -91,7 +91,7 @@ class AlternativeTranslator { final FullTextTranslationResponseModel results = await FullTextTranslationRepo.translate( - accessToken: await choreographer.accessToken, + accessToken: choreographer.accessToken, request: FullTextTranslationRequestModel( text: choreographer.itController.sourceText!, tgtLang: choreographer.l2LangCode!, @@ -117,7 +117,7 @@ class AlternativeTranslator { } similarityResponse = await SimilarityRepo.get( - accessToken: await choreographer.accessToken, + accessToken: choreographer.accessToken, request: SimilarityRequestModel( benchmark: results.bestTranslation, toCompare: [userTranslation!], diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index c3cd0ab09..1a11de0e3 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -402,7 +402,7 @@ class Choreographer { PangeaTextController get textController => _textController; - Future get accessToken => pangeaController.userController.accessToken; + String get accessToken => pangeaController.userController.accessToken; clear() { choreoMode = ChoreoMode.igc; diff --git a/lib/pangea/choreographer/controllers/igc_controller.dart b/lib/pangea/choreographer/controllers/igc_controller.dart index 6295efa16..ab0e48669 100644 --- a/lib/pangea/choreographer/controllers/igc_controller.dart +++ b/lib/pangea/choreographer/controllers/igc_controller.dart @@ -46,7 +46,7 @@ class IgcController { ); final IGCTextData igcTextDataResponse = await IgcRepo.getIGC( - await choreographer.accessToken, + choreographer.accessToken, igcRequest: reqBody, ); diff --git a/lib/pangea/choreographer/controllers/span_data_controller.dart b/lib/pangea/choreographer/controllers/span_data_controller.dart index 5f83f1a53..24470454c 100644 --- a/lib/pangea/choreographer/controllers/span_data_controller.dart +++ b/lib/pangea/choreographer/controllers/span_data_controller.dart @@ -65,7 +65,7 @@ class SpanDataController { response = _cache[cacheKey]!.data; } else { response = SpanDataRepo.getSpanDetails( - await choreographer.accessToken, + choreographer.accessToken, request: SpanDetailsRepoReqAndRes( userL1: choreographer.l1LangCode!, userL2: choreographer.l2LangCode!, diff --git a/lib/pangea/choreographer/widgets/it_feedback_card.dart b/lib/pangea/choreographer/widgets/it_feedback_card.dart index 9cada0548..f959715ce 100644 --- a/lib/pangea/choreographer/widgets/it_feedback_card.dart +++ b/lib/pangea/choreographer/widgets/it_feedback_card.dart @@ -73,7 +73,7 @@ class ITFeedbackCardController extends State { isTranslating = true; }); FullTextTranslationRepo.translate( - accessToken: await controller.userController.accessToken, + accessToken: controller.userController.accessToken, request: FullTextTranslationRequestModel( text: res!.text, tgtLang: controller.languageController.userL1?.langCode ?? diff --git a/lib/pangea/controllers/contextual_definition_controller.dart b/lib/pangea/controllers/contextual_definition_controller.dart index d423c9b38..cfe13ebf0 100644 --- a/lib/pangea/controllers/contextual_definition_controller.dart +++ b/lib/pangea/controllers/contextual_definition_controller.dart @@ -51,7 +51,7 @@ class ContextualDefinitionController { try { final ContextualDefinitionResponseModel res = await _ContextualDefinitionRepo.define( - await _pangeaController.userController.accessToken, + _pangeaController.userController.accessToken, request, ); return res; diff --git a/lib/pangea/controllers/it_feedback_controller.dart b/lib/pangea/controllers/it_feedback_controller.dart index ffef9123f..7a989bda6 100644 --- a/lib/pangea/controllers/it_feedback_controller.dart +++ b/lib/pangea/controllers/it_feedback_controller.dart @@ -52,7 +52,7 @@ class ITFeedbackController { ) async { try { final ITFeedbackResponseModel res = await _ITFeedbackRepo.get( - await _pangeaController.userController.accessToken, + _pangeaController.userController.accessToken, request, ); return res; diff --git a/lib/pangea/controllers/language_detection_controller.dart b/lib/pangea/controllers/language_detection_controller.dart index a3e07b0a3..bcc9b4140 100644 --- a/lib/pangea/controllers/language_detection_controller.dart +++ b/lib/pangea/controllers/language_detection_controller.dart @@ -145,7 +145,7 @@ class LanguageDetectionController { return _cache[params]!.data; } else { final Future response = _fetchResponse( - await _pangeaController.userController.accessToken, + _pangeaController.userController.accessToken, params, ); _cache[params] = _LanguageDetectionCacheItem(data: response); diff --git a/lib/pangea/controllers/message_data_controller.dart b/lib/pangea/controllers/message_data_controller.dart index 7b3a3e6d2..9903eada0 100644 --- a/lib/pangea/controllers/message_data_controller.dart +++ b/lib/pangea/controllers/message_data_controller.dart @@ -42,7 +42,7 @@ class MessageDataController extends BaseController { Future _getTokens( TokensRequestModel req, ) async { - final accessToken = await _pangeaController.userController.accessToken; + final accessToken = _pangeaController.userController.accessToken; final TokensResponseModel igcTextData = await TokensRepo.tokenize(accessToken, req); @@ -195,7 +195,7 @@ class MessageDataController extends BaseController { try { final FullTextTranslationResponseModel res = await FullTextTranslationRepo.translate( - accessToken: await _pangeaController.userController.accessToken, + accessToken: _pangeaController.userController.accessToken, request: req, ); diff --git a/lib/pangea/controllers/speech_to_text_controller.dart b/lib/pangea/controllers/speech_to_text_controller.dart index 67462bcef..4e32d6f9e 100644 --- a/lib/pangea/controllers/speech_to_text_controller.dart +++ b/lib/pangea/controllers/speech_to_text_controller.dart @@ -53,7 +53,7 @@ class SpeechToTextController { return _cache[cacheKey]!.data; } else { final Future response = _fetchResponse( - accessToken: await _pangeaController.userController.accessToken, + accessToken: _pangeaController.userController.accessToken, requestModel: requestModel, ); _cache[cacheKey] = _SpeechToTextCacheItem(data: response); diff --git a/lib/pangea/controllers/text_to_speech_controller.dart b/lib/pangea/controllers/text_to_speech_controller.dart index b34092618..069722590 100644 --- a/lib/pangea/controllers/text_to_speech_controller.dart +++ b/lib/pangea/controllers/text_to_speech_controller.dart @@ -100,7 +100,7 @@ class TextToSpeechController { return _cache[params]!.data; } else { final Future response = _fetchResponse( - await _pangeaController.userController.accessToken, + _pangeaController.userController.accessToken, params, ); _cache[params] = _TextToSpeechCacheItem(data: response); diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index bf8ce3c11..035b122e4 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -9,7 +9,6 @@ import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:jwt_decode/jwt_decode.dart'; import 'package:matrix/matrix.dart' as matrix; -import '../constants/local.key.dart'; import '../models/user_model.dart'; import '../repo/user_repo.dart'; @@ -83,15 +82,6 @@ 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); } @@ -157,41 +147,13 @@ class UserController extends BaseController { /// Returns a boolean value indicating whether a new JWT (JSON Web Token) is needed. bool needNewJWT(String token) => Jwt.isExpired(token); - /// Retrieves the access token for the user. Looks for it locally, - /// and if it's not found or expired, fetches it from the server. - Future get accessToken async { - final localAccessToken = - _pangeaController.pStoreService.read(PLocalKey.access); - - if (localAccessToken == null || needNewJWT(localAccessToken)) { - 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) { - 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, - userModel!.access, - ); - return userModel.access; + /// Retrieves matrix access token. + String get accessToken { + final token = _pangeaController.matrixState.client.accessToken; + if (token == null) { + throw ("Trying to get accessToken with null token. User is not logged in."); } - - return localAccessToken; + return token; } /// Returns the full name of the user. diff --git a/lib/pangea/controllers/word_net_controller.dart b/lib/pangea/controllers/word_net_controller.dart index b7a8d287e..81affd726 100644 --- a/lib/pangea/controllers/word_net_controller.dart +++ b/lib/pangea/controllers/word_net_controller.dart @@ -54,7 +54,7 @@ class WordController extends BaseController { if (local != null) return local; final WordData remote = await WordRepo.getWordNetData( - accessToken: await _pangeaController.userController.accessToken, + accessToken: _pangeaController.userController.accessToken, fullText: fullText, word: word, userL1: userL1, diff --git a/lib/pangea/pages/find_partner/find_partner.dart b/lib/pangea/pages/find_partner/find_partner.dart index a953c7f19..0e50beab6 100644 --- a/lib/pangea/pages/find_partner/find_partner.dart +++ b/lib/pangea/pages/find_partner/find_partner.dart @@ -107,8 +107,7 @@ class FindPartnerController extends State { UserProfileSearchResponse response; try { - final String accessToken = - await pangeaController.userController.accessToken; + final String accessToken = pangeaController.userController.accessToken; response = await PUserRepo.searchUserProfiles( accessToken: accessToken, targetLanguage: targetLanguageSearch.langCode, diff --git a/lib/pangea/repo/user_repo.dart b/lib/pangea/repo/user_repo.dart index 244e21c54..7f3efc48f 100644 --- a/lib/pangea/repo/user_repo.dart +++ b/lib/pangea/repo/user_repo.dart @@ -2,7 +2,6 @@ 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'; @@ -11,33 +10,33 @@ 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, - ); + // 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; - } - } + // 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, diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index 68d3a6e95..10e75a47a 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -59,7 +59,7 @@ class MessageTranslationCardState extends State { oldSelectedText = widget.selection.selectedText; final String accessToken = - await MatrixState.pangeaController.userController.accessToken; + MatrixState.pangeaController.userController.accessToken; final resp = await FullTextTranslationRepo.translate( accessToken: accessToken, diff --git a/lib/pangea/widgets/new_group/vocab_list.dart b/lib/pangea/widgets/new_group/vocab_list.dart index 67089145e..ac0d157a7 100644 --- a/lib/pangea/widgets/new_group/vocab_list.dart +++ b/lib/pangea/widgets/new_group/vocab_list.dart @@ -312,7 +312,7 @@ class GenerateVocabButtonState extends State { Future> _getWords() async { final ChatTopic topic = await TopicDataRepo.generate( - await _pangeaController.userController.accessToken, + _pangeaController.userController.accessToken, request: TopicDataRequest( topicInfo: widget.topic, numWords: 10, @@ -514,7 +514,7 @@ class PromptsFieldState extends State { Future> _getPrompts() async { final ChatTopic res = await TopicDataRepo.generate( - await _pangeaController.userController.accessToken, + _pangeaController.userController.accessToken, request: TopicDataRequest( topicInfo: widget.topic, numPrompts: 10,