From a25bf26779af4e57e87dac9890de7ad102db4455 Mon Sep 17 00:00:00 2001 From: ggurdin Date: Fri, 16 Jan 2026 13:18:26 -0500 Subject: [PATCH] fix: use room state stream to drive updates to analytics request indicator --- .../analytics_request_indicator.dart | 70 ++++++++++++------- 1 file changed, 43 insertions(+), 27 deletions(-) diff --git a/lib/pangea/space_analytics/analytics_request_indicator.dart b/lib/pangea/space_analytics/analytics_request_indicator.dart index 180a0bc6f..9ba4e910b 100644 --- a/lib/pangea/space_analytics/analytics_request_indicator.dart +++ b/lib/pangea/space_analytics/analytics_request_indicator.dart @@ -10,6 +10,7 @@ import 'package:fluffychat/l10n/l10n.dart'; import 'package:fluffychat/pangea/analytics_misc/client_analytics_extension.dart'; import 'package:fluffychat/pangea/events/constants/pangea_event_types.dart'; import 'package:fluffychat/pangea/space_analytics/space_analytics_requested_dialog.dart'; +import 'package:fluffychat/utils/stream_extension.dart'; import 'package:fluffychat/widgets/future_loading_dialog.dart'; class AnalyticsRequestIndicator extends StatefulWidget { @@ -26,51 +27,68 @@ class AnalyticsRequestIndicator extends StatefulWidget { class AnalyticsRequestIndicatorState extends State { AnalyticsRequestIndicatorState(); - - final Map> _knockingAdmins = {}; + StreamSubscription? _analyticsRoomSub; @override void initState() { super.initState(); - _fetchKnockingAdmins(); + _init(); } @override void didUpdateWidget(covariant AnalyticsRequestIndicator oldWidget) { super.didUpdateWidget(oldWidget); if (oldWidget.room.id != widget.room.id) { - _fetchKnockingAdmins(); + _init(); } } - Future _fetchKnockingAdmins() async { - setState(() => _knockingAdmins.clear()); + @override + void dispose() { + _analyticsRoomSub?.cancel(); + super.dispose(); + } - final admins = (await widget.room.requestParticipants( - [Membership.join, Membership.invite, Membership.knock], - false, - true, - )) - .where((u) => u.powerLevel >= 100); + Future _init() async { + final analyticsRooms = widget.room.client.allMyAnalyticsRooms; + final futures = analyticsRooms.map( + (r) => r.requestParticipants( + [Membership.join, Membership.invite, Membership.knock], + false, + true, + ), + ); + await Future.wait(futures); + final analyicsRoomIds = analyticsRooms.map((r) => r.id).toSet(); + _analyticsRoomSub?.cancel(); + _analyticsRoomSub = widget.room.client.onRoomState.stream + .where( + (event) => + analyicsRoomIds.contains(event.roomId) && + event.state.type == EventTypes.RoomMember, + ) + .rateLimit(const Duration(seconds: 1)) + .listen((_) => setState(() {})); + + if (mounted) setState(() {}); + } + + Map> get _knockingAdmins { + final Map> knockingAdmins = {}; for (final analyticsRoom in widget.room.client.allMyAnalyticsRooms) { - final knocking = await analyticsRoom.requestParticipants( - [Membership.knock], - ); - final knockingSpace = - knocking.where((u) => u.content['reason'] == widget.room.id).toList(); - if (knockingSpace.isEmpty) continue; + final knocking = analyticsRoom + .getParticipants([Membership.knock]) + .where((u) => u.content['reason'] == widget.room.id) + .toList(); - for (final admin in admins) { - if (knockingSpace.any((u) => u.id == admin.id)) { - _knockingAdmins.putIfAbsent(admin, () => []).add(analyticsRoom); - } + if (knocking.isEmpty) continue; + for (final admin in knocking) { + knockingAdmins.putIfAbsent(admin, () => []).add(analyticsRoom); } } - if (mounted) { - setState(() {}); - } + return knockingAdmins; } Future _onTap(BuildContext context) async { @@ -109,8 +127,6 @@ class AnalyticsRequestIndicatorState extends State { } }, ); - - if (mounted) _fetchKnockingAdmins(); } @override