Merge pull request #724 from pangeachat/cache-completed-activities

cache number of completed activities
pull/1402/head
ggurdin 1 year ago committed by GitHub
commit b0e8b1a652
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

@ -5,4 +5,5 @@ class PLocalKey {
static const String dismissedPaywall = 'dismissedPaywall'; static const String dismissedPaywall = 'dismissedPaywall';
static const String paywallBackoff = 'paywallBackoff'; static const String paywallBackoff = 'paywallBackoff';
static const String messagesSinceUpdate = 'messagesSinceLastUpdate'; static const String messagesSinceUpdate = 'messagesSinceLastUpdate';
static const String completedActivities = 'completedActivities';
} }

@ -1,6 +1,8 @@
import 'dart:async'; import 'dart:async';
import 'dart:collection';
import 'dart:developer'; import 'dart:developer';
import 'package:fluffychat/pangea/constants/local.key.dart';
import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/constants/pangea_event_types.dart';
import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/controllers/pangea_controller.dart';
import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart';
@ -21,6 +23,7 @@ class _RecordCacheItem {
/// Controller for handling activity completions. /// Controller for handling activity completions.
class PracticeActivityRecordController { class PracticeActivityRecordController {
static const int maxStoredEvents = 100;
static final Map<int, _RecordCacheItem> _cache = {}; static final Map<int, _RecordCacheItem> _cache = {};
late final PangeaController _pangeaController; late final PangeaController _pangeaController;
Timer? _cacheClearTimer; Timer? _cacheClearTimer;
@ -29,6 +32,49 @@ class PracticeActivityRecordController {
_initializeCacheClearing(); _initializeCacheClearing();
} }
LinkedHashMap<String, int> get completedActivities {
try {
final dynamic locallySaved = _pangeaController.pStoreService.read(
PLocalKey.completedActivities,
);
if (locallySaved == null) return LinkedHashMap<String, int>();
try {
final LinkedHashMap<String, int> cache =
LinkedHashMap<String, int>.from(locallySaved);
return cache;
} catch (err) {
_pangeaController.pStoreService.delete(
PLocalKey.completedActivities,
);
return LinkedHashMap<String, int>();
}
} catch (exception, stackTrace) {
ErrorHandler.logError(
e: PangeaWarningError(
"Failed to get completed activities from cache: $exception",
),
s: stackTrace,
m: 'Failed to get completed activities from cache',
);
return LinkedHashMap<String, int>();
}
}
Future<void> completeActivity(String messageID) async {
final LinkedHashMap<String, int> currentCache = completedActivities;
final numCompleted = currentCache[messageID] ?? 0;
currentCache[messageID] = numCompleted + 1;
if (currentCache.length > maxStoredEvents) {
currentCache.remove(currentCache.keys.first);
}
await _pangeaController.pStoreService.save(
PLocalKey.completedActivities,
currentCache,
);
}
void _initializeCacheClearing() { void _initializeCacheClearing() {
const duration = Duration(minutes: 2); const duration = Duration(minutes: 2);
_cacheClearTimer = Timer.periodic(duration, (Timer t) => _clearCache()); _cacheClearTimer = Timer.periodic(duration, (Timer t) => _clearCache());

@ -583,13 +583,15 @@ class PangeaMessageEvent {
/// Otherwise, it checks if every activity in the list is complete using the [isComplete] property. /// Otherwise, it checks if every activity in the list is complete using the [isComplete] property.
/// If any activity is not complete, it returns true, indicating that the activity icon should be shown. /// If any activity is not complete, it returns true, indicating that the activity icon should be shown.
/// Otherwise, it returns false. /// Otherwise, it returns false.
bool get hasUncompletedActivity { // bool get hasUncompletedActivity {
if (practiceActivities.isEmpty) return false; // if (practiceActivities.isEmpty) return false;
return practiceActivities.any((activity) => !(activity.isComplete)); // return practiceActivities.any((activity) => !(activity.isComplete));
} // }
int get numberOfActivitiesCompleted { int get numberOfActivitiesCompleted {
return practiceActivities.where((activity) => activity.isComplete).length; return MatrixState.pangeaController.activityRecordController
.completedActivities[eventId] ??
0;
} }
String? get l2Code => String? get l2Code =>

@ -63,30 +63,26 @@ class PracticeActivityEvent {
/// Completion record assosiated with this activity /// Completion record assosiated with this activity
/// for the logged in user, null if there is none /// for the logged in user, null if there is none
List<PracticeActivityRecordEvent> get allUserRecords => allRecords // List<PracticeActivityRecordEvent> get allUserRecords => allRecords
.where( // .where(
(recordEvent) => // (recordEvent) =>
recordEvent.event.senderId == recordEvent.event.room.client.userID, // recordEvent.event.senderId == recordEvent.event.room.client.userID,
) // )
.toList(); // .toList();
/// Get the most recent user record for this activity /// Get the most recent user record for this activity
PracticeActivityRecordEvent? get latestUserRecord { // PracticeActivityRecordEvent? get latestUserRecord {
final List<PracticeActivityRecordEvent> userRecords = allUserRecords; // final List<PracticeActivityRecordEvent> userRecords = allUserRecords;
if (userRecords.isEmpty) return null; // if (userRecords.isEmpty) return null;
return userRecords.reduce( // return userRecords.reduce(
(a, b) => a.event.originServerTs.isAfter(b.event.originServerTs) ? a : b, // (a, b) => a.event.originServerTs.isAfter(b.event.originServerTs) ? a : b,
); // );
} // }
DateTime? get lastCompletedAt => latestUserRecord?.event.originServerTs; // DateTime? get lastCompletedAt => latestUserRecord?.event.originServerTs;
String get parentMessageId => event.relationshipEventId!; String get parentMessageId => event.relationshipEventId!;
/// Checks if there are any user records in the list for this activity,
/// and, if so, then the activity is complete
bool get isComplete => latestUserRecord != null;
ExistingActivityMetaData get activityRequestMetaData => ExistingActivityMetaData get activityRequestMetaData =>
ExistingActivityMetaData( ExistingActivityMetaData(
activityEventId: event.eventId, activityEventId: event.eventId,

@ -197,6 +197,9 @@ class MessagePracticeActivityCardState extends State<PracticeActivityCard> {
); );
widget.overlayController.onActivityFinish(); widget.overlayController.onActivityFinish();
pangeaController.activityRecordController.completeActivity(
widget.pangeaMessageEvent.eventId,
);
// //
final Iterable<dynamic> result = await Future.wait([ final Iterable<dynamic> result = await Future.wait([

Loading…
Cancel
Save