diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 134f46d0a..bcd9ce9cd 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2894,21 +2894,23 @@ "type": "text", "placeholders": {} }, - "helpMeTranslate": "Help me translate!", + "helpMeTranslate": "Yes!", "@helpMeTranslate": { "type": "text", "placeholders": {} }, - "needsItShortMessage": "Try interactive translation!", + "needsItShortMessage": "Out of target", "needsIGCShortMessage": "Try interactive grammar assistance!", "@needsItShortMessage": { "type": "text", "placeholders": {} }, - "needsItMessage": "This message has too many words in your base language.", + "needsItMessage": "Wait, that's not {targetLanguage}! Do you need help translating?", "@needsItMessage": { "type": "text", - "placeholders": {} + "placeholders": { + "targetLanguage": {} + } }, "needsIgcMessage": "This message has a grammar error.", "tokenTranslationTitle": "A word is in your base language.", @@ -3998,6 +4000,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel": "Hours between discussion prompts", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel": "Responds on ⏩ reaction", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel": "Reaction to send discussion prompt", + "conversationBotCustomZone_title": "Custom Settings", + "conversationBotCustomZone_customSystemPromptLabel": "System prompt", + "conversationBotCustomZone_customSystemPromptPlaceholder": "Set custom system prompt", + "conversationBotCustomZone_customTriggerReactionEnabledLabel": "Responds on ⏩ reaction", "addConversationBotDialogTitleInvite": "Confirm inviting conversation bot", "addConversationBotButtonInvite": "Invite", "addConversationBotDialogInviteConfirmation": "Invite", @@ -4060,5 +4066,22 @@ "noLanguagesSet": "No languages set", "noActivitiesFound": "No practice activities found for this message", "hintTitle": "Hint:", - "speechToTextBody": "See how well you did by looking at your Accuracy and Words Per Minute scores" + "speechToTextBody": "See how well you did by looking at your Accuracy and Words Per Minute scores", + "languageButtonLabel": "Language: {currentLanguage}", + "@languageButtonLabel": { + "type": "text", + "placeholders": { + "currentLanguage": {} + } + }, + "interactiveTranslatorAutoPlaySliderHeader": "Autoplay translation", + "@interactiveTranslatorAutoPlaySliderHeader": { + "type": "text", + "placeholders": {} + }, + "interactiveTranslatorAutoPlayDesc": "Launches the interactive translator without asking.", + "@interactiveTranslatorAutoPlayDesc": { + "type": "text", + "placeholders": {} + } } \ No newline at end of file diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index dc328294a..8631f49af 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -3064,6 +3064,17 @@ "type": "text", "placeholders": {} }, + "interactiveTranslatorAutoPlaySliderHeader": "Traducción de reproducción automática", + "interactiveTranslatorAutoPlay": "Traductora interactiva de reproducción automática", + "@interactiveTranslatorAutoPlay": { + "type": "text", + "placeholders": {} + }, + "interactiveTranslatorAutoPlayDesc": "Inicia el traductor interactivo sin preguntar.", + "@interactiveTranslatorAutoPlayDesc": { + "type": "text", + "placeholders": {} + }, "grammarAssistance": "Asistencia gramatical", "@grammarAssistance": { "type": "text", @@ -3126,10 +3137,16 @@ "translationSeemsFinished": "La traducción parece estar terminada.", "needsItShortMessage": "¡Pruebe la traducción interactiva!", "needsIGCShortMessage": "¡Pruebe el corrector gramatical interactivo!", - "needsItMessage": "Este mensaje tiene demasiadas palabras en su idioma base.", + "needsItMessage": "Espera, ¡ese no es {targetLanguage}! ¿Necesitas ayuda para traducir?", + "@needsItMessage": { + "type": "text", + "placeholders": { + "targetLanguage": {} + } + }, "needsIgcMessage": "Este mensaje tiene un error gramatical.", "tokenTranslationTitle": "Una palabra está en su idioma base.", - "helpMeTranslate": "¡Ayúdeme a traducir!", + "helpMeTranslate": "¡Sí!", "setToPublicSettingsTitle": "¿Quiere encontrar un compañero de conversación?", "setToPublicSettingsDesc": "Antes de que pueda buscar un compañero de conversación, debe configurar la visibilidad de su perfil como pública.", "publicProfileTitle": "Perfil público", diff --git a/assets/pangea/bot_faces/pangea_bot.riv b/assets/pangea/bot_faces/pangea_bot.riv new file mode 100644 index 000000000..94244a30f Binary files /dev/null and b/assets/pangea/bot_faces/pangea_bot.riv differ diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index 6bf19a850..852065acb 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -1,7 +1,6 @@ import 'package:animations/animations.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; -import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart'; import 'package:fluffychat/pangea/choreographer/widgets/send_button.dart'; import 'package:fluffychat/pangea/constants/language_keys.dart'; import 'package:fluffychat/utils/platform_infos.dart'; @@ -55,9 +54,6 @@ class ChatInputRow extends StatelessWidget { return Column( children: [ - ITBar( - choreographer: controller.choreographer, - ), Row( // crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 5ee52c46b..5b4f96606 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -24,6 +24,7 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; +import '../../pangea/choreographer/widgets/it_bar.dart'; import '../../utils/stream_extension.dart'; import 'chat_emoji_picker.dart'; import 'chat_input_row.dart'; @@ -440,6 +441,9 @@ class ChatView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ const ConnectionStatusHeader(), + ITBar( + choreographer: controller.choreographer, + ), ReactionsPicker(controller), ReplyDisplay(controller), ChatInputRow(controller), diff --git a/lib/pages/chat_details/chat_details_view.dart b/lib/pages/chat_details/chat_details_view.dart index 2ff139a93..4f4e091d0 100644 --- a/lib/pages/chat_details/chat_details_view.dart +++ b/lib/pages/chat_details/chat_details_view.dart @@ -102,375 +102,171 @@ class ChatDetailsView extends StatelessWidget { backgroundColor: Theme.of(context).appBarTheme.backgroundColor, ), body: MaxWidthBody( - child: ListView.builder( - physics: const NeverScrollableScrollPhysics(), - shrinkWrap: true, - itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0), - itemBuilder: (BuildContext context, int i) => i == 0 - ? Column( - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - Row( - children: [ - Padding( - padding: const EdgeInsets.all(32.0), - child: Stack( - children: [ - Material( - elevation: Theme.of(context) - .appBarTheme - .scrolledUnderElevation ?? - 4, - shadowColor: Theme.of(context) - .appBarTheme - .shadowColor, - shape: RoundedRectangleBorder( - side: BorderSide( - color: Theme.of(context).dividerColor, + // #Pangea + // Chat description title has its own scrollbar so we disable the parent one + // otherwise they scroll with each other + child: ScrollConfiguration( + behavior: + ScrollConfiguration.of(context).copyWith(scrollbars: false), + // Pangea# + child: ListView.builder( + physics: const NeverScrollableScrollPhysics(), + shrinkWrap: true, + itemCount: members.length + 1 + (canRequestMoreMembers ? 1 : 0), + itemBuilder: (BuildContext context, int i) => i == 0 + ? Column( + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + Row( + children: [ + Padding( + padding: const EdgeInsets.all(32.0), + child: Stack( + children: [ + Material( + elevation: Theme.of(context) + .appBarTheme + .scrolledUnderElevation ?? + 4, + shadowColor: Theme.of(context) + .appBarTheme + .shadowColor, + shape: RoundedRectangleBorder( + side: BorderSide( + color: Theme.of(context).dividerColor, + ), + borderRadius: BorderRadius.circular( + Avatar.defaultSize * 2.5, + ), ), - borderRadius: BorderRadius.circular( - Avatar.defaultSize * 2.5, - ), - ), - child: Hero( - tag: controller - .widget.embeddedCloseButton != - null - ? 'embedded_content_banner' - : 'content_banner', - child: Avatar( - mxContent: room.avatar, - name: displayname, - size: Avatar.defaultSize * 2.5, - ), - ), - ), - if (!room.isDirectChat && - room.canChangeStateEvent( - EventTypes.RoomAvatar, - )) - Positioned( - bottom: 0, - right: 0, - child: FloatingActionButton.small( - onPressed: controller.setAvatarAction, - heroTag: null, - child: const Icon( - Icons.camera_alt_outlined, + child: Hero( + tag: controller.widget + .embeddedCloseButton != + null + ? 'embedded_content_banner' + : 'content_banner', + child: Avatar( + mxContent: room.avatar, + name: displayname, + size: Avatar.defaultSize * 2.5, ), ), ), - ], + if (!room.isDirectChat && + room.canChangeStateEvent( + EventTypes.RoomAvatar, + )) + Positioned( + bottom: 0, + right: 0, + child: FloatingActionButton.small( + onPressed: controller.setAvatarAction, + heroTag: null, + child: const Icon( + Icons.camera_alt_outlined, + ), + ), + ), + ], + ), ), - ), - Expanded( - child: Column( - mainAxisAlignment: MainAxisAlignment.center, - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - TextButton.icon( - onPressed: () => room.isDirectChat - ? null - : room.canChangeStateEvent( - EventTypes.RoomName, - ) - ? controller.setDisplaynameAction() - : FluffyShare.share( - displayname, - context, - copyOnly: true, - ), - icon: Icon( - room.isDirectChat - ? Icons.chat_bubble_outline + Expanded( + child: Column( + mainAxisAlignment: MainAxisAlignment.center, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + TextButton.icon( + onPressed: () => room.isDirectChat + ? null : room.canChangeStateEvent( EventTypes.RoomName, ) - ? Icons.edit_outlined - : Icons.copy_outlined, - size: 16, - ), - style: TextButton.styleFrom( - foregroundColor: Theme.of(context) - .colorScheme - .onSurface, - ), - label: Text( - room.isDirectChat - ? L10n.of(context)!.directChat - : displayname, - maxLines: 1, - overflow: TextOverflow.ellipsis, - // style: const TextStyle(fontSize: 18), - ), - ), - TextButton.icon( - onPressed: () => room.isDirectChat - ? null - : context.push( - '/rooms/${controller.roomId}/details/members', - ), - icon: const Icon( - Icons.group_outlined, - size: 14, - ), - style: TextButton.styleFrom( - foregroundColor: Theme.of(context) - .colorScheme - .secondary, - ), - label: Text( - L10n.of(context)!.countParticipants( - actualMembersCount, + ? controller + .setDisplaynameAction() + : FluffyShare.share( + displayname, + context, + copyOnly: true, + ), + icon: Icon( + room.isDirectChat + ? Icons.chat_bubble_outline + : room.canChangeStateEvent( + EventTypes.RoomName, + ) + ? Icons.edit_outlined + : Icons.copy_outlined, + size: 16, + ), + style: TextButton.styleFrom( + foregroundColor: Theme.of(context) + .colorScheme + .onSurface, + ), + label: Text( + room.isDirectChat + ? L10n.of(context)!.directChat + : displayname, + maxLines: 1, + overflow: TextOverflow.ellipsis, + // style: const TextStyle(fontSize: 18), ), - maxLines: 1, - overflow: TextOverflow.ellipsis, - // style: const TextStyle(fontSize: 12), ), - ), - ], + TextButton.icon( + onPressed: () => room.isDirectChat + ? null + : context.push( + '/rooms/${controller.roomId}/details/members', + ), + icon: const Icon( + Icons.group_outlined, + size: 14, + ), + style: TextButton.styleFrom( + foregroundColor: Theme.of(context) + .colorScheme + .secondary, + ), + label: Text( + L10n.of(context)!.countParticipants( + actualMembersCount, + ), + maxLines: 1, + overflow: TextOverflow.ellipsis, + // style: const TextStyle(fontSize: 12), + ), + ), + ], + ), ), - ), - ], - ), - Divider( - height: 1, - color: Theme.of(context).dividerColor, - ), - // if (room.canSendEvent('m.room.name')) - if (room.isRoomAdmin) - // #Pangea - ClassNameButton( - room: room, - controller: controller, + ], ), - if (room.canSendEvent('m.room.topic')) - ClassDescriptionButton( - room: room, - controller: controller, + Divider( + height: 1, + color: Theme.of(context).dividerColor, ), - // #Pangea - RoomCapacityButton( - room: room, - controller: controller, - ), - // Pangea# - if (room.isSpace && room.isRoomAdmin) - ListTile( - title: Text( - L10n.of(context)!.spaceAnalytics, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: iconColor, - child: const Icon( - Icons.analytics_outlined, - ), - ), - onTap: () => context.go( - '/rooms/analytics/${room.id}', - ), - ), - // commenting out language settings in spaces for now - // if (room.languageSettings != null && room.isRoomAdmin) - // LanguageSettings( - // roomId: controller.roomId, - // startOpen: false, - // ), - if (room.pangeaRoomRules != null) - RoomRulesEditor( - roomId: controller.roomId, - startOpen: false, - ), - // if (!room.canChangeStateEvent(EventTypes.RoomTopic)) - // ListTile( - // title: Text( - // L10n.of(context)!.chatDescription, - // style: TextStyle( - // color: Theme.of(context).colorScheme.secondary, - // fontWeight: FontWeight.bold, - // ), - // ), - // ) - // else - // Padding( - // padding: const EdgeInsets.all(16.0), - // child: TextButton.icon( - // onPressed: controller.setTopicAction, - // label: Text(L10n.of(context)!.setChatDescription), - // icon: const Icon(Icons.edit_outlined), - // style: TextButton.styleFrom( - // backgroundColor: Theme.of(context) - // .colorScheme - // .secondaryContainer, - // foregroundColor: Theme.of(context) - // .colorScheme - // .onSecondaryContainer, - // ), - // ), - // ), - // Padding( - // padding: const EdgeInsets.symmetric( - // horizontal: 16.0, - // ), - // child: SelectableLinkify( - // text: room.topic.isEmpty - // ? L10n.of(context)!.noChatDescriptionYet - // : room.topic, - // options: const LinkifyOptions(humanize: false), - // linkStyle: const TextStyle( - // color: Colors.blueAccent, - // decorationColor: Colors.blueAccent, - // ), - // style: TextStyle( - // fontSize: 14, - // fontStyle: room.topic.isEmpty - // ? FontStyle.italic - // : FontStyle.normal, - // color: - // Theme.of(context).textTheme.bodyMedium!.color, - // decorationColor: - // Theme.of(context).textTheme.bodyMedium!.color, - // ), - // onOpen: (url) => - // UrlLauncher(context, url.url).launchUrl(), - // ), - // ), - // const SizedBox(height: 16), - // Divider( - // height: 1, - // color: Theme.of(context).dividerColor, - // ), - // ListTile( - // leading: CircleAvatar( - // backgroundColor: - // Theme.of(context).scaffoldBackgroundColor, - // foregroundColor: iconColor, - // child: const Icon( - // Icons.insert_emoticon_outlined, - // ), - // ), - // title: - // Text(L10n.of(context)!.customEmojisAndStickers), - // subtitle: Text(L10n.of(context)!.setCustomEmotes), - // onTap: controller.goToEmoteSettings, - // trailing: const Icon(Icons.chevron_right_outlined), - // ), - // if (!room.isDirectChat) - // ListTile( - // leading: CircleAvatar( - // backgroundColor: - // Theme.of(context).scaffoldBackgroundColor, - // foregroundColor: iconColor, - // child: const Icon(Icons.shield_outlined), - // ), - // title: Text( - // L10n.of(context)!.accessAndVisibility, - // ), - // subtitle: Text( - // L10n.of(context)!.accessAndVisibilityDescription, - // ), - // onTap: () => context - // .push('/rooms/${room.id}/details/access'), - // trailing: const Icon(Icons.chevron_right_outlined), - // ), - // if (!room.isDirectChat) - if (!room.isDirectChat && - !room.isSpace && - room.isRoomAdmin) - // Pangea# - ListTile( - // #Pangea - // title: Text(L10n.of(context)!.chatPermissions), - title: Text( - L10n.of(context)!.editChatPermissions, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - // Pangea# - subtitle: Text( - L10n.of(context)!.whoCanPerformWhichAction, - ), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: iconColor, - child: const Icon( - Icons.edit_attributes_outlined, - ), - ), - // #Pangea - // trailing: const Icon(Icons.chevron_right_outlined), - // Pangea# - onTap: () => context - .push('/rooms/${room.id}/details/permissions'), - ), - Divider( - height: 1, - color: Theme.of(context).dividerColor, - ), - // #Pangea - if (room.canInvite && - !room.isDirectChat && - (!room.isSpace || room.isRoomAdmin)) - ListTile( - title: Text( - room.isSpace - ? L10n.of(context)!.inviteUsersFromPangea - : L10n.of(context)!.inviteStudentByUserName, - 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 Icon( - Icons.add, - ), - ), - onTap: () => context.go('/rooms/${room.id}/invite'), - ), - if (room.showClassEditOptions && room.isSpace) - SpaceDetailsToggleAddStudentsTile( - controller: controller, - ), - if (controller.displayAddStudentOptions && - room.showClassEditOptions) - ClassInvitationButtons(roomId: controller.roomId!), - const Divider(height: 1), - if (!room.isSpace && - !room.isDirectChat && - room.canInvite) - ConversationBotSettings( - key: controller.addConversationBotKey, - room: room, - ), - const Divider(height: 1), - if (!room.isDirectChat && room.isRoomAdmin) - AddToSpaceToggles( - roomId: room.id, - key: controller.addToSpaceKey, - startOpen: false, - ), - const Divider(height: 1), - if (!room.isDirectChat) + // if (room.canSendEvent('m.room.name')) if (room.isRoomAdmin) + // #Pangea + ClassNameButton( + room: room, + controller: controller, + ), + if (room.canSendEvent('m.room.topic')) + ClassDescriptionButton( + room: room, + controller: controller, + ), + // #Pangea + RoomCapacityButton( + room: room, + controller: controller, + ), + // Pangea# + if (room.isSpace && room.isRoomAdmin) ListTile( title: Text( - room.isSpace - ? L10n.of(context)!.archiveSpace - : L10n.of(context)!.archive, + L10n.of(context)!.spaceAnalytics, style: TextStyle( color: Theme.of(context).colorScheme.secondary, @@ -482,199 +278,421 @@ class ChatDetailsView extends StatelessWidget { Theme.of(context).scaffoldBackgroundColor, foregroundColor: iconColor, child: const Icon( - Icons.archive_outlined, + Icons.analytics_outlined, ), ), - onTap: () async { - OkCancelResult confirmed = OkCancelResult.ok; - bool shouldGo = false; - // archiveSpace has its own popup; only show if not space - if (!room.isSpace) { - confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.ok, - cancelLabel: L10n.of(context)!.cancel, - message: L10n.of(context)! - .archiveRoomDescription, - ); - } - if (confirmed == OkCancelResult.ok) { - if (room.isSpace) { - shouldGo = await room.archiveSpace( - context, - Matrix.of(context).client, - ); - } else { - final success = - await showFutureLoadingDialog( + onTap: () => context.go( + '/rooms/analytics/${room.id}', + ), + ), + // commenting out language settings in spaces for now + // if (room.languageSettings != null && room.isRoomAdmin) + // LanguageSettings( + // roomId: controller.roomId, + // startOpen: false, + // ), + if (room.pangeaRoomRules != null) + RoomRulesEditor( + roomId: controller.roomId, + startOpen: false, + ), + // if (!room.canChangeStateEvent(EventTypes.RoomTopic)) + // ListTile( + // title: Text( + // L10n.of(context)!.chatDescription, + // style: TextStyle( + // color: Theme.of(context).colorScheme.secondary, + // fontWeight: FontWeight.bold, + // ), + // ), + // ) + // else + // Padding( + // padding: const EdgeInsets.all(16.0), + // child: TextButton.icon( + // onPressed: controller.setTopicAction, + // label: Text(L10n.of(context)!.setChatDescription), + // icon: const Icon(Icons.edit_outlined), + // style: TextButton.styleFrom( + // backgroundColor: Theme.of(context) + // .colorScheme + // .secondaryContainer, + // foregroundColor: Theme.of(context) + // .colorScheme + // .onSecondaryContainer, + // ), + // ), + // ), + // Padding( + // padding: const EdgeInsets.symmetric( + // horizontal: 16.0, + // ), + // child: SelectableLinkify( + // text: room.topic.isEmpty + // ? L10n.of(context)!.noChatDescriptionYet + // : room.topic, + // options: const LinkifyOptions(humanize: false), + // linkStyle: const TextStyle( + // color: Colors.blueAccent, + // decorationColor: Colors.blueAccent, + // ), + // style: TextStyle( + // fontSize: 14, + // fontStyle: room.topic.isEmpty + // ? FontStyle.italic + // : FontStyle.normal, + // color: + // Theme.of(context).textTheme.bodyMedium!.color, + // decorationColor: + // Theme.of(context).textTheme.bodyMedium!.color, + // ), + // onOpen: (url) => + // UrlLauncher(context, url.url).launchUrl(), + // ), + // ), + // const SizedBox(height: 16), + // Divider( + // height: 1, + // color: Theme.of(context).dividerColor, + // ), + // ListTile( + // leading: CircleAvatar( + // backgroundColor: + // Theme.of(context).scaffoldBackgroundColor, + // foregroundColor: iconColor, + // child: const Icon( + // Icons.insert_emoticon_outlined, + // ), + // ), + // title: + // Text(L10n.of(context)!.customEmojisAndStickers), + // subtitle: Text(L10n.of(context)!.setCustomEmotes), + // onTap: controller.goToEmoteSettings, + // trailing: const Icon(Icons.chevron_right_outlined), + // ), + // if (!room.isDirectChat) + // ListTile( + // leading: CircleAvatar( + // backgroundColor: + // Theme.of(context).scaffoldBackgroundColor, + // foregroundColor: iconColor, + // child: const Icon(Icons.shield_outlined), + // ), + // title: Text( + // L10n.of(context)!.accessAndVisibility, + // ), + // subtitle: Text( + // L10n.of(context)!.accessAndVisibilityDescription, + // ), + // onTap: () => context + // .push('/rooms/${room.id}/details/access'), + // trailing: const Icon(Icons.chevron_right_outlined), + // ), + // if (!room.isDirectChat) + if (!room.isDirectChat && + !room.isSpace && + room.isRoomAdmin) + // Pangea# + ListTile( + // #Pangea + // title: Text(L10n.of(context)!.chatPermissions), + title: Text( + L10n.of(context)!.editChatPermissions, + style: TextStyle( + color: + Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + // Pangea# + subtitle: Text( + L10n.of(context)!.whoCanPerformWhichAction, + ), + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: iconColor, + child: const Icon( + Icons.edit_attributes_outlined, + ), + ), + // #Pangea + // trailing: const Icon(Icons.chevron_right_outlined), + // Pangea# + onTap: () => context.push( + '/rooms/${room.id}/details/permissions', + ), + ), + Divider( + height: 1, + color: Theme.of(context).dividerColor, + ), + // #Pangea + if (room.canInvite && + !room.isDirectChat && + (!room.isSpace || room.isRoomAdmin)) + ListTile( + title: Text( + room.isSpace + ? L10n.of(context)!.inviteUsersFromPangea + : L10n.of(context)!.inviteStudentByUserName, + 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 Icon( + Icons.add, + ), + ), + onTap: () => + context.go('/rooms/${room.id}/invite'), + ), + if (room.showClassEditOptions && room.isSpace) + SpaceDetailsToggleAddStudentsTile( + controller: controller, + ), + if (controller.displayAddStudentOptions && + room.showClassEditOptions) + ClassInvitationButtons(roomId: controller.roomId!), + const Divider(height: 1), + if (!room.isSpace && + !room.isDirectChat && + room.canInvite) + ConversationBotSettings( + key: controller.addConversationBotKey, + room: room, + ), + const Divider(height: 1), + if (!room.isDirectChat && room.isRoomAdmin) + AddToSpaceToggles( + roomId: room.id, + key: controller.addToSpaceKey, + startOpen: false, + ), + const Divider(height: 1), + if (!room.isDirectChat) + if (room.isRoomAdmin) + ListTile( + title: Text( + room.isSpace + ? L10n.of(context)!.archiveSpace + : L10n.of(context)!.archive, + style: TextStyle( + color: + Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: iconColor, + child: const Icon( + Icons.archive_outlined, + ), + ), + onTap: () async { + OkCancelResult confirmed = OkCancelResult.ok; + bool shouldGo = false; + // archiveSpace has its own popup; only show if not space + if (!room.isSpace) { + confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, context: context, - future: () async { - await room.archive(); - }, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: L10n.of(context)! + .archiveRoomDescription, ); - shouldGo = (success.error == null); } - if (shouldGo) { - context.go('/rooms'); - } - } - }, - ), - ListTile( - title: Text( - L10n.of(context)!.leave, - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, - ), - ), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - foregroundColor: iconColor, - child: const Icon( - Icons.arrow_forward, - ), - ), - onTap: () async { - OkCancelResult confirmed = OkCancelResult.ok; - bool shouldGo = false; - // If user is only admin, room will be archived - final bool onlyAdmin = await room.isOnlyAdmin(); - // archiveSpace has its own popup; only show if not space - if (!room.isSpace) { - confirmed = await showOkCancelAlertDialog( - useRootNavigator: false, - context: context, - title: L10n.of(context)!.areYouSure, - okLabel: L10n.of(context)!.ok, - cancelLabel: L10n.of(context)!.cancel, - message: onlyAdmin - ? L10n.of(context)!.onlyAdminDescription - : L10n.of(context)!.leaveRoomDescription, - ); - } - if (confirmed == OkCancelResult.ok) { - if (room.isSpace) { - shouldGo = onlyAdmin - ? await room.archiveSpace( - context, - Matrix.of(context).client, - onlyAdmin: true, - ) - : await room.leaveSpace( + if (confirmed == OkCancelResult.ok) { + if (room.isSpace) { + shouldGo = await room.archiveSpace( context, Matrix.of(context).client, ); - } else { - final success = await showFutureLoadingDialog( - context: context, - future: () async { - onlyAdmin - ? await room.archive() - : await room.leave(); - }, - ); - shouldGo = (success.error == null); - } - if (shouldGo) { - context.go('/rooms'); - } - } - }, - ), - if (room.isRoomAdmin && !room.isDirectChat) - SwitchListTile.adaptive( - activeColor: AppConfig.activeToggleColor, + } else { + final success = + await showFutureLoadingDialog( + context: context, + future: () async { + await room.archive(); + }, + ); + shouldGo = (success.error == null); + } + if (shouldGo) { + context.go('/rooms'); + } + } + }, + ), + ListTile( title: Text( - room.isSpace - ? L10n.of(context)!.lockSpace - : L10n.of(context)!.lockChat, + L10n.of(context)!.leave, style: TextStyle( color: Theme.of(context).colorScheme.secondary, fontWeight: FontWeight.bold, ), ), - secondary: CircleAvatar( + leading: CircleAvatar( backgroundColor: Theme.of(context).scaffoldBackgroundColor, foregroundColor: iconColor, - child: Icon( - room.isLocked - ? Icons.lock_outlined - : Icons.no_encryption_outlined, + child: const Icon( + Icons.arrow_forward, ), ), - value: room.isLocked, - onChanged: (value) => showFutureLoadingDialog( - context: context, - future: () => value - ? lockRoom( - room, - Matrix.of(context).client, - ) - : unlockRoom( - room, - Matrix.of(context).client, - ), + onTap: () async { + OkCancelResult confirmed = OkCancelResult.ok; + bool shouldGo = false; + // If user is only admin, room will be archived + final bool onlyAdmin = await room.isOnlyAdmin(); + // archiveSpace has its own popup; only show if not space + if (!room.isSpace) { + confirmed = await showOkCancelAlertDialog( + useRootNavigator: false, + context: context, + title: L10n.of(context)!.areYouSure, + okLabel: L10n.of(context)!.ok, + cancelLabel: L10n.of(context)!.cancel, + message: onlyAdmin + ? L10n.of(context)!.onlyAdminDescription + : L10n.of(context)!.leaveRoomDescription, + ); + } + if (confirmed == OkCancelResult.ok) { + if (room.isSpace) { + shouldGo = onlyAdmin + ? await room.archiveSpace( + context, + Matrix.of(context).client, + onlyAdmin: true, + ) + : await room.leaveSpace( + context, + Matrix.of(context).client, + ); + } else { + final success = await showFutureLoadingDialog( + context: context, + future: () async { + onlyAdmin + ? await room.archive() + : await room.leave(); + }, + ); + shouldGo = (success.error == null); + } + if (shouldGo) { + context.go('/rooms'); + } + } + }, + ), + if (room.isRoomAdmin && !room.isDirectChat) + SwitchListTile.adaptive( + activeColor: AppConfig.activeToggleColor, + title: Text( + room.isSpace + ? L10n.of(context)!.lockSpace + : L10n.of(context)!.lockChat, + style: TextStyle( + color: + Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + secondary: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + foregroundColor: iconColor, + child: Icon( + room.isLocked + ? Icons.lock_outlined + : Icons.no_encryption_outlined, + ), + ), + value: room.isLocked, + onChanged: (value) => showFutureLoadingDialog( + context: context, + future: () => value + ? lockRoom( + room, + Matrix.of(context).client, + ) + : unlockRoom( + room, + Matrix.of(context).client, + ), + ), + ), + const Divider(height: 1), + // Pangea# + ListTile( + title: Text( + L10n.of(context)!.countParticipants( + actualMembersCount.toString(), + ), + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), ), ), - const Divider(height: 1), - // Pangea# - ListTile( - title: Text( - L10n.of(context)!.countParticipants( - actualMembersCount.toString(), + // #Pangea + // if (!room.isDirectChat && room.canInvite) + // ListTile( + // title: Text(L10n.of(context)!.inviteContact), + // leading: CircleAvatar( + // backgroundColor: Theme.of(context) + // .colorScheme + // .primaryContainer, + // foregroundColor: Theme.of(context) + // .colorScheme + // .onPrimaryContainer, + // radius: Avatar.defaultSize / 2, + // child: const Icon(Icons.add_outlined), + // ), + // trailing: const Icon(Icons.chevron_right_outlined), + // onTap: () => context.go('/rooms/${room.id}/invite'), + // ), + // Pangea# + ], + ) + : i < members.length + 1 + ? ParticipantListItem(members[i - 1]) + : ListTile( + title: Text( + L10n.of(context)!.loadCountMoreParticipants( + (actualMembersCount - members.length) + .toString(), + ), ), - style: TextStyle( - color: Theme.of(context).colorScheme.secondary, - fontWeight: FontWeight.bold, + leading: CircleAvatar( + backgroundColor: + Theme.of(context).scaffoldBackgroundColor, + child: const Icon( + Icons.group_outlined, + color: Colors.grey, + ), ), - ), - ), - // #Pangea - // if (!room.isDirectChat && room.canInvite) - // ListTile( - // title: Text(L10n.of(context)!.inviteContact), - // leading: CircleAvatar( - // backgroundColor: Theme.of(context) - // .colorScheme - // .primaryContainer, - // foregroundColor: Theme.of(context) - // .colorScheme - // .onPrimaryContainer, - // radius: Avatar.defaultSize / 2, - // child: const Icon(Icons.add_outlined), - // ), - // trailing: const Icon(Icons.chevron_right_outlined), - // onTap: () => context.go('/rooms/${room.id}/invite'), - // ), - // Pangea# - ], - ) - : i < members.length + 1 - ? ParticipantListItem(members[i - 1]) - : ListTile( - title: Text( - L10n.of(context)!.loadCountMoreParticipants( - (actualMembersCount - members.length).toString(), + onTap: () => context.push( + '/rooms/${controller.roomId!}/details/members', ), + trailing: const Icon(Icons.chevron_right_outlined), ), - leading: CircleAvatar( - backgroundColor: - Theme.of(context).scaffoldBackgroundColor, - child: const Icon( - Icons.group_outlined, - color: Colors.grey, - ), - ), - onTap: () => context.push( - '/rooms/${controller.roomId!}/details/members', - ), - trailing: const Icon(Icons.chevron_right_outlined), - ), + ), ), ), ); diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index a0c6a5f6b..45659a1d0 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -15,6 +15,7 @@ import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/models/representation_content_model.dart'; import 'package:fluffychat/pangea/models/space_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; +import 'package:fluffychat/pangea/models/user_model.dart'; import 'package:fluffychat/pangea/utils/any_state_holder.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/overlay.dart'; @@ -522,6 +523,10 @@ class Choreographer { chatController.room, ); + bool get itAutoPlayEnabled => pangeaController.pStoreService.read( + MatrixProfile.itAutoPlay.title, + ) ?? false; + bool get definitionsEnabled => pangeaController.permissionsController.isToolEnabled( ToolSetting.definitions, diff --git a/lib/pangea/choreographer/controllers/igc_controller.dart b/lib/pangea/choreographer/controllers/igc_controller.dart index b882e4087..68d81389e 100644 --- a/lib/pangea/choreographer/controllers/igc_controller.dart +++ b/lib/pangea/choreographer/controllers/igc_controller.dart @@ -170,6 +170,15 @@ class IgcController { const int firstMatchIndex = 0; final PangeaMatch match = igcTextData!.matches[firstMatchIndex]; + if ( + match.isITStart && + choreographer.itAutoPlayEnabled && + igcTextData != null + ) { + choreographer.onITStart(igcTextData!.matches[firstMatchIndex]); + return; + } + OverlayUtil.showPositionedCard( context: context, cardToShow: SpanCard( @@ -189,7 +198,7 @@ class IgcController { ), roomId: choreographer.roomId, ), - cardSize: match.isITStart ? const Size(350, 220) : const Size(350, 400), + cardSize: match.isITStart ? const Size(350, 260) : const Size(350, 400), transformTargetId: choreographer.inputTransformTargetKey, ); } diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 632db7e9b..d30732d32 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -21,6 +21,7 @@ class ITController { Choreographer choreographer; bool _isOpen = false; + bool _willOpen = false; bool _isEditingSourceText = false; bool showChoiceFeedback = false; @@ -36,6 +37,7 @@ class ITController { void clear() { _isOpen = false; + _willOpen = false; showChoiceFeedback = false; _isEditingSourceText = false; @@ -54,6 +56,7 @@ class ITController { } Future initializeIT(ITStartData itStartData) async { + _willOpen = true; Future.delayed(const Duration(microseconds: 100), () { _isOpen = true; }); @@ -61,11 +64,9 @@ class ITController { } void closeIT() { - //if they close it before choosing anything, just put their text back + //if they close it before completing, just put their text back //PTODO - explore using last itStep - if (choreographer.currentText.isEmpty) { - choreographer.textController.text = sourceText ?? ""; - } + choreographer.textController.text = sourceText ?? ""; clear(); } @@ -217,31 +218,19 @@ class ITController { Future onEditSourceTextSubmit(String newSourceText) async { try { - sourceText = newSourceText; + + _isOpen = true; _isEditingSourceText = false; - final String currentText = choreographer.currentText; + _itStartData = ITStartData(newSourceText, choreographer.l1LangCode); + completedITSteps = []; + currentITStep = null; + nextITStep = null; + goldRouteTracker = GoldRouteTracker.defaultTracker; + payLoadIds = []; - choreographer.startLoading(); + _setSourceText(); + getTranslationData(false); - final List responses = await Future.wait([ - _customInputTranslation(""), - _customInputTranslation(choreographer.currentText), - ]); - if (responses[0].goldContinuances != null && - responses[0].goldContinuances!.isNotEmpty) { - goldRouteTracker = GoldRouteTracker( - responses[0].goldContinuances!, - sourceText!, - ); - } - currentITStep = CurrentITStep( - sourceText: sourceText!, - currentText: currentText, - responseModel: responses[1], - storedGoldContinuances: goldRouteTracker.continuances, - ); - - _addPayloadId(responses[1]); } catch (err, stack) { debugger(when: kDebugMode); if (err is! http.Response) { @@ -252,6 +241,7 @@ class ITController { ); } finally { choreographer.stopLoading(); + choreographer.textController.text = ""; } } @@ -334,6 +324,8 @@ class ITController { bool get isOpen => _isOpen; + bool get willOpen => _willOpen; + String get targetLangCode => choreographer.l2LangCode!; String get sourceLangCode => choreographer.l1LangCode!; diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index c26fd706d..adf30dcb1 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -8,7 +8,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import '../../utils/bot_style.dart'; import 'it_shimmer.dart'; -class ChoicesArray extends StatelessWidget { +class ChoicesArray extends StatefulWidget { final bool isLoading; final List? choices; final void Function(int) onPressed; @@ -32,23 +32,51 @@ class ChoicesArray extends StatelessWidget { this.onLongPress, }); + @override + ChoicesArrayState createState() => ChoicesArrayState(); +} + +class ChoicesArrayState extends State { + bool interactionDisabled = false; + + void disableInteraction() { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + interactionDisabled = true; + }); + }); + } + + void enableInteractions() { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + interactionDisabled = false; + }); + }); + } + @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - return isLoading && (choices == null || choices!.length <= 1) - ? ItShimmer(originalSpan: originalSpan) + return widget.isLoading && + (widget.choices == null || widget.choices!.length <= 1) + ? ItShimmer(originalSpan: widget.originalSpan) : Wrap( alignment: WrapAlignment.center, - children: choices + children: widget.choices ?.asMap() .entries .map( (entry) => ChoiceItem( theme: theme, - onLongPress: isActive ? onLongPress : null, - onPressed: isActive ? onPressed : (_) {}, + onLongPress: + widget.isActive ? widget.onLongPress : null, + onPressed: widget.isActive ? widget.onPressed : (_) {}, entry: entry, - isSelected: selectedChoiceIndex == entry.key, + interactionDisabled: interactionDisabled, + enableInteraction: enableInteractions, + disableInteraction: disableInteraction, + isSelected: widget.selectedChoiceIndex == entry.key, ), ) .toList() ?? @@ -77,6 +105,9 @@ class ChoiceItem extends StatelessWidget { required this.onPressed, required this.entry, required this.isSelected, + required this.interactionDisabled, + required this.enableInteraction, + required this.disableInteraction, }); final MapEntry entry; @@ -84,6 +115,9 @@ class ChoiceItem extends StatelessWidget { final void Function(int p1)? onLongPress; final void Function(int p1) onPressed; final bool isSelected; + final bool interactionDisabled; + final VoidCallback enableInteraction; + final VoidCallback disableInteraction; @override Widget build(BuildContext context) { @@ -97,6 +131,8 @@ class ChoiceItem extends StatelessWidget { key: ValueKey(entry.value.text), selected: entry.value.color != null, isGold: entry.value.isGold, + enableInteraction: enableInteraction, + disableInteraction: disableInteraction, child: Container( margin: const EdgeInsets.all(2), padding: EdgeInsets.zero, @@ -130,9 +166,11 @@ class ChoiceItem extends StatelessWidget { ), ), ), - onLongPress: - onLongPress != null ? () => onLongPress!(entry.key) : null, - onPressed: () => onPressed(entry.key), + onLongPress: onLongPress != null && !interactionDisabled + ? () => onLongPress!(entry.key) + : null, + onPressed: + interactionDisabled ? null : () => onPressed(entry.key), child: Text( entry.value.text, style: BotStyle.text(context), @@ -152,11 +190,15 @@ class ChoiceAnimationWidget extends StatefulWidget { final Widget child; final bool selected; final bool isGold; + final VoidCallback enableInteraction; + final VoidCallback disableInteraction; const ChoiceAnimationWidget({ super.key, required this.child, required this.selected, + required this.enableInteraction, + required this.disableInteraction, this.isGold = false, }); @@ -164,11 +206,13 @@ class ChoiceAnimationWidget extends StatefulWidget { ChoiceAnimationWidgetState createState() => ChoiceAnimationWidgetState(); } +enum AnimationState { ready, forward, reverse, finished } + class ChoiceAnimationWidgetState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Animation _animation; - bool animationPlayed = false; + AnimationState animationState = AnimationState.ready; @override void initState() { @@ -196,17 +240,29 @@ class ChoiceAnimationWidgetState extends State ), ]).animate(_controller); - if (widget.selected && !animationPlayed) { + widget.enableInteraction(); + + if (widget.selected && animationState == AnimationState.ready) { + widget.disableInteraction(); _controller.forward(); - animationPlayed = true; - setState(() {}); + setState(() { + animationState = AnimationState.forward; + }); } _controller.addStatusListener((status) { - if (status == AnimationStatus.completed) { + if (status == AnimationStatus.completed && + animationState == AnimationState.forward) { _controller.reverse(); - } else if (status == AnimationStatus.dismissed) { - _controller.stop(); - _controller.reset(); + setState(() { + animationState = AnimationState.reverse; + }); + } + if (status == AnimationStatus.dismissed && + animationState == AnimationState.reverse) { + widget.enableInteraction(); + setState(() { + animationState = AnimationState.finished; + }); } }); } @@ -214,10 +270,12 @@ class ChoiceAnimationWidgetState extends State @override void didUpdateWidget(ChoiceAnimationWidget oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.selected && !animationPlayed) { + if (widget.selected && animationState == AnimationState.ready) { + widget.disableInteraction(); _controller.forward(); - animationPlayed = true; - setState(() {}); + setState(() { + animationState = AnimationState.forward; + }); } } diff --git a/lib/pangea/choreographer/widgets/it_bar.dart b/lib/pangea/choreographer/widgets/it_bar.dart index 4e26cba58..2ba630900 100644 --- a/lib/pangea/choreographer/widgets/it_bar.dart +++ b/lib/pangea/choreographer/widgets/it_bar.dart @@ -7,6 +7,7 @@ import 'package:fluffychat/pangea/choreographer/widgets/it_feedback_card.dart'; import 'package:fluffychat/pangea/choreographer/widgets/translation_finished_flow.dart'; import 'package:fluffychat/pangea/constants/choreo_constants.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -21,93 +22,107 @@ class ITBar extends StatelessWidget { final Choreographer choreographer; const ITBar({super.key, required this.choreographer}); - ITController get controller => choreographer.itController; + ITController get itController => choreographer.itController; @override Widget build(BuildContext context) { - if (!controller.isOpen) return const SizedBox(); - return CompositedTransformTarget( - link: choreographer.itBarLinkAndKey.link, - child: Container( - key: choreographer.itBarLinkAndKey.key, - decoration: BoxDecoration( - color: Theme.of(context).brightness == Brightness.light - ? Colors.white - : Colors.black, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(AppConfig.borderRadius), - topRight: Radius.circular(AppConfig.borderRadius), - ), - ), - width: double.infinity, - padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), - child: Stack( - children: [ - SingleChildScrollView( - child: Column( + return AnimatedSize( + duration: itController.willOpen + ? const Duration(milliseconds: 2000) + : const Duration(milliseconds: 500), + curve: Curves.fastOutSlowIn, + clipBehavior: Clip.none, + child: !itController.willOpen + ? const SizedBox() + : CompositedTransformTarget( + link: choreographer.itBarLinkAndKey.link, + child: AnimatedOpacity( + duration: itController.willOpen + ? const Duration(milliseconds: 2000) + : const Duration(milliseconds: 500), + opacity: itController.willOpen ? 1.0 : 0.0, + child: Container( + key: choreographer.itBarLinkAndKey.key, + decoration: BoxDecoration( + color: Theme.of(context).brightness == Brightness.light + ? Colors.white + : Colors.black, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(AppConfig.borderRadius), + topRight: Radius.circular(AppConfig.borderRadius), + ), + ), + width: double.infinity, + padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), + child: Stack( children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // // Row( - // // mainAxisAlignment: MainAxisAlignment.start, - // // crossAxisAlignment: CrossAxisAlignment.start, - // // children: [ - // // CounterDisplay( - // // correct: controller.correctChoices, - // // custom: controller.customChoices, - // // incorrect: controller.incorrectChoices, - // // yellow: controller.wildcardChoices, - // // ), - // // CompositedTransformTarget( - // // link: choreographer.itBotLayerLinkAndKey.link, - // // child: ITBotButton( - // // key: choreographer.itBotLayerLinkAndKey.key, - // // choreographer: choreographer, - // // ), - // // ), - // // ], - // // ), - // ITCloseButton(choreographer: choreographer), - // ], - // ), - // const SizedBox(height: 40.0), - OriginalText(controller: controller), - const SizedBox(height: 7.0), - IntrinsicHeight( - child: Container( - constraints: const BoxConstraints(minHeight: 80), - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: Center( - child: controller.choreographer.errorService.isError - ? ITError( - error: controller + SingleChildScrollView( + child: Column( + children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // // Row( + // // mainAxisAlignment: MainAxisAlignment.start, + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // CounterDisplay( + // // correct: controller.correctChoices, + // // custom: controller.customChoices, + // // incorrect: controller.incorrectChoices, + // // yellow: controller.wildcardChoices, + // // ), + // // CompositedTransformTarget( + // // link: choreographer.itBotLayerLinkAndKey.link, + // // child: ITBotButton( + // // key: choreographer.itBotLayerLinkAndKey.key, + // // choreographer: choreographer, + // // ), + // // ), + // // ], + // // ), + // ITCloseButton(choreographer: choreographer), + // ], + // ), + // const SizedBox(height: 40.0), + OriginalText(controller: itController), + const SizedBox(height: 7.0), + IntrinsicHeight( + child: Container( + constraints: const BoxConstraints(minHeight: 80), + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: Center( + child: itController.choreographer.errorService.isError + ? ITError( + error: itController .choreographer.errorService.error!, - controller: controller, + controller: itController, ) - : controller.showChoiceFeedback - ? ChoiceFeedbackText(controller: controller) - : controller.isTranslationDone - ? TranslationFeedback( - controller: controller, - ) - : ITChoices(controller: controller), - ), + : itController.showChoiceFeedback + ? ChoiceFeedbackText(controller: itController) + : itController.isTranslationDone + ? TranslationFeedback( + controller: itController, + ) + : ITChoices(controller: itController), + ), + ), + ), + ], ), ), + Positioned( + top: 0.0, + right: 0.0, + child: ITCloseButton(choreographer: choreographer), + ), ], ), ), - Positioned( - top: 0.0, - right: 0.0, - child: ITCloseButton(choreographer: choreographer), - ), - ], - ), + ), ), ); } @@ -184,10 +199,23 @@ class OriginalText extends StatelessWidget { ), ), ), - if (!controller.isEditingSourceText && controller.sourceText != null) - IconButton( - onPressed: () => controller.setIsEditingSourceText(true), - icon: const Icon(Icons.edit_outlined), + if ( + !controller.isEditingSourceText + && controller.sourceText != null + ) + AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: controller.nextITStep != null + ? 1.0 + : 0.0, + child: IconButton( + onPressed: () => { + if (controller.nextITStep != null) { + controller.setIsEditingSourceText(true), + }, + }, + icon: const Icon(Icons.edit_outlined), + ), ), ], ), diff --git a/lib/pangea/choreographer/widgets/it_bar_buttons.dart b/lib/pangea/choreographer/widgets/it_bar_buttons.dart index 77de39818..9fcaa927e 100644 --- a/lib/pangea/choreographer/widgets/it_bar_buttons.dart +++ b/lib/pangea/choreographer/widgets/it_bar_buttons.dart @@ -45,7 +45,7 @@ class ITBotButton extends StatelessWidget { ); return IconButton( - icon: const BotFace(width: 40.0, expression: BotExpression.right), + icon: const BotFace(width: 40.0, expression: BotExpression.idle), onPressed: () => choreographer.pangeaController.instructions.showInstructionsPopup( context, diff --git a/lib/pangea/choreographer/widgets/it_feedback_card.dart b/lib/pangea/choreographer/widgets/it_feedback_card.dart index 072d24e1a..5424310a8 100644 --- a/lib/pangea/choreographer/widgets/it_feedback_card.dart +++ b/lib/pangea/choreographer/widgets/it_feedback_card.dart @@ -129,7 +129,7 @@ class ITFeedbackCardView extends StatelessWidget { children: [ CardHeader( text: controller.widget.req.chosenContinuance, - botExpression: BotExpression.down, + botExpression: BotExpression.nonGold, ), Text( controller.widget.choiceFeedback, diff --git a/lib/pangea/constants/local.key.dart b/lib/pangea/constants/local.key.dart index 743fe1143..40dd393c5 100644 --- a/lib/pangea/constants/local.key.dart +++ b/lib/pangea/constants/local.key.dart @@ -11,5 +11,6 @@ class PLocalKey { static const String dismissedPaywall = 'dismissedPaywall'; static const String paywallBackoff = 'paywallBackoff'; static const String autoPlayMessages = 'autoPlayMessages'; + static const String itAutoPlay = 'itAutoPlay'; static const String messagesSinceUpdate = 'messagesSinceLastUpdate'; } diff --git a/lib/pangea/constants/model_keys.dart b/lib/pangea/constants/model_keys.dart index c85c8a7bd..ca59d89b7 100644 --- a/lib/pangea/constants/model_keys.dart +++ b/lib/pangea/constants/model_keys.dart @@ -95,17 +95,16 @@ class ModelKey { static const String languageLevel = "difficulty"; static const String safetyModeration = "safety_moderation"; static const String mode = "mode"; - static const String custom = "custom"; static const String discussionTopic = "discussion_topic"; static const String discussionKeywords = "discussion_keywords"; - static const String discussionTriggerScheduleEnabled = - "discussion_trigger_schedule_enabled"; - static const String discussionTriggerScheduleHourInterval = - "discussion_trigger_schedule_hour_interval"; static const String discussionTriggerReactionEnabled = "discussion_trigger_reaction_enabled"; static const String discussionTriggerReactionKey = "discussion_trigger_reaction_key"; + static const String customSystemPrompt = "custom_system_prompt"; + static const String customTriggerReactionEnabled = + "custom_trigger_reaction_enabled"; + static const String customTriggerReactionKey = "custom_trigger_reaction_key"; static const String prevEventId = "prev_event_id"; static const String prevLastUpdated = "prev_last_updated"; diff --git a/lib/pangea/controllers/message_analytics_controller.dart b/lib/pangea/controllers/message_analytics_controller.dart index 7083efbfd..1475c0e6e 100644 --- a/lib/pangea/controllers/message_analytics_controller.dart +++ b/lib/pangea/controllers/message_analytics_controller.dart @@ -62,12 +62,13 @@ class AnalyticsController extends BaseController { timeSpan.toString(), local: true, ); + setState(); } ///////// SPACE ANALYTICS LANGUAGES ////////// String get _analyticsSpaceLangKey => "ANALYTICS_SPACE_LANG_KEY"; - LanguageModel get currentAnalyticsSpaceLang { + LanguageModel get currentAnalyticsLang { try { final String? str = _pangeaController.pStoreService.read( _analyticsSpaceLangKey, @@ -83,41 +84,43 @@ class AnalyticsController extends BaseController { } } - Future setCurrentAnalyticsSpaceLang(LanguageModel lang) async { + Future setCurrentAnalyticsLang(LanguageModel lang) async { await _pangeaController.pStoreService.save( _analyticsSpaceLangKey, lang.langCode, local: true, ); + setState(); } + /// given an analytics event type and the current analytics language, + /// get the last time the user updated their analytics Future myAnalyticsLastUpdated(String type) async { - // given an analytics event type, get the last updated times - // for each of the user's analytics rooms and return the most recent - // Most Recent instead of the oldest because, for instance: - // My last Spanish event was sent 3 days ago. - // My last English event was sent 1 day ago. - // When I go to check if the cached data is out of date, the cached item was set 2 days ago. - // I know there’s new data available because the English update data (the most recent) is after the cache’s creation time. - // So, I should update the cache. final List analyticsRooms = _pangeaController .matrixState.client.allMyAnalyticsRooms .where((room) => room.isAnalyticsRoom) .toList(); - final List lastUpdates = []; + final Map langCodeLastUpdates = {}; for (final Room analyticsRoom in analyticsRooms) { + final String? roomLang = analyticsRoom.madeForLang; + if (roomLang == null) continue; final DateTime? lastUpdated = await analyticsRoom.analyticsLastUpdated( type, _pangeaController.matrixState.client.userID!, ); if (lastUpdated != null) { - lastUpdates.add(lastUpdated); + langCodeLastUpdates[roomLang] = lastUpdated; } } - if (lastUpdates.isEmpty) return null; - return lastUpdates.reduce( + if (langCodeLastUpdates.isEmpty) return null; + final String? l2Code = + _pangeaController.languageController.userL2?.langCode; + if (l2Code != null && langCodeLastUpdates.containsKey(l2Code)) { + return langCodeLastUpdates[l2Code]; + } + return langCodeLastUpdates.values.reduce( (check, mostRecent) => check.isAfter(mostRecent) ? check : mostRecent, ); } @@ -134,7 +137,7 @@ class AnalyticsController extends BaseController { final List> lastUpdatedFutures = []; for (final student in space.students) { final Room? analyticsRoom = _pangeaController.matrixState.client - .analyticsRoomLocal(currentAnalyticsSpaceLang.langCode, student.id); + .analyticsRoomLocal(currentAnalyticsLang.langCode, student.id); if (analyticsRoom == null) continue; lastUpdatedFutures.add( analyticsRoom.analyticsLastUpdated( @@ -177,28 +180,20 @@ class AnalyticsController extends BaseController { //////////////////////////// MESSAGE SUMMARY ANALYTICS //////////////////////////// + /// get all the summary analytics events for the current user + /// in the current language's analytics room Future> mySummaryAnalytics() async { - // gets all the summary analytics events for the user - // since the current timespace's cut off date - final analyticsRooms = - _pangeaController.matrixState.client.allMyAnalyticsRooms; + final Room? analyticsRoom = _pangeaController.matrixState.client + .analyticsRoomLocal(currentAnalyticsLang.langCode); + if (analyticsRoom == null) return []; - final List allEvents = []; - - // TODO switch to using list of futures - for (final Room analyticsRoom in analyticsRooms) { - final List? roomEvents = - await analyticsRoom.getAnalyticsEvents( - type: PangeaEventTypes.summaryAnalytics, - since: currentAnalyticsTimeSpan.cutOffDate, - userId: _pangeaController.matrixState.client.userID!, - ); - - allEvents.addAll( - roomEvents?.cast() ?? [], - ); - } - return allEvents; + final List? roomEvents = + await analyticsRoom.getAnalyticsEvents( + type: PangeaEventTypes.summaryAnalytics, + since: currentAnalyticsTimeSpan.cutOffDate, + userId: _pangeaController.matrixState.client.userID!, + ); + return roomEvents?.cast() ?? []; } Future> spaceMemberAnalytics( @@ -216,7 +211,7 @@ class AnalyticsController extends BaseController { final List analyticsEvents = []; for (final student in space.students) { final Room? analyticsRoom = _pangeaController.matrixState.client - .analyticsRoomLocal(currentAnalyticsSpaceLang.langCode, student.id); + .analyticsRoomLocal(currentAnalyticsLang.langCode, student.id); if (analyticsRoom != null) { final List? roomEvents = @@ -261,7 +256,7 @@ class AnalyticsController extends BaseController { (e.defaultSelected.type == defaultSelected.type) && (e.selected?.id == selected?.id) && (e.selected?.type == selected?.type) && - (e.langCode == currentAnalyticsSpaceLang.langCode), + (e.langCode == currentAnalyticsLang.langCode), ); if (index != -1) { @@ -289,7 +284,7 @@ class AnalyticsController extends BaseController { chartAnalyticsModel: chartAnalyticsModel, defaultSelected: defaultSelected, selected: selected, - langCode: currentAnalyticsSpaceLang.langCode, + langCode: currentAnalyticsLang.langCode, ), ); } @@ -525,20 +520,18 @@ class AnalyticsController extends BaseController { //////////////////////////// CONSTRUCTS //////////////////////////// Future> allMyConstructs() async { - final List analyticsRooms = - _pangeaController.matrixState.client.allMyAnalyticsRooms; + final Room? analyticsRoom = _pangeaController.matrixState.client + .analyticsRoomLocal(currentAnalyticsLang.langCode); + if (analyticsRoom == null) return []; - final List allConstructs = []; - for (final Room analyticsRoom in analyticsRooms) { - final List? roomEvents = - (await analyticsRoom.getAnalyticsEvents( - type: PangeaEventTypes.construct, - since: currentAnalyticsTimeSpan.cutOffDate, - userId: _pangeaController.matrixState.client.userID!, - )) - ?.cast(); - allConstructs.addAll(roomEvents ?? []); - } + final List? roomEvents = + (await analyticsRoom.getAnalyticsEvents( + type: PangeaEventTypes.construct, + since: currentAnalyticsTimeSpan.cutOffDate, + userId: _pangeaController.matrixState.client.userID!, + )) + ?.cast(); + final List allConstructs = roomEvents ?? []; final List adminSpaceRooms = await _pangeaController.matrixState.client.teacherRoomIds; @@ -561,7 +554,7 @@ class AnalyticsController extends BaseController { final List constructEvents = []; for (final student in space.students) { final Room? analyticsRoom = _pangeaController.matrixState.client - .analyticsRoomLocal(currentAnalyticsSpaceLang.langCode, student.id); + .analyticsRoomLocal(currentAnalyticsLang.langCode, student.id); if (analyticsRoom != null) { final List? roomEvents = (await analyticsRoom.getAnalyticsEvents( @@ -661,7 +654,7 @@ class AnalyticsController extends BaseController { e.defaultSelected.type == defaultSelected.type && e.selected?.id == selected?.id && e.selected?.type == selected?.type && - e.langCode == currentAnalyticsSpaceLang.langCode, + e.langCode == currentAnalyticsLang.langCode, ); if (index > -1) { @@ -687,7 +680,7 @@ class AnalyticsController extends BaseController { events: List.from(events), defaultSelected: defaultSelected, selected: selected, - langCode: currentAnalyticsSpaceLang.langCode, + langCode: currentAnalyticsLang.langCode, ); _cachedConstructs.add(entry); } diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index c7a35b3e8..33d74244a 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -123,6 +123,7 @@ class UserController extends BaseController { : null; final bool? autoPlay = migratedProfileInfo(MatrixProfile.autoPlayMessages); + final bool? itAutoPlay = migratedProfileInfo(MatrixProfile.itAutoPlay); final bool? trial = migratedProfileInfo(MatrixProfile.activatedFreeTrial); final bool? interactiveTranslator = migratedProfileInfo(MatrixProfile.interactiveTranslator); @@ -142,6 +143,7 @@ class UserController extends BaseController { await updateMatrixProfile( dateOfBirth: dob, autoPlayMessages: autoPlay, + itAutoPlay: itAutoPlay, activatedFreeTrial: trial, interactiveTranslator: interactiveTranslator, interactiveGrammar: interactiveGrammar, @@ -223,6 +225,7 @@ class UserController extends BaseController { Future updateMatrixProfile({ String? dateOfBirth, bool? autoPlayMessages, + bool? itAutoPlay, bool? activatedFreeTrial, bool? interactiveTranslator, bool? interactiveGrammar, @@ -251,6 +254,12 @@ class UserController extends BaseController { autoPlayMessages, ); } + if (itAutoPlay != null) { + await _pangeaController.pStoreService.save( + MatrixProfile.itAutoPlay.title, + itAutoPlay, + ); + } if (activatedFreeTrial != null) { await _pangeaController.pStoreService.save( MatrixProfile.activatedFreeTrial.title, diff --git a/lib/pangea/enum/span_data_type.dart b/lib/pangea/enum/span_data_type.dart index 5e4fdf8cb..38315fd50 100644 --- a/lib/pangea/enum/span_data_type.dart +++ b/lib/pangea/enum/span_data_type.dart @@ -1,5 +1,5 @@ +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; enum SpanDataTypeEnum { @@ -32,7 +32,10 @@ extension SpanDataTypeEnumExt on SpanDataTypeEnum { case SpanDataTypeEnum.correction: return L10n.of(context)!.correctionDefaultPrompt; case SpanDataTypeEnum.itStart: - return L10n.of(context)!.needsItMessage; + return L10n.of(context)!.needsItMessage( + MatrixState.pangeaController.languageController.userL2?.displayName ?? + L10n.of(context)!.targetLanguage, + ); } } } diff --git a/lib/pangea/models/bot_options_model.dart b/lib/pangea/models/bot_options_model.dart index 00eaddc1b..179461a34 100644 --- a/lib/pangea/models/bot_options_model.dart +++ b/lib/pangea/models/bot_options_model.dart @@ -13,44 +13,66 @@ class BotOptionsModel { List keywords; bool safetyModeration; String mode; - String? custom; String? discussionTopic; String? discussionKeywords; - bool? discussionTriggerScheduleEnabled; - int? discussionTriggerScheduleHourInterval; bool? discussionTriggerReactionEnabled; String? discussionTriggerReactionKey; + String? customSystemPrompt; + bool? customTriggerReactionEnabled; + String? customTriggerReactionKey; BotOptionsModel({ + //////////////////////////////////////////////////////////////////////////// + // General Bot Options + //////////////////////////////////////////////////////////////////////////// this.languageLevel, this.topic = "General Conversation", this.keywords = const [], this.safetyModeration = true, this.mode = "discussion", - this.custom = "", + + //////////////////////////////////////////////////////////////////////////// + // Discussion Mode Options + //////////////////////////////////////////////////////////////////////////// this.discussionTopic, this.discussionKeywords, - this.discussionTriggerScheduleEnabled, - this.discussionTriggerScheduleHourInterval, this.discussionTriggerReactionEnabled = true, - this.discussionTriggerReactionKey, + this.discussionTriggerReactionKey = "⏩", + + //////////////////////////////////////////////////////////////////////////// + // Custom Mode Options + //////////////////////////////////////////////////////////////////////////// + this.customSystemPrompt, + this.customTriggerReactionEnabled = true, + this.customTriggerReactionKey = "⏩", }); factory BotOptionsModel.fromJson(json) { return BotOptionsModel( + ////////////////////////////////////////////////////////////////////////// + // General Bot Options + ////////////////////////////////////////////////////////////////////////// languageLevel: json[ModelKey.languageLevel], safetyModeration: json[ModelKey.safetyModeration] ?? true, mode: json[ModelKey.mode] ?? "discussion", - custom: json[ModelKey.custom], + + ////////////////////////////////////////////////////////////////////////// + // Discussion Mode Options + ////////////////////////////////////////////////////////////////////////// discussionTopic: json[ModelKey.discussionTopic], discussionKeywords: json[ModelKey.discussionKeywords], - discussionTriggerScheduleEnabled: - json[ModelKey.discussionTriggerScheduleEnabled], - discussionTriggerScheduleHourInterval: - json[ModelKey.discussionTriggerScheduleHourInterval], discussionTriggerReactionEnabled: - json[ModelKey.discussionTriggerReactionEnabled], - discussionTriggerReactionKey: json[ModelKey.discussionTriggerReactionKey], + json[ModelKey.discussionTriggerReactionEnabled] ?? true, + discussionTriggerReactionKey: + json[ModelKey.discussionTriggerReactionKey] ?? "⏩", + + ////////////////////////////////////////////////////////////////////////// + // Custom Mode Options + ////////////////////////////////////////////////////////////////////////// + customSystemPrompt: json[ModelKey.customSystemPrompt], + customTriggerReactionEnabled: + json[ModelKey.customTriggerReactionEnabled] ?? true, + customTriggerReactionKey: json[ModelKey.customTriggerReactionKey] ?? "⏩", ); } @@ -61,17 +83,16 @@ class BotOptionsModel { data[ModelKey.languageLevel] = languageLevel; data[ModelKey.safetyModeration] = safetyModeration; data[ModelKey.mode] = mode; - data[ModelKey.custom] = custom; data[ModelKey.discussionTopic] = discussionTopic; data[ModelKey.discussionKeywords] = discussionKeywords; - data[ModelKey.discussionTriggerScheduleEnabled] = - discussionTriggerScheduleEnabled; - data[ModelKey.discussionTriggerScheduleHourInterval] = - discussionTriggerScheduleHourInterval; data[ModelKey.discussionTriggerReactionEnabled] = - discussionTriggerReactionEnabled; + discussionTriggerReactionEnabled ?? true; data[ModelKey.discussionTriggerReactionKey] = - discussionTriggerReactionKey; + discussionTriggerReactionKey ?? "⏩"; + data[ModelKey.customSystemPrompt] = customSystemPrompt; + data[ModelKey.customTriggerReactionEnabled] = + customTriggerReactionEnabled ?? true; + data[ModelKey.customTriggerReactionKey] = customTriggerReactionKey ?? "⏩"; return data; } catch (e, s) { debugger(when: kDebugMode); @@ -92,27 +113,27 @@ class BotOptionsModel { case ModelKey.mode: mode = value; break; - case ModelKey.custom: - custom = value; - break; case ModelKey.discussionTopic: discussionTopic = value; break; case ModelKey.discussionKeywords: discussionKeywords = value; break; - case ModelKey.discussionTriggerScheduleEnabled: - discussionTriggerScheduleEnabled = value; - break; - case ModelKey.discussionTriggerScheduleHourInterval: - discussionTriggerScheduleHourInterval = value; - break; case ModelKey.discussionTriggerReactionEnabled: discussionTriggerReactionEnabled = value; break; case ModelKey.discussionTriggerReactionKey: discussionTriggerReactionKey = value; break; + case ModelKey.customSystemPrompt: + customSystemPrompt = value; + break; + case ModelKey.customTriggerReactionEnabled: + customTriggerReactionEnabled = value; + break; + case ModelKey.customTriggerReactionKey: + customTriggerReactionKey = value; + break; default: throw Exception('Invalid key for bot options - $key'); } diff --git a/lib/pangea/models/user_model.dart b/lib/pangea/models/user_model.dart index afe910610..80d364aac 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -54,6 +54,7 @@ class PUserModel { enum MatrixProfile { dateOfBirth, autoPlayMessages, + itAutoPlay, activatedFreeTrial, interactiveTranslator, interactiveGrammar, @@ -79,6 +80,8 @@ extension MatrixProfileExtension on MatrixProfile { return ModelKey.userDateOfBirth; case MatrixProfile.autoPlayMessages: return PLocalKey.autoPlayMessages; + case MatrixProfile.itAutoPlay: + return PLocalKey.itAutoPlay; case MatrixProfile.activatedFreeTrial: return PLocalKey.activatedTrialKey; case MatrixProfile.interactiveTranslator: diff --git a/lib/pangea/pages/analytics/analytics_language_button.dart b/lib/pangea/pages/analytics/analytics_language_button.dart index d74e07be1..2c3923fb4 100644 --- a/lib/pangea/pages/analytics/analytics_language_button.dart +++ b/lib/pangea/pages/analytics/analytics_language_button.dart @@ -16,7 +16,6 @@ class AnalyticsLanguageButton extends StatelessWidget { @override Widget build(BuildContext context) { return PopupMenuButton( - icon: const Icon(Icons.language_outlined), tooltip: L10n.of(context)!.changeAnalyticsLanguage, initialValue: value, onSelected: (LanguageModel? lang) { @@ -33,6 +32,21 @@ class AnalyticsLanguageButton extends StatelessWidget { child: Text(lang.getDisplayName(context) ?? lang.langCode), ); }).toList(), + child: TextButton.icon( + label: Text( + L10n.of(context)!.languageButtonLabel( + value.getDisplayName(context) ?? value.langCode, + ), + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + icon: Icon( + Icons.language_outlined, + color: Theme.of(context).colorScheme.onSurface, + ), + onPressed: null, + ), ); } } diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart index 3ab8fa0f2..146a5ac70 100644 --- a/lib/pangea/pages/analytics/base_analytics.dart +++ b/lib/pangea/pages/analytics/base_analytics.dart @@ -163,7 +163,7 @@ class BaseAnalyticsController extends State { } Future toggleSpaceLang(LanguageModel lang) async { - await pangeaController.analytics.setCurrentAnalyticsSpaceLang(lang); + await pangeaController.analytics.setCurrentAnalyticsLang(lang); await setChartData(); refreshStream.add(false); } diff --git a/lib/pangea/pages/analytics/base_analytics_view.dart b/lib/pangea/pages/analytics/base_analytics_view.dart index 8cab95396..3d70c9b4c 100644 --- a/lib/pangea/pages/analytics/base_analytics_view.dart +++ b/lib/pangea/pages/analytics/base_analytics_view.dart @@ -108,28 +108,26 @@ class BaseAnalyticsView extends StatelessWidget { ? Column( children: [ Row( - mainAxisAlignment: MainAxisAlignment.end, + mainAxisAlignment: MainAxisAlignment.spaceEvenly, children: [ - if (controller.widget.defaultSelected.type == - AnalyticsEntryType.student) - IconButton( - icon: const Icon(Icons.refresh), - onPressed: controller.onRefresh, - tooltip: L10n.of(context)!.refresh, - ), + // if (controller.widget.defaultSelected.type == + // AnalyticsEntryType.student) + // IconButton( + // icon: const Icon(Icons.refresh), + // onPressed: controller.onRefresh, + // tooltip: L10n.of(context)!.refresh, + // ), TimeSpanMenuButton( value: controller.currentTimeSpan, onChange: (TimeSpan value) => controller.toggleTimeSpan(context, value), ), - if (controller.widget.defaultSelected.type == - AnalyticsEntryType.space) - AnalyticsLanguageButton( - value: controller.pangeaController.analytics - .currentAnalyticsSpaceLang, - onChange: (lang) => controller.toggleSpaceLang(lang), - languages: controller.widget.targetLanguages, - ), + AnalyticsLanguageButton( + value: controller + .pangeaController.analytics.currentAnalyticsLang, + onChange: (lang) => controller.toggleSpaceLang(lang), + languages: controller.widget.targetLanguages, + ), ], ), Expanded( diff --git a/lib/pangea/pages/analytics/construct_list.dart b/lib/pangea/pages/analytics/construct_list.dart index e169922ca..8651b7a74 100644 --- a/lib/pangea/pages/analytics/construct_list.dart +++ b/lib/pangea/pages/analytics/construct_list.dart @@ -355,15 +355,17 @@ class ConstructMessagesDialog extends StatelessWidget { final msgEventMatches = controller.getMessageEventMatches(); + final noData = controller.constructs![controller.lemmaIndex].uses.length > + controller._msgEvents.length; + return AlertDialog( title: Center(child: Text(controller.widget.controller.currentLemma!)), content: SizedBox( - height: 350, - width: 500, + height: noData ? 90 : 250, + width: noData ? 200 : 400, child: Column( children: [ - if (controller.constructs![controller.lemmaIndex].uses.length > - controller._msgEvents.length) + if (noData) Center( child: Padding( padding: const EdgeInsets.all(8.0), @@ -398,8 +400,8 @@ class ConstructMessagesDialog extends StatelessWidget { child: Text( L10n.of(context)!.close.toUpperCase(), style: TextStyle( - color: - Theme.of(context).textTheme.bodyMedium?.color?.withAlpha(150), + color: Theme.of(context).colorScheme.primary, + fontWeight: FontWeight.bold, ), ), ), diff --git a/lib/pangea/pages/analytics/space_list/space_list.dart b/lib/pangea/pages/analytics/space_list/space_list.dart index e325e1e94..e65bb6152 100644 --- a/lib/pangea/pages/analytics/space_list/space_list.dart +++ b/lib/pangea/pages/analytics/space_list/space_list.dart @@ -23,13 +23,24 @@ class AnalyticsSpaceList extends StatefulWidget { class AnalyticsSpaceListController extends State { PangeaController pangeaController = MatrixState.pangeaController; List spaces = []; + StreamSubscription? stateSub; List targetLanguages = []; @override void initState() { super.initState(); - setSpaceList().then((_) => setTargetLanguages()); + + // reload dropdowns when their values change in analytics page + stateSub = pangeaController.analytics.stateStream.listen( + (_) => setState(() {}), + ); + } + + @override + void dispose() { + stateSub?.cancel(); + super.dispose(); } StreamController refreshStream = StreamController.broadcast(); @@ -71,7 +82,7 @@ class AnalyticsSpaceListController extends State { } Future toggleSpaceLang(LanguageModel lang) async { - await pangeaController.analytics.setCurrentAnalyticsSpaceLang(lang); + await pangeaController.analytics.setCurrentAnalyticsLang(lang); refreshStream.add(false); setState(() {}); } diff --git a/lib/pangea/pages/analytics/space_list/space_list_view.dart b/lib/pangea/pages/analytics/space_list/space_list_view.dart index 1837d35f2..7ef5fb45e 100644 --- a/lib/pangea/pages/analytics/space_list/space_list_view.dart +++ b/lib/pangea/pages/analytics/space_list/space_list_view.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/pangea/enum/time_span.dart'; import 'package:fluffychat/pangea/pages/analytics/analytics_language_button.dart'; import 'package:fluffychat/pangea/pages/analytics/analytics_list_tile.dart'; import 'package:fluffychat/pangea/pages/analytics/time_span_menu_button.dart'; @@ -5,7 +6,6 @@ import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:go_router/go_router.dart'; -import '../../../enum/time_span.dart'; import '../base_analytics.dart'; import 'space_list.dart'; @@ -32,27 +32,29 @@ class AnalyticsSpaceListView extends StatelessWidget { icon: const Icon(Icons.close_outlined), onPressed: () => context.pop(), ), - actions: [ - TimeSpanMenuButton( - value: - controller.pangeaController.analytics.currentAnalyticsTimeSpan, - onChange: (TimeSpan value) => controller.toggleTimeSpan( - context, - value, - ), - ), - AnalyticsLanguageButton( - value: - controller.pangeaController.analytics.currentAnalyticsSpaceLang, - onChange: (lang) => controller.toggleSpaceLang(lang), - languages: controller.targetLanguages.isEmpty - ? controller.pangeaController.pLanguageStore.targetOptions - : controller.targetLanguages, - ), - ], ), body: Column( children: [ + Row( + mainAxisAlignment: MainAxisAlignment.spaceEvenly, + children: [ + TimeSpanMenuButton( + value: controller + .pangeaController.analytics.currentAnalyticsTimeSpan, + onChange: (TimeSpan value) => controller.toggleTimeSpan( + context, + value, + ), + ), + AnalyticsLanguageButton( + value: + controller.pangeaController.analytics.currentAnalyticsLang, + onChange: (lang) => controller.toggleSpaceLang(lang), + languages: + controller.pangeaController.pLanguageStore.targetOptions, + ), + ], + ), Flexible( child: ListView.builder( itemCount: controller.spaces.length, diff --git a/lib/pangea/pages/analytics/student_analytics/student_analytics.dart b/lib/pangea/pages/analytics/student_analytics/student_analytics.dart index 65bd533e8..d6bc9d766 100644 --- a/lib/pangea/pages/analytics/student_analytics/student_analytics.dart +++ b/lib/pangea/pages/analytics/student_analytics/student_analytics.dart @@ -1,7 +1,12 @@ import 'dart:async'; import 'dart:developer'; +import 'package:fluffychat/pangea/constants/language_keys.dart'; +import 'package:fluffychat/pangea/controllers/language_list_controller.dart'; import 'package:fluffychat/pangea/enum/bar_chart_view_enum.dart'; +import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart'; +import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/models/language_model.dart'; import 'package:fluffychat/pangea/widgets/common/list_placeholder.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -75,6 +80,24 @@ class StudentAnalyticsController extends State { return id; } + List get targetLanguages { + final LanguageModel? l2 = + _pangeaController.languageController.activeL2Model(); + final List analyticsRoomLangs = + _pangeaController.matrixState.client.allMyAnalyticsRooms + .map((analyticsRoom) => analyticsRoom.madeForLang) + .where((langCode) => langCode != null) + .map((langCode) => PangeaLanguage.byLangCode(langCode!)) + .where( + (langModel) => langModel.langCode != LanguageKeys.unknownLanguage, + ) + .toList(); + if (l2 != null) { + analyticsRoomLangs.add(l2); + } + return analyticsRoomLangs.toSet().toList(); + } + @override Widget build(BuildContext context) { return PLoadingStatusV2( diff --git a/lib/pangea/pages/analytics/student_analytics/student_analytics_view.dart b/lib/pangea/pages/analytics/student_analytics/student_analytics_view.dart index 5b8924581..6ea754891 100644 --- a/lib/pangea/pages/analytics/student_analytics/student_analytics_view.dart +++ b/lib/pangea/pages/analytics/student_analytics/student_analytics_view.dart @@ -59,6 +59,7 @@ class StudentAnalyticsView extends StatelessWidget { AnalyticsEntryType.student, L10n.of(context)!.allChatsAndClasses, ), + targetLanguages: controller.targetLanguages, ) : const SizedBox(); } diff --git a/lib/pangea/pages/analytics/time_span_menu_button.dart b/lib/pangea/pages/analytics/time_span_menu_button.dart index 23d2ad0c8..32f6668bc 100644 --- a/lib/pangea/pages/analytics/time_span_menu_button.dart +++ b/lib/pangea/pages/analytics/time_span_menu_button.dart @@ -15,7 +15,6 @@ class TimeSpanMenuButton extends StatelessWidget { @override Widget build(BuildContext context) { return PopupMenuButton( - icon: const Icon(Icons.calendar_month_outlined), tooltip: L10n.of(context)!.changeDateRange, initialValue: value, onSelected: (TimeSpan? timeSpan) { @@ -32,6 +31,19 @@ class TimeSpanMenuButton extends StatelessWidget { child: Text(timeSpan.string(context)), ); }).toList(), + child: TextButton.icon( + label: Text( + value.string(context), + style: TextStyle( + color: Theme.of(context).colorScheme.onSurface, + ), + ), + icon: Icon( + Icons.calendar_month_outlined, + color: Theme.of(context).colorScheme.onSurface, + ), + onPressed: null, + ), ); } } diff --git a/lib/pangea/pages/class_settings/p_class_widgets/class_description_button.dart b/lib/pangea/pages/class_settings/p_class_widgets/class_description_button.dart index 4fdb38604..ff7d0068a 100644 --- a/lib/pangea/pages/class_settings/p_class_widgets/class_description_button.dart +++ b/lib/pangea/pages/class_settings/p_class_widgets/class_description_button.dart @@ -17,6 +17,7 @@ class ClassDescriptionButton extends StatelessWidget { @override Widget build(BuildContext context) { final iconColor = Theme.of(context).textTheme.bodyLarge!.color; + final ScrollController scrollController = ScrollController(); return Column( children: [ ListTile( @@ -26,14 +27,27 @@ class ClassDescriptionButton extends StatelessWidget { foregroundColor: iconColor, child: const Icon(Icons.topic_outlined), ), - subtitle: Text( - room.topic.isEmpty - ? (room.isRoomAdmin - ? (room.isSpace - ? L10n.of(context)!.classDescriptionDesc - : L10n.of(context)!.chatTopicDesc) - : L10n.of(context)!.topicNotSet) - : room.topic, + subtitle: ConstrainedBox( + constraints: const BoxConstraints( + maxHeight: 190, + ), + child: Scrollbar( + controller: scrollController, + interactive: true, + child: SingleChildScrollView( + controller: scrollController, + primary: false, + child: Text( + room.topic.isEmpty + ? (room.isRoomAdmin + ? (room.isSpace + ? L10n.of(context)!.classDescriptionDesc + : L10n.of(context)!.chatTopicDesc) + : L10n.of(context)!.topicNotSet) + : room.topic, + ), + ), + ), ), title: Text( room.isSpace diff --git a/lib/pangea/pages/settings_learning/settings_learning_view.dart b/lib/pangea/pages/settings_learning/settings_learning_view.dart index ca337222a..191bd76db 100644 --- a/lib/pangea/pages/settings_learning/settings_learning_view.dart +++ b/lib/pangea/pages/settings_learning/settings_learning_view.dart @@ -61,6 +61,16 @@ class SettingsLearningView extends StatelessWidget { pStoreKey: setting.toString(), local: false, ), + PSettingsSwitchListTile.adaptive( + defaultValue: controller.pangeaController.pStoreService.read( + PLocalKey.itAutoPlay, + ) ?? + false, + title: L10n.of(context)!.interactiveTranslatorAutoPlaySliderHeader, + subtitle: L10n.of(context)!.interactiveTranslatorAutoPlayDesc, + pStoreKey: PLocalKey.itAutoPlay, + local: false, + ), PSettingsSwitchListTile.adaptive( defaultValue: controller.pangeaController.pStoreService.read( PLocalKey.autoPlayMessages, diff --git a/lib/pangea/utils/instructions.dart b/lib/pangea/utils/instructions.dart index fb917dedd..097aaa3b0 100644 --- a/lib/pangea/utils/instructions.dart +++ b/lib/pangea/utils/instructions.dart @@ -52,6 +52,11 @@ class InstructionsController { String transformTargetKey, [ bool showToggle = true, ]) async { + if (_instructionsShown[key] ?? false) { + return; + } + _instructionsShown[key] = true; + if (wereInstructionsTurnedOff(key)) { return; } @@ -62,9 +67,6 @@ class InstructionsController { ); return; } - if (_instructionsShown[key] ?? false) { - return; - } final bool userLangsSet = await _pangeaController.userController.areUserLanguagesSet; @@ -72,8 +74,6 @@ class InstructionsController { return; } - _instructionsShown[key] = true; - final botStyle = BotStyle.text(context); Future.delayed( const Duration(seconds: 1), @@ -85,7 +85,7 @@ class InstructionsController { children: [ CardHeader( text: key.title(context), - botExpression: BotExpression.surprised, + botExpression: BotExpression.idle, onClose: () => {_instructionsClosed[key] = true}, ), const SizedBox(height: 10.0), diff --git a/lib/pangea/utils/match_copy.dart b/lib/pangea/utils/match_copy.dart index 28080f9b5..86d784356 100644 --- a/lib/pangea/utils/match_copy.dart +++ b/lib/pangea/utils/match_copy.dart @@ -1,13 +1,13 @@ import 'dart:developer'; -import 'package:flutter/foundation.dart'; -import 'package:flutter/material.dart'; - -import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:sentry_flutter/sentry_flutter.dart'; - import 'package:fluffychat/pangea/enum/span_data_type.dart'; import 'package:fluffychat/pangea/utils/error_handler.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:sentry_flutter/sentry_flutter.dart'; + import '../constants/match_rule_ids.dart'; import '../models/pangea_match_model.dart'; @@ -96,7 +96,11 @@ class MatchCopy { switch (afterColon) { case MatchRuleIds.interactiveTranslation: title = l10n.needsItShortMessage; - description = l10n.needsItMessage; + description = l10n.needsItMessage( + MatrixState + .pangeaController.languageController.userL2?.displayName ?? + "target language", + ); break; case MatchRuleIds.tokenNeedsTranslation: title = l10n.tokenTranslationTitle; diff --git a/lib/pangea/widgets/chat/message_toolbar.dart b/lib/pangea/widgets/chat/message_toolbar.dart index 13ebd3103..e05bc0d6d 100644 --- a/lib/pangea/widgets/chat/message_toolbar.dart +++ b/lib/pangea/widgets/chat/message_toolbar.dart @@ -94,61 +94,64 @@ class ToolbarDisplayController { previousEvent: previousEvent, ); - WidgetsBinding.instance.addPostFrameCallback((timeStamp) { - Widget overlayEntry; - if (toolbar == null) return; - try { - overlayEntry = Column( - mainAxisSize: MainAxisSize.min, - crossAxisAlignment: pangeaMessageEvent.ownMessage - ? CrossAxisAlignment.end - : CrossAxisAlignment.start, - children: [ - toolbarUp ? toolbar! : overlayMessage, - const SizedBox(height: 6), - toolbarUp ? overlayMessage : toolbar!, - ], - ); - } catch (err) { - debugger(when: kDebugMode); - ErrorHandler.logError(e: err, s: StackTrace.current); - return; - } - - OverlayUtil.showOverlay( - context: context, - child: overlayEntry, - transformTargetId: targetId, - targetAnchor: pangeaMessageEvent.ownMessage - ? toolbarUp - ? Alignment.bottomRight - : Alignment.topRight - : toolbarUp - ? Alignment.bottomLeft - : Alignment.topLeft, - followerAnchor: pangeaMessageEvent.ownMessage - ? toolbarUp - ? Alignment.bottomRight - : Alignment.topRight - : toolbarUp - ? Alignment.bottomLeft - : Alignment.topLeft, - backgroundColor: const Color.fromRGBO(0, 0, 0, 1).withAlpha(100), - closePrevOverlay: - MatrixState.pangeaController.subscriptionController.isSubscribed, + // I'm not sure why I put this here, but it causes the toolbar + // not to open immediately after clicking (user has to scroll or move their cursor) + // so I'm commenting it out for now + // WidgetsBinding.instance.addPostFrameCallback((timeStamp) { + Widget overlayEntry; + if (toolbar == null) return; + try { + overlayEntry = Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: pangeaMessageEvent.ownMessage + ? CrossAxisAlignment.end + : CrossAxisAlignment.start, + children: [ + toolbarUp ? toolbar! : overlayMessage, + const SizedBox(height: 6), + toolbarUp ? overlayMessage : toolbar!, + ], ); + } catch (err) { + debugger(when: kDebugMode); + ErrorHandler.logError(e: err, s: StackTrace.current); + return; + } - if (MatrixState.pAnyState.entries.isNotEmpty) { - overlayId = MatrixState.pAnyState.entries.last.hashCode.toString(); - } + OverlayUtil.showOverlay( + context: context, + child: overlayEntry, + transformTargetId: targetId, + targetAnchor: pangeaMessageEvent.ownMessage + ? toolbarUp + ? Alignment.bottomRight + : Alignment.topRight + : toolbarUp + ? Alignment.bottomLeft + : Alignment.topLeft, + followerAnchor: pangeaMessageEvent.ownMessage + ? toolbarUp + ? Alignment.bottomRight + : Alignment.topRight + : toolbarUp + ? Alignment.bottomLeft + : Alignment.topLeft, + backgroundColor: const Color.fromRGBO(0, 0, 0, 1).withAlpha(100), + closePrevOverlay: + MatrixState.pangeaController.subscriptionController.isSubscribed, + ); - if (mode != null) { - Future.delayed( - const Duration(milliseconds: 100), - () => toolbarModeStream.add(mode), - ); - } - }); + if (MatrixState.pAnyState.entries.isNotEmpty) { + overlayId = MatrixState.pAnyState.entries.last.hashCode.toString(); + } + + if (mode != null) { + Future.delayed( + const Duration(milliseconds: 100), + () => toolbarModeStream.add(mode), + ); + } + // }); } bool get highlighted { diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index 3d73106c6..094f481ec 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -35,9 +35,9 @@ class MessageTranslationCardState extends State { String? translationLangCode() { if (widget.immersionMode) return l1Code; - final String? originalWrittenCode = - widget.messageEvent.originalWritten?.content.langCode; - return (l1Code == originalWrittenCode || originalWrittenCode == null) + final String? originalSentCode = + widget.messageEvent.originalSent?.content.langCode; + return (l1Code == originalSentCode || originalSentCode == null) ? l2Code : l1Code; } diff --git a/lib/pangea/widgets/common/bot_face_svg.dart b/lib/pangea/widgets/common/bot_face_svg.dart index 718f10c90..f387b4bc3 100644 --- a/lib/pangea/widgets/common/bot_face_svg.dart +++ b/lib/pangea/widgets/common/bot_face_svg.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; -enum BotExpression { surprised, right, addled, left, down, shocked } +enum BotExpression { gold, nonGold, addled, idle, surprised } + +class BotFace extends StatefulWidget { + final double width; + final Color? forceColor; + final BotExpression expression; -class BotFace extends StatelessWidget { const BotFace({ super.key, required this.width, @@ -10,23 +15,80 @@ class BotFace extends StatelessWidget { this.forceColor, }); - final double width; - final Color? forceColor; - final BotExpression expression; + @override + BotFaceState createState() => BotFaceState(); +} + +class BotFaceState extends State { + Artboard? _artboard; + StateMachineController? _controller; + + @override + void initState() { + super.initState(); + _loadRiveFile(); + } + + double mapExpressionToInput(BotExpression expression) { + switch (expression) { + case BotExpression.gold: + return 1.0; + case BotExpression.nonGold: + return 2.0; + case BotExpression.surprised: + return 3.0; + case BotExpression.addled: + return 4.0; + default: + return 0.0; + } + } + + Future _loadRiveFile() async { + final riveFile = await RiveFile.asset('assets/pangea/bot_faces/pangea_bot.riv'); + + final artboard = riveFile.mainArtboard; + _controller = StateMachineController + .fromArtboard(artboard, 'BotIconStateMachine'); + + if (_controller != null) { + artboard.addController(_controller!); + _controller!.setInputValue( + _controller!.stateMachine.inputs[0].id, + mapExpressionToInput(widget.expression), + ); + } + + setState(() { + _artboard = artboard; + }); + } @override Widget build(BuildContext context) { - return Image.asset( - 'assets/pangea/bot_faces/${expression.toString().split('.').last}.png', - // 'assets/pangea/bot_faces/surprised.png', - width: width, - height: width, - // color: forceColor ?? - // (Theme.of(context).brightness == Brightness.light - // ? Theme.of(context).colorScheme.primary - // : Theme.of(context).colorScheme.primary), + + return SizedBox( + width: widget.width, + height: widget.width, + child: _artboard != null + ? Rive( + artboard: _artboard!, + fit: BoxFit.cover, + ) + : Container(), ); } + + @override + void didUpdateWidget(BotFace oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.expression != widget.expression) { + _controller!.setInputValue( + _controller!.stateMachine.inputs[0].id, + mapExpressionToInput(widget.expression), + ); + } + } } // extension ParseToString on BotExpressions { 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 new file mode 100644 index 000000000..55ec1493d --- /dev/null +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_system_prompt_input.dart @@ -0,0 +1,73 @@ +import 'package:fluffychat/pangea/models/bot_options_model.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +class ConversationBotCustomSystemPromptInput extends StatelessWidget { + final BotOptionsModel initialBotOptions; + // call this to update propagate changes to parents + final void Function(BotOptionsModel) onChanged; + + const ConversationBotCustomSystemPromptInput({ + super.key, + required this.initialBotOptions, + required this.onChanged, + }); + + @override + Widget build(BuildContext context) { + String customSystemPrompt = initialBotOptions.customSystemPrompt ?? ""; + + final TextEditingController textFieldController = + TextEditingController(text: customSystemPrompt); + + void setBotCustomSystemPromptAction() async { + showDialog( + context: context, + useRootNavigator: false, + builder: (BuildContext context) => AlertDialog( + title: Text( + L10n.of(context)!.conversationBotCustomZone_customSystemPromptLabel, + ), + content: TextField( + minLines: 1, + maxLines: 10, + maxLength: 1000, + controller: textFieldController, + onChanged: (value) { + customSystemPrompt = value; + }, + ), + actions: [ + TextButton( + child: Text(L10n.of(context)!.cancel), + onPressed: () { + Navigator.of(context).pop(); + }, + ), + TextButton( + child: Text(L10n.of(context)!.ok), + onPressed: () { + if (customSystemPrompt == "") return; + if (customSystemPrompt != + initialBotOptions.customSystemPrompt) { + initialBotOptions.customSystemPrompt = customSystemPrompt; + onChanged.call(initialBotOptions); + Navigator.of(context).pop(); + } + }, + ), + ], + ), + ); + } + + return ListTile( + onTap: setBotCustomSystemPromptAction, + title: Text( + initialBotOptions.customSystemPrompt ?? + L10n.of(context)! + .conversationBotCustomZone_customSystemPromptPlaceholder, + ), + ); + } +} 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 5fe8880ea..553de7182 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_custom_zone.dart @@ -1,15 +1,75 @@ +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:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; class ConversationBotCustomZone extends StatelessWidget { + final BotOptionsModel initialBotOptions; + // call this to update propagate changes to parents + final void Function(BotOptionsModel) onChanged; + const ConversationBotCustomZone({ super.key, + required this.initialBotOptions, + required this.onChanged, }); @override Widget build(BuildContext context) { - return const Column( + print(initialBotOptions.toJson()); + return Column( children: [ - Text('Custom Zone'), + const SizedBox(height: 12), + Text( + L10n.of(context)!.conversationBotCustomZone_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)! + .conversationBotCustomZone_customSystemPromptLabel, + style: TextStyle( + color: Theme.of(context).colorScheme.secondary, + fontWeight: FontWeight.bold, + ), + ), + ), + ), + Padding( + padding: const EdgeInsets.all(8), + child: ConversationBotCustomSystemPromptInput( + initialBotOptions: initialBotOptions, + onChanged: onChanged, + ), + ), + const SizedBox(height: 12), + CheckboxListTile( + title: Text( + L10n.of(context)! + .conversationBotCustomZone_customTriggerReactionEnabledLabel, + ), + enabled: false, + value: initialBotOptions.customTriggerReactionEnabled ?? true, + onChanged: (value) { + initialBotOptions.customTriggerReactionEnabled = value ?? true; + initialBotOptions.customTriggerReactionKey = + "⏩"; // hard code this for now + onChanged.call(initialBotOptions); + }, + // make this input disabled always + ), + const SizedBox(height: 12), ], ); } 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 ed642a391..2bb4d7a76 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_discussion_zone.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_discussion_zone.dart @@ -82,9 +82,9 @@ class ConversationBotDiscussionZone extends StatelessWidget { .conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel, ), enabled: false, - value: initialBotOptions.discussionTriggerReactionEnabled ?? false, + value: initialBotOptions.discussionTriggerReactionEnabled ?? true, onChanged: (value) { - initialBotOptions.discussionTriggerReactionEnabled = value ?? false; + initialBotOptions.discussionTriggerReactionEnabled = value ?? true; initialBotOptions.discussionTriggerReactionKey = "⏩"; // hard code this for now onChanged.call(initialBotOptions); 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 b0c78888f..b15689357 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,7 +1,5 @@ import 'package:fluffychat/pangea/models/bot_options_model.dart'; -import 'package:fluffychat/pangea/widgets/conversation_bot/conversation_bot_conversation_zone.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'; @@ -23,9 +21,12 @@ class ConversationBotModeDynamicZone extends StatelessWidget { initialBotOptions: initialBotOptions, onChanged: onChanged, ), - "custom": const ConversationBotCustomZone(), - "conversation": const ConversationBotConversationZone(), - "text_adventure": const ConversationBotTextAdventureZone(), + "custom": ConversationBotCustomZone( + initialBotOptions: initialBotOptions, + onChanged: onChanged, + ), + // "conversation": const ConversationBotConversationZone(), + // "text_adventure": const ConversationBotTextAdventureZone(), }; 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 9662dec55..ba60f038c 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_mode_select.dart @@ -16,7 +16,7 @@ class ConversationBotModeSelect extends StatelessWidget { final Map options = { "discussion": L10n.of(context)!.conversationBotModeSelectOption_discussion, - // "custom": L10n.of(context)!.conversationBotModeSelectOption_custom, + "custom": L10n.of(context)!.conversationBotModeSelectOption_custom, // "conversation": // L10n.of(context)!.conversationBotModeSelectOption_conversation, // "text_adventure": diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart index f1f9816bc..1c78fd030 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart @@ -4,6 +4,7 @@ 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'; @@ -44,7 +45,9 @@ class ConversationBotSettingsState extends State { void initState() { super.initState(); isOpen = widget.startOpen; - botOptions = widget.room?.botOptions ?? BotOptionsModel(); + botOptions = widget.room?.botOptions != null + ? BotOptionsModel.fromJson(widget.room?.botOptions?.toJson()) + : BotOptionsModel(); widget.room?.isBotRoom.then((bool isBotRoom) { setState(() { addBot = isBotRoom; @@ -136,7 +139,7 @@ class ConversationBotSettingsState extends State { Theme.of(context).textTheme.bodyLarge!.color, child: const BotFace( width: 30.0, - expression: BotExpression.right, + expression: BotExpression.idle, ), ), trailing: ElevatedButton( @@ -221,28 +224,28 @@ class ConversationBotSettingsState extends State { }), ), ), - // 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(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( diff --git a/lib/pangea/widgets/igc/pangea_text_controller.dart b/lib/pangea/widgets/igc/pangea_text_controller.dart index a40e2cc15..b91186c22 100644 --- a/lib/pangea/widgets/igc/pangea_text_controller.dart +++ b/lib/pangea/widgets/igc/pangea_text_controller.dart @@ -71,6 +71,16 @@ class PangeaTextController extends TextEditingController { choreographer.igc.igcTextData!.getTopMatchIndexForOffset( selection.baseOffset, ); + + // if autoplay on and it start then just start it + if (matchIndex != -1 && + choreographer.itAutoPlayEnabled && + choreographer.igc.igcTextData!.matches[matchIndex].isITStart) { + return choreographer.onITStart( + choreographer.igc.igcTextData!.matches[matchIndex], + ); + } + final Widget? cardToShow = matchIndex != -1 ? SpanCard( scm: SpanCardModel( @@ -100,7 +110,7 @@ class PangeaTextController extends TextEditingController { context: context, cardSize: matchIndex != -1 && choreographer.igc.igcTextData!.matches[matchIndex].isITStart - ? const Size(350, 220) + ? const Size(350, 260) : const Size(350, 400), cardToShow: cardToShow, transformTargetId: choreographer.inputTransformTargetKey, diff --git a/lib/pangea/widgets/igc/span_card.dart b/lib/pangea/widgets/igc/span_card.dart index 6fa4e17b3..2960d229c 100644 --- a/lib/pangea/widgets/igc/span_card.dart +++ b/lib/pangea/widgets/igc/span_card.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pangea/constants/local.key.dart'; import 'package:fluffychat/pangea/enum/span_data_type.dart'; import 'package:fluffychat/pangea/models/span_data.dart'; import 'package:fluffychat/pangea/utils/bot_style.dart'; @@ -49,6 +50,8 @@ class SpanCardState extends State { bool fetchingData = false; int? selectedChoiceIndex; + BotExpression currentExpression = BotExpression.nonGold; + //on initState, get SpanDetails @override void initState() { @@ -150,7 +153,23 @@ class WordMatchContent extends StatelessWidget { .choices?[index] .selected = true; - controller.setState(() => ()); + controller.setState( + () => ( + controller.currentExpression = + controller + .widget + .scm + .choreographer + .igc + .igcTextData + !.matches[controller.widget.scm.matchIndex] + .match + .choices![index] + .isBestCorrection + ? BotExpression.gold + : BotExpression.surprised + ), + ); // if (controller.widget.scm.pangeaMatch.match.choices![index].type == // SpanChoiceType.distractor) { // await controller.getSpanDetails(); @@ -192,10 +211,11 @@ class WordMatchContent extends StatelessWidget { try { return Column( children: [ + // if (!controller.widget.scm.pangeaMatch!.isITStart) CardHeader( text: controller.error?.toString() ?? matchCopy.title, botExpression: controller.error == null - ? BotExpression.right + ? controller.currentExpression : BotExpression.addled, ), Expanded( @@ -321,6 +341,10 @@ class WordMatchContent extends StatelessWidget { ), ], ), + if (controller.widget.scm.pangeaMatch!.isITStart) + DontShowSwitchListTile( + controller: pangeaController, + ), ], ); } on Exception catch (e) { @@ -459,3 +483,40 @@ class StartITButton extends StatelessWidget { ); } } + +class DontShowSwitchListTile extends StatefulWidget { + final PangeaController controller; + + const DontShowSwitchListTile({ + super.key, + required this.controller, + }); + + @override + DontShowSwitchListTileState createState() => DontShowSwitchListTileState(); +} + +class DontShowSwitchListTileState extends State { + bool switchValue = false; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SwitchListTile.adaptive( + activeColor: AppConfig.activeToggleColor, + title: Text(L10n.of(context)!.interactiveTranslatorAutoPlaySliderHeader), + value: switchValue, + onChanged: (value) => { + widget.controller.pStoreService.save( + PLocalKey.itAutoPlay.toString(), + value, + ), + setState(() => switchValue = value), + }, + ); + } +} diff --git a/lib/pangea/widgets/new_group/vocab_list.dart b/lib/pangea/widgets/new_group/vocab_list.dart index e6c2675e4..240e99a85 100644 --- a/lib/pangea/widgets/new_group/vocab_list.dart +++ b/lib/pangea/widgets/new_group/vocab_list.dart @@ -271,7 +271,7 @@ class GenerateVocabButtonState extends State { ElevatedButton.icon( icon: const BotFace( width: 50.0, - expression: BotExpression.right, + expression: BotExpression.idle, ), label: Text(L10n.of(context)!.generateVocabulary), onPressed: () async { @@ -464,9 +464,9 @@ class PromptsFieldState extends State { // button to call API ElevatedButton.icon( - icon: const BotFace( + icon: BotFace( width: 50.0, - expression: BotExpression.right, + expression: BotExpression.idle, ), label: Text(L10n.of(context)!.generatePrompts), onPressed: () async { diff --git a/needed-translations.txt b/needed-translations.txt index 1355bb368..16a1df335 100644 --- a/needed-translations.txt +++ b/needed-translations.txt @@ -819,6 +819,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -863,7 +867,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "be": [ @@ -2314,6 +2321,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -2363,7 +2374,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "bn": [ @@ -3810,6 +3824,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -3859,7 +3877,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "bo": [ @@ -5310,6 +5331,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -5359,7 +5384,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ca": [ @@ -6213,6 +6241,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -6261,7 +6293,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "cs": [ @@ -7197,6 +7232,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -7245,7 +7284,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "de": [ @@ -8068,6 +8110,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -8112,7 +8158,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "el": [ @@ -9514,6 +9563,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -9563,7 +9616,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "eo": [ @@ -10664,6 +10720,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -10712,11 +10772,18 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "es": [ "searchIn", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -10727,7 +10794,8 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel" ], "et": [ @@ -11550,6 +11618,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -11594,7 +11666,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "eu": [ @@ -12417,6 +12492,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -12463,7 +12542,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fa": [ @@ -13421,6 +13503,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -13469,7 +13555,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fi": [ @@ -14391,6 +14480,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -14439,7 +14532,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fil": [ @@ -15717,6 +15813,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -15765,7 +15865,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fr": [ @@ -16722,6 +16825,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -16770,7 +16877,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ga": [ @@ -17856,6 +17966,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -17904,7 +18018,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "gl": [ @@ -18727,6 +18844,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -18771,7 +18892,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "he": [ @@ -19976,6 +20100,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -20024,7 +20152,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "hi": [ @@ -21468,6 +21599,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -21517,7 +21652,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "hr": [ @@ -22415,6 +22553,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -22463,7 +22605,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "hu": [ @@ -23300,6 +23445,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -23346,7 +23495,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ia": [ @@ -24783,6 +24935,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -24832,7 +24988,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "id": [ @@ -25659,6 +25818,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -25705,7 +25868,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ie": [ @@ -26914,6 +27080,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -26962,7 +27132,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "it": [ @@ -27838,6 +28011,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -27886,7 +28063,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ja": [ @@ -28873,6 +29053,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -28921,7 +29105,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ka": [ @@ -30227,6 +30414,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -30275,7 +30466,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ko": [ @@ -31098,6 +31292,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -31144,7 +31342,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "lt": [ @@ -32131,6 +32332,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -32179,7 +32384,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "lv": [ @@ -33008,6 +33216,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -33054,7 +33266,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "nb": [ @@ -34204,6 +34419,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -34253,7 +34472,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "nl": [ @@ -35168,6 +35390,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -35216,7 +35442,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pl": [ @@ -36140,6 +36369,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -36188,7 +36421,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pt": [ @@ -37617,6 +37853,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -37666,7 +37906,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pt_BR": [ @@ -38493,6 +38736,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -38539,7 +38786,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pt_PT": [ @@ -39691,6 +39941,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -39739,7 +39993,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ro": [ @@ -40698,6 +40955,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -40746,7 +41007,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ru": [ @@ -41573,6 +41837,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -41619,7 +41887,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sk": [ @@ -42836,6 +43107,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -42885,7 +43160,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sl": [ @@ -44233,6 +44511,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -44281,7 +44563,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sr": [ @@ -45402,6 +45687,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -45451,7 +45740,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sv": [ @@ -46307,6 +46599,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -46355,7 +46651,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ta": [ @@ -47803,6 +48102,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -47852,7 +48155,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "th": [ @@ -49254,6 +49560,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -49303,7 +49613,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "tr": [ @@ -50126,6 +50439,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -50170,7 +50487,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "uk": [ @@ -51026,6 +51346,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -51074,7 +51398,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "vi": [ @@ -52378,6 +52705,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -52426,7 +52757,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "zh": [ @@ -53249,6 +53583,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -53293,7 +53631,10 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "zh_Hant": [ @@ -54392,6 +54733,10 @@ "conversationBotDiscussionZone_discussionTriggerScheduleHourIntervalLabel", "conversationBotDiscussionZone_discussionTriggerReactionEnabledLabel", "conversationBotDiscussionZone_discussionTriggerReactionKeyLabel", + "conversationBotCustomZone_title", + "conversationBotCustomZone_customSystemPromptLabel", + "conversationBotCustomZone_customSystemPromptPlaceholder", + "conversationBotCustomZone_customTriggerReactionEnabledLabel", "addConversationBotDialogTitleInvite", "addConversationBotButtonInvite", "addConversationBotDialogInviteConfirmation", @@ -54441,6 +54786,9 @@ "suggestToSpaceDesc", "practice", "noLanguagesSet", - "noActivitiesFound" + "noActivitiesFound", + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ] } 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 7cb52b3f8..f1facd835 100644 Binary files a/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock and b/pangea_packages/fcm_shared_isolate/android/.gradle/6.7.1/fileHashes/fileHashes.lock 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 index 487a88833..ea7da199a 100644 Binary files a/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock and b/pangea_packages/fcm_shared_isolate/android/.gradle/buildOutputCleanup/buildOutputCleanup.lock 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 index b99989c33..a148f5b0e 100644 Binary files a/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock and b/pangea_packages/fcm_shared_isolate/android/.gradle/checksums/checksums.lock differ diff --git a/pubspec.lock b/pubspec.lock index c2303486b..3764281a1 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -999,6 +999,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" highlighter: dependency: transitive description: @@ -1925,6 +1933,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + rive: + dependency: "direct main" + description: + name: rive + sha256: "166019487e8bfa6525d4537bfd494deb4f306e32f97a7f50ff452b44ab6b72ea" + url: "https://pub.dev" + source: hosted + version: "0.11.11" + rive_common: + dependency: transitive + description: + name: rive_common + sha256: "83af8b500ad4d23930397229c7ed520e266eb851690a8621afa6cbd782aeac87" + url: "https://pub.dev" + source: hosted + version: "0.2.3" rxdart: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ce6ef99dc..a24dfdff3 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -120,6 +120,7 @@ dependencies: sentry_flutter: ^8.2.0 shimmer: ^3.0.0 syncfusion_flutter_xlsio: ^25.1.40 + rive: 0.11.11 # Pangea# dev_dependencies: