diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 3451205da..ef3042700 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -3128,7 +3128,7 @@ "maybeLater": "Maybe Later", "mainMenu": "Main Menu", "toggleImmersionMode": "Immersion Mode", - "toggleImmersionModeDesc": "When enabled, all messages are displayed in your target language and you can click the message to access definitions and translations.", + "toggleImmersionModeDesc": "When enabled, all messages are displayed in your target language. This setting is most useful in language exchanges.", "itToggleDescription": "This language learning tool will identify words in your base language and help you translate them to your target language. Though rare, the AI can make translation errors.", "igcToggleDescription": "This language learning tool will identify common spelling, grammar and punctuation errors in your message and suggest corrections. Though rare, the AI can make correction errors.", "sendOnEnterDescription": "Turn this off to be able to add line spaces in messages. When the toggle is off on the browser app, you can press Shift + Enter to start a new line. When the toggle is off on mobile apps, just Enter will start a new line.", @@ -3948,8 +3948,16 @@ "roomDataMissing": "Some data may be missing from rooms in which you are not a member.", "updatePhoneOS": "You may need to update your device's OS version.", "wordsPerMinute": "Words per minute", + "autoIGCToolName": "Run Language Assistance Automatically", + "autoIGCToolDescription": "Automatically run language assistance after typing messages", + "runGrammarCorrection": "Run grammar correction", + "grammarCorrectionFailed": "Grammar correction failed", + "grammarCorrectionComplete": "Grammar correction complete", "leaveRoomDescription": "The chat will be moved to the archive. Other users will be able to see that you have left the chat.", "archiveSpaceDescription": "All chats within this space will be moved to the archive for yourself and other non-admin users.", "leaveSpaceDescription": "All chats within this space will be moved to the archive. Other users will be able to see that you have left the space.", - "onlyAdminDescription": "Since there are no other admins, all other participants will also be removed." + "onlyAdminDescription": "Since there are no other admins, all other participants will also be removed.", + "tooltipInstructionsTitle": "Not sure what that does?", + "tooltipInstructionsMobileBody": "Press and hold items to view tooltips.", + "tooltipInstructionsBrowserBody": "Hover over items to view tooltips." } \ No newline at end of file diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index 90ab7cf37..fa097d393 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -3281,7 +3281,7 @@ "generateVocabulary": "Generar vocabulario basado en el título y la descripción", "generatePrompts": "Generar preguntas basado en el título y la descripción", "toggleImmersionMode": "Modo de inmersión", - "toggleImmersionModeDesc": "Cuando está habilitado, todos los mensajes se muestran en su idioma de destino y puede hacer clic en el mensaje para acceder a definiciones y traducciones.", + "toggleImmersionModeDesc": "Cuando está habilitado, todos los mensajes se muestran en su idioma de destino. Esta configuración es más útil en intercambios de idiomas.", "subscribe": "Subscríbase", "getAccess": "Activar herramientas", "subscriptionDesc": "¡Enviar y recibir mensajes es gratis! Suscríbase para aceder a la traducción interactiva, la revisión gramatical y el análisis de aprendizaje.", diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 4a204c404..73a0447d5 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -1327,9 +1327,18 @@ class ChatController extends State } // Pangea# if (!event.redacted) { - if (selectedEvents.contains(event)) { + // #Pangea + // If previous selectedEvent has same eventId, delete previous selectedEvent + final matches = + selectedEvents.where((e) => e.eventId == event.eventId).toList(); + if (matches.isNotEmpty) { + // if (selectedEvents.contains(event)) { + // Pangea# setState( - () => selectedEvents.remove(event), + // #Pangea + () => selectedEvents.remove(matches.first), + // () => selectedEvents.remove(event), + // Pangea# ); } else { setState( diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index ee3ce8909..317d81158 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -9,6 +9,7 @@ import 'package:fluffychat/pages/chat/reactions_picker.dart'; import 'package:fluffychat/pages/chat/reply_display.dart'; import 'package:fluffychat/pangea/choreographer/widgets/has_error_button.dart'; import 'package:fluffychat/pangea/choreographer/widgets/language_permissions_warning_buttons.dart'; +import 'package:fluffychat/pangea/choreographer/widgets/start_igc_button.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/pages/class_analytics/measure_able.dart'; import 'package:fluffychat/utils/account_config.dart'; @@ -449,8 +450,8 @@ class ChatView extends StatelessWidget { // #Pangea // if (controller.dragging) // Container( - // color: Theme.of(context) - // .scaffoldBackgroundColor + // color: Theme.of(context) + // .scaffoldBackgroundColor // .withOpacity(0.9), // alignment: Alignment.center, // child: const Icon( @@ -458,6 +459,11 @@ class ChatView extends StatelessWidget { // size: 100, // ), // ), + Positioned( + left: 20, + bottom: 75, + child: StartIGCButton(controller: controller), + ), // Pangea# ], ), diff --git a/lib/pages/chat/events/message_content.dart b/lib/pages/chat/events/message_content.dart index 41997afea..2d27807b8 100644 --- a/lib/pages/chat/events/message_content.dart +++ b/lib/pages/chat/events/message_content.dart @@ -199,18 +199,8 @@ class MessageContent extends StatelessWidget { case MessageTypes.Notice: case MessageTypes.Emote: if (AppConfig.renderHtml && - !event.redacted && - event.isRichMessage - // #Pangea - && - !(pangeaMessageEvent?.showRichText( - selected, - isOverlay: isOverlay, - highlighted: toolbarController?.highlighted ?? false, - ) ?? - false) - // Pangea# - ) { + !event.redacted && + event.isRichMessage) { var html = event.formattedText; if (event.messageType == MessageTypes.Emote) { html = '* $html'; @@ -306,18 +296,17 @@ class MessageContent extends StatelessWidget { decoration: event.redacted ? TextDecoration.lineThrough : null, height: 1.3, ); - if (pangeaMessageEvent?.showRichText( - selected, - isOverlay: isOverlay, - highlighted: toolbarController?.highlighted ?? false, - ) ?? - false) { + if (immersionMode && pangeaMessageEvent != null) { return PangeaRichText( style: messageTextStyle, pangeaMessageEvent: pangeaMessageEvent!, immersionMode: immersionMode, toolbarController: toolbarController, ); + } else if (pangeaMessageEvent != null) { + toolbarController?.toolbar?.textSelection.setMessageText( + pangeaMessageEvent!.body, + ); } // Pangea# return FutureBuilder( diff --git a/lib/pages/chat_list/chat_list.dart b/lib/pages/chat_list/chat_list.dart index db05bedf8..f7294e571 100644 --- a/lib/pages/chat_list/chat_list.dart +++ b/lib/pages/chat_list/chat_list.dart @@ -105,6 +105,12 @@ class ChatListController extends State selectedRoomIds.clear(); activeSpaceId = spaceId; activeFilter = ActiveFilter.spaces; + // #Pangea + // don't show all spaces view if in column mode + if (spaceId == null && FluffyThemes.isColumnMode(context)) { + activeFilter = ActiveFilter.allChats; + } + // Pangea# }); } @@ -693,7 +699,7 @@ class ChatListController extends State title: L10n.of(context)!.areYouSure, okLabel: L10n.of(context)!.yes, cancelLabel: L10n.of(context)!.cancel, - message: onlyAdmin + message: onlyAdmin && selectedRoomIds.length == 1 ? L10n.of(context)!.onlyAdminDescription : L10n.of(context)!.leaveRoomDescription, ) == diff --git a/lib/pages/chat_list/chat_list_header.dart b/lib/pages/chat_list/chat_list_header.dart index 12f2f6b44..20f41ea08 100644 --- a/lib/pages/chat_list/chat_list_header.dart +++ b/lib/pages/chat_list/chat_list_header.dart @@ -171,6 +171,12 @@ class ChatListHeader extends StatelessWidget implements PreferredSizeWidget { onPressed: controller.toggleMuted, ), // #Pangea + if (controller.selectedRoomIds.length > 1) + IconButton( + icon: const Icon(Icons.arrow_forward), + tooltip: L10n.of(context)!.leave, + onPressed: controller.leaveAction, + ), if (controller.selectedRoomIds.length == 1 && !(Matrix.of(context) .client diff --git a/lib/pages/chat_list/space_view.dart b/lib/pages/chat_list/space_view.dart index 1fde5f0f8..0757354c5 100644 --- a/lib/pages/chat_list/space_view.dart +++ b/lib/pages/chat_list/space_view.dart @@ -147,7 +147,10 @@ class _SpaceViewState extends State { if (activeSpace != null) { await setChatCount( activeSpace, - _lastResponse[activeSpaceId], + _lastResponse[activeSpaceId] ?? + GetSpaceHierarchyResponse( + rooms: [], + ), ); } // Pangea# diff --git a/lib/pages/settings/settings.dart b/lib/pages/settings/settings.dart index 0e32fe478..55b39fa3d 100644 --- a/lib/pages/settings/settings.dart +++ b/lib/pages/settings/settings.dart @@ -1,18 +1,17 @@ import 'dart:async'; -import 'package:flutter/material.dart'; - import 'package:adaptive_dialog/adaptive_dialog.dart'; import 'package:collection/collection.dart'; import 'package:file_picker/file_picker.dart'; +import 'package:fluffychat/pangea/utils/logout.dart'; +import 'package:fluffychat/utils/platform_infos.dart'; +import 'package:fluffychat/widgets/app_lock.dart'; +import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:image_picker/image_picker.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/pangea/utils/logout.dart'; -import 'package:fluffychat/utils/platform_infos.dart'; -import 'package:fluffychat/widgets/app_lock.dart'; import '../../widgets/matrix.dart'; import 'settings_view.dart'; @@ -171,6 +170,10 @@ class SettingsController extends State { // Pangea# super.initState(); + // #Pangea + profileUpdated = true; + profileFuture = null; + // Pangea# } void checkBootstrap() async { diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index 973ca6984..3d84b0e1d 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -13,6 +13,7 @@ import 'package:fluffychat/pangea/enum/edit_type.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/class_model.dart'; import 'package:fluffychat/pangea/models/it_step.dart'; +import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/models/representation_content_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; import 'package:fluffychat/pangea/utils/any_state_holder.dart'; @@ -51,7 +52,7 @@ class Choreographer { // last checked by IGC or translation String? _lastChecked; ChoreoMode choreoMode = ChoreoMode.igc; - final StreamController stateListener = StreamController(); + final StreamController stateListener = StreamController.broadcast(); StreamSubscription? trialStream; Choreographer(this.pangeaController, this.chatController) { @@ -93,7 +94,7 @@ class Choreographer { } } - void _sendWithIGC(BuildContext context) { + Future _sendWithIGC(BuildContext context) async { if (igc.canSendMessage) { final PangeaRepresentation? originalWritten = choreoRecord.includedIT && itController.sourceText != null @@ -105,7 +106,6 @@ class Choreographer { ) : null; - // PTODO - just put this in original message event final PangeaRepresentation originalSent = PangeaRepresentation( langCode: langCodeOfCurrentText ?? LanguageKeys.unknownLanguage, text: currentText, @@ -115,6 +115,22 @@ class Choreographer { final ChoreoRecord? applicableChoreo = isITandIGCEnabled && igc.igcTextData != null ? choreoRecord : null; + // if the message has not been processed to determine its language + // then run it through the language detection endpoint. If the detection + // confidence is high enough, use that language code as the message's language + // to save that pangea representation + if (applicableChoreo == null) { + final resp = await pangeaController.languageDetection.detectLanguage( + currentText, + pangeaController.languageController.userL2?.langCode, + pangeaController.languageController.userL1?.langCode, + ); + final LanguageDetection? bestDetection = resp.bestDetection(); + if (bestDetection != null) { + originalSent.langCode = bestDetection.langCode; + } + } + final UseType useType = useTypeCalculator(applicableChoreo); debugPrint("use type in choreographer $useType"); @@ -205,14 +221,18 @@ class Choreographer { textController.editType = EditType.keyboard; } - Future getLanguageHelp([bool tokensOnly = false]) async { + Future getLanguageHelp([ + bool tokensOnly = false, + bool manual = false, + ]) async { try { if (errorService.isError) return; final CanSendStatus canSendStatus = pangeaController.subscriptionController.canSendStatus; if (canSendStatus != CanSendStatus.subscribed || - (!igcEnabled && !itEnabled)) { + (!igcEnabled && !itEnabled) || + (!isAutoIGCEnabled && !manual && choreoMode != ChoreoMode.it)) { return; } @@ -525,14 +545,50 @@ class Choreographer { chatController.room, ); - bool get translationEnabled => - pangeaController.permissionsController.isToolEnabled( - ToolSetting.translations, - chatController.room, - ); + // bool get translationEnabled => + // pangeaController.permissionsController.isToolEnabled( + // ToolSetting.translations, + // chatController.room, + // ); bool get isITandIGCEnabled => pangeaController.permissionsController.isWritingAssistanceEnabled( chatController.room, ); + + bool get isAutoIGCEnabled => + pangeaController.permissionsController.isToolEnabled( + ToolSetting.autoIGC, + chatController.room, + ); + + AssistanceState get assistanceState { + if (currentText.isEmpty && itController.sourceText == null) { + return AssistanceState.noMessage; + } + + if (igc.igcTextData?.matches.isNotEmpty ?? false) { + return AssistanceState.fetched; + } + + if (isFetching) { + return AssistanceState.fetching; + } + + if (igc.igcTextData == null) { + return AssistanceState.notFetched; + } + + return AssistanceState.complete; + } +} + +// assistance state is, user has not typed a message, user has typed a message and IGC has not run, +// IGC is running, IGC has run and there are remaining steps (either IT or IGC), or all steps are done +enum AssistanceState { + noMessage, + notFetched, + fetching, + fetched, + complete, } diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 6d5f8e347..61c8c2312 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -183,7 +183,7 @@ class ITController { } } - FuturegetNextTranslationData() async { + Future getNextTranslationData() async { try { if (completedITSteps.length < goldRouteTracker.continuances.length) { final String currentText = choreographer.currentText; @@ -478,5 +478,5 @@ class CurrentITStep { // get continuance with highest level Continuance get best => - continuances.reduce((a, b) => a.level > b.level ? a : b); + continuances.reduce((a, b) => a.level < b.level ? a : b); } diff --git a/lib/pangea/choreographer/widgets/language_display_toggle.dart b/lib/pangea/choreographer/widgets/language_display_toggle.dart index 9478b4220..bc0efd492 100644 --- a/lib/pangea/choreographer/widgets/language_display_toggle.dart +++ b/lib/pangea/choreographer/widgets/language_display_toggle.dart @@ -17,9 +17,9 @@ class LanguageDisplayToggle extends StatelessWidget { @override Widget build(BuildContext context) { - if (!controller.choreographer.translationEnabled) { - return const SizedBox(); - } + // if (!controller.choreographer.translationEnabled) { + // return const SizedBox(); + // } return Container( decoration: BoxDecoration( shape: BoxShape.circle, diff --git a/lib/pangea/choreographer/widgets/send_button.dart b/lib/pangea/choreographer/widgets/send_button.dart index 045f0c516..fa3189df5 100644 --- a/lib/pangea/choreographer/widgets/send_button.dart +++ b/lib/pangea/choreographer/widgets/send_button.dart @@ -1,8 +1,7 @@ +import 'package:fluffychat/pangea/constants/colors.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; -import 'package:fluffychat/pangea/constants/colors.dart'; import '../../../pages/chat/chat.dart'; class ChoreographerSendButton extends StatelessWidget { @@ -16,7 +15,8 @@ class ChoreographerSendButton extends StatelessWidget { @override Widget build(BuildContext context) { // commit for cicd - return controller.choreographer.isFetching + return controller.choreographer.isFetching && + controller.choreographer.isAutoIGCEnabled ? Container( height: 56, width: 56, @@ -28,7 +28,8 @@ class ChoreographerSendButton extends StatelessWidget { alignment: Alignment.center, child: IconButton( icon: const Icon(Icons.send_outlined), - color: controller.choreographer.igc.canSendMessage + color: controller.choreographer.igc.canSendMessage || + !controller.choreographer.isAutoIGCEnabled ? null : PangeaColors.igcError, onPressed: () { diff --git a/lib/pangea/choreographer/widgets/start_igc_button.dart b/lib/pangea/choreographer/widgets/start_igc_button.dart new file mode 100644 index 000000000..183ac690d --- /dev/null +++ b/lib/pangea/choreographer/widgets/start_igc_button.dart @@ -0,0 +1,150 @@ +import 'dart:async'; +import 'dart:math' as math; + +import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; +import 'package:fluffychat/pangea/constants/colors.dart'; +import 'package:flutter/material.dart'; +import 'package:flutter_gen/gen_l10n/l10n.dart'; + +import '../../../pages/chat/chat.dart'; + +class StartIGCButton extends StatefulWidget { + const StartIGCButton({ + super.key, + required this.controller, + }); + + final ChatController controller; + + @override + State createState() => StartIGCButtonState(); +} + +class StartIGCButtonState extends State + with SingleTickerProviderStateMixin { + AssistanceState get assistanceState => + widget.controller.choreographer.assistanceState; + AnimationController? _controller; + StreamSubscription? choreoListener; + AssistanceState? prevState; + + @override + void initState() { + _controller = AnimationController( + vsync: this, + duration: const Duration(seconds: 1), + ); + choreoListener = widget.controller.choreographer.stateListener.stream + .listen(updateSpinnerState); + super.initState(); + } + + void updateSpinnerState(_) { + if (prevState != AssistanceState.fetching && + assistanceState == AssistanceState.fetching) { + _controller?.repeat(); + } else if (prevState == AssistanceState.fetching && + assistanceState != AssistanceState.fetching) { + _controller?.stop(); + _controller?.reverse(); + } + setState(() => prevState = assistanceState); + } + + @override + Widget build(BuildContext context) { + if (widget.controller.choreographer.isAutoIGCEnabled) { + return const SizedBox.shrink(); + } + + final Widget icon = Icon( + Icons.autorenew_rounded, + size: 46, + color: assistanceState.stateColor, + ); + + return SizedBox( + height: 50, + width: 50, + child: FloatingActionButton( + tooltip: assistanceState.tooltip( + L10n.of(context)!, + ), + backgroundColor: Colors.white, + disabledElevation: 0, + shape: const CircleBorder(), + onPressed: () { + if (assistanceState != AssistanceState.complete) { + widget.controller.choreographer.getLanguageHelp( + false, + true, + ); + } + }, + child: Stack( + alignment: Alignment.center, + children: [ + _controller != null + ? RotationTransition( + turns: Tween(begin: 0.0, end: math.pi * 2) + .animate(_controller!), + child: icon, + ) + : icon, + Container( + width: 26, + height: 26, + decoration: const BoxDecoration( + shape: BoxShape.circle, + color: Colors.white, + ), + ), + Container( + width: 20, + height: 20, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: assistanceState.stateColor, + ), + ), + const Icon( + size: 16, + Icons.check, + color: Colors.white, + ), + ], + ), + ), + ); + } +} + +extension AssistanceStateExtension on AssistanceState { + Color get stateColor { + switch (this) { + case AssistanceState.noMessage: + case AssistanceState.notFetched: + case AssistanceState.fetching: + return AppConfig.primaryColor; + case AssistanceState.fetched: + return PangeaColors.igcError; + case AssistanceState.complete: + return AppConfig.success; + } + } + + String tooltip(L10n l10n) { + switch (this) { + case AssistanceState.noMessage: + case AssistanceState.notFetched: + return l10n.runGrammarCorrection; + case AssistanceState.fetching: + return ""; + case AssistanceState.fetched: + return l10n.grammarCorrectionFailed; + case AssistanceState.complete: + return l10n.grammarCorrectionComplete; + } + } +} diff --git a/lib/pangea/constants/model_keys.dart b/lib/pangea/constants/model_keys.dart index ce427f3d3..ef84a7064 100644 --- a/lib/pangea/constants/model_keys.dart +++ b/lib/pangea/constants/model_keys.dart @@ -54,6 +54,7 @@ class ModelKey { static const String offset = "offset"; static const String length = "length"; static const String langCode = 'lang_code'; + static const String confidence = 'confidence'; // some old analytics rooms have langCode instead of lang_code in the room creation content static const String oldLangCode = 'langCode'; static const String wordLang = "word_lang"; diff --git a/lib/pangea/controllers/language_detection_controller.dart b/lib/pangea/controllers/language_detection_controller.dart index 0ff18b556..4ddfabc88 100644 --- a/lib/pangea/controllers/language_detection_controller.dart +++ b/lib/pangea/controllers/language_detection_controller.dart @@ -3,6 +3,7 @@ import 'dart:convert'; import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; +import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/network/urls.dart'; import 'package:http/http.dart' as http; @@ -48,7 +49,7 @@ class LanguageDetectionRequest { } class LanguageDetectionResponse { - List> detections; + List detections; String fullText; LanguageDetectionResponse({ @@ -58,7 +59,11 @@ class LanguageDetectionResponse { factory LanguageDetectionResponse.fromJson(Map json) { return LanguageDetectionResponse( - detections: List>.from(json['detections']), + detections: List.from( + json['detections'].map( + (e) => LanguageDetection.fromJson(e), + ), + ), fullText: json['full_text'], ); } @@ -69,6 +74,20 @@ class LanguageDetectionResponse { 'full_text': fullText, }; } + + LanguageDetection? get _bestDetection { + detections.sort((a, b) => b.confidence.compareTo(a.confidence)); + return detections.isNotEmpty ? detections.first : null; + } + + final double _confidenceThreshold = 0.95; + + LanguageDetection? bestDetection({double? threshold}) { + threshold ??= _confidenceThreshold; + return (_bestDetection?.confidence ?? 0) >= _confidenceThreshold + ? _bestDetection! + : null; + } } class _LanguageDetectionCacheItem { @@ -103,6 +122,19 @@ class LanguageDetectionController { _cacheClearTimer?.cancel(); } + Future detectLanguage( + String fullText, + String? userL2, + String? userL1, + ) async { + final LanguageDetectionRequest params = LanguageDetectionRequest( + fullText: fullText, + userL1: userL1, + userL2: userL2, + ); + return get(params); + } + Future get( LanguageDetectionRequest params, ) async { diff --git a/lib/pangea/controllers/local_settings.dart b/lib/pangea/controllers/local_settings.dart index 5984a7bf5..2dc30cfe7 100644 --- a/lib/pangea/controllers/local_settings.dart +++ b/lib/pangea/controllers/local_settings.dart @@ -8,8 +8,14 @@ class LocalSettings { _pangeaController = pangeaController; } - bool userLanguageToolSetting(ToolSetting setting) => - _pangeaController.pStoreService.read(setting.toString()) ?? true; + bool userLanguageToolSetting(ToolSetting setting) { + final profileSetting = + _pangeaController.pStoreService.read(setting.toString()); + if (profileSetting != null) { + return profileSetting; + } + return setting == ToolSetting.immersionMode ? false : true; + } // bool get userEnableIT => // _pangeaController.pStoreService.read(ToolSetting.interactiveTranslator.toString()) ?? true; diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index d3a17d365..c7a35b3e8 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -131,7 +131,7 @@ class UserController extends BaseController { final bool? immersionMode = migratedProfileInfo(MatrixProfile.immersionMode); final bool? definitions = migratedProfileInfo(MatrixProfile.definitions); - final bool? translations = migratedProfileInfo(MatrixProfile.translations); + // final bool? translations = migratedProfileInfo(MatrixProfile.translations); final bool? showItInstructions = migratedProfileInfo(MatrixProfile.showedItInstructions); final bool? showClickMessage = @@ -147,7 +147,7 @@ class UserController extends BaseController { interactiveGrammar: interactiveGrammar, immersionMode: immersionMode, definitions: definitions, - translations: translations, + // translations: translations, showedItInstructions: showItInstructions, showedClickMessage: showClickMessage, showedBlurMeansTranslate: showBlurMeansTranslate, @@ -228,10 +228,11 @@ class UserController extends BaseController { bool? interactiveGrammar, bool? immersionMode, bool? definitions, - bool? translations, + // bool? translations, bool? showedItInstructions, bool? showedClickMessage, bool? showedBlurMeansTranslate, + bool? showedTooltipInstructions, String? createdAt, String? targetLanguage, String? sourceLanguage, @@ -280,12 +281,12 @@ class UserController extends BaseController { definitions, ); } - if (translations != null) { - await _pangeaController.pStoreService.save( - MatrixProfile.translations.title, - translations, - ); - } + // if (translations != null) { + // await _pangeaController.pStoreService.save( + // MatrixProfile.translations.title, + // translations, + // ); + // } if (showedItInstructions != null) { await _pangeaController.pStoreService.save( MatrixProfile.showedItInstructions.title, @@ -304,6 +305,12 @@ class UserController extends BaseController { showedBlurMeansTranslate, ); } + if (showedTooltipInstructions != null) { + await _pangeaController.pStoreService.save( + MatrixProfile.showedTooltipInstructions.title, + showedTooltipInstructions, + ); + } if (createdAt != null) { await _pangeaController.pStoreService.save( MatrixProfile.createdAt.title, diff --git a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart index 5fa2e2659..ff8696989 100644 --- a/lib/pangea/matrix_event_wrappers/pangea_message_event.dart +++ b/lib/pangea/matrix_event_wrappers/pangea_message_event.dart @@ -80,29 +80,6 @@ class PangeaMessageEvent { return _latestEdit; } - bool showRichText( - bool selected, { - bool highlighted = false, - bool isOverlay = false, - }) { - if (!_isValidPangeaMessageEvent) { - return false; - } - - if ([EventStatus.error, EventStatus.sending].contains(_event.status)) { - return false; - } - - if (isOverlay) return true; - - // if ownMessage, don't show rich text if not selected or highlighted - // and don't show is the message is not an overlay - if (ownMessage && ((!selected && !highlighted) || !isOverlay)) { - return false; - } - return true; - } - Future getMatrixAudioFile( String langCode, BuildContext context, diff --git a/lib/pangea/models/class_model.dart b/lib/pangea/models/class_model.dart index 1f588980c..7e95c9d26 100644 --- a/lib/pangea/models/class_model.dart +++ b/lib/pangea/models/class_model.dart @@ -1,13 +1,12 @@ import 'dart:developer'; +import 'package:fluffychat/pangea/constants/model_keys.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:matrix/matrix.dart'; -import 'package:fluffychat/pangea/constants/model_keys.dart'; -import 'package:fluffychat/pangea/utils/error_handler.dart'; import '../constants/class_default_values.dart'; import '../constants/language_keys.dart'; import '../constants/pangea_event_types.dart'; @@ -124,6 +123,7 @@ class PangeaRoomRules { int immersionMode; int definitions; int translations; + int autoIGC; PangeaRoomRules({ this.isPublic = false, @@ -142,6 +142,7 @@ class PangeaRoomRules { this.immersionMode = ClassDefaultValues.languageToolPermissions, this.definitions = ClassDefaultValues.languageToolPermissions, this.translations = ClassDefaultValues.languageToolPermissions, + this.autoIGC = ClassDefaultValues.languageToolPermissions, }); updatePermission(String key, bool value) { @@ -198,8 +199,11 @@ class PangeaRoomRules { case ToolSetting.definitions: definitions = value; break; - case ToolSetting.translations: - translations = value; + // case ToolSetting.translations: + // translations = value; + // break; + case ToolSetting.autoIGC: + autoIGC = value; break; default: throw Exception('Invalid key for setting permissions - $setting'); @@ -235,6 +239,7 @@ class PangeaRoomRules { json['definitions'] ?? ClassDefaultValues.languageToolPermissions, translations: json['translations'] ?? ClassDefaultValues.languageToolPermissions, + autoIGC: json['auto_igc'] ?? ClassDefaultValues.languageToolPermissions, ); Map toJson() { @@ -256,6 +261,7 @@ class PangeaRoomRules { data['immersion_mode'] = immersionMode; data['definitions'] = definitions; data['translations'] = translations; + data['auto_igc'] = autoIGC; return data; } @@ -269,8 +275,10 @@ class PangeaRoomRules { return immersionMode; case ToolSetting.definitions: return definitions; - case ToolSetting.translations: - return translations; + // case ToolSetting.translations: + // return translations; + case ToolSetting.autoIGC: + return autoIGC; default: throw Exception('Invalid key for setting permissions - $setting'); } @@ -298,7 +306,8 @@ enum ToolSetting { interactiveGrammar, immersionMode, definitions, - translations, + // translations, + autoIGC, } extension SettingCopy on ToolSetting { @@ -312,8 +321,10 @@ extension SettingCopy on ToolSetting { return L10n.of(context)!.toggleImmersionMode; case ToolSetting.definitions: return L10n.of(context)!.definitionsToolName; - case ToolSetting.translations: - return L10n.of(context)!.messageTranslationsToolName; + // case ToolSetting.translations: + // return L10n.of(context)!.messageTranslationsToolName; + case ToolSetting.autoIGC: + return L10n.of(context)!.autoIGCToolName; } } @@ -328,8 +339,10 @@ extension SettingCopy on ToolSetting { return L10n.of(context)!.toggleImmersionModeDesc; case ToolSetting.definitions: return L10n.of(context)!.definitionsToolDescription; - case ToolSetting.translations: - return L10n.of(context)!.translationsToolDescrption; + // case ToolSetting.translations: + // return L10n.of(context)!.translationsToolDescrption; + case ToolSetting.autoIGC: + return L10n.of(context)!.autoIGCToolDescription; } } } diff --git a/lib/pangea/models/language_detection_model.dart b/lib/pangea/models/language_detection_model.dart index 6fa3d7299..7ed44868c 100644 --- a/lib/pangea/models/language_detection_model.dart +++ b/lib/pangea/models/language_detection_model.dart @@ -1,19 +1,23 @@ +import 'package:fluffychat/pangea/constants/model_keys.dart'; + class LanguageDetection { String langCode; + double confidence; LanguageDetection({ required this.langCode, + required this.confidence, }); factory LanguageDetection.fromJson(Map json) { return LanguageDetection( - langCode: json[_langCodeKey], + langCode: json[ModelKey.langCode], + confidence: json[ModelKey.confidence], ); } - static const _langCodeKey = "lang_code"; - Map toJson() => { - _langCodeKey: langCode, + ModelKey.langCode: langCode, + ModelKey.confidence: confidence, }; } diff --git a/lib/pangea/models/user_model.dart b/lib/pangea/models/user_model.dart index 2169c6f70..a6ae5730f 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -59,15 +59,17 @@ enum MatrixProfile { interactiveGrammar, immersionMode, definitions, - translations, + // translations, showedItInstructions, showedClickMessage, showedBlurMeansTranslate, + showedTooltipInstructions, createdAt, targetLanguage, sourceLanguage, country, publicProfile, + autoIGC, } extension MatrixProfileExtension on MatrixProfile { @@ -87,14 +89,18 @@ extension MatrixProfileExtension on MatrixProfile { return ToolSetting.immersionMode.toString(); case MatrixProfile.definitions: return ToolSetting.definitions.toString(); - case MatrixProfile.translations: - return ToolSetting.translations.toString(); + // case MatrixProfile.translations: + // return ToolSetting.translations.toString(); + case MatrixProfile.autoIGC: + return ToolSetting.autoIGC.toString(); case MatrixProfile.showedItInstructions: return InstructionsEnum.itInstructions.toString(); case MatrixProfile.showedClickMessage: return InstructionsEnum.clickMessage.toString(); case MatrixProfile.showedBlurMeansTranslate: return InstructionsEnum.blurMeansTranslate.toString(); + case MatrixProfile.showedTooltipInstructions: + return InstructionsEnum.tooltipInstructions.toString(); case MatrixProfile.createdAt: return ModelKey.userCreatedAt; case MatrixProfile.targetLanguage: diff --git a/lib/pangea/repo/igc_repo.dart b/lib/pangea/repo/igc_repo.dart index 068a009e8..9517515d0 100644 --- a/lib/pangea/repo/igc_repo.dart +++ b/lib/pangea/repo/igc_repo.dart @@ -1,13 +1,13 @@ import 'dart:convert'; -import 'package:http/http.dart'; - import 'package:fluffychat/pangea/config/environment.dart'; import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/models/lemma.dart'; import 'package:fluffychat/pangea/models/pangea_match_model.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/repo/span_data_repo.dart'; +import 'package:http/http.dart'; + import '../constants/model_keys.dart'; import '../models/igc_text_data_model.dart'; import '../network/requests.dart'; @@ -39,7 +39,7 @@ class IgcRepo { await Future.delayed(const Duration(seconds: 2)); final IGCTextData igcTextData = IGCTextData( - detections: [LanguageDetection(langCode: "en")], + detections: [LanguageDetection(langCode: "en", confidence: 0.99)], tokens: [ PangeaToken( text: PangeaTokenText(content: "This", offset: 0, length: 4), diff --git a/lib/pangea/utils/get_chat_list_item_subtitle.dart b/lib/pangea/utils/get_chat_list_item_subtitle.dart index 2fee578bf..5ccb623d7 100644 --- a/lib/pangea/utils/get_chat_list_item_subtitle.dart +++ b/lib/pangea/utils/get_chat_list_item_subtitle.dart @@ -1,3 +1,4 @@ +import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/constants/language_keys.dart'; import 'package:fluffychat/pangea/constants/model_keys.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; @@ -10,6 +11,17 @@ import 'package:matrix/matrix.dart'; import '../../utils/matrix_sdk_extensions/matrix_locals.dart'; class GetChatListItemSubtitle { + final List hideContentKeys = [ + ModelKey.transcription, + ]; + + bool moveBackInTimeline(Event event) => + hideContentKeys.any( + (key) => event.content.tryGet(key) != null, + ) || + event.type.startsWith("p.") || + event.type.startsWith("pangea."); + Future getSubtitle( L10n l10n, Event? event, @@ -22,23 +34,14 @@ class GetChatListItemSubtitle { eventContextId = null; } - final Timeline timeline = - await event.room.getTimeline(eventContextId: eventContextId); - - if (event.content.tryGet(ModelKey.transcription) != null) { - int index = timeline.events.indexWhere( - (e) => e.eventId == event!.eventId, - ); - - while (index < timeline.events.length && - (timeline.events[index].content.tryGet(ModelKey.transcription) != - null || - timeline.events[index].type != EventTypes.Message)) { - index++; - } + final Timeline timeline = await event.room.getTimeline( + eventContextId: eventContextId, + ); - if (timeline.events.length > index + 1) { - event = timeline.events[index]; + if (moveBackInTimeline(event)) { + event = timeline.events.firstWhereOrNull((e) => !moveBackInTimeline(e)); + if (event == null) { + return l10n.emptyChat; } } diff --git a/lib/pangea/utils/instructions.dart b/lib/pangea/utils/instructions.dart index f1fa8b59f..43350f518 100644 --- a/lib/pangea/utils/instructions.dart +++ b/lib/pangea/utils/instructions.dart @@ -1,3 +1,4 @@ +import 'package:fluffychat/utils/platform_infos.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; @@ -102,6 +103,7 @@ enum InstructionsEnum { itInstructions, clickMessage, blurMeansTranslate, + tooltipInstructions, } extension Copy on InstructionsEnum { @@ -113,6 +115,8 @@ extension Copy on InstructionsEnum { return L10n.of(context)!.clickMessageTitle; case InstructionsEnum.blurMeansTranslate: return L10n.of(context)!.blurMeansTranslateTitle; + case InstructionsEnum.tooltipInstructions: + return L10n.of(context)!.tooltipInstructionsTitle; } } @@ -124,6 +128,10 @@ extension Copy on InstructionsEnum { return L10n.of(context)!.clickMessageBody; case InstructionsEnum.blurMeansTranslate: return L10n.of(context)!.blurMeansTranslateBody; + case InstructionsEnum.tooltipInstructions: + return PlatformInfos.isMobile + ? L10n.of(context)!.tooltipInstructionsMobileBody + : L10n.of(context)!.tooltipInstructionsBrowserBody; } } } diff --git a/lib/pangea/widgets/chat/message_speech_to_text_card.dart b/lib/pangea/widgets/chat/message_speech_to_text_card.dart index 37b013b53..663e39ffe 100644 --- a/lib/pangea/widgets/chat/message_speech_to_text_card.dart +++ b/lib/pangea/widgets/chat/message_speech_to_text_card.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/speech_to_text_models.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/pangea/utils/instructions.dart'; import 'package:fluffychat/pangea/widgets/chat/toolbar_content_loading_indicator.dart'; import 'package:fluffychat/pangea/widgets/common/icon_number_widget.dart'; import 'package:fluffychat/pangea/widgets/igc/card_error_widget.dart'; @@ -175,12 +176,24 @@ class MessageSpeechToTextCardState extends State { number: "${selectedToken?.confidence ?? speechToTextResponse!.transcript.confidence}%", toolTip: L10n.of(context)!.accuracy, + onPressed: () => MatrixState.pangeaController.instructions.show( + context, + InstructionsEnum.tooltipInstructions, + widget.messageEvent.eventId, + true, + ), ), IconNumberWidget( icon: Icons.speed, number: wordsPerMinuteString != null ? "$wordsPerMinuteString" : "??", toolTip: L10n.of(context)!.wordsPerMinute, + onPressed: () => MatrixState.pangeaController.instructions.show( + context, + InstructionsEnum.tooltipInstructions, + widget.messageEvent.eventId, + true, + ), ), ], ), diff --git a/lib/pangea/widgets/common/icon_number_widget.dart b/lib/pangea/widgets/common/icon_number_widget.dart index b42777f91..f677ea579 100644 --- a/lib/pangea/widgets/common/icon_number_widget.dart +++ b/lib/pangea/widgets/common/icon_number_widget.dart @@ -6,6 +6,7 @@ class IconNumberWidget extends StatelessWidget { final Color? iconColor; final double? iconSize; final String? toolTip; + final VoidCallback onPressed; const IconNumberWidget({ super.key, @@ -14,16 +15,20 @@ class IconNumberWidget extends StatelessWidget { this.toolTip, this.iconColor, this.iconSize, + required this.onPressed, }); Widget _content(BuildContext context) { return Row( mainAxisSize: MainAxisSize.min, children: [ - Icon( - icon, - color: iconColor ?? Theme.of(context).iconTheme.color, - size: iconSize ?? Theme.of(context).iconTheme.size, + IconButton( + icon: Icon( + icon, + color: iconColor ?? Theme.of(context).iconTheme.color, + size: iconSize ?? Theme.of(context).iconTheme.size, + ), + onPressed: onPressed, ), const SizedBox(width: 8), Text( diff --git a/needed-translations.txt b/needed-translations.txt index 70b061369..e29d36ddd 100644 --- a/needed-translations.txt +++ b/needed-translations.txt @@ -839,9 +839,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "be": [ @@ -2279,9 +2288,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "bn": [ @@ -3181,9 +3199,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "bo": [ @@ -4083,9 +4110,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ca": [ @@ -4985,9 +5021,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "cs": [ @@ -5887,9 +5932,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "de": [ @@ -6736,9 +6790,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "el": [ @@ -7638,9 +7701,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "eo": [ @@ -8540,17 +8612,35 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "es": [ "suggestToChat", "suggestToChatDesc", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "et": [ @@ -9393,9 +9483,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "eu": [ @@ -10238,9 +10337,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "fa": [ @@ -11140,9 +11248,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "fi": [ @@ -12042,9 +12159,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "fr": [ @@ -12944,9 +13070,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ga": [ @@ -13846,9 +13981,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "gl": [ @@ -14691,9 +14835,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "he": [ @@ -15593,9 +15746,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "hi": [ @@ -16495,9 +16657,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "hr": [ @@ -17384,9 +17555,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "hu": [ @@ -18286,9 +18466,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ia": [ @@ -19712,9 +19901,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "id": [ @@ -20614,9 +20812,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ie": [ @@ -21516,9 +21723,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "it": [ @@ -22403,9 +22619,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ja": [ @@ -23305,9 +23530,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ko": [ @@ -24207,9 +24441,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "lt": [ @@ -25109,9 +25352,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "lv": [ @@ -26011,9 +26263,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "nb": [ @@ -26913,9 +27174,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "nl": [ @@ -27815,9 +28085,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pl": [ @@ -28717,9 +28996,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pt": [ @@ -29619,9 +29907,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pt_BR": [ @@ -30490,9 +30787,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "pt_PT": [ @@ -31392,9 +31698,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ro": [ @@ -32294,9 +32609,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ru": [ @@ -33139,9 +33463,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sk": [ @@ -34041,9 +34374,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sl": [ @@ -34943,9 +35285,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sr": [ @@ -35845,9 +36196,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "sv": [ @@ -36712,9 +37072,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "ta": [ @@ -37614,9 +37983,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "th": [ @@ -38516,9 +38894,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "tr": [ @@ -39403,9 +39790,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "uk": [ @@ -40248,9 +40644,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "vi": [ @@ -41150,9 +41555,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "zh": [ @@ -41995,9 +42409,18 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ], "zh_Hant": [ @@ -42897,8 +43320,17 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", - "leaveSpaceDescription" + "leaveSpaceDescription", + "onlyAdminDescription", + "tooltipInstructionsTitle", + "tooltipInstructionsMobileBody", + "tooltipInstructionsBrowserBody" ] }