feat: initial work for deleting lemmas from analytics

This commit is contained in:
ggurdin 2025-12-04 12:59:17 -05:00
parent 7663f0193e
commit 4d58b66bf1
No known key found for this signature in database
GPG key ID: A01CB41737CBB478
13 changed files with 243 additions and 279 deletions

View file

@ -4990,5 +4990,6 @@
}
},
"pickDifferentActivity": "Pick a different activity",
"messageLanguageMismatchMessage": "Your target language doesn't match this message. Update your target language?"
"messageLanguageMismatchMessage": "Your target language doesn't match this message. Update your target language?",
"blockLemmaConfirmation": "This vocab word will be permanently removed from your analytics"
}

View file

@ -36,7 +36,6 @@ import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_misc/get_analytics_controller.dart';
import 'package:fluffychat/pangea/analytics_misc/level_up/level_up_banner.dart';
import 'package:fluffychat/pangea/analytics_misc/message_analytics_feedback.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/bot/utils/bot_name.dart';
import 'package:fluffychat/pangea/chat/utils/unlocked_morphs_snackbar.dart';
import 'package:fluffychat/pangea/chat/widgets/event_too_large_dialog.dart';
@ -2106,14 +2105,11 @@ class ChatController extends State<ChatPageWithRoom>
];
_showAnalyticsFeedback(constructs, eventId);
pangeaController.putAnalytics.setState(
AnalyticsStream(
eventId: eventId,
targetID: eventId,
roomId: room.id,
constructs: constructs,
),
pangeaController.putAnalytics.addAnalytics(
constructs,
eventId: eventId,
targetId: eventId,
roomId: room.id,
);
}
}
@ -2160,13 +2156,11 @@ class ChatController extends State<ChatPageWithRoom>
if (constructs.isEmpty) return;
_showAnalyticsFeedback(constructs, eventId);
MatrixState.pangeaController.putAnalytics.setState(
AnalyticsStream(
eventId: eventId,
targetID: eventId,
roomId: room.id,
constructs: constructs,
),
MatrixState.pangeaController.putAnalytics.addAnalytics(
constructs,
eventId: eventId,
targetId: eventId,
roomId: room.id,
);
} catch (e, s) {
ErrorHandler.logError(

View file

@ -135,6 +135,14 @@ class ConstructListModel {
level = calculateLevelWithXp(totalXP);
}
void deleteLemma(String lemma, int offset) {
_uses.removeWhere((use) => use.lemma == lemma);
_constructMap.removeWhere(
(key, value) => value.lemma == lemma,
);
updateConstructs([], offset);
}
List<ConstructUses> constructList({ConstructTypeEnum? type}) => _constructList
.where(
(constructUse) => type == null || constructUse.constructType == type,

View file

@ -12,6 +12,7 @@ import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_event.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/analytics_settings/analytics_settings_extension.dart';
import 'package:fluffychat/pangea/common/constants/local.key.dart';
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
@ -95,6 +96,20 @@ class GetAnalyticsController extends BaseController {
final offset =
_pangeaController.userController.analyticsProfile?.xpOffset ?? 0;
final allUses = [
...(_getConstructsLocal() ?? []),
..._locallyCachedConstructs,
];
final Room? analyticsRoom = _client.analyticsRoomLocal(_l2!);
final blockedLemmas = analyticsRoom?.analyticsSettings?.blockedLemmas;
if (blockedLemmas != null && blockedLemmas.isNotEmpty) {
allUses.removeWhere(
(use) => blockedLemmas.contains(use.identifier.lemma),
);
}
constructListModel.updateConstructs(
[
...(_getConstructsLocal() ?? []),
@ -129,7 +144,6 @@ class GetAnalyticsController extends BaseController {
_joinSpaceSubscription = null;
initCompleter = Completer<void>();
_cache.clear();
// perMessage.dispose();
}
Future<void> _onAnalyticsUpdate(
@ -286,8 +300,7 @@ class GetAnalyticsController extends BaseController {
return formattedCache;
} catch (err) {
// if something goes wrong while trying to format the local data, clear it
_pangeaController.putAnalytics
.clearMessagesSinceUpdate(clearDrafts: true);
clearMessagesCache();
return {};
}
} catch (exception, stackTrace) {

View file

@ -1,6 +1,5 @@
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/put_analytics_controller.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/widgets/matrix.dart';
@ -28,27 +27,27 @@ mixin LemmaEmojiSetter {
String? roomId,
String? targetId,
}) {
MatrixState.pangeaController.putAnalytics.setState(
AnalyticsStream(
eventId: eventId,
roomId: roomId,
targetID: targetId,
constructs: [
OneConstructUse(
useType: ConstructUseTypeEnum.em,
lemma: constructId.lemma,
constructType: constructId.type,
metadata: ConstructUseMetaData(
roomId: roomId,
timeStamp: DateTime.now(),
eventId: eventId,
),
category: constructId.category,
form: constructId.lemma,
xp: ConstructUseTypeEnum.em.pointValue,
),
],
final constructs = [
OneConstructUse(
useType: ConstructUseTypeEnum.em,
lemma: constructId.lemma,
constructType: constructId.type,
metadata: ConstructUseMetaData(
roomId: roomId,
timeStamp: DateTime.now(),
eventId: eventId,
),
category: constructId.category,
form: constructId.lemma,
xp: ConstructUseTypeEnum.em.pointValue,
),
];
MatrixState.pangeaController.putAnalytics.addAnalytics(
constructs,
eventId: eventId,
roomId: roomId,
targetId: targetId,
);
}
}

View file

@ -5,27 +5,24 @@ import 'package:flutter/foundation.dart';
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_use_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
import 'package:fluffychat/pangea/common/controllers/base_controller.dart';
import 'package:fluffychat/pangea/common/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart';
import 'package:fluffychat/pangea/learning_settings/models/language_model.dart';
import 'package:fluffychat/pangea/user/controllers/user_controller.dart';
import 'package:fluffychat/widgets/matrix.dart';
enum AnalyticsUpdateType { server, local, activities, init }
enum AnalyticsUpdateType { server, local, activities, init, delete }
/// handles the processing of analytics for
/// 1) messages sent by the user and
/// 2) constructs used by the user, both in sending messages and doing practice activities
class PutAnalyticsController extends BaseController<AnalyticsStream> {
class PutAnalyticsController {
late PangeaController _pangeaController;
StreamController<AnalyticsUpdate> analyticsUpdateStream =
StreamController.broadcast();
StreamSubscription<AnalyticsStream>? _analyticsStream;
StreamSubscription? _languageStream;
Timer? _updateTimer;
@ -53,31 +50,20 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
}
void initialize() {
// Listen for calls to setState on the analytics stream
// and update the analytics room if necessary
_analyticsStream ??=
stateStream.listen((data) => _onNewAnalyticsData(data));
// Listen for changes to the user's language settings
_languageStream ??=
_pangeaController.userController.languageStream.stream.listen((update) {
_onUpdateLanguages(update.prevTargetLang);
});
_languageStream ??= _pangeaController.userController.languageStream.stream
.listen(_onUpdateLanguages);
_refreshAnalyticsIfOutdated();
}
/// Reset analytics last updated time to null.
@override
void dispose() {
_updateTimer?.cancel();
lastUpdated = null;
lastUpdatedCompleter = Completer<DateTime?>();
_analyticsStream?.cancel();
_analyticsStream = null;
_languageStream?.cancel();
_languageStream = null;
clearMessagesSinceUpdate();
MatrixState.pangeaController.getAnalytics.clearMessagesCache();
}
/// If analytics haven't been updated in the last day, update them
@ -112,137 +98,18 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
/// Given new construct uses, format and cache
/// the data locally and reset the update timer
/// Decide whether to update the analytics room
void _onNewAnalyticsData(AnalyticsStream data) {
final String? eventID = data.eventId;
final String? roomID = data.roomId;
final List<OneConstructUse> constructs = [];
// if (roomID != null) {
// constructs = _getDraftUses(roomID);
// }
constructs.addAll(data.constructs);
if (kDebugMode) {
for (final use in constructs) {
debugPrint(
"_onNewAnalyticsData filtered use: ${use.constructType.string} ${use.useType.string} ${use.lemma} ${use.xp}",
);
}
}
void addAnalytics(
List<OneConstructUse> constructs, {
String? eventId,
String? roomId,
String? targetId,
}) {
final level = _pangeaController.getAnalytics.constructListModel.level;
_addLocalMessage(eventID, constructs).then(
(_) {
if (roomID != null) _clearDraftUses(roomID);
_decideWhetherToUpdateAnalyticsRoom(
level,
data.targetID,
data.constructs,
);
},
_addLocalMessage(eventId, constructs).then(
(_) => _sendAnalytics(level, targetId, constructs),
);
}
Future<void> _onUpdateLanguages(LanguageModel? previousL2) async {
await sendLocalAnalyticsToAnalyticsRoom(
l2Override: previousL2,
);
_pangeaController.resetAnalytics().then((_) {
final level = _pangeaController.getAnalytics.constructListModel.level;
_pangeaController.userController.updateAnalyticsProfile(level: level);
});
}
// void addDraftUses(
// List<PangeaToken> tokens,
// String roomID,
// ConstructUseTypeEnum useType, {
// String? targetID,
// }) {
// final metadata = ConstructUseMetaData(
// roomId: roomID,
// timeStamp: DateTime.now(),
// );
// // we only save those with saveVocab == true
// final tokensToSave =
// tokens.where((token) => token.lemma.saveVocab).toList();
// // get all our vocab constructs
// final uses = tokensToSave
// .map(
// (token) => OneConstructUse(
// useType: useType,
// lemma: token.lemma.text,
// form: token.text.content,
// constructType: ConstructTypeEnum.vocab,
// metadata: metadata,
// category: token.pos,
// ),
// )
// .toList();
// // get all our grammar constructs
// for (final token in tokensToSave) {
// uses.add(
// OneConstructUse(
// useType: useType,
// lemma: token.pos,
// form: token.text.content,
// category: "POS",
// constructType: ConstructTypeEnum.morph,
// metadata: metadata,
// ),
// );
// for (final entry in token.morph.entries) {
// uses.add(
// OneConstructUse(
// useType: useType,
// lemma: entry.value,
// form: token.text.content,
// category: entry.key,
// constructType: ConstructTypeEnum.morph,
// metadata: metadata,
// ),
// );
// }
// }
// if (kDebugMode) {
// for (final use in uses) {
// debugPrint(
// "Draft use: ${use.constructType.string} ${use.useType.string} ${use.lemma} ${use.useType.pointValue}",
// );
// }
// }
// final level = _pangeaController.getAnalytics.constructListModel.level;
// // the list 'uses' gets altered in the _addLocalMessage method,
// // so copy it here to that the list of new uses is accurate
// final List<OneConstructUse> newUses = List.from(uses);
// _addLocalMessage('draft$roomID', uses).then(
// (_) => _decideWhetherToUpdateAnalyticsRoom(
// level,
// targetID,
// newUses,
// ),
// );
// }
// List<OneConstructUse> _getDraftUses(String roomID) {
// final currentCache = _pangeaController.getAnalytics.messagesSinceUpdate;
// return currentCache['draft$roomID'] ?? [];
// }
void _clearDraftUses(String roomID) {
final currentCache = _pangeaController.getAnalytics.messagesSinceUpdate;
currentCache.remove('draft$roomID');
_setMessagesSinceUpdate(currentCache);
}
/// Add a list of construct uses for a new message to the local
/// cache of recently sent messages
Future<void> _addLocalMessage(
@ -255,7 +122,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
// if this is not a draft message, add the eventId to the metadata
// if it's missing (it will be missing for draft constructs)
if (cacheKey != null && !cacheKey.startsWith('draft')) {
if (cacheKey != null) {
constructs = constructs.map((construct) {
if (construct.metadata.eventId != null) return construct;
construct.metadata.eventId = cacheKey;
@ -283,7 +150,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
/// If the addition brought the total number of messages in the cache
/// to the max, or if the addition triggered a level-up, update the analytics.
/// Otherwise, add a local update to the alert stream.
void _decideWhetherToUpdateAnalyticsRoom(
void _sendAnalytics(
int prevLevel,
String? targetID,
List<OneConstructUse> newConstructs,
@ -311,25 +178,14 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
);
}
/// Clears the local cache of recently sent constructs. Called before updating analytics
void clearMessagesSinceUpdate({clearDrafts = false}) {
if (clearDrafts) {
MatrixState.pangeaController.getAnalytics.clearMessagesCache();
return;
}
final localCache = _pangeaController.getAnalytics.messagesSinceUpdate;
final draftKeys = localCache.keys.where((key) => key.startsWith('draft'));
if (draftKeys.isEmpty) {
MatrixState.pangeaController.getAnalytics.clearMessagesCache();
return;
}
final Map<String, List<OneConstructUse>> newCache = {};
for (final key in draftKeys) {
newCache[key] = localCache[key]!;
}
_setMessagesSinceUpdate(newCache);
Future<void> _onUpdateLanguages(LanguageUpdate update) async {
await sendLocalAnalyticsToAnalyticsRoom(
l2Override: update.prevTargetLang,
);
_pangeaController.resetAnalytics().then((_) {
final level = _pangeaController.getAnalytics.constructListModel.level;
_pangeaController.userController.updateAnalyticsProfile(level: level);
});
}
/// Save the local cache of recently sent constructs to the local storage
@ -369,7 +225,7 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
_updateCompleter = Completer<void>();
try {
await _updateAnalytics(l2Override: l2Override);
clearMessagesSinceUpdate();
MatrixState.pangeaController.getAnalytics.clearMessagesCache();
lastUpdated = DateTime.now();
analyticsUpdateStream.add(
@ -434,39 +290,16 @@ class PutAnalyticsController extends BaseController<AnalyticsStream> {
);
}
Future<void> removeActivityAnalytics(String roomId) async {
if (_pangeaController.matrixState.client.userID == null) return;
if (_pangeaController.languageController.userL2 == null) return;
final Room? analyticsRoom = await _client.getMyAnalyticsRoom(
_pangeaController.languageController.userL2!,
);
if (analyticsRoom == null) return;
await analyticsRoom.removeActivityRoomId(roomId);
Future<void> onBlockLemma() async {
analyticsUpdateStream.add(
AnalyticsUpdate(
AnalyticsUpdateType.activities,
AnalyticsUpdateType.delete,
[],
),
);
}
}
class AnalyticsStream {
final String? eventId;
final String? roomId;
final String? targetID;
final List<OneConstructUse> constructs;
AnalyticsStream({
required this.eventId,
required this.roomId,
required this.constructs,
this.targetID,
});
}
class AnalyticsUpdate {
final AnalyticsUpdateType type;
final List<OneConstructUse> newConstructs;

View file

@ -5,15 +5,19 @@ import 'package:go_router/go_router.dart';
import 'package:fluffychat/config/app_config.dart';
import 'package:fluffychat/config/themes.dart';
import 'package:fluffychat/l10n/l10n.dart';
import 'package:fluffychat/pangea/analytics_details_popup/analytics_details_popup.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
import 'package:fluffychat/pangea/analytics_misc/put_analytics_controller.dart';
import 'package:fluffychat/pangea/analytics_page/activity_archive.dart';
import 'package:fluffychat/pangea/analytics_page/analytics_page_constants.dart';
import 'package:fluffychat/pangea/analytics_settings/analytics_settings_extension.dart';
import 'package:fluffychat/pangea/analytics_summary/learning_progress_indicators.dart';
import 'package:fluffychat/pangea/analytics_summary/level_dialog_content.dart';
import 'package:fluffychat/pangea/analytics_summary/progress_indicators_enum.dart';
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
import 'package:fluffychat/widgets/adaptive_dialogs/show_ok_cancel_alert_dialog.dart';
import 'package:fluffychat/widgets/future_loading_dialog.dart';
import 'package:fluffychat/widgets/matrix.dart';
class AnalyticsPage extends StatelessWidget {
@ -28,11 +32,43 @@ class AnalyticsPage extends StatelessWidget {
this.isSidebar = false,
});
Future<void> _blockLemma(BuildContext context) async {
final resp = await showOkCancelAlertDialog(
context: context,
title: L10n.of(context).areYouSure,
message: L10n.of(context).blockLemmaConfirmation,
isDestructive: true,
);
if (resp != OkCancelResult.ok) return;
final res = await showFutureLoadingDialog(
context: context,
future: () => Matrix.of(context).client.blockLemma(construct!.lemma),
);
if (!res.isError) {
context.go("/rooms/analytics/${ConstructTypeEnum.vocab.name}");
}
}
@override
Widget build(BuildContext context) {
final analyticsRoomId = GoRouterState.of(context).pathParameters['roomid'];
return Scaffold(
appBar: construct != null ? AppBar() : null,
appBar: construct != null
? AppBar(
actions: indicator == ProgressIndicatorEnum.wordsUsed
? [
IconButton(
icon: const Icon(Icons.delete_forever_outlined),
color: Theme.of(context).colorScheme.error,
tooltip: L10n.of(context).delete,
onPressed: () => _blockLemma(context),
),
]
: null,
)
: null,
body: SafeArea(
child: StreamBuilder(
stream: MatrixState

View file

@ -0,0 +1,46 @@
import 'package:matrix/matrix.dart';
import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart';
import 'package:fluffychat/pangea/analytics_settings/analytics_settings_model.dart';
import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart';
import 'package:fluffychat/widgets/matrix.dart';
extension AnalyticsSettingsRoomExtension on Room {
AnalyticsSettingsModel? get analyticsSettings {
final event = getState(PangeaEventTypes.analyticsSettings);
if (event == null) return null;
return AnalyticsSettingsModel.fromJson(event.content);
}
Future<void> setAnalyticsSettings(
AnalyticsSettingsModel settings,
) async {
await client.setRoomStateWithKey(
id,
PangeaEventTypes.analyticsSettings,
"",
settings.toJson(),
);
}
}
extension AnalyticsSettingsClientExtension on Client {
Future<void> blockLemma(String lemma) async {
final l2 = MatrixState.pangeaController.languageController.userL2!;
final analyticsRoom = await getMyAnalyticsRoom(l2);
if (analyticsRoom == null) {
throw Exception("Could not get or create analytics room");
}
final current = analyticsRoom.analyticsSettings;
final blockedLemmas = current?.blockedLemmas ?? {};
final updated = current?.copyWith(
blockedLemmas: {
...blockedLemmas,
lemma,
},
);
await analyticsRoom.setAnalyticsSettings(updated!);
}
}

View file

@ -0,0 +1,34 @@
class AnalyticsSettingsModel {
final Set<String> blockedLemmas;
const AnalyticsSettingsModel({
required this.blockedLemmas,
});
AnalyticsSettingsModel copyWith({
Set<String>? blockedLemmas,
}) {
return AnalyticsSettingsModel(
blockedLemmas: blockedLemmas ?? this.blockedLemmas,
);
}
factory AnalyticsSettingsModel.fromJson(Map<String, dynamic> json) {
final blockedLemmas = <String>{};
if (json['blocked_lemmas'] != null) {
final lemmas = json['blocked_lemmas'] as List<dynamic>;
for (final lemma in lemmas) {
blockedLemmas.add(lemma as String);
}
}
return AnalyticsSettingsModel(
blockedLemmas: blockedLemmas,
);
}
Map<String, dynamic> toJson() {
return {
'blocked_lemmas': blockedLemmas.toList(),
};
}
}

View file

@ -54,4 +54,6 @@ class PangeaEventTypes {
static const courseUser = "p.course_user";
static const teacherMode = "pangea.teacher_mode";
static const courseChatList = "pangea.course_chat_list";
static const analyticsSettings = "pangea.analytics_settings";
}

View file

@ -13,7 +13,6 @@ import 'package:fluffychat/pages/chat/chat.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
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/put_analytics_controller.dart';
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_message_event.dart';
import 'package:fluffychat/pangea/events/event_wrappers/pangea_representation_event.dart';
@ -198,27 +197,26 @@ class MessageOverlayController extends State<MessageSelectionOverlay>
setState(() {});
if (selectedToken != null && isNewToken(selectedToken!)) {
final token = selectedToken!;
MatrixState.pangeaController.putAnalytics.setState(
AnalyticsStream(
eventId: event.eventId,
roomId: event.room.id,
constructs: [
OneConstructUse(
useType: ConstructUseTypeEnum.click,
lemma: token.lemma.text,
constructType: ConstructTypeEnum.vocab,
metadata: ConstructUseMetaData(
roomId: event.room.id,
timeStamp: DateTime.now(),
eventId: event.eventId,
),
category: token.pos,
form: token.text.content,
xp: ConstructUseTypeEnum.click.pointValue,
),
],
targetID: "word-zoom-card-${token.text.uniqueKey}",
final constructs = [
OneConstructUse(
useType: ConstructUseTypeEnum.click,
lemma: token.lemma.text,
constructType: ConstructTypeEnum.vocab,
metadata: ConstructUseMetaData(
roomId: event.room.id,
timeStamp: DateTime.now(),
eventId: event.eventId,
),
category: token.pos,
form: token.text.content,
xp: ConstructUseTypeEnum.click.pointValue,
),
];
MatrixState.pangeaController.putAnalytics.addAnalytics(
constructs,
eventId: event.eventId,
roomId: event.room.id,
targetId: "word-zoom-card-${token.text.uniqueKey}",
);
}
}

View file

@ -6,7 +6,6 @@ import 'package:collection/collection.dart';
import 'package:fluffychat/pangea/analytics_misc/construct_type_enum.dart';
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/put_analytics_controller.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/practice_activities/activity_type_enum.dart';
@ -125,28 +124,28 @@ class PracticeController with ChangeNotifier {
final constructUseType = _activity!.practiceTarget.record.responses.last
.useType(_activity!.activityType);
MatrixState.pangeaController.putAnalytics.setState(
AnalyticsStream(
eventId: pangeaMessageEvent.eventId,
roomId: pangeaMessageEvent.room.id,
constructs: [
OneConstructUse(
useType: constructUseType,
lemma: token.lemma.text,
constructType: ConstructTypeEnum.vocab,
metadata: ConstructUseMetaData(
roomId: pangeaMessageEvent.room.id,
timeStamp: DateTime.now(),
eventId: pangeaMessageEvent.eventId,
),
category: token.pos,
// in the case of a wrong answer, the cId doesn't match the token
form: token.text.content,
xp: constructUseType.pointValue,
),
],
targetID: targetId,
final constructs = [
OneConstructUse(
useType: constructUseType,
lemma: token.lemma.text,
constructType: ConstructTypeEnum.vocab,
metadata: ConstructUseMetaData(
roomId: pangeaMessageEvent.room.id,
timeStamp: DateTime.now(),
eventId: pangeaMessageEvent.eventId,
),
category: token.pos,
// in the case of a wrong answer, the cId doesn't match the token
form: token.text.content,
xp: constructUseType.pointValue,
),
];
MatrixState.pangeaController.putAnalytics.addAnalytics(
constructs,
eventId: pangeaMessageEvent.eventId,
roomId: pangeaMessageEvent.room.id,
targetId: targetId,
);
}

View file

@ -152,6 +152,7 @@ abstract class ClientManager {
PangeaEventTypes.courseUser,
PangeaEventTypes.teacherMode,
PangeaEventTypes.courseChatList,
PangeaEventTypes.analyticsSettings,
// Pangea#
},
logLevel: kReleaseMode ? Level.warning : Level.verbose,