diff --git a/lib/screens/channel/chat/chat.dart b/lib/screens/channel/chat/chat.dart index b97a0161..efc4275b 100644 --- a/lib/screens/channel/chat/chat.dart +++ b/lib/screens/channel/chat/chat.dart @@ -42,9 +42,9 @@ class Chat extends StatelessWidget { padding: EdgeInsets.zero, addAutomaticKeepAlives: false, controller: chatStore.scrollController, - itemCount: chatStore.messages.length, + itemCount: chatStore.renderMessages.length, itemBuilder: (context, index) => ChatMessage( - ircMessage: chatStore.messages.reversed.toList()[index], + ircMessage: chatStore.renderMessages.reversed.toList()[index], chatStore: chatStore, ), ); diff --git a/lib/screens/channel/chat/stores/chat_store.dart b/lib/screens/channel/chat/stores/chat_store.dart index 93506f85..fa8d693c 100644 --- a/lib/screens/channel/chat/stores/chat_store.dart +++ b/lib/screens/channel/chat/stores/chat_store.dart @@ -22,6 +22,9 @@ abstract class ChatStoreBase with Store { /// The total maximum amount of messages in chat. static const _messageLimit = 5000; + /// The maximum ammount of messages to render when autoscroll is enabled. + static const _renderMessageLimit = 100; + /// The amount of messages to free (remove) when the [_messageLimit] is reached. final _messagesToRemove = (_messageLimit * 0.2).toInt(); @@ -91,6 +94,19 @@ abstract class ChatStoreBase with Store { @readonly var _messages = ObservableList(); + /// The list of chat messages that should be rendered. Used to prevent jank when resuming scroll. + @computed + List get renderMessages { + // If autoscroll is disabled, render ALL messages in chat. + // The second condition is to prevent an out of index error with sublist. + if (!_autoScroll || _messages.length < _renderMessageLimit) return _messages; + + // When autoscroll is enabled, only show the first [_renderMessageLimit] messages. + // This will improve performance by only rendering a limited amount of messages + // instead of the entire history at all times. + return _messages.sublist(_messages.length - _renderMessageLimit); + } + /// If the chat should automatically scroll/jump to the latest message. @readonly var _autoScroll = true; diff --git a/lib/screens/channel/chat/stores/chat_store.g.dart b/lib/screens/channel/chat/stores/chat_store.g.dart index dce8e323..700ff54d 100644 --- a/lib/screens/channel/chat/stores/chat_store.g.dart +++ b/lib/screens/channel/chat/stores/chat_store.g.dart @@ -9,6 +9,14 @@ part of 'chat_store.dart'; // ignore_for_file: non_constant_identifier_names, unnecessary_brace_in_string_interps, unnecessary_lambdas, prefer_expression_function_bodies, lines_longer_than_80_chars, avoid_as, avoid_annotating_with_dynamic, no_leading_underscores_for_local_identifiers mixin _$ChatStore on ChatStoreBase, Store { + Computed>? _$renderMessagesComputed; + + @override + List get renderMessages => (_$renderMessagesComputed ??= + Computed>(() => super.renderMessages, + name: 'ChatStoreBase.renderMessages')) + .value; + late final _$_notificationAtom = Atom(name: 'ChatStoreBase._notification', context: context); @@ -244,7 +252,8 @@ mixin _$ChatStore on ChatStoreBase, Store { @override String toString() { return ''' -expandChat: ${expandChat} +expandChat: ${expandChat}, +renderMessages: ${renderMessages} '''; } }