Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: if example message contains multiple of the same lemma, bold eac… #1795

Merged
merged 1 commit into from
Feb 14, 2025
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
109 changes: 71 additions & 38 deletions lib/pangea/analytics_details_popup/lemma_use_example_messages.dart
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand All @@ -21,14 +22,15 @@ 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 ||
use.form == null ||
use.pointValue <= 0) {
continue;
}

final Room? room = MatrixState.pangeaController.matrixState.client
.getRoomById(use.metadata.roomId);
if (room == null) continue;
Expand All @@ -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,
Expand All @@ -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;
}

Expand All @@ -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,
Expand All @@ -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,
),
),
);
Expand All @@ -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;
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<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;
}
}
Loading