diff --git a/lib/screens/channel/chat/chat.dart b/lib/screens/channel/chat/chat.dart index ba32c99c..7a30638a 100644 --- a/lib/screens/channel/chat/chat.dart +++ b/lib/screens/channel/chat/chat.dart @@ -80,7 +80,7 @@ class Chat extends StatelessWidget { if (data != null) chatStore.textController.text = data.text!; - chatStore.notification = null; + chatStore.updateNotification(''); }, fill: false, child: const Text('Paste'), diff --git a/lib/screens/channel/chat/widgets/chat_message.dart b/lib/screens/channel/chat/widgets/chat_message.dart index 8d6b312b..08f6f9f3 100644 --- a/lib/screens/channel/chat/widgets/chat_message.dart +++ b/lib/screens/channel/chat/widgets/chat_message.dart @@ -46,7 +46,7 @@ class ChatMessage extends StatelessWidget { await Clipboard.setData(ClipboardData(text: ircMessage.message)); - chatStore.notification = 'Message copied'; + chatStore.updateNotification('Message copied'); } return Observer( diff --git a/lib/screens/channel/stores/chat_store.dart b/lib/screens/channel/stores/chat_store.dart index 00c42e4c..cd3ed751 100644 --- a/lib/screens/channel/stores/chat_store.dart +++ b/lib/screens/channel/stores/chat_store.dart @@ -77,6 +77,13 @@ abstract class ChatStoreBase with Store { /// This is used as an optimization to prevent the list from being updated/shifted while the user is scrolling. final _messageBuffer = []; + /// Timer used for dismissing the notification. + Timer? _notificationTimer; + + /// A notification message to display above the chat. + @readonly + String? _notification; + /// The list of chat messages to render and display. @readonly var _messages = ObservableList(); @@ -113,13 +120,6 @@ abstract class ChatStoreBase with Store { @observable var expandChat = false; - /// A notification message to display above the chat. - @observable - String? notification; - - /// Timer used for dismissing the notification. - Timer? _notificationTimer; - ChatStoreBase({ required this.auth, required this.chatDetailsStore, @@ -141,16 +141,6 @@ abstract class ChatStoreBase with Store { ), ); - reactions.add( - reaction( - (_) => notification, - (_) { - if (_notificationTimer != null) _notificationTimer?.cancel(); - _notificationTimer = Timer(const Duration(seconds: 2), () => notification = null); - }, - ), - ); - // Create a timer that will add messages from the buffer every 200 milliseconds. _messageBufferTimer = Timer.periodic(const Duration(milliseconds: 200), (timer) => addMessages()); @@ -427,9 +417,28 @@ abstract class ChatStoreBase with Store { textController.selection = TextSelection.fromPosition(TextPosition(offset: textController.text.length)); } + /// Cancels the previous notification/timer and creates a new one with the provided [notificationMessage]. + @action + void updateNotification(String notificationMessage) { + // Cancel the previous notification to prevent the notification from phasing in and out + // when copying messages repeatedly. + _notificationTimer?.cancel(); + + // If empty, clear the notification and don't make a new timer (empty message means cancelling the notification). + if (notificationMessage.isEmpty) { + _notification = null; + return; + } + + // Set the new notification message and create a new timer that will dismiss it after 2 seconds. + _notification = notificationMessage; + _notificationTimer = Timer(const Duration(seconds: 2), () => _notification = null); + } + /// Closes and disposes all the channels and controllers used by the store. void dispose() { _messageBufferTimer.cancel(); + _notificationTimer?.cancel(); _channel?.sink.close(1001); _channel = null; diff --git a/lib/screens/channel/stores/chat_store.g.dart b/lib/screens/channel/stores/chat_store.g.dart index f8ef850c..700ff54d 100644 --- a/lib/screens/channel/stores/chat_store.g.dart +++ b/lib/screens/channel/stores/chat_store.g.dart @@ -17,6 +17,24 @@ mixin _$ChatStore on ChatStoreBase, Store { name: 'ChatStoreBase.renderMessages')) .value; + late final _$_notificationAtom = + Atom(name: 'ChatStoreBase._notification', context: context); + + String? get notification { + _$_notificationAtom.reportRead(); + return super._notification; + } + + @override + String? get _notification => notification; + + @override + set _notification(String? value) { + _$_notificationAtom.reportWrite(value, super._notification, () { + super._notification = value; + }); + } + late final _$_messagesAtom = Atom(name: 'ChatStoreBase._messages', context: context); @@ -143,22 +161,6 @@ mixin _$ChatStore on ChatStoreBase, Store { }); } - late final _$notificationAtom = - Atom(name: 'ChatStoreBase.notification', context: context); - - @override - String? get notification { - _$notificationAtom.reportRead(); - return super.notification; - } - - @override - set notification(String? value) { - _$notificationAtom.reportWrite(value, super.notification, () { - super.notification = value; - }); - } - late final _$getAssetsAsyncAction = AsyncAction('ChatStoreBase.getAssets', context: context); @@ -236,11 +238,21 @@ mixin _$ChatStore on ChatStoreBase, Store { } } + @override + void updateNotification(String notificationMessage) { + final _$actionInfo = _$ChatStoreBaseActionController.startAction( + name: 'ChatStoreBase.updateNotification'); + try { + return super.updateNotification(notificationMessage); + } finally { + _$ChatStoreBaseActionController.endAction(_$actionInfo); + } + } + @override String toString() { return ''' expandChat: ${expandChat}, -notification: ${notification}, renderMessages: ${renderMessages} '''; }