diff --git a/lib/pages/chat/chat.dart b/lib/pages/chat/chat.dart index 025de396d..4f7da0d22 100644 --- a/lib/pages/chat/chat.dart +++ b/lib/pages/chat/chat.dart @@ -28,6 +28,7 @@ import 'package:fluffychat/pages/chat/event_info_dialog.dart'; import 'package:fluffychat/pages/chat/recording_dialog.dart'; import 'package:fluffychat/pages/chat_details/chat_details.dart'; import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart'; +import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart'; import 'package:fluffychat/pangea/analytics_misc/level_up.dart'; import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/chat/utils/unlocked_morphs_snackbar.dart'; @@ -129,8 +130,10 @@ class ChatController extends State // #Pangea final PangeaController pangeaController = MatrixState.pangeaController; late Choreographer choreographer = Choreographer(pangeaController, this); - StreamSubscription? _levelSubscription; late GoRouter _router; + + StreamSubscription? _levelSubscription; + StreamSubscription? _analyticsSubscription; // Pangea# Room get room => sendingClient.getRoomById(roomId) ?? widget.room; @@ -399,6 +402,23 @@ class ChatController extends State } }, ); + + _analyticsSubscription = + pangeaController.getAnalytics.analyticsStream.stream.listen((u) { + if (u.targetID == null) return; + OverlayUtil.showOverlay( + overlayKey: u.targetID, + followerAnchor: Alignment.bottomCenter, + targetAnchor: Alignment.bottomCenter, + context: context, + child: PointsGainedAnimation( + points: u.points, + targetID: u.targetID!, + ), + transformTargetId: u.targetID ?? "", + closePrevOverlay: false, + ); + }); // Pangea# _tryLoadTimeline(); if (kIsWeb) { @@ -645,6 +665,7 @@ class ChatController extends State stopAudioStream.close(); hideTextController.dispose(); _levelSubscription?.cancel(); + _analyticsSubscription?.cancel(); _router.routeInformationProvider.removeListener(_onRouteChanged); //Pangea# super.dispose(); @@ -798,6 +819,7 @@ class ChatController extends State pangeaController.putAnalytics.setState( AnalyticsStream( eventId: msgEventId, + targetID: msgEventId, roomId: room.id, constructs: [ ...originalSent.vocabAndMorphUses( @@ -806,7 +828,6 @@ class ChatController extends State metadata: metadata, ), ], - origin: AnalyticsUpdateOrigin.sendMessage, ), ); } diff --git a/lib/pangea/analytics_misc/gain_points_animation.dart b/lib/pangea/analytics_misc/gain_points_animation.dart index 0e3bf29e7..fb2f53040 100644 --- a/lib/pangea/analytics_misc/gain_points_animation.dart +++ b/lib/pangea/analytics_misc/gain_points_animation.dart @@ -1,24 +1,19 @@ -import 'dart:async'; import 'dart:math'; import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; -import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/bot/utils/bot_style.dart'; import 'package:fluffychat/widgets/matrix.dart'; class PointsGainedAnimation extends StatefulWidget { - final Color? gainColor; - final Color? loseColor; - final AnalyticsUpdateOrigin origin; + final int points; + final String targetID; const PointsGainedAnimation({ super.key, - required this.origin, - this.gainColor = AppConfig.gold, - this.loseColor = Colors.red, + required this.points, + required this.targetID, }); @override @@ -27,25 +22,22 @@ class PointsGainedAnimation extends StatefulWidget { class PointsGainedAnimationState extends State with SingleTickerProviderStateMixin { + final Color? gainColor = AppConfig.gold; + final Color? loseColor = Colors.red; + late AnimationController _controller; late Animation _offsetAnimation; late Animation _fadeAnimation; final List> _swayAnimation = []; - final List _randomSwayOffset = []; final List _particleTrajectories = []; - StreamSubscription? _pointsSubscription; - int? get _prevXP => - MatrixState.pangeaController.getAnalytics.constructListModel.prevXP; - int? get _currentXP => - MatrixState.pangeaController.getAnalytics.constructListModel.totalXP; - int? _addedPoints; - final Random _random = Random(); @override void initState() { super.initState(); + if (widget.points == 0) return; + _controller = AnimationController( duration: const Duration(milliseconds: 2000), vsync: this, @@ -71,14 +63,12 @@ class PointsGainedAnimationState extends State ), ); - _pointsSubscription = MatrixState - .pangeaController.getAnalytics.analyticsStream.stream - .listen(_showPointsGained); + _showPointsGained(); } void initParticleTrajectories() { _particleTrajectories.clear(); - for (int i = 0; i < (_addedPoints?.abs() ?? 0); i++) { + for (int i = 0; i < widget.points.abs(); i++) { final angle = _random.nextDouble() * (pi / 2) + pi / 4; // Random angle in the V-shaped range. const baseSpeed = 20; // Initial base speed. @@ -93,10 +83,9 @@ class PointsGainedAnimationState extends State void initSwayAnimations() { _swayAnimation.clear(); - _randomSwayOffset.clear(); initParticleTrajectories(); - for (int i = 0; i < (_addedPoints ?? 0); i++) { + for (int i = 0; i < widget.points; i++) { _swayAnimation.add( Tween( begin: 0.0, @@ -108,41 +97,41 @@ class PointsGainedAnimationState extends State ), ), ); - _randomSwayOffset.add(_random.nextDouble() * 2 * pi); } } @override void dispose() { _controller.dispose(); - _pointsSubscription?.cancel(); super.dispose(); } - void _showPointsGained(AnalyticsStreamUpdate update) { - if (update.origin != widget.origin) return; - setState(() => _addedPoints = (_currentXP ?? 0) - (_prevXP ?? 0)); - if (_prevXP != _currentXP) { - initSwayAnimations(); - _controller.reset(); - _controller.forward(); - } + void _showPointsGained() { + initSwayAnimations(); + _controller.reset(); + _controller.forward().then( + (_) { + if (!mounted) return; + MatrixState.pAnyState.closeOverlay(widget.targetID); + }, + ); } - bool get animate => - _currentXP != null && - _prevXP != null && - _addedPoints != null && - _prevXP! != _currentXP!; - @override Widget build(BuildContext context) { - if (!animate) return const SizedBox(); + if (widget.points == 0) { + WidgetsBinding.instance.addPostFrameCallback((_) { + if (mounted) { + MatrixState.pAnyState.closeOverlay(widget.targetID); + } + }); + return const SizedBox(); + } - final textColor = _addedPoints! > 0 ? widget.gainColor : widget.loseColor; + final textColor = widget.points > 0 ? gainColor : loseColor; final plusWidget = Text( - _addedPoints! > 0 ? "+" : "-", + widget.points > 0 ? "+" : "-", style: BotStyle.text( context, big: true, @@ -153,29 +142,32 @@ class PointsGainedAnimationState extends State ), ); - return SlideTransition( - position: _offsetAnimation, - child: FadeTransition( - opacity: _fadeAnimation, - child: IgnorePointer( - ignoring: _controller.isAnimating, - child: Stack( - children: List.generate(_addedPoints!.abs(), (index) { - return AnimatedBuilder( - animation: _controller, - builder: (context, child) { - final progress = _controller.value; - final trajectory = _particleTrajectories[index]; - return Transform.translate( - offset: Offset( - trajectory.dx * pow(progress, 2), - trajectory.dy * pow(progress, 2), - ), - child: plusWidget, - ); - }, - ); - }), + return Material( + type: MaterialType.transparency, + child: SlideTransition( + position: _offsetAnimation, + child: FadeTransition( + opacity: _fadeAnimation, + child: IgnorePointer( + ignoring: _controller.isAnimating, + child: Stack( + children: List.generate(widget.points.abs(), (index) { + return AnimatedBuilder( + animation: _controller, + builder: (context, child) { + final progress = _controller.value; + final trajectory = _particleTrajectories[index]; + return Transform.translate( + offset: Offset( + trajectory.dx * pow(progress, 2), + trajectory.dy * pow(progress, 2), + ), + child: plusWidget, + ); + }, + ); + }), + ), ), ), ), diff --git a/lib/pangea/analytics_misc/get_analytics_controller.dart b/lib/pangea/analytics_misc/get_analytics_controller.dart index 2f1d125dc..ccbf2a8fa 100644 --- a/lib/pangea/analytics_misc/get_analytics_controller.dart +++ b/lib/pangea/analytics_misc/get_analytics_controller.dart @@ -109,7 +109,7 @@ class GetAnalyticsController extends BaseController { data: {}, ); } finally { - _updateAnalyticsStream(); + _updateAnalyticsStream(points: 0); if (!initCompleter.isCompleted) initCompleter.complete(); _initializing = false; } @@ -154,7 +154,13 @@ class GetAnalyticsController extends BaseController { if (newUnlockedMorphs.isNotEmpty) { _onUnlockMorphLemmas(newUnlockedMorphs); } - _updateAnalyticsStream(origin: analyticsUpdate.origin); + _updateAnalyticsStream( + points: analyticsUpdate.newConstructs.fold( + 0, + (previousValue, element) => previousValue + element.pointValue, + ), + targetID: analyticsUpdate.targetID, + ); // Update public profile each time that new analytics are added. // If the level hasn't changed, this will not send an update to the server. // Do this on all updates (not just on level updates) to account for cases @@ -165,9 +171,15 @@ class GetAnalyticsController extends BaseController { } void _updateAnalyticsStream({ - AnalyticsUpdateOrigin? origin, + required int points, + String? targetID, }) => - analyticsStream.add(AnalyticsStreamUpdate(origin: origin)); + analyticsStream.add( + AnalyticsStreamUpdate( + points: points, + targetID: targetID, + ), + ); Future _onLevelUp(final int lowerLevel, final int upperLevel) async { final result = await _generateLevelUpAnalyticsAndSaveToStateEvent( @@ -484,9 +496,11 @@ class AnalyticsCacheEntry { } class AnalyticsStreamUpdate { - final AnalyticsUpdateOrigin? origin; + final int points; + final String? targetID; AnalyticsStreamUpdate({ - this.origin, + required this.points, + this.targetID, }); } diff --git a/lib/pangea/analytics_misc/put_analytics_controller.dart b/lib/pangea/analytics_misc/put_analytics_controller.dart index 693792d47..7a7110e64 100644 --- a/lib/pangea/analytics_misc/put_analytics_controller.dart +++ b/lib/pangea/analytics_misc/put_analytics_controller.dart @@ -144,7 +144,7 @@ class PutAnalyticsController extends BaseController { if (roomID != null) _clearDraftUses(roomID); _decideWhetherToUpdateAnalyticsRoom( level, - data.origin, + data.targetID, data.constructs, ); }, @@ -164,9 +164,9 @@ class PutAnalyticsController extends BaseController { void addDraftUses( List tokens, String roomID, - ConstructUseTypeEnum useType, - AnalyticsUpdateOrigin origin, - ) { + ConstructUseTypeEnum useType, { + String? targetID, + }) { final metadata = ConstructUseMetaData( roomId: roomID, timeStamp: DateTime.now(), @@ -230,7 +230,11 @@ class PutAnalyticsController extends BaseController { // so copy it here to that the list of new uses is accurate final List newUses = List.from(uses); _addLocalMessage('draft$roomID', uses).then( - (_) => _decideWhetherToUpdateAnalyticsRoom(level, origin, newUses), + (_) => _decideWhetherToUpdateAnalyticsRoom( + level, + targetID, + newUses, + ), ); } @@ -287,7 +291,7 @@ class PutAnalyticsController extends BaseController { /// Otherwise, add a local update to the alert stream. void _decideWhetherToUpdateAnalyticsRoom( int prevLevel, - AnalyticsUpdateOrigin? origin, + String? targetID, List newConstructs, ) { // cancel the last timer that was set on message event and @@ -308,7 +312,7 @@ class PutAnalyticsController extends BaseController { AnalyticsUpdate( AnalyticsUpdateType.local, newConstructs, - origin: origin, + targetID: targetID, ), ); } @@ -426,7 +430,7 @@ class PutAnalyticsController extends BaseController { class AnalyticsStream { final String? eventId; final String? roomId; - final AnalyticsUpdateOrigin? origin; + final String? targetID; final List constructs; @@ -434,29 +438,20 @@ class AnalyticsStream { required this.eventId, required this.roomId, required this.constructs, - this.origin, + this.targetID, }); } -enum AnalyticsUpdateOrigin { - it, - igc, - sendMessage, - practiceActivity, - inputBar, - wordZoom, -} - class AnalyticsUpdate { final AnalyticsUpdateType type; - final AnalyticsUpdateOrigin? origin; final List newConstructs; final bool isLogout; + final String? targetID; AnalyticsUpdate( this.type, this.newConstructs, { this.isLogout = false, - this.origin, + this.targetID, }); } diff --git a/lib/pangea/chat/widgets/chat_input_bar_header.dart b/lib/pangea/chat/widgets/chat_input_bar_header.dart index 274c26da1..cc3408790 100644 --- a/lib/pangea/chat/widgets/chat_input_bar_header.dart +++ b/lib/pangea/chat/widgets/chat_input_bar_header.dart @@ -1,10 +1,7 @@ import 'package:flutter/material.dart'; -import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; import 'package:fluffychat/pages/chat/chat.dart'; -import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/chat/widgets/chat_floating_action_button.dart'; class ChatInputBarHeader extends StatelessWidget { @@ -35,11 +32,6 @@ class ChatInputBarHeader extends StatelessWidget { child: Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - const PointsGainedAnimation( - gainColor: AppConfig.gold, - origin: AnalyticsUpdateOrigin.sendMessage, - ), - const SizedBox(width: 100), ChatFloatingActionButton( controller: controller, ), diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 6e6580f36..2eb738c1f 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -8,7 +8,6 @@ import 'package:http/http.dart' as http; import 'package:sentry_flutter/sentry_flutter.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart'; import 'package:fluffychat/pangea/choreographer/controllers/error_service.dart'; import 'package:fluffychat/pangea/choreographer/enums/edit_type.dart'; @@ -333,7 +332,6 @@ class ITController { ignoredTokens ?? [], choreographer.roomId, ConstructUseTypeEnum.ignIt, - AnalyticsUpdateOrigin.it, ); Future.delayed( diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index 3db3a43ed..ea1c87d66 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -9,6 +9,7 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart'; +import 'package:fluffychat/widgets/matrix.dart'; import '../../bot/utils/bot_style.dart'; import 'it_shimmer.dart'; @@ -29,7 +30,6 @@ class ChoicesArray extends StatefulWidget { final ChoiceCallback? onLongPress; final int? selectedChoiceIndex; final String originalSpan; - final String Function(int) uniqueKeyForLayerLink; /// If null then should not be used /// We don't want tts in the case of L1 options @@ -60,7 +60,6 @@ class ChoicesArray extends StatefulWidget { required this.choices, required this.onPressed, required this.originalSpan, - required this.uniqueKeyForLayerLink, required this.selectedChoiceIndex, required this.tts, this.enableAudio = true, @@ -214,60 +213,68 @@ class ChoiceItem extends StatelessWidget { waitDuration: onLongPress != null ? const Duration(milliseconds: 500) : const Duration(days: 1), - child: ChoiceAnimationWidget( - key: ValueKey("${entry.value.text}$id"), - selected: entry.value.color != null, - isGold: entry.value.isGold, - enableInteraction: enableInteraction, - disableInteraction: disableInteraction, - child: Container( - margin: const EdgeInsets.all(2), - padding: EdgeInsets.zero, - decoration: BoxDecoration( - borderRadius: const BorderRadius.all( - Radius.circular(AppConfig.borderRadius), + child: CompositedTransformTarget( + link: MatrixState.pAnyState + .layerLinkAndKey("${entry.value.text}$id") + .link, + child: ChoiceAnimationWidget( + key: MatrixState.pAnyState + .layerLinkAndKey("${entry.value.text}$id") + .key, + selected: entry.value.color != null, + isGold: entry.value.isGold, + enableInteraction: enableInteraction, + disableInteraction: disableInteraction, + child: Container( + margin: const EdgeInsets.all(2), + padding: EdgeInsets.zero, + decoration: BoxDecoration( + borderRadius: const BorderRadius.all( + Radius.circular(AppConfig.borderRadius), + ), + border: Border.all( + color: isSelected + ? entry.value.color ?? theme.colorScheme.primary + : Colors.transparent, + style: BorderStyle.solid, + width: 2.0, + ), ), - border: Border.all( - color: isSelected - ? entry.value.color ?? theme.colorScheme.primary - : Colors.transparent, - style: BorderStyle.solid, - width: 2.0, - ), - ), - child: TextButton( - style: ButtonStyle( - padding: WidgetStateProperty.all( - const EdgeInsets.symmetric(horizontal: 8, vertical: 4), - ), - //if index is selected, then give the background a slight primary color - backgroundColor: WidgetStateProperty.all( - entry.value.color?.withAlpha(50) ?? - theme.colorScheme.primary.withAlpha(10), - ), - textStyle: WidgetStateProperty.all( - BotStyle.text(context), - ), - shape: WidgetStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(AppConfig.borderRadius), + child: TextButton( + style: ButtonStyle( + padding: WidgetStateProperty.all( + const EdgeInsets.symmetric(horizontal: 8, vertical: 4), + ), + //if index is selected, then give the background a slight primary color + backgroundColor: WidgetStateProperty.all( + entry.value.color?.withAlpha(50) ?? + theme.colorScheme.primary.withAlpha(10), + ), + textStyle: WidgetStateProperty.all( + BotStyle.text(context), + ), + shape: WidgetStateProperty.all( + RoundedRectangleBorder( + borderRadius: + BorderRadius.circular(AppConfig.borderRadius), + ), ), ), - ), - onLongPress: onLongPress != null && !interactionDisabled - ? () => onLongPress!(entry.value.text, entry.key) - : null, - onPressed: interactionDisabled - ? null - : () => onPressed(entry.value.text, entry.key), - child: Text( - getDisplayCopy != null - ? getDisplayCopy!(entry.value.text) - : entry.value.text, - style: BotStyle.text(context).copyWith( - fontSize: fontSize, + onLongPress: onLongPress != null && !interactionDisabled + ? () => onLongPress!(entry.value.text, entry.key) + : null, + onPressed: interactionDisabled + ? null + : () => onPressed(entry.value.text, entry.key), + child: Text( + getDisplayCopy != null + ? getDisplayCopy!(entry.value.text) + : entry.value.text, + style: BotStyle.text(context).copyWith( + fontSize: fontSize, + ), + textAlign: TextAlign.center, ), - textAlign: TextAlign.center, ), ), ), diff --git a/lib/pangea/choreographer/widgets/igc/span_card.dart b/lib/pangea/choreographer/widgets/igc/span_card.dart index 2125e11cf..135936e31 100644 --- a/lib/pangea/choreographer/widgets/igc/span_card.dart +++ b/lib/pangea/choreographer/widgets/igc/span_card.dart @@ -7,8 +7,6 @@ import 'package:flutter_gen/gen_l10n/l10n.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart'; -import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/bot/utils/bot_style.dart'; import 'package:fluffychat/pangea/choreographer/enums/span_data_type.dart'; import 'package:fluffychat/pangea/choreographer/models/span_data.dart'; @@ -150,7 +148,7 @@ class SpanCardState extends State { } } - Future onChoiceSelect(String value, int index) async { + Future onChoiceSelect(int index) async { selectedChoiceIndex = index; if (selectedChoice != null) { if (!selectedChoice!.selected) { @@ -160,7 +158,8 @@ class SpanCardState extends State { selectedChoice!.isBestCorrection ? ConstructUseTypeEnum.corIGC : ConstructUseTypeEnum.incIGC, - AnalyticsUpdateOrigin.igc, + targetID: + "${selectedChoice!.value}${widget.scm.pangeaMatch?.hashCode.toString()}", ); } @@ -191,7 +190,6 @@ class SpanCardState extends State { ignoredTokens ?? [], widget.roomId, ConstructUseTypeEnum.ignIGC, - AnalyticsUpdateOrigin.igc, ); } @@ -261,156 +259,143 @@ class WordMatchContent extends StatelessWidget { final ScrollController scrollController = ScrollController(); try { - return Stack( - alignment: Alignment.topCenter, + return Column( children: [ - const Positioned( - top: 40, - child: PointsGainedAnimation( - origin: AnalyticsUpdateOrigin.igc, + // if (!controller.widget.scm.pangeaMatch!.isITStart) + CardHeader( + text: controller.error?.toString() ?? matchCopy.title, + botExpression: controller.error == null + ? controller.currentExpression + : BotExpression.addled, + ), + Scrollbar( + controller: scrollController, + thumbVisibility: true, + child: SingleChildScrollView( + controller: scrollController, + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.stretch, + children: [ + // const SizedBox(height: 10.0), + // if (matchCopy.description != null) + // Padding( + // padding: const EdgeInsets.only(), + // child: Text( + // matchCopy.description!, + // style: BotStyle.text(context), + // ), + // ), + const SizedBox(height: 8), + if (!controller.widget.scm.pangeaMatch!.isITStart) + ChoicesArray( + originalSpan: + controller.widget.scm.pangeaMatch!.matchContent, + isLoading: controller.fetchingData, + choices: controller.widget.scm.pangeaMatch!.match.choices + ?.map( + (e) => Choice( + text: e.value, + color: e.selected ? e.type.color : null, + isGold: e.type.name == 'bestCorrection', + ), + ) + .toList(), + onPressed: (value, index) => + controller.onChoiceSelect(index), + selectedChoiceIndex: controller.selectedChoiceIndex, + tts: controller.tts, + id: controller.widget.scm.pangeaMatch!.hashCode + .toString(), + ), + const SizedBox(height: 12), + PromptAndFeedback(controller: controller), + ], + ), ), ), - Column( + Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [ - // if (!controller.widget.scm.pangeaMatch!.isITStart) - CardHeader( - text: controller.error?.toString() ?? matchCopy.title, - botExpression: controller.error == null - ? controller.currentExpression - : BotExpression.addled, - ), - Scrollbar( - controller: scrollController, - thumbVisibility: true, - child: SingleChildScrollView( - controller: scrollController, - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.stretch, - children: [ - // const SizedBox(height: 10.0), - // if (matchCopy.description != null) - // Padding( - // padding: const EdgeInsets.only(), - // child: Text( - // matchCopy.description!, - // style: BotStyle.text(context), - // ), - // ), - const SizedBox(height: 8), - if (!controller.widget.scm.pangeaMatch!.isITStart) - ChoicesArray( - originalSpan: - controller.widget.scm.pangeaMatch!.matchContent, - isLoading: controller.fetchingData, - choices: - controller.widget.scm.pangeaMatch!.match.choices - ?.map( - (e) => Choice( - text: e.value, - color: e.selected ? e.type.color : null, - isGold: e.type.name == 'bestCorrection', - ), - ) - .toList(), - onPressed: controller.onChoiceSelect, - uniqueKeyForLayerLink: (int index) => - "wordMatch$index", - selectedChoiceIndex: controller.selectedChoiceIndex, - tts: controller.tts, - ), - const SizedBox(height: 12), - PromptAndFeedback(controller: controller), - ], + const SizedBox(width: 10), + Expanded( + child: Opacity( + opacity: 0.8, + child: TextButton( + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + Theme.of(context).colorScheme.primary.withAlpha(25), + ), + ), + onPressed: controller.onIgnoreMatch, + child: Center( + child: Text(L10n.of(context).ignoreInThisText), + ), ), ), ), - Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - children: [ - const SizedBox(width: 10), - Expanded( - child: Opacity( - opacity: 0.8, - child: TextButton( - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - Theme.of(context).colorScheme.primary.withAlpha(25), - ), - ), - onPressed: controller.onIgnoreMatch, - child: Center( - child: Text(L10n.of(context).ignoreInThisText), + const SizedBox(width: 10), + if (!controller.widget.scm.pangeaMatch!.isITStart) + Expanded( + child: Opacity( + opacity: controller.selectedChoiceIndex != null ? 1.0 : 0.5, + child: TextButton( + onPressed: controller.selectedChoiceIndex != null + ? controller.onReplaceSelected + : null, + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + (controller.selectedChoice != null + ? controller.selectedChoice!.color + : Theme.of(context).colorScheme.primary) + .withAlpha(50), ), + // Outline if Replace button enabled + side: controller.selectedChoice != null + ? WidgetStateProperty.all( + BorderSide( + color: controller.selectedChoice!.color, + style: BorderStyle.solid, + width: 2.0, + ), + ) + : null, ), + child: Text(L10n.of(context).replace), ), ), - const SizedBox(width: 10), - if (!controller.widget.scm.pangeaMatch!.isITStart) - Expanded( - child: Opacity( - opacity: - controller.selectedChoiceIndex != null ? 1.0 : 0.5, - child: TextButton( - onPressed: controller.selectedChoiceIndex != null - ? controller.onReplaceSelected - : null, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - (controller.selectedChoice != null - ? controller.selectedChoice!.color - : Theme.of(context).colorScheme.primary) - .withAlpha(50), - ), - // Outline if Replace button enabled - side: controller.selectedChoice != null - ? WidgetStateProperty.all( - BorderSide( - color: controller.selectedChoice!.color, - style: BorderStyle.solid, - width: 2.0, - ), - ) - : null, - ), - child: Text(L10n.of(context).replace), - ), + ), + const SizedBox(width: 10), + if (controller.widget.scm.pangeaMatch!.isITStart) + Expanded( + child: TextButton( + onPressed: () { + MatrixState.pAnyState.closeOverlay(); + Future.delayed( + Duration.zero, + () => controller.widget.scm.onITStart(), + ); + }, + style: ButtonStyle( + backgroundColor: WidgetStateProperty.all( + (Theme.of(context).colorScheme.primary).withAlpha(25), ), ), - const SizedBox(width: 10), - if (controller.widget.scm.pangeaMatch!.isITStart) - Expanded( - child: TextButton( - onPressed: () { - MatrixState.pAnyState.closeOverlay(); - Future.delayed( - Duration.zero, - () => controller.widget.scm.onITStart(), - ); - }, - style: ButtonStyle( - backgroundColor: WidgetStateProperty.all( - (Theme.of(context).colorScheme.primary) - .withAlpha(25), - ), - ), - child: Text(L10n.of(context).helpMeTranslate), - ), - ), - ], - ), - // if (controller.widget.scm.pangeaMatch!.isITStart) - // DontShowSwitchListTile( - // controller: pangeaController, - // onSwitch: (bool value) { - // pangeaController.userController.updateProfile((profile) { - // profile.userSettings.itAutoPlay = value; - // return profile; - // }); - // }, - // ), + child: Text(L10n.of(context).helpMeTranslate), + ), + ), ], ), + // if (controller.widget.scm.pangeaMatch!.isITStart) + // DontShowSwitchListTile( + // controller: pangeaController, + // onSwitch: (bool value) { + // pangeaController.userController.updateProfile((profile) { + // profile.userSettings.itAutoPlay = value; + // return profile; + // }); + // }, + // ), ], ); } on Exception catch (e) { diff --git a/lib/pangea/choreographer/widgets/it_bar.dart b/lib/pangea/choreographer/widgets/it_bar.dart index 537d829f2..cde32a074 100644 --- a/lib/pangea/choreographer/widgets/it_bar.dart +++ b/lib/pangea/choreographer/widgets/it_bar.dart @@ -5,8 +5,6 @@ import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart'; -import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/choreographer/constants/choreo_constants.dart'; import 'package:fluffychat/pangea/choreographer/controllers/choreographer.dart'; import 'package:fluffychat/pangea/choreographer/controllers/it_controller.dart'; @@ -111,142 +109,130 @@ class ITBarState extends State with SingleTickerProviderStateMixin { : Colors.black, ), padding: const EdgeInsets.fromLTRB(0, 3, 3, 3), - child: Stack( - alignment: Alignment.topCenter, - children: [ - SingleChildScrollView( - child: Column( + child: SingleChildScrollView( + child: Column( + children: [ + Row( + mainAxisAlignment: MainAxisAlignment.end, + crossAxisAlignment: CrossAxisAlignment.center, children: [ - Row( - mainAxisAlignment: MainAxisAlignment.end, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - if (itController.isEditingSourceText) - Expanded( - child: Padding( - padding: const EdgeInsets.only( - left: 20, - right: 10, - top: 10, - ), - child: TextField( - controller: TextEditingController( - text: itController.sourceText, - ), - autofocus: true, - enableSuggestions: false, - maxLines: null, - textInputAction: TextInputAction.send, - onSubmitted: - itController.onEditSourceTextSubmit, - obscureText: false, - decoration: const InputDecoration( - border: OutlineInputBorder(), - ), - ), - ), + if (itController.isEditingSourceText) + Expanded( + child: Padding( + padding: const EdgeInsets.only( + left: 20, + right: 10, + top: 10, ), - if (!itController.isEditingSourceText && - itController.sourceText != null) - SizedBox( - width: iconDimension, - height: iconDimension, - child: IconButton( - iconSize: iconSize, - color: Theme.of(context).colorScheme.primary, - onPressed: () { - if (itController.nextITStep != null) { - itController.setIsEditingSourceText(true); - } - }, - icon: const Icon(Icons.edit_outlined), - // iconSize: 20, + child: TextField( + controller: TextEditingController( + text: itController.sourceText, ), - ), - if (!itController.isEditingSourceText) - SizedBox( - width: iconDimension, - height: iconDimension, - child: IconButton( - iconSize: iconSize, - color: Theme.of(context).colorScheme.primary, - icon: const Icon(Icons.settings_outlined), - onPressed: () => showDialog( - context: context, - builder: (c) => const SettingsLearning(), - barrierDismissible: false, - ), + autofocus: true, + enableSuggestions: false, + maxLines: null, + textInputAction: TextInputAction.send, + onSubmitted: itController.onEditSourceTextSubmit, + obscureText: false, + decoration: const InputDecoration( + border: OutlineInputBorder(), ), ), - SizedBox( - width: iconDimension, - height: iconDimension, - child: IconButton( - iconSize: iconSize, - color: Theme.of(context).colorScheme.primary, - icon: const Icon(Icons.close_outlined), - onPressed: () { - itController.isEditingSourceText - ? itController.setIsEditingSourceText(false) - : itController.closeIT(); - }, - ), ), - ], - ), + ), + if (!itController.isEditingSourceText && + itController.sourceText != null) + SizedBox( + width: iconDimension, + height: iconDimension, + child: IconButton( + iconSize: iconSize, + color: Theme.of(context).colorScheme.primary, + onPressed: () { + if (itController.nextITStep != null) { + itController.setIsEditingSourceText(true); + } + }, + icon: const Icon(Icons.edit_outlined), + // iconSize: 20, + ), + ), if (!itController.isEditingSourceText) - Padding( - padding: const EdgeInsets.only(top: 8.0), - child: itController.sourceText != null - ? Text( - itController.sourceText!, - textAlign: TextAlign.center, - ) - : const LinearProgressIndicator(), - ), - const SizedBox(height: 8.0), - if (showITInstructionsTooltip) - const InstructionsInlineTooltip( - instructionsEnum: InstructionsEnum.clickBestOption, - ), - if (showTranslationsChoicesTooltip) - const InstructionsInlineTooltip( - instructionsEnum: InstructionsEnum.translationChoices, - ), - Container( - padding: const EdgeInsets.symmetric(horizontal: 4.0), - constraints: const BoxConstraints(minHeight: 80), - child: AnimatedSize( - duration: itController.animationSpeed, - child: Center( - child: itController.choreographer.errorService.isError - ? ITError( - error: itController - .choreographer.errorService.error!, - controller: itController, - ) - : itController.showChoiceFeedback - ? ChoiceFeedbackText( - controller: itController, - ) - : itController.isTranslationDone - ? TranslationFeedback( - controller: itController, - ) - : ITChoices(controller: itController), + SizedBox( + width: iconDimension, + height: iconDimension, + child: IconButton( + iconSize: iconSize, + color: Theme.of(context).colorScheme.primary, + icon: const Icon(Icons.settings_outlined), + onPressed: () => showDialog( + context: context, + builder: (c) => const SettingsLearning(), + barrierDismissible: false, + ), ), ), + SizedBox( + width: iconDimension, + height: iconDimension, + child: IconButton( + iconSize: iconSize, + color: Theme.of(context).colorScheme.primary, + icon: const Icon(Icons.close_outlined), + onPressed: () { + itController.isEditingSourceText + ? itController.setIsEditingSourceText(false) + : itController.closeIT(); + }, + ), ), ], ), - ), - const Positioned( - top: 60, - child: PointsGainedAnimation( - origin: AnalyticsUpdateOrigin.it, + if (!itController.isEditingSourceText) + Padding( + padding: const EdgeInsets.only(top: 8.0), + child: itController.sourceText != null + ? Text( + itController.sourceText!, + textAlign: TextAlign.center, + ) + : const LinearProgressIndicator(), + ), + const SizedBox(height: 8.0), + if (showITInstructionsTooltip) + const InstructionsInlineTooltip( + instructionsEnum: InstructionsEnum.clickBestOption, + ), + if (showTranslationsChoicesTooltip) + const InstructionsInlineTooltip( + instructionsEnum: InstructionsEnum.translationChoices, + ), + Container( + padding: const EdgeInsets.symmetric(horizontal: 4.0), + constraints: const BoxConstraints(minHeight: 80), + child: AnimatedSize( + duration: itController.animationSpeed, + child: Center( + child: itController.choreographer.errorService.isError + ? ITError( + error: itController + .choreographer.errorService.error!, + controller: itController, + ) + : itController.showChoiceFeedback + ? ChoiceFeedbackText( + controller: itController, + ) + : itController.isTranslationDone + ? TranslationFeedback( + controller: itController, + ) + : ITChoices(controller: itController), + ), + ), ), - ), - ], + ], + ), ), ), ), @@ -390,7 +376,8 @@ class ITChoices extends StatelessWidget { continuance.level > 1 ? ConstructUseTypeEnum.incIt : ConstructUseTypeEnum.corIt, - AnalyticsUpdateOrigin.it, + targetID: + "${continuance.text.trim()}${controller.currentITStep.hashCode.toString()}", ); } controller.currentITStep!.continuances[index].wasClicked = true; @@ -430,7 +417,6 @@ class ITChoices extends StatelessWidget { }).toList(), onPressed: (value, index) => selectContinuance(index, context), onLongPress: (value, index) => showCard(context, index), - uniqueKeyForLayerLink: (int index) => "itChoices$index", selectedChoiceIndex: null, tts: controller.choreographer.tts, ); diff --git a/lib/pangea/choreographer/widgets/translation_finished_flow.dart b/lib/pangea/choreographer/widgets/translation_finished_flow.dart index e9e322854..d7a8d273a 100644 --- a/lib/pangea/choreographer/widgets/translation_finished_flow.dart +++ b/lib/pangea/choreographer/widgets/translation_finished_flow.dart @@ -87,7 +87,6 @@ class AlternativeTranslations extends StatelessWidget { controller.choreographer.altTranslator.translations[index], ); }, - uniqueKeyForLayerLink: (int index) => "altTranslation$index", selectedChoiceIndex: null, tts: null, ); diff --git a/lib/pangea/common/utils/any_state_holder.dart b/lib/pangea/common/utils/any_state_holder.dart index 94a1682ca..ddfdce0a8 100644 --- a/lib/pangea/common/utils/any_state_holder.dart +++ b/lib/pangea/common/utils/any_state_holder.dart @@ -51,7 +51,6 @@ class PangeaAnyState { void openOverlay( OverlayEntry entry, BuildContext context, { - bool closePrevOverlay = true, String? overlayKey, }) { if (overlayKey != null && @@ -59,9 +58,6 @@ class PangeaAnyState { return; } - if (closePrevOverlay) { - closeOverlay(); - } entries.add(OverlayListEntry(entry, key: overlayKey)); Overlay.of(context).insert(entry); } diff --git a/lib/pangea/common/utils/overlay.dart b/lib/pangea/common/utils/overlay.dart index d626b3dd2..612f47dcc 100644 --- a/lib/pangea/common/utils/overlay.dart +++ b/lib/pangea/common/utils/overlay.dart @@ -77,7 +77,6 @@ class OverlayUtil { MatrixState.pAnyState.openOverlay( entry, context, - closePrevOverlay: closePrevOverlay, overlayKey: overlayKey, ); } catch (err, stack) { diff --git a/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity.dart b/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity.dart index b13ca1cc9..7f2c6dcb3 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity.dart @@ -69,12 +69,15 @@ class MessageMatchActivity extends StatelessWidget { @override Widget build(BuildContext context) { if (overlayController.messageAnalyticsEntry == null || - overlayController.messageLemmaInfos == null || activityType == null) { debugger(when: kDebugMode); return const SizedBox(); } + if (overlayController.messageLemmaInfos == null) { + return const CircularProgressIndicator.adaptive(); + } + return Column( mainAxisAlignment: MainAxisAlignment.center, mainAxisSize: MainAxisSize.max, diff --git a/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity_item.dart b/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity_item.dart index 86b033479..57b919e4e 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity_item.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/message_match_activity_item.dart @@ -142,7 +142,10 @@ class MessageMatchActivityItemState extends State { Widget build(BuildContext context) { return LongPressDraggable( data: widget.constructForm, - feedback: content(context), + feedback: Material( + type: MaterialType.transparency, + child: content(context), + ), delay: const Duration(milliseconds: 100), onDragStarted: () { widget.overlayController.onChoiceSelect(widget.constructForm, true); diff --git a/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice.dart b/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice.dart index cbdb66e32..0d2a8a735 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/message_morph_choice.dart @@ -143,7 +143,7 @@ class MessageMorphInputBarContentState form: token!.text.content, ), ], - origin: AnalyticsUpdateOrigin.wordZoom, + targetID: token!.text.uniqueKey, ), ); @@ -183,14 +183,17 @@ class MessageMorphInputBarContentState size: const Size(30, 30), showTooltip: false, ), - Text( - L10n.of(context).whatIsTheMorphTag( - morph!.getDisplayCopy(context), - token!.text.content, + Flexible( + child: Text( + L10n.of(context).whatIsTheMorphTag( + morph!.getDisplayCopy(context), + token!.text.content, + ), + style: Theme.of(context).textTheme.bodyLarge?.copyWith( + fontWeight: FontWeight.bold, + ), + textAlign: TextAlign.center, ), - style: Theme.of(context).textTheme.bodyLarge?.copyWith( - fontWeight: FontWeight.bold, - ), ), ], ), diff --git a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart index 1c4f66ab1..9942d4155 100644 --- a/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart +++ b/lib/pangea/toolbar/reading_assistance_input_row/reading_assistance_input_bar.dart @@ -5,7 +5,6 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pages/chat/chat.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; @@ -53,7 +52,6 @@ class ReadingAssistanceInputBar extends StatelessWidget { ), overlayController: overlayController, morphFeature: morphFeature, - location: AnalyticsUpdateOrigin.inputBar, ); } diff --git a/lib/pangea/toolbar/widgets/message_selection_overlay.dart b/lib/pangea/toolbar/widgets/message_selection_overlay.dart index 09d1a4914..a44c23342 100644 --- a/lib/pangea/toolbar/widgets/message_selection_overlay.dart +++ b/lib/pangea/toolbar/widgets/message_selection_overlay.dart @@ -167,6 +167,7 @@ class MessageOverlayController extends State } finally { _initializeSelectedToken(); _setInitialToolbarMode(); + messageLemmaInfos ??= {}; initialized = true; if (mounted) setState(() {}); } @@ -290,7 +291,7 @@ class MessageOverlayController extends State pangeaMessageEvent: pangeaMessageEvent!, overlayController: this, ); - if (context.mounted) { + if (mounted) { OverlayUtil.showPositionedCard( context: context, cardToShow: entry, @@ -363,7 +364,7 @@ class MessageOverlayController extends State form: token.text.content, ), ], - origin: AnalyticsUpdateOrigin.wordZoom, + targetID: token.text.uniqueKey, ), ); } diff --git a/lib/pangea/toolbar/widgets/practice_activity/multiple_choice_activity.dart b/lib/pangea/toolbar/widgets/practice_activity/multiple_choice_activity.dart index 41baebdb1..b6bb8857b 100644 --- a/lib/pangea/toolbar/widgets/practice_activity/multiple_choice_activity.dart +++ b/lib/pangea/toolbar/widgets/practice_activity/multiple_choice_activity.dart @@ -115,7 +115,6 @@ class MultipleChoiceActivityState extends State { widget.practiceCardController.currentActivity!, widget.practiceCardController.metadata, ), - origin: AnalyticsUpdateOrigin.practiceActivity, ), ); @@ -226,7 +225,6 @@ class MultipleChoiceActivityState extends State { ), ChoicesArray( isLoading: false, - uniqueKeyForLayerLink: (index) => "multiple_choice_$index", originalSpan: "placeholder", onPressed: updateChoice, selectedChoiceIndex: selectedChoiceIndex, diff --git a/lib/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart b/lib/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart index 7701a0587..11840e780 100644 --- a/lib/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart +++ b/lib/pangea/toolbar/widgets/practice_activity/practice_activity_card.dart @@ -8,8 +8,6 @@ import 'package:collection/collection.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart'; -import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/choreographer/widgets/igc/card_error_widget.dart'; import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/common/utils/error_handler.dart'; @@ -36,7 +34,6 @@ class PracticeActivityCard extends StatefulWidget { final TargetTokensAndActivityType targetTokensAndActivityType; final MessageOverlayController overlayController; final WordZoomWidget? wordDetailsController; - final AnalyticsUpdateOrigin location; final String? morphFeature; @@ -47,7 +44,6 @@ class PracticeActivityCard extends StatefulWidget { required this.overlayController, this.morphFeature, this.wordDetailsController, - required this.location, }); @override @@ -341,12 +337,6 @@ class PracticeActivityCardState extends State { return Stack( alignment: Alignment.center, children: [ - // Main content - Positioned( - child: PointsGainedAnimation( - origin: widget.location, - ), - ), if (activityWidget != null) activityWidget!, // Conditionally show the darkening and progress indicator based on the loading state if (!savoringTheJoy && fetchingActivity) ...[ diff --git a/lib/pangea/toolbar/widgets/reading_assistance_content.dart b/lib/pangea/toolbar/widgets/reading_assistance_content.dart index e004c1fdc..48ef26b2d 100644 --- a/lib/pangea/toolbar/widgets/reading_assistance_content.dart +++ b/lib/pangea/toolbar/widgets/reading_assistance_content.dart @@ -5,7 +5,6 @@ import 'package:matrix/matrix_api_lite/model/message_types.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/config/themes.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart'; import 'package:fluffychat/pangea/toolbar/controllers/tts_controller.dart'; @@ -58,7 +57,6 @@ class ReadingAssistanceContentState extends State { targetTokensAndActivityType: widget .overlayController.messageAnalyticsEntry! .nextActivity(ActivityTypeEnum.hiddenWordListening)!, - location: AnalyticsUpdateOrigin.practiceActivity, ); } @@ -71,7 +69,6 @@ class ReadingAssistanceContentState extends State { targetTokensAndActivityType: widget .overlayController.messageAnalyticsEntry! .nextActivity(ActivityTypeEnum.messageMeaning)!, - location: AnalyticsUpdateOrigin.practiceActivity, ); } diff --git a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart index 6d1c327c4..763458ab4 100644 --- a/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart +++ b/lib/pangea/toolbar/widgets/word_zoom/word_zoom_widget.dart @@ -3,8 +3,6 @@ import 'package:flutter/material.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart'; import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart'; -import 'package:fluffychat/pangea/analytics_misc/gain_points_animation.dart'; -import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart'; import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/events/models/pangea_token_model.dart'; import 'package:fluffychat/pangea/learning_settings/constants/language_constants.dart'; @@ -54,136 +52,126 @@ class WordZoomWidget extends StatelessWidget { maxHeight: AppConfig.toolbarMaxHeight, maxWidth: AppConfig.toolbarMinWidth, ), - child: Stack( - alignment: Alignment.topCenter, - children: [ - const Positioned( - child: PointsGainedAnimation( - origin: AnalyticsUpdateOrigin.wordZoom, + child: SingleChildScrollView( + padding: const EdgeInsets.all(8.0), + child: Column( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + mainAxisSize: MainAxisSize.min, + children: [ + Container( + constraints: const BoxConstraints( + minHeight: 40, + ), + color: Theme.of(context).colorScheme.surface, + child: Row( + mainAxisAlignment: MainAxisAlignment.spaceBetween, + crossAxisAlignment: CrossAxisAlignment.center, + children: [ + //@ggurdin - might need to play with size to properly center + IconButton( + onPressed: () => + overlayController.onClickOverlayMessageToken(token), + icon: const Icon(Icons.close), + ), + LemmaWidget( + token: _selectedToken, + pangeaMessageEvent: messageEvent, + // onEdit: () => _setHideCenterContent(true), + onEdit: () { + debugPrint("what are we doing edits with?"); + }, + onEditDone: () { + debugPrint("what are we doing edits with?"); + onEditDone(); + }, + tts: tts, + overlayController: overlayController, + ), + ConstructXpWidget( + id: token.vocabConstructID, + onTap: () => showDialog( + context: context, + builder: (context) => AnalyticsPopupWrapper( + constructZoom: token.vocabConstructID, + view: ConstructTypeEnum.vocab, + ), + ), + ), + ], + ), ), - ), - SingleChildScrollView( - padding: const EdgeInsets.all(8.0), - child: Column( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - mainAxisSize: MainAxisSize.min, + const SizedBox( + height: 8.0, + ), + Row( + mainAxisAlignment: MainAxisAlignment.center, children: [ - Container( - constraints: const BoxConstraints( - minHeight: 40, - ), - color: Theme.of(context).colorScheme.surface, - child: Row( - mainAxisAlignment: MainAxisAlignment.spaceBetween, - crossAxisAlignment: CrossAxisAlignment.center, - children: [ - //@ggurdin - might need to play with size to properly center - IconButton( - onPressed: () => - overlayController.onClickOverlayMessageToken(token), - icon: const Icon(Icons.close), - ), - LemmaWidget( - token: _selectedToken, - pangeaMessageEvent: messageEvent, - // onEdit: () => _setHideCenterContent(true), - onEdit: () { - debugPrint("what are we doing edits with?"); - }, - onEditDone: () { - debugPrint("what are we doing edits with?"); - onEditDone(); - }, - tts: tts, - overlayController: overlayController, - ), - ConstructXpWidget( - id: token.vocabConstructID, - onTap: () => showDialog( - context: context, - builder: (context) => AnalyticsPopupWrapper( - constructZoom: token.vocabConstructID, - view: ConstructTypeEnum.vocab, - ), - ), - ), - ], - ), - ), - const SizedBox( - height: 8.0, - ), - Row( - mainAxisAlignment: MainAxisAlignment.center, - children: [ - Container( - constraints: const BoxConstraints( - minHeight: 40, - ), - alignment: Alignment.center, - child: LemmaEmojiRow( - cId: _selectedToken.vocabConstructID, - onTapOverride: hasEmojiActivity - ? () => overlayController.updateToolbarMode( - MessageMode.wordEmoji, - ) - : null, - isSelected: overlayController.toolbarMode == - MessageMode.wordEmoji, - emojiSetCallback: () => - overlayController.setState(() {}), - shouldShowEmojis: !hasEmojiActivity, - ), - ), - ], - ), - const SizedBox( - height: 8.0, - ), Container( constraints: const BoxConstraints( minHeight: 40, ), alignment: Alignment.center, - child: Wrap( - alignment: WrapAlignment.center, - runAlignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - spacing: 8, - children: [ - LemmaMeaningWidget( - constructUse: token.vocabConstructID.constructUses, - langCode: MatrixState.pangeaController - .languageController.userL2?.langCodeShort ?? - LanguageKeys.defaultLanguage, - token: overlayController.selectedToken!, - controller: overlayController, - style: Theme.of(context).textTheme.bodyLarge, - ), - ], + child: LemmaEmojiRow( + cId: _selectedToken.vocabConstructID, + onTapOverride: hasEmojiActivity + ? () => overlayController.updateToolbarMode( + MessageMode.wordEmoji, + ) + : null, + isSelected: + overlayController.toolbarMode == MessageMode.wordEmoji, + emojiSetCallback: () => overlayController.setState(() {}), + shouldShowEmojis: !hasEmojiActivity, ), ), - const SizedBox( - height: 8.0, - ), - Wrap( - alignment: WrapAlignment.center, - crossAxisAlignment: WrapCrossAlignment.center, - children: [ - if (!_selectedToken.doesLemmaTextMatchTokenText) ...[ - Text( - _selectedToken.text.content, - style: Theme.of(context).textTheme.bodyLarge, - overflow: TextOverflow.ellipsis, - ), - WordAudioButton( - text: _selectedToken.text.content, - isSelected: MessageMode.listening == - overlayController.toolbarMode, - baseOpacity: 0.4, - callbackOverride: overlayController - .messageAnalyticsEntry - ?.hasActivity( + ], + ), + const SizedBox( + height: 8.0, + ), + Container( + constraints: const BoxConstraints( + minHeight: 40, + ), + alignment: Alignment.center, + child: Wrap( + alignment: WrapAlignment.center, + runAlignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + spacing: 8, + children: [ + LemmaMeaningWidget( + constructUse: token.vocabConstructID.constructUses, + langCode: MatrixState.pangeaController.languageController + .userL2?.langCodeShort ?? + LanguageKeys.defaultLanguage, + token: overlayController.selectedToken!, + controller: overlayController, + style: Theme.of(context).textTheme.bodyLarge, + ), + ], + ), + ), + const SizedBox( + height: 8.0, + ), + Wrap( + alignment: WrapAlignment.center, + crossAxisAlignment: WrapCrossAlignment.center, + children: [ + if (!_selectedToken.doesLemmaTextMatchTokenText) ...[ + Text( + _selectedToken.text.content, + style: Theme.of(context).textTheme.bodyLarge, + overflow: TextOverflow.ellipsis, + ), + WordAudioButton( + text: _selectedToken.text.content, + isSelected: + MessageMode.listening == overlayController.toolbarMode, + baseOpacity: 0.4, + callbackOverride: + overlayController.messageAnalyticsEntry?.hasActivity( MessageMode.listening.associatedActivityType!, _selectedToken, ) == @@ -191,33 +179,30 @@ class WordZoomWidget extends StatelessWidget { ? () => overlayController .updateToolbarMode(MessageMode.listening) : null, - ), - ], - ..._selectedToken - .morphsBasicallyEligibleForPracticeByPriority - .map( - (cId) => MorphologicalListItem( - morphFeature: MorphFeaturesEnumExtension.fromString( - cId.category, - ), - token: _selectedToken, - overlayController: overlayController, - ), + ), + ], + ..._selectedToken.morphsBasicallyEligibleForPracticeByPriority + .map( + (cId) => MorphologicalListItem( + morphFeature: MorphFeaturesEnumExtension.fromString( + cId.category, ), - ], + token: _selectedToken, + overlayController: overlayController, + ), ), - // if (_selectedMorphFeature != null) - // MorphologicalCenterWidget( - // token: token, - // morphFeature: _selectedMorphFeature!, - // pangeaMessageEvent: messageEvent, - // overlayController: overlayController, - // onEditDone: onEditDone, - // ), ], ), - ), - ], + // if (_selectedMorphFeature != null) + // MorphologicalCenterWidget( + // token: token, + // morphFeature: _selectedMorphFeature!, + // pangeaMessageEvent: messageEvent, + // overlayController: overlayController, + // onEditDone: onEditDone, + // ), + ], + ), ), ); }