feat: load more message history when scrolling to top

This commit is contained in:
Stone_Red
2026-04-20 17:42:05 +02:00
committed by HueByte
parent fe6dfd3d4d
commit e42f1a0965
10 changed files with 110 additions and 12 deletions
@@ -186,6 +186,39 @@ public sealed class ChatMessageManager
MessagesChanged?.Invoke(channelName);
}
/// <summary>
/// Prepend older messages at the front of a channel's buffer, skipping any that are already present.
/// Fires <see cref="HistoryPrepended"/> when new lines are actually inserted.
/// </summary>
public void PrependHistory(string channelName, List<MessageDto> olderMessages)
{
if (!_channelMessages.TryGetValue(channelName, out var existing))
return;
var existingIds = existing
.Where(l => l.MessageId.HasValue)
.Select(l => l.MessageId!.Value)
.ToHashSet();
var newLines = olderMessages
.Where(m => !existingIds.Contains(m.Id))
.SelectMany(FormatMessage)
.ToList();
if (newLines.Count == 0)
return;
existing.InsertRange(0, newLines);
if (channelName == _currentChannel)
HistoryPrepended?.Invoke(channelName);
}
/// <summary>
/// Fired after older messages are prepended to a channel's buffer. Parameter is the channel name.
/// </summary>
public event Action<string>? HistoryPrepended;
/// <summary>
/// Reset all message state (used on disconnect).
/// </summary>
+36
View File
@@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Text.RegularExpressions;
using EchoHub.Client.Services;
using EchoHub.Client.Themes;
@@ -117,6 +118,11 @@ public sealed partial class MainWindow : Runnable
/// </summary>
public event Action? OnSavedServersRequested;
/// <summary>
/// Fired when the user scrolls to the top of the message list and older messages should be loaded.
/// </summary>
public event Action? OnLoadMoreRequested;
/// <summary>
/// Fired when the user requests to create a new channel.
/// </summary>
@@ -162,6 +168,7 @@ public sealed partial class MainWindow : Runnable
_app = app;
_messageManager = messageManager;
_messageManager.MessagesChanged += OnMessagesChanged;
_messageManager.HistoryPrepended += OnHistoryPrepended;
Arrangement = ViewArrangement.Fixed;
// Menu bar at the top
@@ -222,6 +229,9 @@ public sealed partial class MainWindow : Runnable
};
_messageList.Source = new ChatListSource();
_messageList.Accepting += OnMessageListAccepting;
_messageList.VerticalScrollBar.Scrolled += OnMessageListVerticalScrollBarScrolled;
_messageList.VerticalScrollBar.Visible = true;
_chatFrame.Add(_messageList);
Add(_chatFrame);
@@ -478,6 +488,12 @@ public sealed partial class MainWindow : Runnable
}
}
private void OnMessageListVerticalScrollBarScrolled(object? sender, EventArgs<int> e)
{
if (_messageList.VerticalScrollBar.Value == 0)
OnLoadMoreRequested?.Invoke();
}
private void OnUsersListAccepting(object? sender, CommandEventArgs e)
{
var index = _usersList.SelectedItem;
@@ -631,6 +647,26 @@ public sealed partial class MainWindow : Runnable
RefreshChannelList();
}
private void OnHistoryPrepended(string channelName)
{
if (channelName != _messageManager.CurrentChannel)
return;
var messages = _messageManager.GetMessages(channelName);
if (messages is null)
return;
var oldCount = (_messageList.Source as ChatListSource)?.Count ?? 0;
RefreshMessages();
// Scroll to the item that was at the top before the prepend so the user
// stays at their previous reading position rather than jumping to the top.
var prependedCount = (_messageList.Source as ChatListSource)?.Count - oldCount;
if (prependedCount > 0)
_messageList.SelectedItem = prependedCount;
}
/// <summary>
/// Set the list of available channels, storing topics, and refresh the channel list view.
/// </summary>