fix: if example message contains multiple of the same lemma, bold each of them instead of showing as seperate messages (#1795)

This commit is contained in:
ggurdin 2025-02-14 12:06:43 -05:00 committed by GitHub
parent 918c3193af
commit f296012a0e
No known key found for this signature in database
GPG key ID: B5690EEEBB952194

View file

@ -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<List<ExampleMessage>> _getExampleMessages() async {
final Set<ExampleMessage> examples = {};
final List<ExampleMessage> 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<int, int> _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;
return other is ExampleMessage &&
other.message == message &&
other.offset == offset &&
other.length == length;
void addTokenPosition(int offset, int length) {
_tokenPositions[offset] = length;
}
@override
int get hashCode => message.hashCode ^ offset.hashCode ^ length.hashCode;
bool isTokenAdded(PangeaToken token) {
return _tokenPositions.keys.any(
(offset) => offset == token.text.offset,
);
}
List<List<int>> get _sortedTokenPositions {
return _tokenPositions.entries
.sorted((a, b) => a.key.compareTo(b.key))
.map((entry) => [entry.key, entry.value])
.toList();
}
List<TextSpan> get textSpans {
final spans = <TextSpan>[];
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;
}
}