From 3e8eba0872faf37e88ae3b1a56da5ed3309e5653 Mon Sep 17 00:00:00 2001 From: Henry-Hiles Date: Sun, 12 Apr 2026 15:07:49 -0400 Subject: [PATCH] disable react button while last action is pending --- lib/controllers/room_chat_controller.dart | 1 + lib/models/requests/send_event_request.dart | 1 + .../chat_page/wrappers/reaction_row.dart | 130 +++++++++++------- 3 files changed, 79 insertions(+), 53 deletions(-) diff --git a/lib/controllers/room_chat_controller.dart b/lib/controllers/room_chat_controller.dart index 94a7ccb9..fa32bf85 100644 --- a/lib/controllers/room_chat_controller.dart +++ b/lib/controllers/room_chat_controller.dart @@ -377,6 +377,7 @@ class RoomChatController extends AsyncNotifier { "key": reaction, }, }, + synchronous: true, disableEncryption: true, ), ); diff --git a/lib/models/requests/send_event_request.dart b/lib/models/requests/send_event_request.dart index 8b2d5c82..da5de323 100644 --- a/lib/models/requests/send_event_request.dart +++ b/lib/models/requests/send_event_request.dart @@ -8,6 +8,7 @@ abstract class SendEventRequest with _$SendEventRequest { required String roomId, required String type, required Map content, + @Default(false) bool synchronous, @Default(false) bool disableEncryption, }) = _SendEventRequest; diff --git a/lib/widgets/chat_page/wrappers/reaction_row.dart b/lib/widgets/chat_page/wrappers/reaction_row.dart index 62f58ee3..f20d2ad9 100644 --- a/lib/widgets/chat_page/wrappers/reaction_row.dart +++ b/lib/widgets/chat_page/wrappers/reaction_row.dart @@ -2,6 +2,7 @@ import "package:cross_cache/cross_cache.dart"; import "package:fast_immutable_collections/fast_immutable_collections.dart"; import "package:flutter/material.dart"; import "package:flutter_chat_core/flutter_chat_core.dart"; +import "package:flutter_hooks/flutter_hooks.dart"; import "package:flutter_riverpod/flutter_riverpod.dart"; import "package:nexus/controllers/client_state_controller.dart"; import "package:nexus/controllers/cross_cache_controller.dart"; @@ -24,63 +25,86 @@ class ReactionRow extends ConsumerWidget { runSpacing: 4, children: clientState?.homeserverUrl == null || message.reactions == null ? [] - : message.reactions!.mapTo((reaction, reactors) { - final selected = reactors.contains(clientState!.userId); - return SizedBox( - child: Tooltip( - message: reactors.join(", "), - child: ChoiceChip( - showCheckmark: false, - selected: selected, - label: Row( - mainAxisSize: MainAxisSize.min, - spacing: 8, - children: [ - reaction.startsWith("mxc://") - ? Image( - height: 20, - image: CachedNetworkImage( - headers: ref.headers, - Uri.parse(reaction) - .mxcToHttps(clientState.homeserverUrl!) - .toString(), - ref.watch(CrossCacheController.provider), - ), - ) - : Text(reaction), - Text(reactors.length.toString()), - ], - ), - onSelected: (value) async { - final roomId = ref.watch( - SelectedRoomController.provider.select( - (value) => value?.metadata?.id, + : message.reactions! + .mapTo( + (reaction, reactors) => HookBuilder( + builder: (context) { + final enabled = useState(true); + final selected = reactors.contains(clientState!.userId); + return SizedBox( + child: Tooltip( + message: reactors.join(", "), + child: ChoiceChip( + showCheckmark: false, + selected: selected, + label: Row( + mainAxisSize: MainAxisSize.min, + spacing: 8, + children: [ + reaction.startsWith("mxc://") + ? Image( + height: 20, + image: CachedNetworkImage( + headers: ref.headers, + Uri.parse(reaction) + .mxcToHttps( + clientState.homeserverUrl!, + ) + .toString(), + ref.watch( + CrossCacheController.provider, + ), + ), + ) + : Text(reaction), + Text(reactors.length.toString()), + ], + ), + onSelected: enabled.value + ? (value) async { + enabled.value = false; + try { + final roomId = ref.watch( + SelectedRoomController.provider.select( + (value) => value?.metadata?.id, + ), + ); + if (roomId == null || + clientState.userId == null) { + return; + } + + final controller = ref.watch( + RoomChatController.provider( + roomId, + ).notifier, + ); + + if (selected) { + await controller + .removeReaction( + reaction, + message, + clientState.userId!, + ) + .onError(showError); + } else { + await controller + .sendReaction(reaction, message) + .onError(showError); + } + } finally { + enabled.value = true; + } + } + : null, + ), ), ); - if (roomId == null || clientState.userId == null) return; - - final controller = ref.watch( - RoomChatController.provider(roomId).notifier, - ); - - if (selected) { - await controller - .removeReaction( - reaction, - message, - clientState.userId!, - ) - .onError(showError); - } else { - await controller - .sendReaction(reaction, message) - .onError(showError); - } }, ), - ), - ); - }).toList(), + ) + .toList(), ); } }