From c8b38ab0732d111bcc80ad4e53521662f72cf498 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Thu, 13 Jun 2024 16:06:07 -0400 Subject: [PATCH] fix for construct caching issues with other user's analytics showing up in the logged in user's analytics --- .../message_analytics_controller.dart | 24 ++--- .../models/analytics/constructs_model.dart | 46 +++++++++- .../pages/analytics/base_analytics.dart | 16 +--- .../class_analytics/class_analytics.dart | 1 + .../pages/analytics/construct_list.dart | 90 ++++++++++--------- 5 files changed, 97 insertions(+), 80 deletions(-) diff --git a/lib/pangea/controllers/message_analytics_controller.dart b/lib/pangea/controllers/message_analytics_controller.dart index 74e6e256e..c0c8ecd1a 100644 --- a/lib/pangea/controllers/message_analytics_controller.dart +++ b/lib/pangea/controllers/message_analytics_controller.dart @@ -514,11 +514,6 @@ class AnalyticsController extends BaseController { //////////////////////////// CONSTRUCTS //////////////////////////// - List? _constructs; - bool settingConstructs = false; - - List? get constructs => _constructs; - Future> allMyConstructs() async { final List analyticsRooms = _pangeaController.matrixState.client.allMyAnalyticsRooms; @@ -782,15 +777,13 @@ class AnalyticsController extends BaseController { } } - Future?> setConstructs({ + Future?> getConstructs({ required ConstructType constructType, required AnalyticsSelected defaultSelected, AnalyticsSelected? selected, bool removeIT = true, bool forceUpdate = false, }) async { - if (settingConstructs) return _constructs; - settingConstructs = true; await _pangeaController.matrixState.client.roomsLoading; Room? space; @@ -807,8 +800,7 @@ class AnalyticsController extends BaseController { "selected": selected, }, ); - settingConstructs = false; - return _constructs; + return []; } await space.postLoad(); langCode = _pangeaController.languageController.activeL2Code( @@ -821,8 +813,7 @@ class AnalyticsController extends BaseController { "space": space, }, ); - settingConstructs = false; - return _constructs; + return []; } } @@ -852,8 +843,6 @@ class AnalyticsController extends BaseController { lastUpdated: lastUpdated, ); if (local != null && !forceUpdate) { - _constructs = local; - settingConstructs = false; return local; } @@ -881,19 +870,16 @@ class AnalyticsController extends BaseController { } } - _constructs = filteredConstructs; - if (local == null) { cacheConstructs( constructType: constructType, - events: _constructs!, + events: filteredConstructs, defaultSelected: defaultSelected, selected: selected, ); } - settingConstructs = false; - return _constructs; + return filteredConstructs; } } diff --git a/lib/pangea/models/analytics/constructs_model.dart b/lib/pangea/models/analytics/constructs_model.dart index 209926f8e..6e6bad1b6 100644 --- a/lib/pangea/models/analytics/constructs_model.dart +++ b/lib/pangea/models/analytics/constructs_model.dart @@ -1,6 +1,7 @@ import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/models/analytics/analytics_model.dart'; import 'package:fluffychat/pangea/models/pangea_token_model.dart'; +import 'package:fluffychat/pangea/utils/error_handler.dart'; import 'package:flutter/material.dart'; import 'package:matrix/matrix.dart'; @@ -16,11 +17,48 @@ class ConstructAnalyticsModel extends AnalyticsModel { static const _usesKey = "uses"; factory ConstructAnalyticsModel.fromJson(Map json) { + final List uses = []; + if (json[_usesKey] is List) { + // This is the new format + uses.addAll( + json[_usesKey] + .map((use) => OneConstructUse.fromJson(use)) + .cast() + .toList(), + ); + } else { + // This is the old format. No data on production should be + // structured this way, but it's useful for testing. + try { + final useValues = (json[_usesKey] as Map).values; + for (final useValue in useValues) { + final lemma = useValue['lemma']; + final lemmaUses = useValue[_usesKey]; + for (final useData in lemmaUses) { + final use = OneConstructUse( + useType: ConstructUseType.ga, + chatId: useData["chatId"], + timeStamp: DateTime.parse(useData["timeStamp"]), + lemma: lemma, + form: useData["form"], + msgId: useData["msgId"], + constructType: ConstructType.grammar, + ); + uses.add(use); + } + } + } catch (err, s) { + debugPrint("Error parsing ConstructAnalyticsModel"); + ErrorHandler.logError( + e: err, + s: s, + m: "Error parsing ConstructAnalyticsModel", + ); + // debugger(when: kDebugMode); + } + } return ConstructAnalyticsModel( - uses: json[_usesKey] - .map((use) => OneConstructUse.fromJson(use)) - .cast() - .toList(), + uses: uses, ); } diff --git a/lib/pangea/pages/analytics/base_analytics.dart b/lib/pangea/pages/analytics/base_analytics.dart index 768050082..2b548226b 100644 --- a/lib/pangea/pages/analytics/base_analytics.dart +++ b/lib/pangea/pages/analytics/base_analytics.dart @@ -1,7 +1,6 @@ import 'dart:async'; import 'package:fluffychat/pangea/constants/pangea_event_types.dart'; -import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; import 'package:fluffychat/pangea/extensions/client_extension/client_extension.dart'; import 'package:fluffychat/pangea/extensions/pangea_room_extension/pangea_room_extension.dart'; import 'package:fluffychat/pangea/models/analytics/analytics_event.dart'; @@ -147,26 +146,13 @@ class BaseAnalyticsController extends State { currentLemma = null; selected = isSelected(selectedParam.id) ? null : selectedParam; }); - - await pangeaController.analytics.setConstructs( - constructType: ConstructType.grammar, - defaultSelected: widget.defaultSelected, - selected: selected, - removeIT: true, - ); await setChartData(); - + refreshStream.add(false); Future.delayed(Duration.zero, () => setState(() {})); } Future toggleTimeSpan(BuildContext context, TimeSpan timeSpan) async { await pangeaController.analytics.setCurrentAnalyticsTimeSpan(timeSpan); - await pangeaController.analytics.setConstructs( - constructType: ConstructType.grammar, - defaultSelected: widget.defaultSelected, - selected: selected, - removeIT: true, - ); await setChartData(); refreshStream.add(false); } diff --git a/lib/pangea/pages/analytics/class_analytics/class_analytics.dart b/lib/pangea/pages/analytics/class_analytics/class_analytics.dart index 7219e7113..9bf5ac7a3 100644 --- a/lib/pangea/pages/analytics/class_analytics/class_analytics.dart +++ b/lib/pangea/pages/analytics/class_analytics/class_analytics.dart @@ -64,6 +64,7 @@ class ClassAnalyticsV2Controller extends State { Future getChatAndStudents() async { try { + await classRoom?.postLoad(); await classRoom?.requestParticipants(); if (classRoom != null) { diff --git a/lib/pangea/pages/analytics/construct_list.dart b/lib/pangea/pages/analytics/construct_list.dart index c227491b9..c1338d550 100644 --- a/lib/pangea/pages/analytics/construct_list.dart +++ b/lib/pangea/pages/analytics/construct_list.dart @@ -6,6 +6,7 @@ import 'package:fluffychat/pangea/controllers/pangea_controller.dart'; import 'package:fluffychat/pangea/enum/construct_type_enum.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_message_event.dart'; import 'package:fluffychat/pangea/matrix_event_wrappers/pangea_representation_event.dart'; +import 'package:fluffychat/pangea/models/analytics/constructs_event.dart'; import 'package:fluffychat/pangea/models/analytics/constructs_model.dart'; import 'package:fluffychat/pangea/models/pangea_match_model.dart'; import 'package:fluffychat/pangea/pages/analytics/base_analytics.dart'; @@ -40,29 +41,9 @@ class ConstructList extends StatefulWidget { } class ConstructListState extends State { - bool initialized = false; String? langCode; String? error; - @override - void initState() { - super.initState(); - widget.pangeaController.analytics - .setConstructs( - constructType: widget.constructType, - removeIT: true, - defaultSelected: widget.defaultSelected, - selected: widget.selected, - forceUpdate: true, - ) - .whenComplete(() => setState(() => initialized = true)); - } - - @override - void dispose() { - super.dispose(); - } - @override Widget build(BuildContext context) { return error != null @@ -72,7 +53,6 @@ class ConstructListState extends State { : Column( children: [ ConstructListView( - init: initialized, controller: widget.controller, pangeaController: widget.pangeaController, defaultSelected: widget.defaultSelected, @@ -94,7 +74,6 @@ class ConstructListState extends State { // subtitle = total uses, equal to construct.content.uses.length // list has a fixed height of 400 and is scrollable class ConstructListView extends StatefulWidget { - final bool init; final BaseAnalyticsController controller; final PangeaController pangeaController; final AnalyticsSelected defaultSelected; @@ -103,7 +82,6 @@ class ConstructListView extends StatefulWidget { const ConstructListView({ super.key, - required this.init, required this.controller, required this.pangeaController, required this.defaultSelected, @@ -120,22 +98,46 @@ class ConstructListViewState extends State { final Map _timelinesCache = {}; final Map _msgEventCache = {}; final List _msgEvents = []; + bool fetchingConstructs = true; bool fetchingUses = false; StreamSubscription? refreshSubscription; @override void initState() { super.initState(); + widget.pangeaController.analytics + .getConstructs( + constructType: constructType, + removeIT: true, + defaultSelected: widget.defaultSelected, + selected: widget.selected, + forceUpdate: true, + ) + .whenComplete(() => setState(() => fetchingConstructs = false)) + .then((value) => setState(() => _constructs = value)); + refreshSubscription = widget.refreshStream.stream.listen((forceUpdate) { - widget.pangeaController.analytics - .setConstructs( - constructType: constructType, - removeIT: true, - defaultSelected: widget.defaultSelected, - selected: widget.selected, - forceUpdate: true, - ) - .then((_) => setState(() {})); + debugPrint("updating constructs"); + // postframe callback to let widget rebuild with the new selected parameter + // before sending selected to getConstructs function + WidgetsBinding.instance.addPostFrameCallback((_) { + widget.pangeaController.analytics + .getConstructs( + constructType: constructType, + removeIT: true, + defaultSelected: widget.defaultSelected, + selected: widget.selected, + forceUpdate: true, + ) + .then( + (value) => setState(() { + _constructs = value; + debugPrint( + "constructs is now: ${constructs?.map((event) => event.uses.map((use) => use.lemma)).toList()}", + ); + }), + ); + }); }); } @@ -219,18 +221,19 @@ class ConstructListViewState extends State { } } + List? _constructs; + List? get constructs { - if (widget.pangeaController.analytics.constructs == null) { + if (_constructs == null) { return null; } - final List filtered = - List.from(widget.pangeaController.analytics.constructs!) - .map((event) => event.content.uses) - .expand((uses) => uses) - .cast() - .where((use) => use.constructType == constructType) - .toList(); + final List filtered = List.from(_constructs!) + .map((event) => event.content.uses) + .expand((uses) => uses) + .cast() + .where((use) => use.constructType == constructType) + .toList(); final Map> lemmaToUses = {}; for (final use in filtered) { @@ -303,7 +306,7 @@ class ConstructListViewState extends State { @override Widget build(BuildContext context) { - if (!widget.init || fetchingUses) { + if (fetchingConstructs || fetchingUses) { return const Expanded( child: Center(child: CircularProgressIndicator()), ); @@ -347,7 +350,10 @@ class ConstructMessagesDialog extends StatelessWidget { @override Widget build(BuildContext context) { - if (controller.widget.controller.currentLemma == null) { + if (controller.widget.controller.currentLemma == null || + controller.constructs == null || + controller.lemmaIndex < 0 || + controller.lemmaIndex >= controller.constructs!.length) { return const AlertDialog(content: CircularProgressIndicator.adaptive()); }