feat: initial work for deleting lemmas from analytics
This commit is contained in:
parent
7663f0193e
commit
4d58b66bf1
13 changed files with 243 additions and 279 deletions
|
|
@ -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"
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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(
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
|
|
|
|||
|
|
@ -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) {
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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;
|
||||
|
|
|
|||
|
|
@ -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
|
||||
|
|
|
|||
|
|
@ -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!);
|
||||
}
|
||||
}
|
||||
34
lib/pangea/analytics_settings/analytics_settings_model.dart
Normal file
34
lib/pangea/analytics_settings/analytics_settings_model.dart
Normal 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(),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
|
@ -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";
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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}",
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -152,6 +152,7 @@ abstract class ClientManager {
|
|||
PangeaEventTypes.courseUser,
|
||||
PangeaEventTypes.teacherMode,
|
||||
PangeaEventTypes.courseChatList,
|
||||
PangeaEventTypes.analyticsSettings,
|
||||
// Pangea#
|
||||
},
|
||||
logLevel: kReleaseMode ? Level.warning : Level.verbose,
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue