diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index 68ce39bfd..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,6 +3948,11 @@ "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.", 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_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/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/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 f5ecc879d..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,7 +228,7 @@ class UserController extends BaseController { bool? interactiveGrammar, bool? immersionMode, bool? definitions, - bool? translations, + // bool? translations, bool? showedItInstructions, bool? showedClickMessage, bool? showedBlurMeansTranslate, @@ -281,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, 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 c5d597f57..a6ae5730f 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -59,7 +59,7 @@ enum MatrixProfile { interactiveGrammar, immersionMode, definitions, - translations, + // translations, showedItInstructions, showedClickMessage, showedBlurMeansTranslate, @@ -69,6 +69,7 @@ enum MatrixProfile { sourceLanguage, country, publicProfile, + autoIGC, } extension MatrixProfileExtension on MatrixProfile { @@ -88,8 +89,10 @@ 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: 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/needed-translations.txt b/needed-translations.txt index 4b09cb2ee..e29d36ddd 100644 --- a/needed-translations.txt +++ b/needed-translations.txt @@ -839,6 +839,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -2283,6 +2288,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -3189,6 +3199,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -4095,6 +4110,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -5001,6 +5021,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -5907,6 +5932,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -6760,6 +6790,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -7666,6 +7701,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -8572,6 +8612,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -8584,6 +8629,11 @@ "es": [ "suggestToChat", "suggestToChatDesc", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -9433,6 +9483,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -10282,6 +10337,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -11188,6 +11248,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -12094,6 +12159,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -13000,6 +13070,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -13906,6 +13981,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -14755,6 +14835,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -15661,6 +15746,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -16567,6 +16657,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -17460,6 +17555,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -18366,6 +18466,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -19796,6 +19901,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -20702,6 +20812,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -21608,6 +21723,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -22499,6 +22619,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -23405,6 +23530,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -24311,6 +24441,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -25217,6 +25352,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -26123,6 +26263,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -27029,6 +27174,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -27935,6 +28085,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -28841,6 +28996,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -29747,6 +29907,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -30622,6 +30787,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -31528,6 +31698,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -32434,6 +32609,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -33283,6 +33463,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -34189,6 +34374,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -35095,6 +35285,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -36001,6 +36196,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -36872,6 +37072,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -37778,6 +37983,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -38684,6 +38894,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -39575,6 +39790,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -40424,6 +40644,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -41330,6 +41555,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -42179,6 +42409,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription", @@ -43085,6 +43320,11 @@ "roomDataMissing", "updatePhoneOS", "wordsPerMinute", + "autoIGCToolName", + "autoIGCToolDescription", + "runGrammarCorrection", + "grammarCorrectionFailed", + "grammarCorrectionComplete", "leaveRoomDescription", "archiveSpaceDescription", "leaveSpaceDescription",