diff --git a/assets/l10n/intl_en.arb b/assets/l10n/intl_en.arb index a260274430..706f5adebb 100644 --- a/assets/l10n/intl_en.arb +++ b/assets/l10n/intl_en.arb @@ -2894,21 +2894,23 @@ "type": "text", "placeholders": {} }, - "helpMeTranslate": "Help me translate!", + "helpMeTranslate": "Yes!", "@helpMeTranslate": { "type": "text", "placeholders": {} }, - "needsItShortMessage": "Try interactive translation!", + "needsItShortMessage": "Out of target", "needsIGCShortMessage": "Try interactive grammar assistance!", "@needsItShortMessage": { "type": "text", "placeholders": {} }, - "needsItMessage": "This message has too many words in your base language.", + "needsItMessage": "Wait, that's not {targetLanguage}! Do you need help translating?", "@needsItMessage": { "type": "text", - "placeholders": {} + "placeholders": { + "targetLanguage": {} + } }, "needsIgcMessage": "This message has a grammar error.", "tokenTranslationTitle": "A word is in your base language.", @@ -4069,5 +4071,15 @@ "placeholders": { "currentLanguage": {} } + }, + "interactiveTranslatorAutoPlaySliderHeader": "Autoplay translation", + "@interactiveTranslatorAutoPlaySliderHeader": { + "type": "text", + "placeholders": {} + }, + "interactiveTranslatorAutoPlayDesc": "Launches the interactive translator without asking.", + "@interactiveTranslatorAutoPlayDesc": { + "type": "text", + "placeholders": {} } } \ No newline at end of file diff --git a/assets/l10n/intl_es.arb b/assets/l10n/intl_es.arb index dc328294a3..8631f49afe 100644 --- a/assets/l10n/intl_es.arb +++ b/assets/l10n/intl_es.arb @@ -3064,6 +3064,17 @@ "type": "text", "placeholders": {} }, + "interactiveTranslatorAutoPlaySliderHeader": "Traducción de reproducción automática", + "interactiveTranslatorAutoPlay": "Traductora interactiva de reproducción automática", + "@interactiveTranslatorAutoPlay": { + "type": "text", + "placeholders": {} + }, + "interactiveTranslatorAutoPlayDesc": "Inicia el traductor interactivo sin preguntar.", + "@interactiveTranslatorAutoPlayDesc": { + "type": "text", + "placeholders": {} + }, "grammarAssistance": "Asistencia gramatical", "@grammarAssistance": { "type": "text", @@ -3126,10 +3137,16 @@ "translationSeemsFinished": "La traducción parece estar terminada.", "needsItShortMessage": "¡Pruebe la traducción interactiva!", "needsIGCShortMessage": "¡Pruebe el corrector gramatical interactivo!", - "needsItMessage": "Este mensaje tiene demasiadas palabras en su idioma base.", + "needsItMessage": "Espera, ¡ese no es {targetLanguage}! ¿Necesitas ayuda para traducir?", + "@needsItMessage": { + "type": "text", + "placeholders": { + "targetLanguage": {} + } + }, "needsIgcMessage": "Este mensaje tiene un error gramatical.", "tokenTranslationTitle": "Una palabra está en su idioma base.", - "helpMeTranslate": "¡Ayúdeme a traducir!", + "helpMeTranslate": "¡Sí!", "setToPublicSettingsTitle": "¿Quiere encontrar un compañero de conversación?", "setToPublicSettingsDesc": "Antes de que pueda buscar un compañero de conversación, debe configurar la visibilidad de su perfil como pública.", "publicProfileTitle": "Perfil público", diff --git a/assets/pangea/bot_faces/pangea_bot.riv b/assets/pangea/bot_faces/pangea_bot.riv new file mode 100644 index 0000000000..94244a30f9 Binary files /dev/null and b/assets/pangea/bot_faces/pangea_bot.riv differ diff --git a/lib/pages/chat/chat_input_row.dart b/lib/pages/chat/chat_input_row.dart index 6bf19a850e..852065acba 100644 --- a/lib/pages/chat/chat_input_row.dart +++ b/lib/pages/chat/chat_input_row.dart @@ -1,7 +1,6 @@ import 'package:animations/animations.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; -import 'package:fluffychat/pangea/choreographer/widgets/it_bar.dart'; import 'package:fluffychat/pangea/choreographer/widgets/send_button.dart'; import 'package:fluffychat/pangea/constants/language_keys.dart'; import 'package:fluffychat/utils/platform_infos.dart'; @@ -55,9 +54,6 @@ class ChatInputRow extends StatelessWidget { return Column( children: [ - ITBar( - choreographer: controller.choreographer, - ), Row( // crossAxisAlignment: CrossAxisAlignment.end, crossAxisAlignment: CrossAxisAlignment.center, diff --git a/lib/pages/chat/chat_view.dart b/lib/pages/chat/chat_view.dart index 5ee52c46bf..5b4f966061 100644 --- a/lib/pages/chat/chat_view.dart +++ b/lib/pages/chat/chat_view.dart @@ -24,6 +24,7 @@ import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:go_router/go_router.dart'; import 'package:matrix/matrix.dart'; +import '../../pangea/choreographer/widgets/it_bar.dart'; import '../../utils/stream_extension.dart'; import 'chat_emoji_picker.dart'; import 'chat_input_row.dart'; @@ -440,6 +441,9 @@ class ChatView extends StatelessWidget { mainAxisSize: MainAxisSize.min, children: [ const ConnectionStatusHeader(), + ITBar( + choreographer: controller.choreographer, + ), ReactionsPicker(controller), ReplyDisplay(controller), ChatInputRow(controller), diff --git a/lib/pangea/choreographer/controllers/choreographer.dart b/lib/pangea/choreographer/controllers/choreographer.dart index a0c6a5f6bc..45659a1d0c 100644 --- a/lib/pangea/choreographer/controllers/choreographer.dart +++ b/lib/pangea/choreographer/controllers/choreographer.dart @@ -15,6 +15,7 @@ import 'package:fluffychat/pangea/models/language_detection_model.dart'; import 'package:fluffychat/pangea/models/representation_content_model.dart'; import 'package:fluffychat/pangea/models/space_model.dart'; import 'package:fluffychat/pangea/models/tokens_event_content_model.dart'; +import 'package:fluffychat/pangea/models/user_model.dart'; import 'package:fluffychat/pangea/utils/any_state_holder.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:fluffychat/pangea/utils/overlay.dart'; @@ -522,6 +523,10 @@ class Choreographer { chatController.room, ); + bool get itAutoPlayEnabled => pangeaController.pStoreService.read( + MatrixProfile.itAutoPlay.title, + ) ?? false; + bool get definitionsEnabled => pangeaController.permissionsController.isToolEnabled( ToolSetting.definitions, diff --git a/lib/pangea/choreographer/controllers/igc_controller.dart b/lib/pangea/choreographer/controllers/igc_controller.dart index b882e40875..68d81389e3 100644 --- a/lib/pangea/choreographer/controllers/igc_controller.dart +++ b/lib/pangea/choreographer/controllers/igc_controller.dart @@ -170,6 +170,15 @@ class IgcController { const int firstMatchIndex = 0; final PangeaMatch match = igcTextData!.matches[firstMatchIndex]; + if ( + match.isITStart && + choreographer.itAutoPlayEnabled && + igcTextData != null + ) { + choreographer.onITStart(igcTextData!.matches[firstMatchIndex]); + return; + } + OverlayUtil.showPositionedCard( context: context, cardToShow: SpanCard( @@ -189,7 +198,7 @@ class IgcController { ), roomId: choreographer.roomId, ), - cardSize: match.isITStart ? const Size(350, 220) : const Size(350, 400), + cardSize: match.isITStart ? const Size(350, 260) : const Size(350, 400), transformTargetId: choreographer.inputTransformTargetKey, ); } diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 632db7e9ba..d30732d329 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -21,6 +21,7 @@ class ITController { Choreographer choreographer; bool _isOpen = false; + bool _willOpen = false; bool _isEditingSourceText = false; bool showChoiceFeedback = false; @@ -36,6 +37,7 @@ class ITController { void clear() { _isOpen = false; + _willOpen = false; showChoiceFeedback = false; _isEditingSourceText = false; @@ -54,6 +56,7 @@ class ITController { } Future initializeIT(ITStartData itStartData) async { + _willOpen = true; Future.delayed(const Duration(microseconds: 100), () { _isOpen = true; }); @@ -61,11 +64,9 @@ class ITController { } void closeIT() { - //if they close it before choosing anything, just put their text back + //if they close it before completing, just put their text back //PTODO - explore using last itStep - if (choreographer.currentText.isEmpty) { - choreographer.textController.text = sourceText ?? ""; - } + choreographer.textController.text = sourceText ?? ""; clear(); } @@ -217,31 +218,19 @@ class ITController { Future onEditSourceTextSubmit(String newSourceText) async { try { - sourceText = newSourceText; + + _isOpen = true; _isEditingSourceText = false; - final String currentText = choreographer.currentText; + _itStartData = ITStartData(newSourceText, choreographer.l1LangCode); + completedITSteps = []; + currentITStep = null; + nextITStep = null; + goldRouteTracker = GoldRouteTracker.defaultTracker; + payLoadIds = []; - choreographer.startLoading(); + _setSourceText(); + getTranslationData(false); - final List responses = await Future.wait([ - _customInputTranslation(""), - _customInputTranslation(choreographer.currentText), - ]); - if (responses[0].goldContinuances != null && - responses[0].goldContinuances!.isNotEmpty) { - goldRouteTracker = GoldRouteTracker( - responses[0].goldContinuances!, - sourceText!, - ); - } - currentITStep = CurrentITStep( - sourceText: sourceText!, - currentText: currentText, - responseModel: responses[1], - storedGoldContinuances: goldRouteTracker.continuances, - ); - - _addPayloadId(responses[1]); } catch (err, stack) { debugger(when: kDebugMode); if (err is! http.Response) { @@ -252,6 +241,7 @@ class ITController { ); } finally { choreographer.stopLoading(); + choreographer.textController.text = ""; } } @@ -334,6 +324,8 @@ class ITController { bool get isOpen => _isOpen; + bool get willOpen => _willOpen; + String get targetLangCode => choreographer.l2LangCode!; String get sourceLangCode => choreographer.l1LangCode!; diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index c26fd706d6..adf30dcb1f 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -8,7 +8,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import '../../utils/bot_style.dart'; import 'it_shimmer.dart'; -class ChoicesArray extends StatelessWidget { +class ChoicesArray extends StatefulWidget { final bool isLoading; final List? choices; final void Function(int) onPressed; @@ -32,23 +32,51 @@ class ChoicesArray extends StatelessWidget { this.onLongPress, }); + @override + ChoicesArrayState createState() => ChoicesArrayState(); +} + +class ChoicesArrayState extends State { + bool interactionDisabled = false; + + void disableInteraction() { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + interactionDisabled = true; + }); + }); + } + + void enableInteractions() { + WidgetsBinding.instance.addPostFrameCallback((_) { + setState(() { + interactionDisabled = false; + }); + }); + } + @override Widget build(BuildContext context) { final ThemeData theme = Theme.of(context); - return isLoading && (choices == null || choices!.length <= 1) - ? ItShimmer(originalSpan: originalSpan) + return widget.isLoading && + (widget.choices == null || widget.choices!.length <= 1) + ? ItShimmer(originalSpan: widget.originalSpan) : Wrap( alignment: WrapAlignment.center, - children: choices + children: widget.choices ?.asMap() .entries .map( (entry) => ChoiceItem( theme: theme, - onLongPress: isActive ? onLongPress : null, - onPressed: isActive ? onPressed : (_) {}, + onLongPress: + widget.isActive ? widget.onLongPress : null, + onPressed: widget.isActive ? widget.onPressed : (_) {}, entry: entry, - isSelected: selectedChoiceIndex == entry.key, + interactionDisabled: interactionDisabled, + enableInteraction: enableInteractions, + disableInteraction: disableInteraction, + isSelected: widget.selectedChoiceIndex == entry.key, ), ) .toList() ?? @@ -77,6 +105,9 @@ class ChoiceItem extends StatelessWidget { required this.onPressed, required this.entry, required this.isSelected, + required this.interactionDisabled, + required this.enableInteraction, + required this.disableInteraction, }); final MapEntry entry; @@ -84,6 +115,9 @@ class ChoiceItem extends StatelessWidget { final void Function(int p1)? onLongPress; final void Function(int p1) onPressed; final bool isSelected; + final bool interactionDisabled; + final VoidCallback enableInteraction; + final VoidCallback disableInteraction; @override Widget build(BuildContext context) { @@ -97,6 +131,8 @@ class ChoiceItem extends StatelessWidget { key: ValueKey(entry.value.text), selected: entry.value.color != null, isGold: entry.value.isGold, + enableInteraction: enableInteraction, + disableInteraction: disableInteraction, child: Container( margin: const EdgeInsets.all(2), padding: EdgeInsets.zero, @@ -130,9 +166,11 @@ class ChoiceItem extends StatelessWidget { ), ), ), - onLongPress: - onLongPress != null ? () => onLongPress!(entry.key) : null, - onPressed: () => onPressed(entry.key), + onLongPress: onLongPress != null && !interactionDisabled + ? () => onLongPress!(entry.key) + : null, + onPressed: + interactionDisabled ? null : () => onPressed(entry.key), child: Text( entry.value.text, style: BotStyle.text(context), @@ -152,11 +190,15 @@ class ChoiceAnimationWidget extends StatefulWidget { final Widget child; final bool selected; final bool isGold; + final VoidCallback enableInteraction; + final VoidCallback disableInteraction; const ChoiceAnimationWidget({ super.key, required this.child, required this.selected, + required this.enableInteraction, + required this.disableInteraction, this.isGold = false, }); @@ -164,11 +206,13 @@ class ChoiceAnimationWidget extends StatefulWidget { ChoiceAnimationWidgetState createState() => ChoiceAnimationWidgetState(); } +enum AnimationState { ready, forward, reverse, finished } + class ChoiceAnimationWidgetState extends State with SingleTickerProviderStateMixin { late final AnimationController _controller; late final Animation _animation; - bool animationPlayed = false; + AnimationState animationState = AnimationState.ready; @override void initState() { @@ -196,17 +240,29 @@ class ChoiceAnimationWidgetState extends State ), ]).animate(_controller); - if (widget.selected && !animationPlayed) { + widget.enableInteraction(); + + if (widget.selected && animationState == AnimationState.ready) { + widget.disableInteraction(); _controller.forward(); - animationPlayed = true; - setState(() {}); + setState(() { + animationState = AnimationState.forward; + }); } _controller.addStatusListener((status) { - if (status == AnimationStatus.completed) { + if (status == AnimationStatus.completed && + animationState == AnimationState.forward) { _controller.reverse(); - } else if (status == AnimationStatus.dismissed) { - _controller.stop(); - _controller.reset(); + setState(() { + animationState = AnimationState.reverse; + }); + } + if (status == AnimationStatus.dismissed && + animationState == AnimationState.reverse) { + widget.enableInteraction(); + setState(() { + animationState = AnimationState.finished; + }); } }); } @@ -214,10 +270,12 @@ class ChoiceAnimationWidgetState extends State @override void didUpdateWidget(ChoiceAnimationWidget oldWidget) { super.didUpdateWidget(oldWidget); - if (widget.selected && !animationPlayed) { + if (widget.selected && animationState == AnimationState.ready) { + widget.disableInteraction(); _controller.forward(); - animationPlayed = true; - setState(() {}); + setState(() { + animationState = AnimationState.forward; + }); } } diff --git a/lib/pangea/choreographer/widgets/it_bar.dart b/lib/pangea/choreographer/widgets/it_bar.dart index 4e26cba589..2ba6309007 100644 --- a/lib/pangea/choreographer/widgets/it_bar.dart +++ b/lib/pangea/choreographer/widgets/it_bar.dart @@ -7,6 +7,7 @@ import 'package:fluffychat/pangea/choreographer/widgets/it_feedback_card.dart'; import 'package:fluffychat/pangea/choreographer/widgets/translation_finished_flow.dart'; import 'package:fluffychat/pangea/constants/choreo_constants.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:flutter/cupertino.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; @@ -21,93 +22,107 @@ class ITBar extends StatelessWidget { final Choreographer choreographer; const ITBar({super.key, required this.choreographer}); - ITController get controller => choreographer.itController; + ITController get itController => choreographer.itController; @override Widget build(BuildContext context) { - if (!controller.isOpen) return const SizedBox(); - return CompositedTransformTarget( - link: choreographer.itBarLinkAndKey.link, - child: Container( - key: choreographer.itBarLinkAndKey.key, - decoration: BoxDecoration( - color: Theme.of(context).brightness == Brightness.light - ? Colors.white - : Colors.black, - borderRadius: const BorderRadius.only( - topLeft: Radius.circular(AppConfig.borderRadius), - topRight: Radius.circular(AppConfig.borderRadius), - ), - ), - width: double.infinity, - padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), - child: Stack( - children: [ - SingleChildScrollView( - child: Column( + return AnimatedSize( + duration: itController.willOpen + ? const Duration(milliseconds: 2000) + : const Duration(milliseconds: 500), + curve: Curves.fastOutSlowIn, + clipBehavior: Clip.none, + child: !itController.willOpen + ? const SizedBox() + : CompositedTransformTarget( + link: choreographer.itBarLinkAndKey.link, + child: AnimatedOpacity( + duration: itController.willOpen + ? const Duration(milliseconds: 2000) + : const Duration(milliseconds: 500), + opacity: itController.willOpen ? 1.0 : 0.0, + child: Container( + key: choreographer.itBarLinkAndKey.key, + decoration: BoxDecoration( + color: Theme.of(context).brightness == Brightness.light + ? Colors.white + : Colors.black, + borderRadius: const BorderRadius.only( + topLeft: Radius.circular(AppConfig.borderRadius), + topRight: Radius.circular(AppConfig.borderRadius), + ), + ), + width: double.infinity, + padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), + child: Stack( children: [ - // Row( - // mainAxisAlignment: MainAxisAlignment.spaceBetween, - // crossAxisAlignment: CrossAxisAlignment.start, - // children: [ - // // Row( - // // mainAxisAlignment: MainAxisAlignment.start, - // // crossAxisAlignment: CrossAxisAlignment.start, - // // children: [ - // // CounterDisplay( - // // correct: controller.correctChoices, - // // custom: controller.customChoices, - // // incorrect: controller.incorrectChoices, - // // yellow: controller.wildcardChoices, - // // ), - // // CompositedTransformTarget( - // // link: choreographer.itBotLayerLinkAndKey.link, - // // child: ITBotButton( - // // key: choreographer.itBotLayerLinkAndKey.key, - // // choreographer: choreographer, - // // ), - // // ), - // // ], - // // ), - // ITCloseButton(choreographer: choreographer), - // ], - // ), - // const SizedBox(height: 40.0), - OriginalText(controller: controller), - const SizedBox(height: 7.0), - IntrinsicHeight( - child: Container( - constraints: const BoxConstraints(minHeight: 80), - width: double.infinity, - padding: const EdgeInsets.symmetric(horizontal: 4.0), - child: Center( - child: controller.choreographer.errorService.isError - ? ITError( - error: controller + SingleChildScrollView( + child: Column( + children: [ + // Row( + // mainAxisAlignment: MainAxisAlignment.spaceBetween, + // crossAxisAlignment: CrossAxisAlignment.start, + // children: [ + // // Row( + // // mainAxisAlignment: MainAxisAlignment.start, + // // crossAxisAlignment: CrossAxisAlignment.start, + // // children: [ + // // CounterDisplay( + // // correct: controller.correctChoices, + // // custom: controller.customChoices, + // // incorrect: controller.incorrectChoices, + // // yellow: controller.wildcardChoices, + // // ), + // // CompositedTransformTarget( + // // link: choreographer.itBotLayerLinkAndKey.link, + // // child: ITBotButton( + // // key: choreographer.itBotLayerLinkAndKey.key, + // // choreographer: choreographer, + // // ), + // // ), + // // ], + // // ), + // ITCloseButton(choreographer: choreographer), + // ], + // ), + // const SizedBox(height: 40.0), + OriginalText(controller: itController), + const SizedBox(height: 7.0), + IntrinsicHeight( + child: Container( + constraints: const BoxConstraints(minHeight: 80), + width: double.infinity, + padding: const EdgeInsets.symmetric(horizontal: 4.0), + child: Center( + child: itController.choreographer.errorService.isError + ? ITError( + error: itController .choreographer.errorService.error!, - controller: controller, + controller: itController, + ) + : itController.showChoiceFeedback + ? ChoiceFeedbackText(controller: itController) + : itController.isTranslationDone + ? TranslationFeedback( + controller: itController, ) - : controller.showChoiceFeedback - ? ChoiceFeedbackText(controller: controller) - : controller.isTranslationDone - ? TranslationFeedback( - controller: controller, - ) - : ITChoices(controller: controller), - ), + : ITChoices(controller: itController), + ), + ), + ), + ], ), ), + Positioned( + top: 0.0, + right: 0.0, + child: ITCloseButton(choreographer: choreographer), + ), ], ), ), - Positioned( - top: 0.0, - right: 0.0, - child: ITCloseButton(choreographer: choreographer), - ), - ], - ), + ), ), ); } @@ -184,10 +199,23 @@ class OriginalText extends StatelessWidget { ), ), ), - if (!controller.isEditingSourceText && controller.sourceText != null) - IconButton( - onPressed: () => controller.setIsEditingSourceText(true), - icon: const Icon(Icons.edit_outlined), + if ( + !controller.isEditingSourceText + && controller.sourceText != null + ) + AnimatedOpacity( + duration: const Duration(milliseconds: 500), + opacity: controller.nextITStep != null + ? 1.0 + : 0.0, + child: IconButton( + onPressed: () => { + if (controller.nextITStep != null) { + controller.setIsEditingSourceText(true), + }, + }, + icon: const Icon(Icons.edit_outlined), + ), ), ], ), diff --git a/lib/pangea/choreographer/widgets/it_bar_buttons.dart b/lib/pangea/choreographer/widgets/it_bar_buttons.dart index 815020d176..786c17c07f 100644 --- a/lib/pangea/choreographer/widgets/it_bar_buttons.dart +++ b/lib/pangea/choreographer/widgets/it_bar_buttons.dart @@ -45,7 +45,7 @@ class ITBotButton extends StatelessWidget { ); return IconButton( - icon: const BotFace(width: 40.0, expression: BotExpression.right), + icon: const BotFace(width: 40.0, expression: BotExpression.idle), onPressed: () => choreographer.pangeaController.instructions.show( context, InstructionsEnum.itInstructions, diff --git a/lib/pangea/choreographer/widgets/it_feedback_card.dart b/lib/pangea/choreographer/widgets/it_feedback_card.dart index 072d24e1ad..5424310a86 100644 --- a/lib/pangea/choreographer/widgets/it_feedback_card.dart +++ b/lib/pangea/choreographer/widgets/it_feedback_card.dart @@ -129,7 +129,7 @@ class ITFeedbackCardView extends StatelessWidget { children: [ CardHeader( text: controller.widget.req.chosenContinuance, - botExpression: BotExpression.down, + botExpression: BotExpression.nonGold, ), Text( controller.widget.choiceFeedback, diff --git a/lib/pangea/constants/local.key.dart b/lib/pangea/constants/local.key.dart index 743fe11436..40dd393c53 100644 --- a/lib/pangea/constants/local.key.dart +++ b/lib/pangea/constants/local.key.dart @@ -11,5 +11,6 @@ class PLocalKey { static const String dismissedPaywall = 'dismissedPaywall'; static const String paywallBackoff = 'paywallBackoff'; static const String autoPlayMessages = 'autoPlayMessages'; + static const String itAutoPlay = 'itAutoPlay'; static const String messagesSinceUpdate = 'messagesSinceLastUpdate'; } diff --git a/lib/pangea/controllers/user_controller.dart b/lib/pangea/controllers/user_controller.dart index c7a35b3e86..33d74244a9 100644 --- a/lib/pangea/controllers/user_controller.dart +++ b/lib/pangea/controllers/user_controller.dart @@ -123,6 +123,7 @@ class UserController extends BaseController { : null; final bool? autoPlay = migratedProfileInfo(MatrixProfile.autoPlayMessages); + final bool? itAutoPlay = migratedProfileInfo(MatrixProfile.itAutoPlay); final bool? trial = migratedProfileInfo(MatrixProfile.activatedFreeTrial); final bool? interactiveTranslator = migratedProfileInfo(MatrixProfile.interactiveTranslator); @@ -142,6 +143,7 @@ class UserController extends BaseController { await updateMatrixProfile( dateOfBirth: dob, autoPlayMessages: autoPlay, + itAutoPlay: itAutoPlay, activatedFreeTrial: trial, interactiveTranslator: interactiveTranslator, interactiveGrammar: interactiveGrammar, @@ -223,6 +225,7 @@ class UserController extends BaseController { Future updateMatrixProfile({ String? dateOfBirth, bool? autoPlayMessages, + bool? itAutoPlay, bool? activatedFreeTrial, bool? interactiveTranslator, bool? interactiveGrammar, @@ -251,6 +254,12 @@ class UserController extends BaseController { autoPlayMessages, ); } + if (itAutoPlay != null) { + await _pangeaController.pStoreService.save( + MatrixProfile.itAutoPlay.title, + itAutoPlay, + ); + } if (activatedFreeTrial != null) { await _pangeaController.pStoreService.save( MatrixProfile.activatedFreeTrial.title, diff --git a/lib/pangea/enum/span_data_type.dart b/lib/pangea/enum/span_data_type.dart index 5e4fdf8cbc..38315fd50a 100644 --- a/lib/pangea/enum/span_data_type.dart +++ b/lib/pangea/enum/span_data_type.dart @@ -1,5 +1,5 @@ +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; enum SpanDataTypeEnum { @@ -32,7 +32,10 @@ extension SpanDataTypeEnumExt on SpanDataTypeEnum { case SpanDataTypeEnum.correction: return L10n.of(context)!.correctionDefaultPrompt; case SpanDataTypeEnum.itStart: - return L10n.of(context)!.needsItMessage; + return L10n.of(context)!.needsItMessage( + MatrixState.pangeaController.languageController.userL2?.displayName ?? + L10n.of(context)!.targetLanguage, + ); } } } diff --git a/lib/pangea/models/user_model.dart b/lib/pangea/models/user_model.dart index f8e929a13b..43cd9afb53 100644 --- a/lib/pangea/models/user_model.dart +++ b/lib/pangea/models/user_model.dart @@ -54,6 +54,7 @@ class PUserModel { enum MatrixProfile { dateOfBirth, autoPlayMessages, + itAutoPlay, activatedFreeTrial, interactiveTranslator, interactiveGrammar, @@ -79,6 +80,8 @@ extension MatrixProfileExtension on MatrixProfile { return ModelKey.userDateOfBirth; case MatrixProfile.autoPlayMessages: return PLocalKey.autoPlayMessages; + case MatrixProfile.itAutoPlay: + return PLocalKey.itAutoPlay; case MatrixProfile.activatedFreeTrial: return PLocalKey.activatedTrialKey; case MatrixProfile.interactiveTranslator: diff --git a/lib/pangea/pages/settings_learning/settings_learning_view.dart b/lib/pangea/pages/settings_learning/settings_learning_view.dart index ca337222a5..191bd76db9 100644 --- a/lib/pangea/pages/settings_learning/settings_learning_view.dart +++ b/lib/pangea/pages/settings_learning/settings_learning_view.dart @@ -61,6 +61,16 @@ class SettingsLearningView extends StatelessWidget { pStoreKey: setting.toString(), local: false, ), + PSettingsSwitchListTile.adaptive( + defaultValue: controller.pangeaController.pStoreService.read( + PLocalKey.itAutoPlay, + ) ?? + false, + title: L10n.of(context)!.interactiveTranslatorAutoPlaySliderHeader, + subtitle: L10n.of(context)!.interactiveTranslatorAutoPlayDesc, + pStoreKey: PLocalKey.itAutoPlay, + local: false, + ), PSettingsSwitchListTile.adaptive( defaultValue: controller.pangeaController.pStoreService.read( PLocalKey.autoPlayMessages, diff --git a/lib/pangea/utils/instructions.dart b/lib/pangea/utils/instructions.dart index b9eecd799d..d3a2b0ba0a 100644 --- a/lib/pangea/utils/instructions.dart +++ b/lib/pangea/utils/instructions.dart @@ -74,7 +74,7 @@ class InstructionsController { children: [ CardHeader( text: key.title(context), - botExpression: BotExpression.surprised, + botExpression: BotExpression.idle, onClose: () => {_instructionsClosed[key] = true}, ), const SizedBox(height: 10.0), diff --git a/lib/pangea/utils/match_copy.dart b/lib/pangea/utils/match_copy.dart index 28080f9b5b..86d7843563 100644 --- a/lib/pangea/utils/match_copy.dart +++ b/lib/pangea/utils/match_copy.dart @@ -1,13 +1,13 @@ import 'dart:developer'; +import 'package:fluffychat/pangea/enum/span_data_type.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; - import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:sentry_flutter/sentry_flutter.dart'; -import 'package:fluffychat/pangea/enum/span_data_type.dart'; -import 'package:fluffychat/pangea/utils/error_handler.dart'; import '../constants/match_rule_ids.dart'; import '../models/pangea_match_model.dart'; @@ -96,7 +96,11 @@ class MatchCopy { switch (afterColon) { case MatchRuleIds.interactiveTranslation: title = l10n.needsItShortMessage; - description = l10n.needsItMessage; + description = l10n.needsItMessage( + MatrixState + .pangeaController.languageController.userL2?.displayName ?? + "target language", + ); break; case MatchRuleIds.tokenNeedsTranslation: title = l10n.tokenTranslationTitle; diff --git a/lib/pangea/widgets/chat/message_translation_card.dart b/lib/pangea/widgets/chat/message_translation_card.dart index 3d73106c68..094f481ec6 100644 --- a/lib/pangea/widgets/chat/message_translation_card.dart +++ b/lib/pangea/widgets/chat/message_translation_card.dart @@ -35,9 +35,9 @@ class MessageTranslationCardState extends State { String? translationLangCode() { if (widget.immersionMode) return l1Code; - final String? originalWrittenCode = - widget.messageEvent.originalWritten?.content.langCode; - return (l1Code == originalWrittenCode || originalWrittenCode == null) + final String? originalSentCode = + widget.messageEvent.originalSent?.content.langCode; + return (l1Code == originalSentCode || originalSentCode == null) ? l2Code : l1Code; } diff --git a/lib/pangea/widgets/common/bot_face_svg.dart b/lib/pangea/widgets/common/bot_face_svg.dart index 718f10c901..f387b4bc32 100644 --- a/lib/pangea/widgets/common/bot_face_svg.dart +++ b/lib/pangea/widgets/common/bot_face_svg.dart @@ -1,8 +1,13 @@ import 'package:flutter/material.dart'; +import 'package:rive/rive.dart'; -enum BotExpression { surprised, right, addled, left, down, shocked } +enum BotExpression { gold, nonGold, addled, idle, surprised } + +class BotFace extends StatefulWidget { + final double width; + final Color? forceColor; + final BotExpression expression; -class BotFace extends StatelessWidget { const BotFace({ super.key, required this.width, @@ -10,23 +15,80 @@ class BotFace extends StatelessWidget { this.forceColor, }); - final double width; - final Color? forceColor; - final BotExpression expression; + @override + BotFaceState createState() => BotFaceState(); +} + +class BotFaceState extends State { + Artboard? _artboard; + StateMachineController? _controller; + + @override + void initState() { + super.initState(); + _loadRiveFile(); + } + + double mapExpressionToInput(BotExpression expression) { + switch (expression) { + case BotExpression.gold: + return 1.0; + case BotExpression.nonGold: + return 2.0; + case BotExpression.surprised: + return 3.0; + case BotExpression.addled: + return 4.0; + default: + return 0.0; + } + } + + Future _loadRiveFile() async { + final riveFile = await RiveFile.asset('assets/pangea/bot_faces/pangea_bot.riv'); + + final artboard = riveFile.mainArtboard; + _controller = StateMachineController + .fromArtboard(artboard, 'BotIconStateMachine'); + + if (_controller != null) { + artboard.addController(_controller!); + _controller!.setInputValue( + _controller!.stateMachine.inputs[0].id, + mapExpressionToInput(widget.expression), + ); + } + + setState(() { + _artboard = artboard; + }); + } @override Widget build(BuildContext context) { - return Image.asset( - 'assets/pangea/bot_faces/${expression.toString().split('.').last}.png', - // 'assets/pangea/bot_faces/surprised.png', - width: width, - height: width, - // color: forceColor ?? - // (Theme.of(context).brightness == Brightness.light - // ? Theme.of(context).colorScheme.primary - // : Theme.of(context).colorScheme.primary), + + return SizedBox( + width: widget.width, + height: widget.width, + child: _artboard != null + ? Rive( + artboard: _artboard!, + fit: BoxFit.cover, + ) + : Container(), ); } + + @override + void didUpdateWidget(BotFace oldWidget) { + super.didUpdateWidget(oldWidget); + if (oldWidget.expression != widget.expression) { + _controller!.setInputValue( + _controller!.stateMachine.inputs[0].id, + mapExpressionToInput(widget.expression), + ); + } + } } // extension ParseToString on BotExpressions { diff --git a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart index 8d72a79e89..1c78fd0307 100644 --- a/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart +++ b/lib/pangea/widgets/conversation_bot/conversation_bot_settings.dart @@ -139,7 +139,7 @@ class ConversationBotSettingsState extends State { Theme.of(context).textTheme.bodyLarge!.color, child: const BotFace( width: 30.0, - expression: BotExpression.right, + expression: BotExpression.idle, ), ), trailing: ElevatedButton( diff --git a/lib/pangea/widgets/igc/pangea_text_controller.dart b/lib/pangea/widgets/igc/pangea_text_controller.dart index a40e2cc157..b91186c226 100644 --- a/lib/pangea/widgets/igc/pangea_text_controller.dart +++ b/lib/pangea/widgets/igc/pangea_text_controller.dart @@ -71,6 +71,16 @@ class PangeaTextController extends TextEditingController { choreographer.igc.igcTextData!.getTopMatchIndexForOffset( selection.baseOffset, ); + + // if autoplay on and it start then just start it + if (matchIndex != -1 && + choreographer.itAutoPlayEnabled && + choreographer.igc.igcTextData!.matches[matchIndex].isITStart) { + return choreographer.onITStart( + choreographer.igc.igcTextData!.matches[matchIndex], + ); + } + final Widget? cardToShow = matchIndex != -1 ? SpanCard( scm: SpanCardModel( @@ -100,7 +110,7 @@ class PangeaTextController extends TextEditingController { context: context, cardSize: matchIndex != -1 && choreographer.igc.igcTextData!.matches[matchIndex].isITStart - ? const Size(350, 220) + ? const Size(350, 260) : const Size(350, 400), cardToShow: cardToShow, transformTargetId: choreographer.inputTransformTargetKey, diff --git a/lib/pangea/widgets/igc/span_card.dart b/lib/pangea/widgets/igc/span_card.dart index 6fa4e17b3f..2960d229ce 100644 --- a/lib/pangea/widgets/igc/span_card.dart +++ b/lib/pangea/widgets/igc/span_card.dart @@ -1,6 +1,7 @@ import 'dart:developer'; import 'package:fluffychat/config/app_config.dart'; +import 'package:fluffychat/pangea/constants/local.key.dart'; import 'package:fluffychat/pangea/enum/span_data_type.dart'; import 'package:fluffychat/pangea/models/span_data.dart'; import 'package:fluffychat/pangea/utils/bot_style.dart'; @@ -49,6 +50,8 @@ class SpanCardState extends State { bool fetchingData = false; int? selectedChoiceIndex; + BotExpression currentExpression = BotExpression.nonGold; + //on initState, get SpanDetails @override void initState() { @@ -150,7 +153,23 @@ class WordMatchContent extends StatelessWidget { .choices?[index] .selected = true; - controller.setState(() => ()); + controller.setState( + () => ( + controller.currentExpression = + controller + .widget + .scm + .choreographer + .igc + .igcTextData + !.matches[controller.widget.scm.matchIndex] + .match + .choices![index] + .isBestCorrection + ? BotExpression.gold + : BotExpression.surprised + ), + ); // if (controller.widget.scm.pangeaMatch.match.choices![index].type == // SpanChoiceType.distractor) { // await controller.getSpanDetails(); @@ -192,10 +211,11 @@ class WordMatchContent extends StatelessWidget { try { return Column( children: [ + // if (!controller.widget.scm.pangeaMatch!.isITStart) CardHeader( text: controller.error?.toString() ?? matchCopy.title, botExpression: controller.error == null - ? BotExpression.right + ? controller.currentExpression : BotExpression.addled, ), Expanded( @@ -321,6 +341,10 @@ class WordMatchContent extends StatelessWidget { ), ], ), + if (controller.widget.scm.pangeaMatch!.isITStart) + DontShowSwitchListTile( + controller: pangeaController, + ), ], ); } on Exception catch (e) { @@ -459,3 +483,40 @@ class StartITButton extends StatelessWidget { ); } } + +class DontShowSwitchListTile extends StatefulWidget { + final PangeaController controller; + + const DontShowSwitchListTile({ + super.key, + required this.controller, + }); + + @override + DontShowSwitchListTileState createState() => DontShowSwitchListTileState(); +} + +class DontShowSwitchListTileState extends State { + bool switchValue = false; + + @override + void initState() { + super.initState(); + } + + @override + Widget build(BuildContext context) { + return SwitchListTile.adaptive( + activeColor: AppConfig.activeToggleColor, + title: Text(L10n.of(context)!.interactiveTranslatorAutoPlaySliderHeader), + value: switchValue, + onChanged: (value) => { + widget.controller.pStoreService.save( + PLocalKey.itAutoPlay.toString(), + value, + ), + setState(() => switchValue = value), + }, + ); + } +} diff --git a/lib/pangea/widgets/new_group/vocab_list.dart b/lib/pangea/widgets/new_group/vocab_list.dart index e6c2675e43..240e99a859 100644 --- a/lib/pangea/widgets/new_group/vocab_list.dart +++ b/lib/pangea/widgets/new_group/vocab_list.dart @@ -271,7 +271,7 @@ class GenerateVocabButtonState extends State { ElevatedButton.icon( icon: const BotFace( width: 50.0, - expression: BotExpression.right, + expression: BotExpression.idle, ), label: Text(L10n.of(context)!.generateVocabulary), onPressed: () async { @@ -464,9 +464,9 @@ class PromptsFieldState extends State { // button to call API ElevatedButton.icon( - icon: const BotFace( + icon: BotFace( width: 50.0, - expression: BotExpression.right, + expression: BotExpression.idle, ), label: Text(L10n.of(context)!.generatePrompts), onPressed: () async { diff --git a/needed-translations.txt b/needed-translations.txt index bf58ae3122..16a1df3355 100644 --- a/needed-translations.txt +++ b/needed-translations.txt @@ -868,7 +868,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "be": [ @@ -2373,7 +2375,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "bn": [ @@ -3874,7 +3878,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "bo": [ @@ -5379,7 +5385,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ca": [ @@ -6286,7 +6294,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "cs": [ @@ -7275,7 +7285,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "de": [ @@ -8147,7 +8159,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "el": [ @@ -9603,7 +9617,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "eo": [ @@ -10757,7 +10773,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "es": [ @@ -11649,7 +11667,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "eu": [ @@ -12523,7 +12543,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fa": [ @@ -13534,7 +13556,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fi": [ @@ -14509,7 +14533,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fil": [ @@ -15840,7 +15866,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "fr": [ @@ -16850,7 +16878,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ga": [ @@ -17989,7 +18019,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "gl": [ @@ -18861,7 +18893,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "he": [ @@ -20119,7 +20153,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "hi": [ @@ -21617,7 +21653,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "hr": [ @@ -22568,7 +22606,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "hu": [ @@ -23456,7 +23496,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ia": [ @@ -24947,7 +24989,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "id": [ @@ -25825,7 +25869,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ie": [ @@ -27087,7 +27133,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "it": [ @@ -28016,7 +28064,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ja": [ @@ -29056,7 +29106,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ka": [ @@ -30415,7 +30467,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ko": [ @@ -31289,7 +31343,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "lt": [ @@ -32329,7 +32385,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "lv": [ @@ -33209,7 +33267,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "nb": [ @@ -34413,7 +34473,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "nl": [ @@ -35381,7 +35443,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pl": [ @@ -36358,7 +36422,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pt": [ @@ -37841,7 +37907,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pt_BR": [ @@ -38719,7 +38787,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "pt_PT": [ @@ -39924,7 +39994,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ro": [ @@ -40936,7 +41008,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ru": [ @@ -41814,7 +41888,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sk": [ @@ -43085,7 +43161,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sl": [ @@ -44486,7 +44564,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sr": [ @@ -45661,7 +45741,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "sv": [ @@ -46570,7 +46652,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "ta": [ @@ -48072,7 +48156,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "th": [ @@ -49528,7 +49614,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "tr": [ @@ -50400,7 +50488,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "uk": [ @@ -51309,7 +51399,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "vi": [ @@ -52666,7 +52758,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "zh": [ @@ -53538,7 +53632,9 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ], "zh_Hant": [ @@ -54691,6 +54787,8 @@ "practice", "noLanguagesSet", "noActivitiesFound", - "languageButtonLabel" + "languageButtonLabel", + "interactiveTranslatorAutoPlaySliderHeader", + "interactiveTranslatorAutoPlayDesc" ] } diff --git a/pubspec.lock b/pubspec.lock index c2303486b8..3764281a10 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -999,6 +999,14 @@ packages: url: "https://pub.dev" source: hosted version: "1.0.0" + graphs: + dependency: transitive + description: + name: graphs + sha256: aedc5a15e78fc65a6e23bcd927f24c64dd995062bcd1ca6eda65a3cff92a4d19 + url: "https://pub.dev" + source: hosted + version: "2.3.1" highlighter: dependency: transitive description: @@ -1925,6 +1933,22 @@ packages: url: "https://pub.dev" source: hosted version: "3.1.2" + rive: + dependency: "direct main" + description: + name: rive + sha256: "166019487e8bfa6525d4537bfd494deb4f306e32f97a7f50ff452b44ab6b72ea" + url: "https://pub.dev" + source: hosted + version: "0.11.11" + rive_common: + dependency: transitive + description: + name: rive_common + sha256: "83af8b500ad4d23930397229c7ed520e266eb851690a8621afa6cbd782aeac87" + url: "https://pub.dev" + source: hosted + version: "0.2.3" rxdart: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index ce6ef99dcf..a24dfdff30 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -120,6 +120,7 @@ dependencies: sentry_flutter: ^8.2.0 shimmer: ^3.0.0 syncfusion_flutter_xlsio: ^25.1.40 + rive: 0.11.11 # Pangea# dev_dependencies: