From 91f5fab0ea29a5dbe67468d44ab4092e5ae929e8 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Tue, 4 Jun 2024 10:00:04 -0400 Subject: [PATCH] fix for out-of-date cached analytics not updating --- .../message_analytics_controller.dart | 55 ++++++++++++++----- .../controllers/my_analytics_controller.dart | 19 +++++++ .../pages/analytics/base_analytics.dart | 10 +--- .../pages/analytics/base_analytics_view.dart | 12 ++-- .../pages/analytics/construct_list.dart | 15 ++--- 5 files changed, 75 insertions(+), 36 deletions(-) diff --git a/lib/pangea/controllers/message_analytics_controller.dart b/lib/pangea/controllers/message_analytics_controller.dart index 954bb357e..1a5741db7 100644 --- a/lib/pangea/controllers/message_analytics_controller.dart +++ b/lib/pangea/controllers/message_analytics_controller.dart @@ -117,6 +117,7 @@ class AnalyticsController extends BaseController { ChartAnalyticsModel? getAnalyticsLocal({ TimeSpan? timeSpan, required AnalyticsSelected defaultSelected, + required DateTime? analyticsLastUpdated, AnalyticsSelected? selected, bool forceUpdate = false, bool updateExpired = false, @@ -132,8 +133,11 @@ class AnalyticsController extends BaseController { ); if (index != -1) { + final DateTime? cachedLastUpdate = + _cachedAnalyticsModels[index].summaryLastUpdated; if ((updateExpired && _cachedAnalyticsModels[index].isExpired) || - forceUpdate) { + forceUpdate || + cachedLastUpdate != analyticsLastUpdated) { _cachedAnalyticsModels.removeAt(index); } else { return _cachedAnalyticsModels[index].chartAnalyticsModel; @@ -146,6 +150,7 @@ class AnalyticsController extends BaseController { void cacheAnalytics({ required ChartAnalyticsModel chartAnalyticsModel, required AnalyticsSelected defaultSelected, + required DateTime? summaryLastUpdated, AnalyticsSelected? selected, TimeSpan? timeSpan, }) { @@ -155,6 +160,7 @@ class AnalyticsController extends BaseController { chartAnalyticsModel: chartAnalyticsModel, defaultSelected: defaultSelected, selected: selected, + summaryLastUpdated: summaryLastUpdated, ), ); } @@ -273,10 +279,13 @@ class AnalyticsController extends BaseController { bool forceUpdate = false, }) async { try { + final DateTime? analyticsLastUpdated = await _pangeaController.myAnalytics + .analyticsLastUpdated(PangeaEventTypes.summaryAnalytics); final local = getAnalyticsLocal( defaultSelected: defaultSelected, selected: selected, forceUpdate: forceUpdate, + analyticsLastUpdated: analyticsLastUpdated, ); if (local != null && !forceUpdate) { return local; @@ -330,6 +339,7 @@ class AnalyticsController extends BaseController { defaultSelected: defaultSelected, selected: selected, timeSpan: currentAnalyticsTimeSpan, + summaryLastUpdated: analyticsLastUpdated, ); } @@ -510,26 +520,36 @@ class AnalyticsController extends BaseController { required TimeSpan timeSpan, required ConstructType constructType, required AnalyticsSelected defaultSelected, + required DateTime? constructsLastUpdated, AnalyticsSelected? selected, }) { - final cachedEntry = _cachedConstructs - .firstWhereOrNull( - (e) => - e.timeSpan == timeSpan && - e.type == constructType && - e.defaultSelected.id == defaultSelected.id && - e.defaultSelected.type == defaultSelected.type && - e.selected?.id == selected?.id && - e.selected?.type == selected?.type, - ) - ?.events; - return cachedEntry; + final index = _cachedConstructs.indexWhere( + (e) => + e.timeSpan == timeSpan && + e.type == constructType && + e.defaultSelected.id == defaultSelected.id && + e.defaultSelected.type == defaultSelected.type && + e.selected?.id == selected?.id && + e.selected?.type == selected?.type, + ); + + if (index > -1) { + if (_cachedConstructs[index].constructsLastUpdated != + constructsLastUpdated) { + _cachedConstructs.removeAt(index); + return null; + } + return _cachedConstructs[index].events; + } + + return null; } void cacheConstructs({ required ConstructType constructType, required List events, required AnalyticsSelected defaultSelected, + required DateTime? constructsLastUpdated, AnalyticsSelected? selected, }) { _cachedConstructs.add( @@ -539,6 +559,7 @@ class AnalyticsController extends BaseController { events: events, defaultSelected: defaultSelected, selected: selected, + constructsLastUpdated: constructsLastUpdated, ), ); } @@ -638,11 +659,14 @@ class AnalyticsController extends BaseController { bool removeIT = false, bool forceUpdate = false, }) async { + final DateTime? constructsLastUpdated = await _pangeaController.myAnalytics + .analyticsLastUpdated(PangeaEventTypes.construct); final List? local = getConstructsLocal( timeSpan: currentAnalyticsTimeSpan, constructType: constructType, defaultSelected: defaultSelected, selected: selected, + constructsLastUpdated: constructsLastUpdated, ); if (local != null && !forceUpdate) { _constructs = local; @@ -691,6 +715,7 @@ class AnalyticsController extends BaseController { events: _constructs!, defaultSelected: defaultSelected, selected: selected, + constructsLastUpdated: constructsLastUpdated, ); } @@ -705,12 +730,14 @@ class ConstructCacheEntry { final List events; final AnalyticsSelected defaultSelected; AnalyticsSelected? selected; + final DateTime? constructsLastUpdated; ConstructCacheEntry({ required this.timeSpan, required this.type, required this.events, required this.defaultSelected, + required this.constructsLastUpdated, this.selected, }); } @@ -721,11 +748,13 @@ class AnalyticsCacheModel { final AnalyticsSelected defaultSelected; AnalyticsSelected? selected; late DateTime _createdAt; + final DateTime? summaryLastUpdated; AnalyticsCacheModel({ required this.timeSpan, required this.chartAnalyticsModel, required this.defaultSelected, + required this.summaryLastUpdated, this.selected, }) { _createdAt = DateTime.now(); diff --git a/lib/pangea/controllers/my_analytics_controller.dart b/lib/pangea/controllers/my_analytics_controller.dart index 2b296009e..608596c93 100644 --- a/lib/pangea/controllers/my_analytics_controller.dart +++ b/lib/pangea/controllers/my_analytics_controller.dart @@ -316,6 +316,25 @@ class MyAnalyticsController extends BaseController { } return aggregatedConstructs; } + + Future analyticsLastUpdated(String type) async { + final List analyticsRooms = + _pangeaController.matrixState.client.allMyAnalyticsRooms; + if (analyticsRooms.isEmpty) return null; + final List lastUpdates = []; + for (final analyticsRoom in analyticsRooms) { + final AnalyticsEvent? lastEvent = + await analyticsRoom.getLastAnalyticsEvent( + type, + ); + if (lastEvent?.content.lastUpdated != null) { + lastUpdates.add(lastEvent!.content.lastUpdated!); + } + } + return lastUpdates.reduce( + (value, element) => value.isAfter(element) ? value : element, + ); + } } class AggregateConstructUses { diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart index f0234e854..2cc2fce6c 100644 --- a/lib/pangea/pages/analytics/base_analytics.dart +++ b/lib/pangea/pages/analytics/base_analytics.dart @@ -65,14 +65,8 @@ class BaseAnalyticsController extends State { AnalyticsSelected? params, { forceUpdate = false, }) async { - ChartAnalyticsModel? data = pangeaController.analytics.getAnalyticsLocal( - timeSpan: currentTimeSpan, - defaultSelected: widget.defaultSelected, - selected: params, - forceUpdate: forceUpdate, - ); - - data ??= await pangeaController.analytics.getAnalytics( + final ChartAnalyticsModel data = + await pangeaController.analytics.getAnalytics( defaultSelected: widget.defaultSelected, selected: params, forceUpdate: forceUpdate, diff --git a/lib/pangea/pages/analytics/base_analytics_view.dart b/lib/pangea/pages/analytics/base_analytics_view.dart index 5c2b9fef1..f8ca491be 100644 --- a/lib/pangea/pages/analytics/base_analytics_view.dart +++ b/lib/pangea/pages/analytics/base_analytics_view.dart @@ -95,11 +95,13 @@ class BaseAnalyticsView extends StatelessWidget { Row( mainAxisAlignment: MainAxisAlignment.end, children: [ - IconButton( - icon: const Icon(Icons.refresh), - onPressed: controller.onRefresh, - tooltip: L10n.of(context)!.refresh, - ), + if (controller.widget.defaultSelected.type == + AnalyticsEntryType.student) + IconButton( + icon: const Icon(Icons.refresh), + onPressed: controller.onRefresh, + tooltip: L10n.of(context)!.refresh, + ), TimeSpanMenuButton( value: controller.currentTimeSpan, onChange: (TimeSpan value) => diff --git a/lib/pangea/pages/analytics/construct_list.dart b/lib/pangea/pages/analytics/construct_list.dart index dd5025b46..6b60b2ca2 100644 --- a/lib/pangea/pages/analytics/construct_list.dart +++ b/lib/pangea/pages/analytics/construct_list.dart @@ -278,14 +278,16 @@ class ConstructListViewState extends State { @override Widget build(BuildContext context) { + debugPrint( + "constructs lengths: ${constructs?.map((x) => '${x.lemma}: ${x.uses.length}').toList()}", + ); if (!widget.init || fetchingUses) { return const Expanded( child: Center(child: CircularProgressIndicator()), ); } - if ((constructs?.isEmpty ?? true) || - (widget.controller.currentLemma != null && currentConstruct == null)) { + if (constructs?.isEmpty ?? true) { return Expanded( child: Center(child: Text(L10n.of(context)!.noDataFound)), ); @@ -551,14 +553,7 @@ class ConstructMessageMetadata extends StatelessWidget { @override Widget build(BuildContext context) { - final String roomName = msgEvent.event.room.name.isEmpty - ? Matrix.of(context) - .client - .getRoomById(msgEvent.event.room.id) - ?.getLocalizedDisplayname() ?? - "" - : msgEvent.event.room.name; - + final String roomName = msgEvent.event.room.getLocalizedDisplayname(); return Padding( padding: const EdgeInsets.fromLTRB(10, 0, 30, 0), child: Column(