@@ -10,6 +10,7 @@ import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
10
10
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart' ;
11
11
import 'package:fluffychat/pangea/analytics_misc/learning_skills_enum.dart' ;
12
12
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart' ;
13
+ import 'package:fluffychat/pangea/events/models/pangea_token_model.dart' ;
13
14
import 'package:fluffychat/widgets/matrix.dart' ;
14
15
15
16
class LemmaUseExampleMessages extends StatelessWidget {
@@ -21,14 +22,15 @@ class LemmaUseExampleMessages extends StatelessWidget {
21
22
});
22
23
23
24
Future <List <ExampleMessage >> _getExampleMessages () async {
24
- final Set <ExampleMessage > examples = {} ;
25
+ final List <ExampleMessage > examples = [] ;
25
26
for (final OneConstructUse use in construct.uses) {
26
27
if (use.useType.skillsEnumType != LearningSkillsEnum .writing ||
27
28
use.metadata.eventId == null ||
28
29
use.form == null ||
29
30
use.pointValue <= 0 ) {
30
31
continue ;
31
32
}
33
+
32
34
final Room ? room = MatrixState .pangeaController.matrixState.client
33
35
.getRoomById (use.metadata.roomId);
34
36
if (room == null ) continue ;
@@ -38,7 +40,14 @@ class LemmaUseExampleMessages extends StatelessWidget {
38
40
timeline = await room.getTimeline ();
39
41
}
40
42
41
- final Event ? event = await room.getEventById (use.metadata.eventId! );
43
+ final exampleIndex = examples.indexWhere (
44
+ (example) => example.event.eventId == use.metadata.eventId! ,
45
+ );
46
+
47
+ final Event ? event = exampleIndex != - 1
48
+ ? examples[exampleIndex].event
49
+ : await room.getEventById (use.metadata.eventId! );
50
+
42
51
if (event == null ) continue ;
43
52
final PangeaMessageEvent pangeaMessageEvent = PangeaMessageEvent (
44
53
event: event,
@@ -48,18 +57,24 @@ class LemmaUseExampleMessages extends StatelessWidget {
48
57
);
49
58
final tokens = pangeaMessageEvent.messageDisplayRepresentation? .tokens;
50
59
if (tokens == null || tokens.isEmpty) continue ;
51
- final token =
52
- tokens.firstWhereOrNull ((token) => token.text.content == use.form);
60
+ final token = tokens.firstWhereOrNull (
61
+ (token) => token.text.content == use.form,
62
+ );
53
63
if (token == null ) continue ;
54
64
55
- final int offset = token.text.offset;
56
- examples.add (
57
- ExampleMessage (
58
- message: pangeaMessageEvent.messageDisplayText,
59
- offset: offset,
60
- length: use.form! .length,
61
- ),
62
- );
65
+ final example = exampleIndex == - 1
66
+ ? ExampleMessage (
67
+ event: event,
68
+ message: pangeaMessageEvent.messageDisplayText,
69
+ )
70
+ : examples[exampleIndex];
71
+
72
+ if (example.isTokenAdded (token)) continue ;
73
+ example.addTokenPosition (token.text.offset, token.text.length);
74
+
75
+ exampleIndex == - 1
76
+ ? examples.add (example)
77
+ : examples[exampleIndex] = example;
63
78
if (examples.length > 4 ) break ;
64
79
}
65
80
@@ -77,7 +92,7 @@ class LemmaUseExampleMessages extends StatelessWidget {
77
92
child: Column (
78
93
crossAxisAlignment: CrossAxisAlignment .start,
79
94
mainAxisAlignment: MainAxisAlignment .start,
80
- children: snapshot.data! .map ((e ) {
95
+ children: snapshot.data! .map ((example ) {
81
96
return Container (
82
97
decoration: BoxDecoration (
83
98
color: construct.lemmaCategory.color,
@@ -95,17 +110,7 @@ class LemmaUseExampleMessages extends StatelessWidget {
95
110
fontSize: AppConfig .fontSizeFactor *
96
111
AppConfig .messageFontSize,
97
112
),
98
- children: [
99
- TextSpan (text: e.message.substring (0 , e.offset)),
100
- TextSpan (
101
- text: e.message
102
- .substring (e.offset, e.offset + e.length),
103
- style: const TextStyle (fontWeight: FontWeight .bold),
104
- ),
105
- TextSpan (
106
- text: e.message.substring (e.offset + e.length),
107
- ),
108
- ],
113
+ children: example.textSpans,
109
114
),
110
115
),
111
116
);
@@ -128,26 +133,54 @@ class LemmaUseExampleMessages extends StatelessWidget {
128
133
}
129
134
130
135
class ExampleMessage {
136
+ final Event event;
131
137
final String message;
132
- final int offset;
133
- final int length;
138
+ final Map <int , int > _tokenPositions;
134
139
135
140
ExampleMessage ({
141
+ required this .event,
136
142
required this .message,
137
- required this .offset,
138
- required this .length,
139
- });
143
+ }) : _tokenPositions = {};
140
144
141
- @override
142
- bool operator == ( Object other) {
143
- if ( identical ( this , other)) return true ;
145
+ void addTokenPosition ( int offset, int length) {
146
+ _tokenPositions[offset] = length;
147
+ }
144
148
145
- return other is ExampleMessage &&
146
- other.message == message &&
147
- other. offset == offset &&
148
- other.length == length ;
149
+ bool isTokenAdded ( PangeaToken token) {
150
+ return _tokenPositions.keys. any (
151
+ (offset) => offset == token.text. offset,
152
+ ) ;
149
153
}
150
154
151
- @override
152
- int get hashCode => message.hashCode ^ offset.hashCode ^ length.hashCode;
155
+ List <List <int >> get _sortedTokenPositions {
156
+ return _tokenPositions.entries
157
+ .sorted ((a, b) => a.key.compareTo (b.key))
158
+ .map ((entry) => [entry.key, entry.value])
159
+ .toList ();
160
+ }
161
+
162
+ List <TextSpan > get textSpans {
163
+ final spans = < TextSpan > [];
164
+ int lastOffset = 0 ;
165
+ for (final token in _sortedTokenPositions) {
166
+ spans.add (
167
+ TextSpan (
168
+ text: message.substring (lastOffset, token[0 ]),
169
+ ),
170
+ );
171
+ spans.add (
172
+ TextSpan (
173
+ text: message.substring (token[0 ], token[0 ] + token[1 ]),
174
+ style: const TextStyle (fontWeight: FontWeight .bold),
175
+ ),
176
+ );
177
+ lastOffset = token[0 ] + token[1 ];
178
+ }
179
+ spans.add (
180
+ TextSpan (
181
+ text: message.substring (lastOffset),
182
+ ),
183
+ );
184
+ return spans;
185
+ }
153
186
}
0 commit comments