diff --git a/lib/pangea/choreographer/controllers/it_controller.dart b/lib/pangea/choreographer/controllers/it_controller.dart index 83d678e98..6d5f8e347 100644 --- a/lib/pangea/choreographer/controllers/it_controller.dart +++ b/lib/pangea/choreographer/controllers/it_controller.dart @@ -28,6 +28,7 @@ class ITController { String? sourceText; List completedITSteps = []; CurrentITStep? currentITStep; + CurrentITStep? nextITStep; GoldRouteTracker goldRouteTracker = GoldRouteTracker.defaultTracker; List payLoadIds = []; @@ -42,6 +43,7 @@ class ITController { sourceText = null; completedITSteps = []; currentITStep = null; + nextITStep = null; goldRouteTracker = GoldRouteTracker.defaultTracker; payLoadIds = []; @@ -130,36 +132,75 @@ class ITController { ); } - currentITStep = null; - - final ITResponseModel res = await _customInputTranslation(currentText); - // final ITResponseModel res = await (useCustomInput || - // currentText.isEmpty || - // translationId == null || - // completedITSteps.last.chosenContinuance?.indexSavedByServer == - // null - // ? _customInputTranslation(currentText) - // : _systemChoiceTranslation(translationId)); - - if (res.goldContinuances != null && res.goldContinuances!.isNotEmpty) { - goldRouteTracker = GoldRouteTracker( - res.goldContinuances!, - sourceText!, + if (nextITStep == null) { + currentITStep = null; + + final ITResponseModel res = await _customInputTranslation(currentText); + // final ITResponseModel res = await (useCustomInput || + // currentText.isEmpty || + // translationId == null || + // completedITSteps.last.chosenContinuance?.indexSavedByServer == + // null + // ? _customInputTranslation(currentText) + // : _systemChoiceTranslation(translationId)); + + if (res.goldContinuances != null && res.goldContinuances!.isNotEmpty) { + goldRouteTracker = GoldRouteTracker( + res.goldContinuances!, + sourceText!, + ); + } + + currentITStep = CurrentITStep( + sourceText: sourceText!, + currentText: currentText, + responseModel: res, + storedGoldContinuances: goldRouteTracker.continuances, ); - } - - currentITStep = CurrentITStep( - sourceText: sourceText!, - currentText: currentText, - responseModel: res, - storedGoldContinuances: goldRouteTracker.continuances, - ); - _addPayloadId(res); + _addPayloadId(res); + } else { + currentITStep = nextITStep; + nextITStep = null; + } if (isTranslationDone) { choreographer.altTranslator.setTranslationFeedback(); choreographer.getLanguageHelp(true); + } else { + getNextTranslationData(); + } + } catch (e, s) { + debugger(when: kDebugMode); + if (e is! http.Response) { + ErrorHandler.logError(e: e, s: s); + } + choreographer.errorService.setErrorAndLock( + ChoreoError(type: ChoreoErrorType.unknown, raw: e), + ); + } finally { + choreographer.stopLoading(); + } + } + + FuturegetNextTranslationData() async { + try { + if (completedITSteps.length < goldRouteTracker.continuances.length) { + final String currentText = choreographer.currentText; + final String nextText = + goldRouteTracker.continuances[completedITSteps.length].text; + + final ITResponseModel res = + await _customInputTranslation(currentText + nextText); + + nextITStep = CurrentITStep( + sourceText: sourceText!, + currentText: nextText, + responseModel: res, + storedGoldContinuances: goldRouteTracker.continuances, + ); + } else { + nextITStep = null; } } catch (e, s) { debugger(when: kDebugMode); diff --git a/lib/pangea/choreographer/widgets/choice_array.dart b/lib/pangea/choreographer/widgets/choice_array.dart index ca3f3bf7d..54fd601b9 100644 --- a/lib/pangea/choreographer/widgets/choice_array.dart +++ b/lib/pangea/choreographer/widgets/choice_array.dart @@ -1,9 +1,11 @@ import 'dart:developer'; +import 'dart:math'; import 'package:flutter/foundation.dart'; import 'package:flutter/material.dart'; import 'package:flutter_gen/gen_l10n/l10n.dart'; +import 'package:matrix/matrix.dart'; import '../../utils/bot_style.dart'; import 'it_shimmer.dart'; @@ -56,10 +58,12 @@ class Choice { Choice({ this.color, required this.text, + this.isGold = false, }); final Color? color; final String text; + final bool isGold; } class ChoiceItem extends StatelessWidget { @@ -86,45 +90,50 @@ class ChoiceItem extends StatelessWidget { waitDuration: onLongPress != null ? const Duration(milliseconds: 500) : const Duration(days: 1), - child: Container( - margin: const EdgeInsets.all(2), - padding: EdgeInsets.zero, - decoration: isSelected - ? BoxDecoration( - borderRadius: const BorderRadius.all(Radius.circular(10)), - border: Border.all( - color: entry.value.color ?? theme.colorScheme.primary, - style: BorderStyle.solid, - width: 2.0, + child: ChoiceAnimationWidget( + key: ValueKey(entry.value.text), + selected: entry.value.color != null, + isGold: entry.value.isGold, + child: Container( + margin: const EdgeInsets.all(2), + padding: EdgeInsets.zero, + decoration: isSelected + ? BoxDecoration( + borderRadius: const BorderRadius.all(Radius.circular(10)), + border: Border.all( + color: entry.value.color ?? theme.colorScheme.primary, + style: BorderStyle.solid, + width: 2.0, + ), + ) + : null, + child: TextButton( + style: ButtonStyle( + padding: MaterialStateProperty.all( + const EdgeInsets.symmetric(horizontal: 7), + ), + //if index is selected, then give the background a slight primary color + backgroundColor: MaterialStateProperty.all( + entry.value.color != null + ? entry.value.color!.withOpacity(0.2) + : theme.colorScheme.primary.withOpacity(0.1), + ), + textStyle: MaterialStateProperty.all( + BotStyle.text(context), + ), + shape: MaterialStateProperty.all( + RoundedRectangleBorder( + borderRadius: BorderRadius.circular(10), ), - ) - : null, - child: TextButton( - style: ButtonStyle( - padding: MaterialStateProperty.all( - const EdgeInsets.symmetric(horizontal: 7), - ), - //if index is selected, then give the background a slight primary color - backgroundColor: MaterialStateProperty.all( - entry.value.color != null - ? entry.value.color!.withOpacity(0.2) - : theme.colorScheme.primary.withOpacity(0.1), - ), - textStyle: MaterialStateProperty.all( - BotStyle.text(context), - ), - shape: MaterialStateProperty.all( - RoundedRectangleBorder( - borderRadius: BorderRadius.circular(10), ), ), - ), - onLongPress: - onLongPress != null ? () => onLongPress!(entry.key) : null, - onPressed: () => onPressed(entry.key), - child: Text( - entry.value.text, - style: BotStyle.text(context), + onLongPress: + onLongPress != null ? () => onLongPress!(entry.key) : null, + onPressed: () => onPressed(entry.key), + child: Text( + entry.value.text, + style: BotStyle.text(context), + ), ), ), ), @@ -135,3 +144,110 @@ class ChoiceItem extends StatelessWidget { } } } + +class ChoiceAnimationWidget extends StatefulWidget { + final Widget child; + final bool selected; + final bool isGold; + + const ChoiceAnimationWidget({ + super.key, + required this.child, + required this.selected, + this.isGold = false, + }); + + @override + ChoiceAnimationWidgetState createState() => ChoiceAnimationWidgetState(); +} + +class ChoiceAnimationWidgetState extends State + with SingleTickerProviderStateMixin { + late final AnimationController _controller; + late final Animation _animation; + bool animationPlayed = false; + + @override + void initState() { + super.initState(); + + _controller = AnimationController( + duration: const Duration(milliseconds: 300), + vsync: this, + ); + + _animation = widget.isGold + ? Tween(begin: 1.0, end: 1.2).animate(_controller) + : TweenSequence([ + TweenSequenceItem( + tween: Tween(begin: 0, end: -8 * pi / 180), + weight: 1.0, + ), + TweenSequenceItem( + tween: Tween(begin: -8 * pi / 180, end: 16 * pi / 180), + weight: 2.0, + ), + TweenSequenceItem( + tween: Tween(begin: 16 * pi / 180, end: 0), + weight: 1.0, + ), + ]).animate(_controller); + + if (widget.selected && !animationPlayed) { + _controller.forward(); + animationPlayed = true; + setState(() {}); + } + _controller.addStatusListener((status) { + if (status == AnimationStatus.completed) { + _controller.reverse(); + } else if (status == AnimationStatus.dismissed) { + _controller.stop(); + _controller.reset(); + } + }); + } + + @override + void didUpdateWidget(ChoiceAnimationWidget oldWidget) { + super.didUpdateWidget(oldWidget); + if (widget.selected && !animationPlayed) { + _controller.forward(); + animationPlayed = true; + setState(() {}); + } + } + + @override + Widget build(BuildContext context) { + return widget.isGold + ? AnimatedBuilder( + key: UniqueKey(), + animation: _animation, + builder: (context, child) { + return Transform.scale( + scale: _animation.value, + child: child, + ); + }, + child: widget.child, + ) + : AnimatedBuilder( + key: UniqueKey(), + animation: _animation, + builder: (context, child) { + return Transform.rotate( + angle: _animation.value, + child: child, + ); + }, + child: widget.child, + ); + } + + @override + void dispose() { + _controller.dispose(); + super.dispose(); + } +} diff --git a/lib/pangea/choreographer/widgets/it_bar.dart b/lib/pangea/choreographer/widgets/it_bar.dart index 2ab811008..4e26cba58 100644 --- a/lib/pangea/choreographer/widgets/it_bar.dart +++ b/lib/pangea/choreographer/widgets/it_bar.dart @@ -280,7 +280,11 @@ class ITChoices extends StatelessWidget { originalSpan: "dummy", choices: controller.currentITStep!.continuances.map((e) { try { - return Choice(text: e.text.trim(), color: e.color); + return Choice( + text: e.text.trim(), + color: e.color, + isGold: e.description == "best", + ); } catch (e) { debugger(when: kDebugMode); return Choice(text: "error", color: Colors.red); diff --git a/lib/pangea/controllers/my_analytics_controller.dart b/lib/pangea/controllers/my_analytics_controller.dart index 808355b47..eb3969bd1 100644 --- a/lib/pangea/controllers/my_analytics_controller.dart +++ b/lib/pangea/controllers/my_analytics_controller.dart @@ -3,6 +3,7 @@ import 'dart:developer'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; +import 'package:fluffychat/pangea/matrix_event_wrappers/construct_analytics_event.dart'; import 'package:fluffychat/pangea/models/student_analytics_summary_model.dart'; import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/foundation.dart'; @@ -111,4 +112,48 @@ class MyAnalyticsController { ErrorHandler.logError(e: err, s: s); } } + + // used to aggregate ConstructEvents, from multiple senders (students) with the same lemma + List aggregateConstructData( + List constructs, + ) { + final Map> lemmasToConstructs = {}; + for (final construct in constructs) { + lemmasToConstructs[construct.content.lemma] ??= []; + lemmasToConstructs[construct.content.lemma]!.add(construct); + } + + final List aggregatedConstructs = []; + for (final lemmaToConstructs in lemmasToConstructs.entries) { + final List lemmaConstructs = lemmaToConstructs.value; + final AggregateConstructUses aggregatedData = AggregateConstructUses( + constructs: lemmaConstructs, + ); + aggregatedConstructs.add(aggregatedData); + } + return aggregatedConstructs; + } +} + +class AggregateConstructUses { + final List _constructs; + + AggregateConstructUses({required List constructs}) + : _constructs = constructs; + + String get lemma { + assert( + _constructs.isNotEmpty && + _constructs.every( + (construct) => + construct.content.lemma == _constructs.first.content.lemma, + ), + ); + return _constructs.first.content.lemma; + } + + List get uses => _constructs + .map((construct) => construct.content.uses) + .expand((element) => element) + .toList(); } diff --git a/lib/pangea/models/constructs_analytics_model.dart b/lib/pangea/models/constructs_analytics_model.dart index 0d940ab80..a62145485 100644 --- a/lib/pangea/models/constructs_analytics_model.dart +++ b/lib/pangea/models/constructs_analytics_model.dart @@ -68,26 +68,33 @@ class ConstructUses { } enum ConstructUseType { - /// encountered match and accepted it + /// produced in chat by user, igc was run, and we've judged it to be a correct use + wa, + + /// produced in chat by user, igc was run, and we've judged it to be a incorrect use + /// Note: if the IGC match is ignored, this is not counted as an incorrect use ga, - /// used without assistance - wa, + /// produced in chat by user and igc was not run + unk, /// selected correctly in IT flow corIt, - /// encountered as it distractor and selected it - incIt, - /// encountered as IT distractor and correctly ignored it ignIt, + /// encountered as it distractor and selected it + incIt, + /// encountered in igc match and ignored match ignIGC, - /// encountered in igc match and ignored match + /// selected correctly in IGC flow corIGC, + + /// encountered as distractor in IGC flow and selected it + incIGC, } extension on ConstructUseType { @@ -107,6 +114,10 @@ extension on ConstructUseType { return 'ignIGC'; case ConstructUseType.corIGC: return 'corIGC'; + case ConstructUseType.incIGC: + return 'incIGC'; + case ConstructUseType.unk: + return 'unk'; } } @@ -126,6 +137,10 @@ extension on ConstructUseType { return Icons.close; case ConstructUseType.corIGC: return Icons.check; + case ConstructUseType.incIGC: + return Icons.close; + case ConstructUseType.unk: + return Icons.help; } } } diff --git a/lib/pangea/models/headwords.dart b/lib/pangea/models/headwords.dart index cd0a68108..3586253b8 100644 --- a/lib/pangea/models/headwords.dart +++ b/lib/pangea/models/headwords.dart @@ -1,10 +1,10 @@ import 'dart:convert'; import 'dart:developer'; +import 'package:fluffychat/pangea/models/constructs_analytics_model.dart'; import 'package:flutter/foundation.dart'; import 'package:flutter/services.dart'; -import 'package:fluffychat/pangea/models/constructs_analytics_model.dart'; import '../enum/vocab_proficiency_enum.dart'; class VocabHeadwords { @@ -176,6 +176,11 @@ class VocabTotals { case ConstructUseType.corIGC: corIt++; break; + case ConstructUseType.incIGC: + incIt++; + break; + case ConstructUseType.unk: + break; } } } diff --git a/lib/pangea/pages/analytics/analytics_list_tile.dart b/lib/pangea/pages/analytics/analytics_list_tile.dart index ab35b2610..811f02f6f 100644 --- a/lib/pangea/pages/analytics/analytics_list_tile.dart +++ b/lib/pangea/pages/analytics/analytics_list_tile.dart @@ -104,7 +104,6 @@ class AnalyticsListTileState extends State { ) : null, selected: widget.selected, - enabled: widget.enabled, onTap: () { (room?.isSpace ?? false) && widget.allowNavigateOnSelect ? context.go( diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart index 634a39980..55731cfb3 100644 --- a/lib/pangea/pages/analytics/base_analytics.dart +++ b/lib/pangea/pages/analytics/base_analytics.dart @@ -5,6 +5,7 @@ import 'package:fluffychat/pangea/extensions/client_extension.dart'; import 'package:fluffychat/pangea/pages/analytics/base_analytics_view.dart'; import 'package:fluffychat/pangea/pages/analytics/student_analytics/student_analytics.dart'; import 'package:flutter/material.dart'; +import 'package:future_loading_dialog/future_loading_dialog.dart'; import 'package:matrix/matrix.dart'; import '../../../widgets/matrix.dart'; @@ -101,18 +102,40 @@ class BaseAnalyticsController extends State { } } - void toggleSelection(AnalyticsSelected selectedParam) { + Future toggleSelection(AnalyticsSelected selectedParam) async { + final bool joinSelectedRoom = + selectedParam.type == AnalyticsEntryType.room && + !enableSelection( + selectedParam, + ); + + if (joinSelectedRoom) { + await showFutureLoadingDialog( + context: context, + future: () async { + final waitForRoom = Matrix.of(context).client.waitForRoomInSync( + selectedParam.id, + join: true, + ); + await Matrix.of(context).client.joinRoom(selectedParam.id); + await waitForRoom; + }, + ); + } + setState(() { debugPrint("selectedParam.id is ${selectedParam.id}"); currentLemma = null; selected = isSelected(selectedParam.id) ? null : selectedParam; }); + pangeaController.analytics.setConstructs( constructType: ConstructType.grammar, defaultSelected: widget.defaultSelected, selected: selected, removeIT: true, ); + Future.delayed(Duration.zero, () => setState(() {})); } diff --git a/lib/pangea/pages/analytics/base_analytics_view.dart b/lib/pangea/pages/analytics/base_analytics_view.dart index 86f179829..0c9bf3bc4 100644 --- a/lib/pangea/pages/analytics/base_analytics_view.dart +++ b/lib/pangea/pages/analytics/base_analytics_view.dart @@ -145,6 +145,7 @@ class BaseAnalyticsView extends StatelessWidget { ) * 72, child: TabBarView( + physics: const NeverScrollableScrollPhysics(), children: [ Column( crossAxisAlignment: diff --git a/lib/pangea/pages/analytics/class_list/class_list.dart b/lib/pangea/pages/analytics/class_list/class_list.dart index 6ce8b994d..e96538a11 100644 --- a/lib/pangea/pages/analytics/class_list/class_list.dart +++ b/lib/pangea/pages/analytics/class_list/class_list.dart @@ -1,11 +1,10 @@ import 'dart:async'; +import 'package:fluffychat/pangea/enum/time_span.dart'; +import 'package:fluffychat/pangea/pages/analytics/class_list/class_list_view.dart'; import 'package:flutter/material.dart'; - import 'package:matrix/matrix.dart'; -import 'package:fluffychat/pangea/enum/time_span.dart'; -import 'package:fluffychat/pangea/pages/analytics/class_list/class_list_view.dart'; import '../../../../widgets/matrix.dart'; import '../../../constants/pangea_event_types.dart'; import '../../../controllers/pangea_controller.dart'; @@ -42,7 +41,11 @@ class AnalyticsClassListController extends State { if (!(refreshTimer[newState.room.id]?.isActive ?? false)) { refreshTimer[newState.room.id] = Timer( const Duration(seconds: 3), - () => updateClassAnalytics(context, newState.room), + () { + if (newState.room.isSpace) { + updateClassAnalytics(context, newState.room); + } + }, ); } } diff --git a/lib/pangea/pages/analytics/construct_list.dart b/lib/pangea/pages/analytics/construct_list.dart index ffcf0e79a..f050222ec 100644 --- a/lib/pangea/pages/analytics/construct_list.dart +++ b/lib/pangea/pages/analytics/construct_list.dart @@ -3,9 +3,9 @@ import 'dart:async'; import 'package:collection/collection.dart'; import 'package:fluffychat/config/app_config.dart'; import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; +import 'package:fluffychat/pangea/controllers/my_analytics_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; -import 'package:fluffychat/pangea/matrix_event_wrappers/construct_analytics_event.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_representation_event.dart'; import 'package:fluffychat/pangea/models/constructs_analytics_model.dart'; @@ -169,7 +169,7 @@ class ConstructListViewState extends State { int get lemmaIndex => constructs?.indexWhere( - (element) => element.content.lemma == widget.controller.currentLemma, + (element) => element.lemma == widget.controller.currentLemma, ) ?? -1; @@ -217,7 +217,7 @@ class ConstructListViewState extends State { setState(() => fetchingUses = true); try { - final List uses = currentConstruct!.content.uses; + final List uses = currentConstruct!.uses; _msgEvents.clear(); for (final OneConstructUse use in uses) { @@ -236,16 +236,24 @@ class ConstructListViewState extends State { ErrorHandler.logError( e: err, s: s, - m: "Failed to fetch uses for current construct ${currentConstruct?.content.lemma}", + m: "Failed to fetch uses for current construct ${currentConstruct?.lemma}", ); } } - List? get constructs => - widget.pangeaController.analytics.constructs; - - ConstructEvent? get currentConstruct => constructs?.firstWhereOrNull( - (element) => element.content.lemma == widget.controller.currentLemma, + List? get constructs => + widget.pangeaController.analytics.constructs != null + ? widget.pangeaController.myAnalytics + .aggregateConstructData( + widget.pangeaController.analytics.constructs!, + ) + .sorted( + (a, b) => b.uses.length.compareTo(a.uses.length), + ) + : null; + + AggregateConstructUses? get currentConstruct => constructs?.firstWhereOrNull( + (element) => element.lemma == widget.controller.currentLemma, ); // given the current lemma and list of message events, return a list of @@ -280,6 +288,13 @@ class ConstructListViewState extends State { return allMsgErrorSteps; } + Future showConstructMessagesDialog() async { + await showDialog( + context: context, + builder: (c) => ConstructMessagesDialog(controller: this), + ); + } + @override Widget build(BuildContext context) { if (!widget.init || fetchingUses) { @@ -294,58 +309,92 @@ class ConstructListViewState extends State { ); } - final msgEventMatches = getMessageEventMatches(); + return Expanded( + child: ListView.builder( + itemCount: constructs!.length, + itemBuilder: (context, index) { + return ListTile( + title: Text( + constructs![index].lemma, + ), + subtitle: Text( + '${L10n.of(context)!.total} ${constructs![index].uses.length}', + ), + onTap: () async { + final String lemma = constructs![index].lemma; + widget.controller.setCurrentLemma(lemma); + fetchUses().then((_) => showConstructMessagesDialog()); + }, + ); + }, + ), + ); + } +} - return widget.controller.currentLemma == null - ? Expanded( - child: ListView.builder( - itemCount: constructs!.length, - itemBuilder: (context, index) { - return ListTile( - title: Text( - constructs![index].content.lemma, - ), - subtitle: Text( - '${L10n.of(context)!.total} ${constructs![index].content.uses.length}', - ), - onTap: () { - final String lemma = constructs![index].content.lemma; - widget.controller.setCurrentLemma(lemma); - fetchUses(); - }, - ); - }, +class ConstructMessagesDialog extends StatelessWidget { + final ConstructListViewState controller; + const ConstructMessagesDialog({ + super.key, + required this.controller, + }); + + @override + Widget build(BuildContext context) { + if (controller.widget.controller.currentLemma == null) { + return const AlertDialog(content: CircularProgressIndicator.adaptive()); + } + + final msgEventMatches = controller.getMessageEventMatches(); + + return AlertDialog( + title: Center(child: Text(controller.widget.controller.currentLemma!)), + content: Column( + mainAxisSize: MainAxisSize.min, + crossAxisAlignment: CrossAxisAlignment.start, + children: [ + if (controller.constructs![controller.lemmaIndex].uses.length > + controller._msgEvents.length) + Center( + child: Padding( + padding: const EdgeInsets.all(8.0), + child: Text(L10n.of(context)!.roomDataMissing), + ), ), - ) - : Expanded( + SingleChildScrollView( child: Column( - crossAxisAlignment: CrossAxisAlignment.start, children: [ - if (constructs![lemmaIndex].content.uses.length > - _msgEvents.length) - Center( - child: Padding( - padding: const EdgeInsets.all(8.0), - child: Text(L10n.of(context)!.roomDataMissing), - ), - ), - Expanded( - child: ListView.separated( - separatorBuilder: (context, index) => + ...msgEventMatches.mapIndexed( + (index, event) => Column( + children: [ + ConstructMessage( + msgEvent: event.msgEvent, + lemma: controller.widget.controller.currentLemma!, + errorMessage: event.lemmaMatch, + ), + if (index < msgEventMatches.length - 1) const Divider(height: 1), - itemCount: msgEventMatches.length, - itemBuilder: (context, index) { - return ConstructMessage( - msgEvent: msgEventMatches[index].msgEvent, - lemma: widget.controller.currentLemma!, - errorMessage: msgEventMatches[index].lemmaMatch, - ); - }, + ], ), ), ], ), - ); + ), + ], + ), + actions: [ + TextButton( + onPressed: () => Navigator.of(context, rootNavigator: false).pop(), + child: Text( + L10n.of(context)!.close.toUpperCase(), + style: TextStyle( + color: + Theme.of(context).textTheme.bodyMedium?.color?.withAlpha(150), + ), + ), + ), + ], + ); } } diff --git a/lib/pangea/widgets/igc/span_card.dart b/lib/pangea/widgets/igc/span_card.dart index 9ef2f4122..fd44383a0 100644 --- a/lib/pangea/widgets/igc/span_card.dart +++ b/lib/pangea/widgets/igc/span_card.dart @@ -198,6 +198,7 @@ class WordMatchContent extends StatelessWidget { (e) => Choice( text: e.value, color: e.selected ? e.type.color : null, + isGold: e.type.name == 'bestCorrection', ), ) .toList(),