From 093aef3873faf556d3b717d58a9f4a62df20d45d Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 14 Feb 2025 12:06:07 -0500 Subject: [PATCH] fix: if example message contains multiple of the same lemma, bold each of them instead of showing as seperate messages --- .../lemma_use_example_messages.dart | 109 ++++++++++++------ 1 file changed, 71 insertions(+), 38 deletions(-) diff --git a/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart b/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart index 2eff14e4d2..966cc4b09b 100644 --- a/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart +++ b/lib/pangea/analytics_details_popup/lemma_use_example_messages.dart @@ -10,6 +10,7 @@ import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart'; import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart'; import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.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/widgets/matrix.dart'; class LemmaUseExampleMessages extends StatelessWidget { @@ -21,7 +22,7 @@ class LemmaUseExampleMessages extends StatelessWidget { }); Future> _getExampleMessages() async { - final Set examples = {}; + final List examples = []; for (final OneConstructUse use in construct.uses) { if (use.useType.skillsEnumType != LearningSkillsEnum.writing || use.metadata.eventId == null || @@ -29,6 +30,7 @@ class LemmaUseExampleMessages extends StatelessWidget { use.pointValue <= 0) { continue; } + final Room? room = MatrixState.pangeaController.matrixState.client .getRoomById(use.metadata.roomId); if (room == null) continue; @@ -38,7 +40,14 @@ class LemmaUseExampleMessages extends StatelessWidget { timeline = await room.getTimeline(); } - final Event? event = await room.getEventById(use.metadata.eventId!); + final exampleIndex = examples.indexWhere( + (example) => example.event.eventId == use.metadata.eventId!, + ); + + final Event? event = exampleIndex != -1 + ? examples[exampleIndex].event + : await room.getEventById(use.metadata.eventId!); + if (event == null) continue; final PangeaMessageEvent pangeaMessageEvent = PangeaMessageEvent( event: event, @@ -48,18 +57,24 @@ class LemmaUseExampleMessages extends StatelessWidget { ); final tokens = pangeaMessageEvent.messageDisplayRepresentation?.tokens; if (tokens == null || tokens.isEmpty) continue; - final token = - tokens.firstWhereOrNull((token) => token.text.content == use.form); + final token = tokens.firstWhereOrNull( + (token) => token.text.content == use.form, + ); if (token == null) continue; - final int offset = token.text.offset; - examples.add( - ExampleMessage( - message: pangeaMessageEvent.messageDisplayText, - offset: offset, - length: use.form!.length, - ), - ); + final example = exampleIndex == -1 + ? ExampleMessage( + event: event, + message: pangeaMessageEvent.messageDisplayText, + ) + : examples[exampleIndex]; + + if (example.isTokenAdded(token)) continue; + example.addTokenPosition(token.text.offset, token.text.length); + + exampleIndex == -1 + ? examples.add(example) + : examples[exampleIndex] = example; if (examples.length > 4) break; } @@ -77,7 +92,7 @@ class LemmaUseExampleMessages extends StatelessWidget { child: Column( crossAxisAlignment: CrossAxisAlignment.start, mainAxisAlignment: MainAxisAlignment.start, - children: snapshot.data!.map((e) { + children: snapshot.data!.map((example) { return Container( decoration: BoxDecoration( color: construct.lemmaCategory.color, @@ -95,17 +110,7 @@ class LemmaUseExampleMessages extends StatelessWidget { fontSize: AppConfig.fontSizeFactor * AppConfig.messageFontSize, ), - children: [ - TextSpan(text: e.message.substring(0, e.offset)), - TextSpan( - text: e.message - .substring(e.offset, e.offset + e.length), - style: const TextStyle(fontWeight: FontWeight.bold), - ), - TextSpan( - text: e.message.substring(e.offset + e.length), - ), - ], + children: example.textSpans, ), ), ); @@ -128,26 +133,54 @@ class LemmaUseExampleMessages extends StatelessWidget { } class ExampleMessage { + final Event event; final String message; - final int offset; - final int length; + final Map _tokenPositions; ExampleMessage({ + required this.event, required this.message, - required this.offset, - required this.length, - }); + }) : _tokenPositions = {}; - @override - bool operator ==(Object other) { - if (identical(this, other)) return true; + void addTokenPosition(int offset, int length) { + _tokenPositions[offset] = length; + } - return other is ExampleMessage && - other.message == message && - other.offset == offset && - other.length == length; + bool isTokenAdded(PangeaToken token) { + return _tokenPositions.keys.any( + (offset) => offset == token.text.offset, + ); } - @override - int get hashCode => message.hashCode ^ offset.hashCode ^ length.hashCode; + List> get _sortedTokenPositions { + return _tokenPositions.entries + .sorted((a, b) => a.key.compareTo(b.key)) + .map((entry) => [entry.key, entry.value]) + .toList(); + } + + List get textSpans { + final spans = []; + int lastOffset = 0; + for (final token in _sortedTokenPositions) { + spans.add( + TextSpan( + text: message.substring(lastOffset, token[0]), + ), + ); + spans.add( + TextSpan( + text: message.substring(token[0], token[0] + token[1]), + style: const TextStyle(fontWeight: FontWeight.bold), + ), + ); + lastOffset = token[0] + token[1]; + } + spans.add( + TextSpan( + text: message.substring(lastOffset), + ), + ); + return spans; + } }