diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb
index 4ccb42939..3aed42f1a 100644
--- a/assets/l10n/intl_en.arb
+++ b/assets/l10n/intl_en.arb
@@ -3875,5 +3875,15 @@
"placeholders": {}
},
"define": "Define",
- "listen": "Listen"
+ "listen": "Listen",
+ "addConversationBot": "Enable Conversation Bot",
+ "addConversationBotDesc": "Add a bot to this group chat that will ask questions on a specific topic",
+ "convoBotSettingsTitle": "Conversation Bot Settings",
+ "convoBotSettingsDescription": "Edit conversation topic and difficulty",
+ "enterAConversationTopic": "Enter a conversation topic",
+ "conversationTopic": "Conversation topic",
+ "enableModeration": "Enable moderation",
+ "enableModerationDesc": "Enable automatic moderation to review messages before they are sent",
+ "conversationLanguageLevel": "What is the language level of this conversation?",
+ "showDefinition": "Show Definition"
}
\ No newline at end of file
diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb
index 471e79f4c..71daf4635 100644
--- a/assets/l10n/intl_es.arb
+++ b/assets/l10n/intl_es.arb
@@ -2872,8 +2872,8 @@
"type": "text",
"placeholders": {}
},
- "langaugeLevel": "Nivel de lengua",
- "@langaugeLevel": {
+ "languageLevel": "Nivel de lengua",
+ "@languageLevel": {
"type": "text",
"placeholders": {}
},
@@ -4534,5 +4534,14 @@
"placeholders": {
"roomName": {}
}
- }
+ },
+ "addConversationBot": "Añadir bot de conversación",
+ "addConversationBotDesc": "Añadir un bot de conversación para enviar mensajes automáticos a este chat",
+ "convoBotSettingsTitle": "Configuración del bot de conversación",
+ "convoBotSettingsDescription": "Editar tema de conversación y dificultad",
+ "enterAConversationTopic": "Introducir un tema de conversación",
+ "conversationTopic": "Tema de conversación",
+ "enableModeration": "Activar la moderación",
+ "enableModerationDesc": "Activar la moderación automática para revisar los mensajes antes de enviarlos",
+ "conversationLanguageLevel": "¿Cuál es el nivel lingüístico de esta conversación?"
}
\ No newline at end of file
diff --git a/ios/FluffyChat Share/FluffyChat Share.entitlements b/ios/FluffyChat Share/FluffyChat Share.entitlements
index 932f3e01e..2eb7e333a 100644
--- a/ios/FluffyChat Share/FluffyChat Share.entitlements
+++ b/ios/FluffyChat Share/FluffyChat Share.entitlements
@@ -3,8 +3,6 @@
com.apple.security.application-groups
-
- group.im.fluffychat.app
-
+
diff --git a/ios/Flutter/AppFrameworkInfo.plist b/ios/Flutter/AppFrameworkInfo.plist
index 4f8d4d245..8c6e56146 100644
--- a/ios/Flutter/AppFrameworkInfo.plist
+++ b/ios/Flutter/AppFrameworkInfo.plist
@@ -21,6 +21,6 @@
CFBundleVersion
1.0
MinimumOSVersion
- 11.0
+ 12.0
diff --git a/ios/Runner.xcodeproj/project.pbxproj b/ios/Runner.xcodeproj/project.pbxproj
index e5c2d6a2b..73d46da15 100644
--- a/ios/Runner.xcodeproj/project.pbxproj
+++ b/ios/Runner.xcodeproj/project.pbxproj
@@ -457,7 +457,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
@@ -546,7 +546,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = YES;
ONLY_ACTIVE_ARCH = YES;
SDKROOT = iphoneos;
@@ -595,7 +595,7 @@
GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
GCC_WARN_UNUSED_FUNCTION = YES;
GCC_WARN_UNUSED_VARIABLE = YES;
- IPHONEOS_DEPLOYMENT_TARGET = 11.0;
+ IPHONEOS_DEPLOYMENT_TARGET = 12.0;
MTL_ENABLE_DEBUG_INFO = NO;
SDKROOT = iphoneos;
SUPPORTED_PLATFORMS = iphoneos;
diff --git a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
index b52b2e698..a6b826db2 100644
--- a/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
+++ b/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme
@@ -27,8 +27,6 @@
selectedDebuggerIdentifier = "Xcode.DebuggerFoundation.Debugger.LLDB"
selectedLauncherIdentifier = "Xcode.DebuggerFoundation.Launcher.LLDB"
shouldUseLaunchSchemeArgsEnv = "YES">
-
-
-
-
+
+
-
-
{
// #Pangea
final GlobalKey addToSpaceKey = GlobalKey();
+ final GlobalKey addConversationBotKey =
+ GlobalKey();
bool displayAddStudentOptions = false;
void toggleAddStudentOptions() =>
@@ -424,5 +425,11 @@ class ChatDetailsController extends State {
bool showEditNameIcon = false;
void hoverEditNameIcon(bool hovering) =>
setState(() => showEditNameIcon = !showEditNameIcon);
+
+ @override
+ void initState() {
+ super.initState();
+ MatrixState.pangeaController.classController.addMissingRoomRules(roomId);
+ }
// Pangea#
}
diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart
index d51c488c4..a095d49fd 100644
--- a/lib/pages/chat_details/chat_details_view.dart
+++ b/lib/pages/chat_details/chat_details_view.dart
@@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/utils/archive_space.dart';
import 'package:fluffychat/pangea/utils/lock_room.dart';
import 'package:fluffychat/pangea/widgets/class/add_class_and_invite.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/space/class_settings.dart';
import 'package:fluffychat/utils/fluffy_share.dart';
import 'package:fluffychat/utils/matrix_sdk_extensions/matrix_locals.dart';
@@ -489,6 +490,13 @@ class ChatDetailsView extends StatelessWidget {
if (controller.displayAddStudentOptions &&
room.showClassEditOptions)
ClassInvitationButtons(roomId: controller.roomId!),
+ const Divider(height: 1),
+ if (!room.isSpace && room.canInvite)
+ ConversationBotSettings(
+ key: controller.addConversationBotKey,
+ room: room,
+ ),
+ const Divider(height: 1),
if (!room.isPangeaClass)
AddToSpaceToggles(
roomId: room.id,
diff --git a/lib/pages/new_group/new_group.dart b/lib/pages/new_group/new_group.dart
index b01186a53..b4633ea7d 100644
--- a/lib/pages/new_group/new_group.dart
+++ b/lib/pages/new_group/new_group.dart
@@ -1,20 +1,20 @@
import 'dart:typed_data';
-import 'package:flutter/material.dart';
-
import 'package:file_picker/file_picker.dart';
-import 'package:flutter_gen/gen_l10n/l10n.dart';
-import 'package:go_router/go_router.dart';
-import 'package:matrix/matrix.dart' as sdk;
-
import 'package:fluffychat/pages/new_group/new_group_view.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/models/chat_topic_model.dart';
import 'package:fluffychat/pangea/models/lemma.dart';
+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/widgets/matrix.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/l10n.dart';
+import 'package:go_router/go_router.dart';
+import 'package:matrix/matrix.dart' as sdk;
class NewGroup extends StatefulWidget {
const NewGroup({super.key});
@@ -42,6 +42,8 @@ class NewGroupController extends State {
// #Pangea
PangeaController pangeaController = MatrixState.pangeaController;
final GlobalKey addToSpaceKey = GlobalKey();
+ final GlobalKey addConversationBotKey =
+ GlobalKey();
ChatTopic chatTopic = ChatTopic.empty;
@@ -121,6 +123,10 @@ class NewGroupController extends State {
.map((suggestionStatus) => suggestionStatus.room)
.toList(),
),
+ invite: [
+ if (addConversationBotKey.currentState?.addBot ?? false)
+ BotName.byEnvironment,
+ ],
// Pangea#
);
if (!mounted) return;
diff --git a/lib/pages/new_group/new_group_view.dart b/lib/pages/new_group/new_group_view.dart
index 72d663618..eb0fa605d 100644
--- a/lib/pages/new_group/new_group_view.dart
+++ b/lib/pages/new_group/new_group_view.dart
@@ -1,14 +1,13 @@
-import 'package:flutter/material.dart';
-
-import 'package:flutter_gen/gen_l10n/l10n.dart';
-
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/new_group/new_group.dart';
import 'package:fluffychat/pangea/widgets/class/add_class_and_invite.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/localized_exception_extension.dart';
import 'package:fluffychat/widgets/avatar.dart';
import 'package:fluffychat/widgets/layouts/max_width_body.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/l10n.dart';
class NewGroupView extends StatelessWidget {
final NewGroupController controller;
@@ -85,6 +84,10 @@ class NewGroupView extends StatelessWidget {
// ),
// ),
// ),
+ ConversationBotSettings(
+ key: controller.addConversationBotKey,
+ ),
+ const Divider(height: 1),
AddToSpaceToggles(
key: controller.addToSpaceKey,
startOpen: false,
diff --git a/lib/pangea/constants/model_keys.dart b/lib/pangea/constants/model_keys.dart
index 094ccaa84..d027bce1d 100644
--- a/lib/pangea/constants/model_keys.dart
+++ b/lib/pangea/constants/model_keys.dart
@@ -89,4 +89,10 @@ class ModelKey {
static const String feedbackLang = "feedback_lang";
static const String transcription = "transcription";
+
+ // bot options
+ static const String languageLevel = "difficulty";
+ static const String conversationTopic = "conversation_topic";
+ static const String keywords = "keywords";
+ static const String safetyModeration = "safety_moderation";
}
diff --git a/lib/pangea/constants/pangea_event_types.dart b/lib/pangea/constants/pangea_event_types.dart
index b98492871..3eb642a0c 100644
--- a/lib/pangea/constants/pangea_event_types.dart
+++ b/lib/pangea/constants/pangea_event_types.dart
@@ -15,4 +15,5 @@ class PangeaEventTypes {
static const roomInfo = "pangea.roomtopic";
static const audio = "p.audio";
+ static const botOptions = "pangea.bot_options";
}
diff --git a/lib/pangea/controllers/class_controller.dart b/lib/pangea/controllers/class_controller.dart
index c91eab1c0..6d028fda2 100644
--- a/lib/pangea/controllers/class_controller.dart
+++ b/lib/pangea/controllers/class_controller.dart
@@ -3,9 +3,11 @@ import 'dart:developer';
import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/constants/local.key.dart';
+import 'package:fluffychat/pangea/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/extensions/client_extension.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
+import 'package:fluffychat/pangea/models/class_model.dart';
import 'package:fluffychat/pangea/utils/class_code.dart';
import 'package:fluffychat/pangea/utils/error_handler.dart';
import 'package:flutter/foundation.dart';
@@ -156,4 +158,24 @@ class ClassController extends BaseController {
// BE - check class code and if class code is correct, invite student to room
// FE - look for invite from room and automatically accept
}
+
+ Future addMissingRoomRules(String? roomId) async {
+ if (roomId == null) return;
+ final Room? room = _pangeaController.matrixState.client.getRoomById(roomId);
+ if (room == null) return;
+
+ if (room.classSettings != null && room.pangeaRoomRules == null) {
+ try {
+ await _pangeaController.matrixState.client.setRoomStateWithKey(
+ roomId,
+ PangeaEventTypes.rules,
+ '',
+ PangeaRoomRules().toJson(),
+ );
+ } catch (err, stack) {
+ debugger(when: kDebugMode);
+ ErrorHandler.logError(e: err, s: stack);
+ }
+ }
+ }
}
diff --git a/lib/pangea/extensions/pangea_room_extension.dart b/lib/pangea/extensions/pangea_room_extension.dart
index f15a9e87d..8901085db 100644
--- a/lib/pangea/extensions/pangea_room_extension.dart
+++ b/lib/pangea/extensions/pangea_room_extension.dart
@@ -4,6 +4,7 @@ import 'dart:developer';
import 'package:fluffychat/pangea/constants/class_default_values.dart';
import 'package:fluffychat/pangea/constants/model_keys.dart';
import 'package:fluffychat/pangea/constants/pangea_room_types.dart';
+import 'package:fluffychat/pangea/models/bot_options_model.dart';
import 'package:fluffychat/pangea/models/class_model.dart';
import 'package:fluffychat/pangea/models/pangea_message_event.dart';
import 'package:fluffychat/pangea/utils/bot_name.dart';
@@ -980,4 +981,18 @@ extension PangeaRoom on Room {
if (!isSpace) return null;
return pangeaRoomRulesStateEvent?.originServerTs ?? creationTime;
}
+
+ Future get isBotRoom async {
+ final List participants = await requestParticipants();
+ return participants.any(
+ (User user) => user.id == BotName.byEnvironment,
+ );
+ }
+
+ BotOptionsModel? get botOptions {
+ if (isSpace) return null;
+ return BotOptionsModel.fromJson(
+ getState(PangeaEventTypes.botOptions)?.content ?? {},
+ );
+ }
}
diff --git a/lib/pangea/models/bot_options_model.dart b/lib/pangea/models/bot_options_model.dart
new file mode 100644
index 000000000..0cba5fd78
--- /dev/null
+++ b/lib/pangea/models/bot_options_model.dart
@@ -0,0 +1,72 @@
+import 'dart:developer';
+
+import 'package:fluffychat/pangea/constants/model_keys.dart';
+import 'package:fluffychat/pangea/utils/error_handler.dart';
+import 'package:flutter/foundation.dart';
+import 'package:matrix/matrix.dart';
+
+import '../constants/pangea_event_types.dart';
+
+class BotOptionsModel {
+ int? languageLevel;
+ String topic;
+ List keywords;
+ bool safetyModeration;
+
+ BotOptionsModel({
+ this.languageLevel,
+ this.topic = "General Conversation",
+ this.keywords = const [],
+ this.safetyModeration = true,
+ });
+
+ factory BotOptionsModel.fromJson(json) {
+ return BotOptionsModel(
+ languageLevel: json[ModelKey.languageLevel],
+ topic: json[ModelKey.conversationTopic] ?? "General Conversation",
+ keywords: (json[ModelKey.keywords] ?? []).cast(),
+ safetyModeration: json[ModelKey.safetyModeration] ?? true,
+ );
+ }
+
+ Map toJson() {
+ final data = {};
+ try {
+ // data[ModelKey.isConversationBotChat] = isConversationBotChat;
+ data[ModelKey.languageLevel] = languageLevel;
+ data[ModelKey.conversationTopic] = topic;
+ data[ModelKey.keywords] = keywords;
+ data[ModelKey.safetyModeration] = safetyModeration;
+ return data;
+ } catch (e, s) {
+ debugger(when: kDebugMode);
+ ErrorHandler.logError(e: e, s: s);
+ return data;
+ }
+ }
+
+ //TODO: define enum with all possible values
+ updateBotOption(String key, dynamic value) {
+ switch (key) {
+ case ModelKey.languageLevel:
+ languageLevel = value;
+ break;
+ case ModelKey.conversationTopic:
+ topic = value;
+ break;
+ case ModelKey.keywords:
+ keywords = value;
+ break;
+ case ModelKey.safetyModeration:
+ safetyModeration = value;
+ break;
+ default:
+ throw Exception('Invalid key for bot options - $key');
+ }
+ }
+
+ StateEvent get toStateEvent => StateEvent(
+ content: toJson(),
+ type: PangeaEventTypes.botOptions,
+ );
+}
diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart
index 4dc2ac4b6..690593fcc 100644
--- a/lib/pangea/widgets/chat/message_toolbar.dart
+++ b/lib/pangea/widgets/chat/message_toolbar.dart
@@ -1,4 +1,5 @@
import 'dart:async';
+
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/models/pangea_message_event.dart';
@@ -161,8 +162,8 @@ class MessageToolbarState extends State {
case MessageMode.play:
return true;
case MessageMode.definition:
- debugPrint("checking");
- return widget.textSelection.selectedText != null;
+ // return widget.textSelection.selectedText != null;
+ return true;
default:
return false;
}
diff --git a/lib/pangea/widgets/chat/overlay_message.dart b/lib/pangea/widgets/chat/overlay_message.dart
index 068908ba6..8bc1b5cf0 100644
--- a/lib/pangea/widgets/chat/overlay_message.dart
+++ b/lib/pangea/widgets/chat/overlay_message.dart
@@ -1,8 +1,9 @@
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/pages/chat/events/message_content.dart';
-import 'package:fluffychat/pangea/models/language_model.dart';
+import 'package:fluffychat/pangea/enum/use_type.dart';
import 'package:fluffychat/pangea/models/pangea_message_event.dart';
import 'package:fluffychat/pangea/widgets/chat/message_toolbar.dart';
+import 'package:fluffychat/utils/date_time_extension.dart';
import 'package:flutter/material.dart';
import 'package:matrix/matrix.dart';
@@ -102,16 +103,64 @@ class OverlayMessage extends StatelessWidget {
constraints: BoxConstraints(
maxWidth: width ?? FluffyThemes.columnWidth * 1.25,
),
- child: MessageContent(
- event,
- textColor: textColor,
- borderRadius: borderRadius,
- selected: selected,
- pangeaMessageEvent: pangeaMessageEvent,
- // selectedDisplayLang: selectedDisplayLang,
- immersionMode: immersionMode,
- // definitions: definitions,
- toolbarController: toolbarController,
+ child: Column(
+ mainAxisSize: MainAxisSize.min,
+ crossAxisAlignment: CrossAxisAlignment.start,
+ children: [
+ MessageContent(
+ event,
+ textColor: textColor,
+ borderRadius: borderRadius,
+ selected: selected,
+ pangeaMessageEvent: pangeaMessageEvent,
+ immersionMode: immersionMode,
+ toolbarController: toolbarController,
+ ),
+ if (event.hasAggregatedEvents(
+ timeline,
+ RelationshipTypes.edit,
+ ) // #Pangea
+ ||
+ (pangeaMessageEvent.showUseType)
+ // Pangea#
+ )
+ Padding(
+ padding: const EdgeInsets.only(
+ top: 4.0,
+ ),
+ child: Row(
+ mainAxisSize: MainAxisSize.min,
+ children: [
+ // #Pangea
+ if (pangeaMessageEvent.showUseType) ...[
+ pangeaMessageEvent.useType.iconView(
+ context,
+ textColor.withAlpha(164),
+ ),
+ const SizedBox(width: 4),
+ ],
+ if (event.hasAggregatedEvents(
+ timeline,
+ RelationshipTypes.edit,
+ )) ...[
+ // Pangea#
+ Icon(
+ Icons.edit_outlined,
+ color: textColor.withAlpha(164),
+ size: 14,
+ ),
+ Text(
+ ' - ${event.originServerTs.localizedTimeShort(context)}',
+ style: TextStyle(
+ color: textColor.withAlpha(164),
+ fontSize: 12,
+ ),
+ ),
+ ],
+ ],
+ ),
+ ),
+ ],
),
),
);
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..a9171a11d
--- /dev/null
+++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart
@@ -0,0 +1,245 @@
+import 'dart:developer';
+
+import 'package:adaptive_dialog/adaptive_dialog.dart';
+import 'package:fluffychat/config/app_config.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/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.dart';
+import '../../utils/error_handler.dart';
+
+class ConversationBotSettings extends StatefulWidget {
+ final Room? room;
+ final bool startOpen;
+ // final ClassSettingsModel? initialSettings;
+
+ const ConversationBotSettings({
+ super.key,
+ this.room,
+ this.startOpen = false,
+ // this.initialSettings,
+ });
+
+ @override
+ ConversationBotSettingsState createState() => ConversationBotSettingsState();
+}
+
+class ConversationBotSettingsState extends State {
+ late BotOptionsModel botOptions;
+ late bool isOpen;
+ bool addBot = false;
+
+ ConversationBotSettingsState({Key? key});
+
+ @override
+ void initState() {
+ super.initState();
+ isOpen = widget.startOpen;
+ botOptions = widget.room?.botOptions ?? BotOptionsModel();
+ widget.room?.isBotRoom.then((bool isBotRoom) {
+ setState(() {
+ addBot = isBotRoom;
+ });
+ });
+ }
+
+ 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: SwitchListTile.adaptive(
+ title: Text(
+ L10n.of(context)!.addConversationBot,
+ style: TextStyle(
+ color: Theme.of(context).colorScheme.secondary,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ subtitle: Text(L10n.of(context)!.addConversationBotDesc),
+ secondary: CircleAvatar(
+ backgroundColor:
+ Theme.of(context).scaffoldBackgroundColor,
+ foregroundColor:
+ Theme.of(context).textTheme.bodyLarge!.color,
+ child: const BotFace(
+ width: 30.0,
+ expression: BotExpression.right,
+ ),
+ ),
+ activeColor: AppConfig.activeToggleColor,
+ value: addBot,
+ onChanged: (bool add) {
+ setState(() => addBot = add);
+ add
+ ? widget.room?.invite(BotName.byEnvironment)
+ : widget.room?.kick(BotName.byEnvironment);
+ },
+ ),
+ ),
+ if (addBot) ...[
+ Padding(
+ padding: const EdgeInsets.only(left: 16),
+ child: ListTile(
+ onTap: () async {
+ final topic = await showTextInputDialog(
+ context: context,
+ textFields: [
+ DialogTextField(
+ initialText: botOptions.topic.isEmpty
+ ? ""
+ : botOptions.topic,
+ hintText:
+ L10n.of(context)!.enterAConversationTopic,
+ ),
+ ],
+ title: L10n.of(context)!.conversationTopic,
+ );
+ if (topic == null) return;
+ updateBotOption(() {
+ botOptions.topic = topic.single;
+ });
+ },
+ leading: CircleAvatar(
+ backgroundColor:
+ Theme.of(context).scaffoldBackgroundColor,
+ foregroundColor:
+ Theme.of(context).textTheme.bodyLarge!.color,
+ child: const Icon(Icons.topic_outlined),
+ ),
+ subtitle: Text(
+ botOptions.topic.isEmpty
+ ? L10n.of(context)!.enterAConversationTopic
+ : botOptions.topic,
+ ),
+ title: Text(
+ L10n.of(context)!.conversationTopic,
+ style: TextStyle(
+ color: Theme.of(context).colorScheme.secondary,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ ),
+ ),
+ Padding(
+ padding: const EdgeInsets.only(left: 16),
+ child: SwitchListTile.adaptive(
+ title: Text(
+ L10n.of(context)!.enableModeration,
+ style: TextStyle(
+ color: Theme.of(context).colorScheme.secondary,
+ fontWeight: FontWeight.bold,
+ ),
+ ),
+ subtitle: Text(L10n.of(context)!.enableModerationDesc),
+ secondary: CircleAvatar(
+ backgroundColor:
+ Theme.of(context).scaffoldBackgroundColor,
+ foregroundColor:
+ Theme.of(context).textTheme.bodyLarge!.color,
+ child: const Icon(Icons.shield_outlined),
+ ),
+ activeColor: AppConfig.activeToggleColor,
+ value: botOptions.safetyModeration,
+ onChanged: (bool newValue) => updateBotOption(() {
+ botOptions.safetyModeration = newValue;
+ }),
+ ),
+ ),
+ 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!;
+ }),
+ ),
+ ),
+ const SizedBox(height: 16),
+ ],
+ ],
+ ),
+ ),
+ ],
+ );
+}
diff --git a/lib/pangea/widgets/space/class_settings.dart b/lib/pangea/widgets/space/class_settings.dart
index 15025be32..c9851ff03 100644
--- a/lib/pangea/widgets/space/class_settings.dart
+++ b/lib/pangea/widgets/space/class_settings.dart
@@ -1,6 +1,7 @@
import 'dart:developer';
import 'package:fluffychat/pangea/models/class_model.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';
@@ -9,14 +10,12 @@ import 'package:matrix/matrix.dart';
import '../../../widgets/matrix.dart';
import '../../constants/language_keys.dart';
-import '../../constants/language_level_type.dart';
import '../../constants/pangea_event_types.dart';
import '../../controllers/language_list_controller.dart';
import '../../controllers/pangea_controller.dart';
import '../../extensions/pangea_room_extension.dart';
import '../../models/language_model.dart';
import '../../utils/error_handler.dart';
-import '../../utils/language_level_copy.dart';
import '../user_settings/p_language_dropdown.dart';
import '../user_settings/p_question_container.dart';
@@ -169,72 +168,11 @@ class ClassSettingsState extends State {
PQuestionContainer(
title: L10n.of(context)!.whatIsYourClassLanguageLevel,
),
- Padding(
- padding: const EdgeInsets.all(12.0),
- child: Container(
- decoration: BoxDecoration(
- border: Border.all(
- color: Theme.of(context).colorScheme.secondary,
- width: 0.5,
- ),
- borderRadius:
- const BorderRadius.all(Radius.circular(10)),
- ),
- child: DropdownButton(
- // Initial Value
- hint: Padding(
- padding: const EdgeInsets.only(left: 15),
- child: Text(
- classSettings.languageLevel == null
- ? L10n.of(context)!.selectLanguageLevel
- : LanguageLevelTextPicker.languageLevelText(
- context,
- classSettings.languageLevel!,
- ),
- style: const TextStyle().copyWith(
- color: Theme.of(context)
- .textTheme
- .bodyLarge!
- .color,
- fontSize: 14,
- ),
- overflow: TextOverflow.clip,
- textAlign: TextAlign.center,
- ),
- ),
- isExpanded: true,
- underline: Container(),
- // Down Arrow Icon
- icon: const Icon(Icons.keyboard_arrow_down),
- // Array list of items
- items:
- LanguageLevelType.allInts.map((int levelOption) {
- return DropdownMenuItem(
- value: levelOption,
- child: Text(
- LanguageLevelTextPicker.languageLevelText(
- context,
- levelOption,
- ),
- style: const TextStyle().copyWith(
- color: Theme.of(context)
- .textTheme
- .bodyLarge!
- .color,
- fontSize: 14,
- ),
- overflow: TextOverflow.clip,
- textAlign: TextAlign.center,
- ),
- );
- }).toList(),
- // After selecting the desired option,it will
- // change button value to selected value
- onChanged: (int? newValue) => updatePermission(() {
- classSettings.languageLevel = newValue!;
- }),
- ),
- ),
+ LanguageLevelDropdown(
+ initialLevel: classSettings.languageLevel,
+ onChanged: (int? newValue) => updatePermission(() {
+ classSettings.languageLevel = newValue!;
+ }),
),
],
),
diff --git a/lib/pangea/widgets/space/language_level_dropdown.dart b/lib/pangea/widgets/space/language_level_dropdown.dart
new file mode 100644
index 000000000..3b2678e29
--- /dev/null
+++ b/lib/pangea/widgets/space/language_level_dropdown.dart
@@ -0,0 +1,76 @@
+import 'package:fluffychat/pangea/constants/language_level_type.dart';
+import 'package:fluffychat/pangea/utils/language_level_copy.dart';
+import 'package:flutter/material.dart';
+import 'package:flutter_gen/gen_l10n/l10n.dart';
+
+class LanguageLevelDropdown extends StatelessWidget {
+ final int? initialLevel;
+ final void Function(int?)? onChanged;
+
+ const LanguageLevelDropdown({
+ super.key,
+ this.initialLevel,
+ this.onChanged,
+ });
+
+ @override
+ Widget build(BuildContext context) {
+ return Padding(
+ padding: const EdgeInsets.all(12.0),
+ child: Container(
+ decoration: BoxDecoration(
+ border: Border.all(
+ color: Theme.of(context).colorScheme.secondary,
+ width: 0.5,
+ ),
+ borderRadius: const BorderRadius.all(Radius.circular(10)),
+ ),
+ child: DropdownButton(
+ // Initial Value
+ hint: Padding(
+ padding: const EdgeInsets.only(left: 15),
+ child: Text(
+ initialLevel == null
+ ? L10n.of(context)!.selectLanguageLevel
+ : LanguageLevelTextPicker.languageLevelText(
+ context,
+ initialLevel!,
+ ),
+ style: const TextStyle().copyWith(
+ color: Theme.of(context).textTheme.bodyLarge!.color,
+ fontSize: 14,
+ ),
+ overflow: TextOverflow.clip,
+ textAlign: TextAlign.center,
+ ),
+ ),
+ isExpanded: true,
+ underline: Container(),
+ // Down Arrow Icon
+ icon: const Icon(Icons.keyboard_arrow_down),
+ // Array list of items
+ items: LanguageLevelType.allInts.map((int levelOption) {
+ return DropdownMenuItem(
+ value: levelOption,
+ child: Text(
+ LanguageLevelTextPicker.languageLevelText(
+ context,
+ levelOption,
+ ),
+ style: const TextStyle().copyWith(
+ color: Theme.of(context).textTheme.bodyLarge!.color,
+ fontSize: 14,
+ ),
+ overflow: TextOverflow.clip,
+ textAlign: TextAlign.center,
+ ),
+ );
+ }).toList(),
+ // After selecting the desired option,it will
+ // change button value to selected value
+ onChanged: onChanged,
+ ),
+ ),
+ );
+ }
+}
diff --git a/lib/utils/client_manager.dart b/lib/utils/client_manager.dart
index 517c852ec..52f6a968c 100644
--- a/lib/utils/client_manager.dart
+++ b/lib/utils/client_manager.dart
@@ -115,6 +115,7 @@ abstract class ClientManager {
PangeaEventTypes.classSettings,
PangeaEventTypes.rules,
PangeaEventTypes.vocab,
+ PangeaEventTypes.botOptions,
EventTypes.RoomTopic,
EventTypes.RoomAvatar,
// Pangea#
diff --git a/pubspec.yaml b/pubspec.yaml
index 24f5e0ac8..b36f4c64c 100644
--- a/pubspec.yaml
+++ b/pubspec.yaml
@@ -142,7 +142,6 @@ flutter:
generate: true
uses-material-design: true
assets:
- - .env
- assets/
# #Pangea
- assets/pangea/