Merge pull request #5661 from pangeachat/respond-to-analytics-server-updates
Respond to analytics server updates
This commit is contained in:
commit
81e68fe556
11 changed files with 225 additions and 107 deletions
|
|
@ -130,29 +130,24 @@ class AnalyticsDataService {
|
|||
await _analyticsClientGetter.database.updateUserID(client.userID!);
|
||||
}
|
||||
|
||||
final resp = await client.getUserProfile(client.userID!);
|
||||
final analyticsProfile = AnalyticsProfileModel.fromJson(
|
||||
resp.additionalProperties,
|
||||
);
|
||||
|
||||
_syncController?.dispose();
|
||||
_syncController = AnalyticsSyncController(
|
||||
client: client,
|
||||
dataService: this,
|
||||
);
|
||||
|
||||
await _syncController!.bulkUpdate();
|
||||
|
||||
final vocab = await getAggregatedConstructs(ConstructTypeEnum.vocab);
|
||||
final morphs = await getAggregatedConstructs(ConstructTypeEnum.morph);
|
||||
final constructs = [...vocab.values, ...morphs.values];
|
||||
final totalXP = constructs.fold(0, (total, c) => total + c.points);
|
||||
await _analyticsClientGetter.database.updateDerivedStats(
|
||||
DerivedAnalyticsDataModel(
|
||||
totalXP: totalXP,
|
||||
offset: analyticsProfile.xpOffset ?? 0,
|
||||
),
|
||||
final resp = await client.getUserProfile(client.userID!);
|
||||
final analyticsProfile = AnalyticsProfileModel.fromJson(
|
||||
resp.additionalProperties,
|
||||
);
|
||||
|
||||
final l2 = MatrixState.pangeaController.userController.userL2;
|
||||
if (l2 != null) {
|
||||
await updateXPOffset(analyticsProfile.xpOffsetByLanguage(l2) ?? 0);
|
||||
}
|
||||
|
||||
_syncController!.start();
|
||||
|
||||
await _initMergeTable();
|
||||
|
|
@ -161,7 +156,7 @@ class AnalyticsDataService {
|
|||
} finally {
|
||||
Logs().i("Analytics database initialized.");
|
||||
initCompleter.complete();
|
||||
updateDispatcher.sendConstructAnalyticsUpdate(AnalyticsUpdate([]));
|
||||
updateDispatcher.sendEmptyAnalyticsUpdate();
|
||||
updateDispatcher.sendActivityAnalyticsUpdate(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -413,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;
|
||||
|
|
@ -422,7 +417,7 @@ class AnalyticsDataService {
|
|||
events.add(XPGainedEvent(points, update.targetID));
|
||||
}
|
||||
|
||||
final newData = prevData.copyWith(totalXP: prevData.totalXP + points);
|
||||
final newData = prevData.addXP(points);
|
||||
await _analyticsClientGetter.database.updateDerivedStats(newData);
|
||||
|
||||
// Update public profile each time that new analytics are added.
|
||||
|
|
@ -474,10 +469,6 @@ class AnalyticsDataService {
|
|||
}
|
||||
}
|
||||
|
||||
if (update.blockedConstruct != null) {
|
||||
events.add(ConstructBlockedEvent(update.blockedConstruct!));
|
||||
}
|
||||
|
||||
if (newUnusedConstructs.isNotEmpty) {
|
||||
events.add(NewConstructsEvent(newUnusedConstructs));
|
||||
}
|
||||
|
|
@ -494,6 +485,12 @@ class AnalyticsDataService {
|
|||
_mergeTable.addConstructsByUses(event.content.uses, blocked);
|
||||
}
|
||||
await _analyticsClientGetter.database.updateServerAnalytics(events);
|
||||
final vocab = await getAggregatedConstructs(ConstructTypeEnum.vocab);
|
||||
final morphs = await getAggregatedConstructs(ConstructTypeEnum.morph);
|
||||
final constructs = [...vocab.values, ...morphs.values];
|
||||
final totalXP = constructs.fold(0, (total, c) => total + c.points);
|
||||
|
||||
await _analyticsClientGetter.database.updateTotalXP(totalXP);
|
||||
}
|
||||
|
||||
Future<void> updateBlockedConstructs(ConstructIdentifier constructId) async {
|
||||
|
|
@ -512,14 +509,8 @@ class AnalyticsDataService {
|
|||
level: newLevel,
|
||||
);
|
||||
|
||||
await _analyticsClientGetter.database.updateDerivedStats(
|
||||
DerivedAnalyticsDataModel(totalXP: newXP),
|
||||
);
|
||||
|
||||
await _analyticsClientGetter.database.updateTotalXP(newXP);
|
||||
_invalidateCaches();
|
||||
updateDispatcher.sendConstructAnalyticsUpdate(
|
||||
AnalyticsUpdate([], blockedConstruct: constructId),
|
||||
);
|
||||
}
|
||||
|
||||
Future<void> clearLocalAnalytics() async {
|
||||
|
|
|
|||
|
|
@ -468,7 +468,15 @@ class AnalyticsDatabase with DatabaseFileStorage {
|
|||
Future<void> updateXPOffset(int offset) {
|
||||
return _transaction(() async {
|
||||
final stats = await getDerivedStats();
|
||||
final updatedStats = stats.copyWith(offset: offset);
|
||||
final updatedStats = stats.copyWithOffset(offset);
|
||||
await _derivedStatsBox.put('derived_stats', updatedStats.toJson());
|
||||
});
|
||||
}
|
||||
|
||||
Future<void> updateTotalXP(int totalXP) {
|
||||
return _transaction(() async {
|
||||
final stats = await getDerivedStats();
|
||||
final updatedStats = stats.copyWithTotalXP(totalXP);
|
||||
await _derivedStatsBox.put('derived_stats', updatedStats.toJson());
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,36 @@ import 'dart:async';
|
|||
import 'package:matrix/matrix.dart';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_data/analytics_data_service.dart';
|
||||
import 'package:fluffychat/pangea/analytics_data/analytics_update_dispatcher.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;
|
||||
|
|
@ -31,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<void> _dispatchSyncEvents(
|
||||
_AnalyticsUpdateEvent type,
|
||||
List<MatrixEvent> 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<void> _onConstructEvents(
|
||||
List<MatrixEvent> events,
|
||||
Room analyticsRoom,
|
||||
) async {
|
||||
final constructEvents = events
|
||||
.map(
|
||||
(e) => ConstructAnalyticsEvent(
|
||||
|
|
@ -50,16 +101,65 @@ class AnalyticsSyncController {
|
|||
.toList();
|
||||
|
||||
if (constructEvents.isEmpty) return;
|
||||
await dataService.updateServerAnalytics(constructEvents);
|
||||
|
||||
// Server updates do not usually need to update the UI, since usually they are only
|
||||
// transfering local data to the server. However, if a user if using multiple devices,
|
||||
// we do need to update the UI when new data comes from the server.
|
||||
dataService.updateDispatcher.sendConstructAnalyticsUpdate(
|
||||
AnalyticsUpdate([]),
|
||||
await dataService.updateDispatcher.sendServerAnalyticsUpdate(
|
||||
constructEvents,
|
||||
);
|
||||
}
|
||||
|
||||
void _onActivityEvents(List<MatrixEvent> events) {
|
||||
for (final event in events) {
|
||||
if (event.content[ModelKey.roomIds] is! List) continue;
|
||||
final roomIds = List<String>.from(
|
||||
event.content[ModelKey.roomIds]! as List,
|
||||
);
|
||||
final prevContent =
|
||||
event.unsigned?['prev_content'] as Map<String, Object?>?;
|
||||
final prevRoomIds =
|
||||
prevContent != null && prevContent[ModelKey.roomIds] is List
|
||||
? List<String>.from(prevContent[ModelKey.roomIds] as List)
|
||||
: [];
|
||||
final newRoomIds = roomIds
|
||||
.where((id) => !prevRoomIds.contains(id))
|
||||
.toList();
|
||||
|
||||
if (newRoomIds.isNotEmpty) {
|
||||
dataService.updateDispatcher.sendActivityAnalyticsUpdate(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void _onLemmaInfoEvents(List<MatrixEvent> 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<void> _onBlockedConstructEvents(List<MatrixEvent> events) async {
|
||||
for (final event in events) {
|
||||
final current = AnalyticsSettingsModel.fromJson(event.content);
|
||||
final prevContent =
|
||||
event.unsigned?['prev_content'] as Map<String, Object?>?;
|
||||
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<void> waitForSync(String analyticsRoomId) async {
|
||||
await client.onSync.stream.firstWhere((update) {
|
||||
final roomUpdate = update.rooms?.join?[analyticsRoomId];
|
||||
|
|
|
|||
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:fluffychat/pangea/analytics_data/analytics_data_service.dart';
|
||||
import 'package:fluffychat/pangea/analytics_data/analytics_update_events.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_event.dart';
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_identifier.dart';
|
||||
import 'package:fluffychat/pangea/constructs/construct_level_enum.dart';
|
||||
|
|
@ -16,10 +17,9 @@ class LevelUpdate {
|
|||
|
||||
class AnalyticsUpdate {
|
||||
final List<OneConstructUse> addedConstructs;
|
||||
final ConstructIdentifier? blockedConstruct;
|
||||
final String? targetID;
|
||||
|
||||
AnalyticsUpdate(this.addedConstructs, {this.blockedConstruct, this.targetID});
|
||||
AnalyticsUpdate(this.addedConstructs, {this.targetID});
|
||||
}
|
||||
|
||||
class ConstructLevelUpdate {
|
||||
|
|
@ -85,9 +85,26 @@ class AnalyticsUpdateDispatcher {
|
|||
UserSetLemmaInfo lemmaInfo,
|
||||
) => _lemmaInfoUpdateStream.add(MapEntry(constructId, lemmaInfo));
|
||||
|
||||
Future<void> sendConstructAnalyticsUpdate(
|
||||
AnalyticsUpdate analyticsUpdate,
|
||||
Future<void> sendBlockedConstructUpdate(
|
||||
ConstructIdentifier blockedConstruct,
|
||||
) async {
|
||||
await dataService.updateBlockedConstructs(blockedConstruct);
|
||||
final update = AnalyticsStreamUpdate(blockedConstruct: blockedConstruct);
|
||||
constructUpdateStream.add(update);
|
||||
}
|
||||
|
||||
void sendEmptyAnalyticsUpdate() {
|
||||
constructUpdateStream.add(AnalyticsStreamUpdate());
|
||||
}
|
||||
|
||||
Future<void> sendServerAnalyticsUpdate(
|
||||
List<ConstructAnalyticsEvent> events,
|
||||
) async {
|
||||
await dataService.updateServerAnalytics(events);
|
||||
sendEmptyAnalyticsUpdate();
|
||||
}
|
||||
|
||||
Future<void> sendLocalAnalyticsUpdate(AnalyticsUpdate analyticsUpdate) async {
|
||||
final events = await dataService.updateLocalAnalytics(analyticsUpdate);
|
||||
for (final event in events) {
|
||||
_dispatch(event);
|
||||
|
|
@ -105,9 +122,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;
|
||||
|
|
@ -155,11 +169,6 @@ class AnalyticsUpdateDispatcher {
|
|||
);
|
||||
}
|
||||
|
||||
void _onBlockedConstruct(ConstructIdentifier constructId) {
|
||||
final update = AnalyticsStreamUpdate(blockedConstruct: constructId);
|
||||
constructUpdateStream.add(update);
|
||||
}
|
||||
|
||||
void _onNewConstruct(Set<ConstructIdentifier> constructIds) {
|
||||
if (constructIds.isEmpty) return;
|
||||
newConstructsStream.add(constructIds);
|
||||
|
|
|
|||
|
|
@ -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<ConstructIdentifier> newConstructs;
|
||||
NewConstructsEvent(this.newConstructs);
|
||||
|
|
|
|||
|
|
@ -62,7 +62,7 @@ class AnalyticsUpdateService {
|
|||
List<OneConstructUse> newConstructs, {
|
||||
bool forceUpdate = false,
|
||||
}) async {
|
||||
await dataService.updateDispatcher.sendConstructAnalyticsUpdate(
|
||||
await dataService.updateDispatcher.sendLocalAnalyticsUpdate(
|
||||
AnalyticsUpdate(newConstructs, targetID: targetID),
|
||||
);
|
||||
|
||||
|
|
@ -127,9 +127,6 @@ class AnalyticsUpdateService {
|
|||
if (analyticsRoom == null) return;
|
||||
|
||||
await analyticsRoom.addActivityRoomId(roomId);
|
||||
if (lang.langCodeShort == _l2?.langCodeShort) {
|
||||
dataService.updateDispatcher.sendActivityAnalyticsUpdate(roomId);
|
||||
}
|
||||
}
|
||||
|
||||
Future<void> blockConstruct(ConstructIdentifier constructId) async {
|
||||
|
|
@ -143,7 +140,6 @@ class AnalyticsUpdateService {
|
|||
);
|
||||
|
||||
await analyticsRoom.setAnalyticsSettings(updated);
|
||||
await dataService.updateBlockedConstructs(constructId);
|
||||
}
|
||||
|
||||
Future<void> setLemmaInfo(
|
||||
|
|
@ -160,7 +156,6 @@ class AnalyticsUpdateService {
|
|||
meaning: meaning,
|
||||
);
|
||||
if (userLemmaInfo == updated) return;
|
||||
dataService.updateDispatcher.sendLemmaInfoUpdate(constructId, updated);
|
||||
|
||||
try {
|
||||
await analyticsRoom.setUserSetLemmaInfo(constructId, updated);
|
||||
|
|
|
|||
|
|
@ -1,6 +1,5 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:fluffychat/pangea/analytics_misc/constructs_model.dart';
|
||||
import 'package:fluffychat/pangea/common/utils/error_handler.dart';
|
||||
|
||||
class DerivedAnalyticsDataModel {
|
||||
|
|
@ -12,7 +11,7 @@ class DerivedAnalyticsDataModel {
|
|||
|
||||
int get totalXP => _totalXP + offset;
|
||||
|
||||
int get level => calculateLevelWithXp(_totalXP);
|
||||
int get level => calculateLevelWithXp(totalXP);
|
||||
|
||||
// the minimum XP required for a given level
|
||||
int get _minXPForLevel => calculateXpWithLevel(level);
|
||||
|
|
@ -23,7 +22,7 @@ class DerivedAnalyticsDataModel {
|
|||
// the progress within the current level as a percentage (0.0 to 1.0)
|
||||
double get levelProgress {
|
||||
final progress =
|
||||
(_totalXP - _minXPForLevel) / (minXPForNextLevel - _minXPForLevel);
|
||||
(totalXP - _minXPForLevel) / (minXPForNextLevel - _minXPForLevel);
|
||||
return progress >= 0 ? progress : 0;
|
||||
}
|
||||
|
||||
|
|
@ -60,35 +59,29 @@ class DerivedAnalyticsDataModel {
|
|||
}
|
||||
}
|
||||
|
||||
DerivedAnalyticsDataModel update(List<OneConstructUse> uses) {
|
||||
int xp = _totalXP;
|
||||
|
||||
for (final u in uses) {
|
||||
xp += u.xp;
|
||||
}
|
||||
|
||||
return copyWith(totalXP: xp);
|
||||
DerivedAnalyticsDataModel copyWithOffset(int offset) {
|
||||
return DerivedAnalyticsDataModel(totalXP: _totalXP, offset: offset);
|
||||
}
|
||||
|
||||
DerivedAnalyticsDataModel merge(DerivedAnalyticsDataModel other) {
|
||||
DerivedAnalyticsDataModel copyWithTotalXP(int totalXP) {
|
||||
return DerivedAnalyticsDataModel(totalXP: totalXP, offset: offset);
|
||||
}
|
||||
|
||||
DerivedAnalyticsDataModel addXP(int xpToAdd) {
|
||||
return DerivedAnalyticsDataModel(
|
||||
totalXP: _totalXP + other.totalXP,
|
||||
totalXP: _totalXP + xpToAdd,
|
||||
offset: offset,
|
||||
);
|
||||
}
|
||||
|
||||
DerivedAnalyticsDataModel copyWith({int? totalXP, int? offset}) {
|
||||
factory DerivedAnalyticsDataModel.fromJson(Map<String, dynamic> map) {
|
||||
return DerivedAnalyticsDataModel(
|
||||
totalXP: totalXP ?? this.totalXP,
|
||||
offset: offset ?? this.offset,
|
||||
totalXP: map['total_xp'] ?? 0,
|
||||
offset: map['offset'] ?? 0,
|
||||
);
|
||||
}
|
||||
|
||||
factory DerivedAnalyticsDataModel.fromJson(Map<String, dynamic> map) {
|
||||
return DerivedAnalyticsDataModel(totalXP: map['total_xp'] ?? 0);
|
||||
}
|
||||
|
||||
Map<String, dynamic> toJson() {
|
||||
return {'total_xp': _totalXP};
|
||||
return {'total_xp': _totalXP, 'offset': offset};
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -136,6 +136,9 @@ class AnalyticsProfileModel {
|
|||
int? get level => languageAnalytics?[targetLanguage]?.level;
|
||||
|
||||
int? get xpOffset => languageAnalytics?[targetLanguage]?.xpOffset;
|
||||
|
||||
int? xpOffsetByLanguage(LanguageModel language) =>
|
||||
languageAnalytics?[language]?.xpOffset;
|
||||
}
|
||||
|
||||
class LanguageAnalyticsProfileEntry {
|
||||
|
|
|
|||
|
|
@ -37,8 +37,8 @@ class LanguageUpdate {
|
|||
class UserController {
|
||||
final StreamController<LanguageUpdate> languageStream =
|
||||
StreamController.broadcast();
|
||||
final StreamController settingsUpdateStream =
|
||||
StreamController<Profile>.broadcast();
|
||||
final StreamController<Profile> settingsUpdateStream =
|
||||
StreamController.broadcast();
|
||||
|
||||
/// Cached version of the user profile, so it doesn't have
|
||||
/// to be read in from client's account data each time it is accessed.
|
||||
|
|
@ -52,10 +52,40 @@ class UserController {
|
|||
matrix.Client get client => MatrixState.pangeaController.matrixState.client;
|
||||
|
||||
void _onProfileUpdate(matrix.SyncUpdate sync) {
|
||||
final prevTargetLang = userL2;
|
||||
final prevBaseLang = userL1;
|
||||
|
||||
final profileData = client.accountData[ModelKey.userProfile]?.content;
|
||||
final Profile? fromAccountData = Profile.fromAccountData(profileData);
|
||||
if (fromAccountData != null) {
|
||||
if (fromAccountData != null && fromAccountData != _cachedProfile) {
|
||||
_cachedProfile = fromAccountData;
|
||||
|
||||
if ((prevTargetLang != userL2) || (prevBaseLang != userL1)) {
|
||||
if (userL1 == null || userL2 == null) {
|
||||
// if either language is null, then we want to send a settings update instead of a language update
|
||||
ErrorHandler.logError(
|
||||
e: "One of the user languages is null. Sending settings update instead of language update.",
|
||||
data: {
|
||||
'prevBaseLang': prevBaseLang?.langCode,
|
||||
'prevTargetLang': prevTargetLang?.langCode,
|
||||
'userL1': userL1?.langCode,
|
||||
'userL2': userL2?.langCode,
|
||||
},
|
||||
);
|
||||
settingsUpdateStream.add(fromAccountData);
|
||||
return;
|
||||
}
|
||||
languageStream.add(
|
||||
LanguageUpdate(
|
||||
baseLang: userL1!,
|
||||
targetLang: userL2!,
|
||||
prevBaseLang: prevBaseLang,
|
||||
prevTargetLang: prevTargetLang,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
settingsUpdateStream.add(fromAccountData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -92,8 +122,6 @@ class UserController {
|
|||
waitForDataInSync = false,
|
||||
}) async {
|
||||
await initialize();
|
||||
final prevTargetLang = userL2;
|
||||
final prevBaseLang = userL1;
|
||||
final prevHash = profile.hashCode;
|
||||
|
||||
final Profile updatedProfile = update(profile);
|
||||
|
|
@ -103,19 +131,6 @@ class UserController {
|
|||
}
|
||||
|
||||
await updatedProfile.saveProfileData(waitForDataInSync: waitForDataInSync);
|
||||
|
||||
if ((prevTargetLang != userL2) || (prevBaseLang != userL1)) {
|
||||
languageStream.add(
|
||||
LanguageUpdate(
|
||||
baseLang: userL1!,
|
||||
targetLang: userL2!,
|
||||
prevBaseLang: prevBaseLang,
|
||||
prevTargetLang: prevTargetLang,
|
||||
),
|
||||
);
|
||||
} else {
|
||||
settingsUpdateStream.add(updatedProfile);
|
||||
}
|
||||
}
|
||||
|
||||
/// A completer for the profile model of a user.
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
|
|
|
|||
|
|
@ -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:
|
||||
dependency_overrides:
|
||||
fcm_shared_isolate:
|
||||
path: pangea_packages/fcm_shared_isolate
|
||||
Loading…
Add table
Reference in a new issue