feat: always show new tokens with green underlines (#3984)

pull/2245/head
ggurdin 1 month ago committed by GitHub
parent 47f4740e63
commit 6c05ffaf2a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -14,7 +14,7 @@ import 'package:fluffychat/pages/chat/chat.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/pangea/message_token_text/message_token_button.dart';
import 'package:fluffychat/pangea/message_token_text/token_position_model.dart';
import 'package:fluffychat/pangea/message_token_text/tokens_util.dart';
import 'package:fluffychat/pangea/toolbar/enums/reading_assistance_mode_enum.dart';
import 'package:fluffychat/pangea/toolbar/utils/token_rendering_util.dart';
import 'package:fluffychat/pangea/toolbar/widgets/message_selection_overlay.dart';
@ -396,6 +396,9 @@ class HtmlMessage extends StatelessWidget {
);
final fontSize = renderer.fontSize(context) ?? this.fontSize;
final newTokens = pangeaMessageEvent != null
? TokensUtil.getNewTokens(pangeaMessageEvent!)
: [];
// Pangea#
switch (node.localName) {
@ -415,10 +418,7 @@ class HtmlMessage extends StatelessWidget {
? isHighlighted!.call(token)
: false;
final isNew = token != null &&
overlayController != null &&
overlayController!.isNewToken(token);
final isNew = token != null && newTokens.contains(token.text);
final tokenWidth = renderer.tokenTextWidthForContainer(
context,
node.text,

@ -68,9 +68,7 @@ class CoursePlanController extends State<CoursePlanBuilder> {
widget.onNotFound?.call();
error = e;
} finally {
setState(() {
loading = false;
});
if (mounted) setState(() => loading = false);
}
}

@ -1,4 +1,27 @@
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
import 'package:fluffychat/widgets/matrix.dart';
class _TokenPositionCacheItem {
final List<TokenPosition> positions;
final DateTime timestamp;
_TokenPositionCacheItem(
this.positions,
this.timestamp,
);
}
class _NewTokenCacheItem {
final List<PangeaTokenText> tokens;
final DateTime timestamp;
_NewTokenCacheItem(
this.tokens,
this.timestamp,
);
}
class TokenPosition {
final PangeaToken? token;
@ -15,9 +38,74 @@ class TokenPosition {
class TokensUtil {
/// A cache of calculated adjacent token positions
static final Map<String, _TokenPositionCacheItem> _tokenPositionCache = {};
static final Map<String, _NewTokenCacheItem> _newTokenCache = {};
static const Duration _cacheDuration = Duration(minutes: 1);
static List<PangeaTokenText>? _getCachedNewTokens(String eventID) {
final cacheItem = _newTokenCache[eventID];
if (cacheItem == null) return null;
if (cacheItem.timestamp.isBefore(DateTime.now().subtract(_cacheDuration))) {
_newTokenCache.remove(eventID);
return null;
}
return cacheItem.tokens;
}
static void _setCachedNewTokens(
String eventID,
List<PangeaTokenText> tokens,
) {
_newTokenCache[eventID] = _NewTokenCacheItem(
tokens,
DateTime.now(),
);
}
static List<PangeaTokenText> getNewTokens(
PangeaMessageEvent event,
) {
final messageInUserL2 = event.messageDisplayLangCode.split("-")[0] ==
MatrixState.pangeaController.languageController.userL2?.langCodeShort;
final cached = _getCachedNewTokens(event.eventId);
if (cached != null) {
if (!messageInUserL2) {
_newTokenCache.remove(event.eventId);
return [];
}
return cached;
}
final tokens = event.messageDisplayRepresentation?.tokens;
if (!messageInUserL2 || tokens == null || tokens.isEmpty) {
return [];
}
final List<PangeaTokenText> newTokens = [];
for (final token in tokens) {
if (!token.lemma.saveVocab || !token.isContentWord) continue;
if (token.vocabConstruct.uses.isNotEmpty) continue;
if (newTokens.any((t) => t == token.text)) continue;
newTokens.add(token.text);
if (newTokens.length >= 3) break;
}
_setCachedNewTokens(event.eventId, newTokens);
return newTokens;
}
static bool isNewToken(PangeaToken token, PangeaMessageEvent event) {
final newTokens = getNewTokens(event);
return newTokens.any((t) => t == token.text);
}
static clearNewTokenCache(String eventID) {
_newTokenCache.remove(eventID);
}
static List<TokenPosition>? _getCachedTokenPositions(String eventID) {
final cacheItem = _tokenPositionCache[eventID];
if (cacheItem == null) return null;
@ -158,13 +246,3 @@ class TokensUtil {
return tokenPositions;
}
}
class _TokenPositionCacheItem {
final List<TokenPosition> positions;
final DateTime timestamp;
_TokenPositionCacheItem(
this.positions,
this.timestamp,
);
}

@ -19,6 +19,7 @@ import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dar
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_text_model.dart';
import 'package:fluffychat/pangea/message_token_text/tokens_util.dart';
import 'package:fluffychat/pangea/practice_activities/activity_type_enum.dart';
import 'package:fluffychat/pangea/practice_activities/practice_activity_model.dart';
import 'package:fluffychat/pangea/practice_activities/practice_choice.dart';
@ -102,8 +103,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
double maxWidth = AppConfig.toolbarMinWidth;
List<PangeaToken> newTokens = [];
/////////////////////////////////////
/// Lifecycle
/////////////////////////////////////
@ -148,14 +147,6 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
MatrixState.pangeaController.languageController.userL2!.langCode,
);
}
newTokens = pangeaMessageEvent?.messageDisplayRepresentation?.tokens
?.where((token) {
return token.lemma.saveVocab == true &&
token.vocabConstruct.uses.isEmpty &&
messageInUserL2;
}).toList() ??
[];
} catch (e, s) {
debugger(when: kDebugMode);
ErrorHandler.logError(
@ -554,14 +545,8 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
);
if (mounted) {
setState(() {
newTokens.removeWhere(
(t) =>
t.text.offset == token.text.offset &&
t.text.length == token.text.length &&
t.lemma.text.equals(token.lemma.text),
);
});
TokensUtil.clearNewTokenCache(event.eventId);
setState(() {});
}
}
@ -579,14 +564,8 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
return isSelected;
}
bool isNewToken(PangeaToken token) {
if (newTokens.isEmpty) return false;
return newTokens.any(
(t) =>
t.text.offset == token.text.offset &&
t.text.length == token.text.length,
);
}
bool isNewToken(PangeaToken token) =>
TokensUtil.isNewToken(token, pangeaMessageEvent!);
bool isTokenHighlighted(PangeaToken token) {
if (_highlightedTokens == null) return false;

@ -1,7 +1,7 @@
import 'package:flutter/material.dart';
import 'package:fluffychat/pangea/events/models/pangea_token_model.dart';
import 'package:fluffychat/pangea/message_token_text/token_position_model.dart';
import 'package:fluffychat/pangea/message_token_text/tokens_util.dart';
import 'package:fluffychat/pangea/toolbar/models/speech_to_text_models.dart';
class SttTranscriptTokens extends StatelessWidget {

Loading…
Cancel
Save