diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 385009ff6..981a36238 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,12 +4004,15 @@ "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", "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/pages/chat_details/chat_details.dart b/lib/pages/chat_details/chat_details.dart index 7b7bbfd1c..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.dart'; import 'package:fluffychat/utils/platform_infos.dart'; import 'package:fluffychat/widgets/app_lock.dart'; import 'package:fluffychat/widgets/matrix.dart'; @@ -43,8 +42,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/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 1c78fd030..e4054f4e5 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.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_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'; -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; @@ -36,6 +33,7 @@ class ConversationBotSettings extends StatefulWidget { class ConversationBotSettingsState extends State { late BotOptionsModel botOptions; late bool isOpen; + late bool isCreating; bool addBot = false; Room? parentSpace; @@ -56,6 +54,22 @@ class ConversationBotSettingsState extends State { 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 { @@ -74,196 +88,191 @@ class ConversationBotSettingsState extends State { ); } - 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( + Widget build(BuildContext context) { + return AnimatedContainer( + duration: const Duration(milliseconds: 300), + width: double.infinity, + child: Column( + crossAxisAlignment: CrossAxisAlignment.start, children: [ ListTile( title: Text( - L10n.of(context)!.convoBotSettingsTitle, + isCreating + ? L10n.of(context)!.addConversationBot + : L10n.of(context)!.botConfig, style: TextStyle( color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.bold, ), ), - subtitle: Text(L10n.of(context)!.convoBotSettingsDescription), + subtitle: isCreating + ? Text(L10n.of(context)!.addConversationBotDesc) + : null, leading: CircleAvatar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, foregroundColor: Theme.of(context).textTheme.bodyLarge!.color, - child: const Icon(Icons.psychology_outlined), + child: const BotFace( + width: 30.0, + expression: BotExpression.idle, + ), ), - 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 + 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)! - .addConversationBotButtonTitleRemove, + .addConversationBotDialogRemoveConfirmation, ) : Text( L10n.of(context)! - .addConversationBotDialogTitleInvite, + .addConversationBotDialogInviteConfirmation, ), - 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), - ], - ], - ), + ); + + 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; + }); + } + }, + ), + if (isCreating && addBot) + ConversationBotSettingsForm( + 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 deleted file mode 100644 index f1facd835..000000000 Binary files a/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock and /dev/null differ 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 ea7da199a..000000000 Binary files a/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock and /dev/null differ 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 a148f5b0e..000000000 Binary files a/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock and /dev/null differ