From 4de8530a7e357235713894f4a3f22fddba174112 Mon Sep 17 00:00:00 2001 From: WilsonLe Date: Thu, 1 Aug 2024 17:15:25 -0400 Subject: [PATCH] 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), + ], + ], + ), + ); +}