diff --git a/lib/pangea/analytics_data/analytics_data_service.dart b/lib/pangea/analytics_data/analytics_data_service.dart index 5adbfe5f6..fea3203db 100644 --- a/lib/pangea/analytics_data/analytics_data_service.dart +++ b/lib/pangea/analytics_data/analytics_data_service.dart @@ -156,7 +156,7 @@ class AnalyticsDataService { } finally { Logs().i("Analytics database initialized."); initCompleter.complete(); - updateDispatcher.sendLocalAnalyticsUpdate(AnalyticsUpdate([])); + updateDispatcher.sendEmptyAnalyticsUpdate(); updateDispatcher.sendActivityAnalyticsUpdate(null); } } @@ -408,7 +408,7 @@ class AnalyticsDataService { final newConstructs = await getConstructUses(updateIds); int points = 0; - if (update.blockedConstruct == null || updateIds.isNotEmpty) { + if (updateIds.isNotEmpty) { for (final id in updateIds) { final prevPoints = prevConstructs[id]?.points ?? 0; final newPoints = newConstructs[id]?.points ?? 0; @@ -469,10 +469,6 @@ class AnalyticsDataService { } } - if (update.blockedConstruct != null) { - events.add(ConstructBlockedEvent(update.blockedConstruct!)); - } - if (newUnusedConstructs.isNotEmpty) { events.add(NewConstructsEvent(newUnusedConstructs)); } @@ -518,11 +514,7 @@ class AnalyticsDataService { ); await _analyticsClientGetter.database.updateTotalXP(newXP); - _invalidateCaches(); - updateDispatcher.sendLocalAnalyticsUpdate( - AnalyticsUpdate([], blockedConstruct: constructId), - ); } Future clearLocalAnalytics() async { diff --git a/lib/pangea/analytics_data/analytics_sync_controller.dart b/lib/pangea/analytics_data/analytics_sync_controller.dart index f06d402dd..559db2ed0 100644 --- a/lib/pangea/analytics_data/analytics_sync_controller.dart +++ b/lib/pangea/analytics_data/analytics_sync_controller.dart @@ -5,10 +5,34 @@ import 'package:matrix/matrix.dart'; import 'package:fluffychat/pangea/analytics_data/analytics_data_service.dart'; import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart'; import 'package:fluffychat/pangea/analytics_misc/constructs_event.dart'; +import 'package:fluffychat/pangea/analytics_settings/analytics_settings_model.dart'; +import 'package:fluffychat/pangea/common/constants/model_keys.dart'; +import 'package:fluffychat/pangea/constructs/construct_identifier.dart'; import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension.dart'; +import 'package:fluffychat/pangea/lemmas/user_set_lemma_info.dart'; import 'package:fluffychat/widgets/matrix.dart'; +enum _AnalyticsUpdateEvent { + constructAnalytics, + activityAnalytics, + lemmaInfo, + blockedConstruct; + + String get eventType { + switch (this) { + case _AnalyticsUpdateEvent.constructAnalytics: + return PangeaEventTypes.construct; + case _AnalyticsUpdateEvent.activityAnalytics: + return PangeaEventTypes.activityRoomIds; + case _AnalyticsUpdateEvent.lemmaInfo: + return PangeaEventTypes.userSetLemmaInfo; + case _AnalyticsUpdateEvent.blockedConstruct: + return PangeaEventTypes.analyticsSettings; + } + } +} + class AnalyticsSyncController { final Client client; final AnalyticsDataService dataService; @@ -30,15 +54,43 @@ class AnalyticsSyncController { final analyticsRoom = _getAnalyticsRoom(); if (analyticsRoom == null) return; - final events = update.rooms?.join?[analyticsRoom.id]?.timeline?.events - ?.where( - (e) => - e.type == PangeaEventTypes.construct && - e.senderId == client.userID, - ); + final roomUpdates = update.rooms?.join?[analyticsRoom.id]?.timeline?.events; + if (roomUpdates == null) return; - if (events == null || events.isEmpty) return; + for (final type in _AnalyticsUpdateEvent.values) { + await _dispatchSyncEvents(type, roomUpdates, analyticsRoom); + } + } + Future _dispatchSyncEvents( + _AnalyticsUpdateEvent type, + List events, + Room analyticsRoom, + ) async { + final updates = events + .where((e) => e.type == type.eventType && e.senderId == client.userID) + .toList(); + + switch (type) { + case _AnalyticsUpdateEvent.constructAnalytics: + await _onConstructEvents(updates, analyticsRoom); + break; + case _AnalyticsUpdateEvent.activityAnalytics: + _onActivityEvents(updates); + break; + case _AnalyticsUpdateEvent.lemmaInfo: + _onLemmaInfoEvents(updates); + break; + case _AnalyticsUpdateEvent.blockedConstruct: + await _onBlockedConstructEvents(updates); + break; + } + } + + Future _onConstructEvents( + List events, + Room analyticsRoom, + ) async { final constructEvents = events .map( (e) => ConstructAnalyticsEvent( @@ -54,6 +106,60 @@ class AnalyticsSyncController { ); } + void _onActivityEvents(List events) { + for (final event in events) { + if (event.content[ModelKey.roomIds] is! List) continue; + final roomIds = List.from( + event.content[ModelKey.roomIds]! as List, + ); + final prevContent = + event.unsigned?['prev_content'] as Map?; + final prevRoomIds = + prevContent != null && prevContent[ModelKey.roomIds] is List + ? List.from(prevContent[ModelKey.roomIds] as List) + : []; + final newRoomIds = roomIds + .where((id) => !prevRoomIds.contains(id)) + .toList(); + + for (final roomId in newRoomIds) { + dataService.updateDispatcher.sendActivityAnalyticsUpdate(roomId); + } + } + } + + void _onLemmaInfoEvents(List events) { + for (final event in events) { + if (event.stateKey == null) continue; + final cID = ConstructIdentifier.fromString(event.stateKey!); + if (cID == null) continue; + + final update = UserSetLemmaInfo.fromJson(event.content); + dataService.updateDispatcher.sendLemmaInfoUpdate(cID, update); + } + } + + Future _onBlockedConstructEvents(List events) async { + for (final event in events) { + final current = AnalyticsSettingsModel.fromJson(event.content); + final prevContent = + event.unsigned?['prev_content'] as Map?; + final prev = prevContent != null + ? AnalyticsSettingsModel.fromJson(prevContent) + : null; + + final newBlocked = current.blockedConstructs; + final prevBlocked = prev?.blockedConstructs ?? {}; + + final newlyBlocked = newBlocked.where((c) => !prevBlocked.contains(c)); + for (final constructId in newlyBlocked) { + await dataService.updateDispatcher.sendBlockedConstructUpdate( + constructId, + ); + } + } + } + Future waitForSync(String analyticsRoomId) async { await client.onSync.stream.firstWhere((update) { final roomUpdate = update.rooms?.join?[analyticsRoomId]; diff --git a/lib/pangea/analytics_data/analytics_update_dispatcher.dart b/lib/pangea/analytics_data/analytics_update_dispatcher.dart index c30cbb295..c9e4736d0 100644 --- a/lib/pangea/analytics_data/analytics_update_dispatcher.dart +++ b/lib/pangea/analytics_data/analytics_update_dispatcher.dart @@ -17,10 +17,9 @@ class LevelUpdate { class AnalyticsUpdate { final List addedConstructs; - final ConstructIdentifier? blockedConstruct; final String? targetID; - AnalyticsUpdate(this.addedConstructs, {this.blockedConstruct, this.targetID}); + AnalyticsUpdate(this.addedConstructs, {this.targetID}); } class ConstructLevelUpdate { @@ -86,6 +85,18 @@ class AnalyticsUpdateDispatcher { UserSetLemmaInfo lemmaInfo, ) => _lemmaInfoUpdateStream.add(MapEntry(constructId, lemmaInfo)); + Future sendBlockedConstructUpdate( + ConstructIdentifier blockedConstruct, + ) async { + await dataService.updateBlockedConstructs(blockedConstruct); + final update = AnalyticsStreamUpdate(blockedConstruct: blockedConstruct); + constructUpdateStream.add(update); + } + + void sendEmptyAnalyticsUpdate() { + constructUpdateStream.add(AnalyticsStreamUpdate()); + } + Future sendServerAnalyticsUpdate( List events, ) async { @@ -113,9 +124,6 @@ class AnalyticsUpdateDispatcher { case final XPGainedEvent e: _onXPGained(e.points, e.targetID); break; - case final ConstructBlockedEvent e: - _onBlockedConstruct(e.blockedConstruct); - break; case final ConstructLevelUpEvent e: _onConstructLevelUp(e.constructId, e.level, e.targetID); break; @@ -163,11 +171,6 @@ class AnalyticsUpdateDispatcher { ); } - void _onBlockedConstruct(ConstructIdentifier constructId) { - final update = AnalyticsStreamUpdate(blockedConstruct: constructId); - constructUpdateStream.add(update); - } - void _onNewConstruct(Set constructIds) { if (constructIds.isEmpty) return; newConstructsStream.add(constructIds); diff --git a/lib/pangea/analytics_data/analytics_update_events.dart b/lib/pangea/analytics_data/analytics_update_events.dart index a202baa06..e35767943 100644 --- a/lib/pangea/analytics_data/analytics_update_events.dart +++ b/lib/pangea/analytics_data/analytics_update_events.dart @@ -27,11 +27,6 @@ class XPGainedEvent extends AnalyticsUpdateEvent { XPGainedEvent(this.points, this.targetID); } -class ConstructBlockedEvent extends AnalyticsUpdateEvent { - final ConstructIdentifier blockedConstruct; - ConstructBlockedEvent(this.blockedConstruct); -} - class NewConstructsEvent extends AnalyticsUpdateEvent { final Set newConstructs; NewConstructsEvent(this.newConstructs); diff --git a/lib/pangea/analytics_data/analytics_update_service.dart b/lib/pangea/analytics_data/analytics_update_service.dart index 7d11ed795..156b035c8 100644 --- a/lib/pangea/analytics_data/analytics_update_service.dart +++ b/lib/pangea/analytics_data/analytics_update_service.dart @@ -127,9 +127,6 @@ class AnalyticsUpdateService { if (analyticsRoom == null) return; await analyticsRoom.addActivityRoomId(roomId); - if (lang.langCodeShort == _l2?.langCodeShort) { - dataService.updateDispatcher.sendActivityAnalyticsUpdate(roomId); - } } Future blockConstruct(ConstructIdentifier constructId) async { @@ -143,7 +140,6 @@ class AnalyticsUpdateService { ); await analyticsRoom.setAnalyticsSettings(updated); - await dataService.updateBlockedConstructs(constructId); } Future setLemmaInfo( @@ -160,7 +156,6 @@ class AnalyticsUpdateService { meaning: meaning, ); if (userLemmaInfo == updated) return; - dataService.updateDispatcher.sendLemmaInfoUpdate(constructId, updated); try { await analyticsRoom.setUserSetLemmaInfo(constructId, updated); diff --git a/pubspec.lock b/pubspec.lock index e7d3e9179..47cfd7155 100644 --- a/pubspec.lock +++ b/pubspec.lock @@ -538,6 +538,13 @@ packages: url: "https://pub.dev" source: hosted version: "1.3.3" + fcm_shared_isolate: + dependency: "direct overridden" + description: + path: "pangea_packages/fcm_shared_isolate" + relative: true + source: path + version: "0.2.0" ffi: dependency: transitive description: diff --git a/pubspec.yaml b/pubspec.yaml index 188e91b74..fa51d0f34 100644 --- a/pubspec.yaml +++ b/pubspec.yaml @@ -170,4 +170,6 @@ flutter: # 1. Don't do it if you can avoid it or fix it upstream in a manageable time # 2. Always link an (upstream?) issue # 3. Explain how and when this can be removed (overrides must be temporarily) -dependency_overrides: \ No newline at end of file +dependency_overrides: + fcm_shared_isolate: + path: pangea_packages/fcm_shared_isolate \ No newline at end of file