1
0
mirror of https://github.com/ppy/osu.git synced 2025-02-22 16:03:21 +08:00

Improve robustness of chat auto-scrolling logic

Fix auto-scrolling state changing by old messages removal logic
This commit is contained in:
Salman Ahmed 2021-01-31 23:37:52 +03:00
parent 39d46d21e6
commit e806e5bcd1

View File

@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Chat
{ {
public readonly Channel Channel; public readonly Channel Channel;
protected FillFlowContainer ChatLineFlow; protected FillFlowContainer ChatLineFlow;
private OsuScrollContainer scroll; private ChannelScrollContainer scroll;
private bool scrollbarVisible = true; private bool scrollbarVisible = true;
@ -56,7 +56,7 @@ namespace osu.Game.Overlays.Chat
{ {
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
Masking = true, Masking = true,
Child = scroll = new OsuScrollContainer Child = scroll = new ChannelScrollContainer
{ {
ScrollbarVisible = scrollbarVisible, ScrollbarVisible = scrollbarVisible,
RelativeSizeAxes = Axes.Both, RelativeSizeAxes = Axes.Both,
@ -80,12 +80,6 @@ namespace osu.Game.Overlays.Chat
Channel.PendingMessageResolved += pendingMessageResolved; Channel.PendingMessageResolved += pendingMessageResolved;
} }
protected override void LoadComplete()
{
base.LoadComplete();
scrollToEnd();
}
protected override void Dispose(bool isDisposing) protected override void Dispose(bool isDisposing)
{ {
base.Dispose(isDisposing); base.Dispose(isDisposing);
@ -113,8 +107,6 @@ namespace osu.Game.Overlays.Chat
ChatLineFlow.Clear(); ChatLineFlow.Clear();
} }
bool shouldScrollToEnd = scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage);
// Add up to last Channel.MAX_HISTORY messages // Add up to last Channel.MAX_HISTORY messages
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
@ -153,8 +145,10 @@ namespace osu.Game.Overlays.Chat
} }
} }
if (shouldScrollToEnd) // due to the scroll adjusts from old messages removal above, a scroll-to-end must be enforced,
scrollToEnd(); // to avoid making the container think the user has scrolled back up and unwantedly disable auto-scrolling.
if (scroll.ShouldAutoScroll || newMessages.Any(m => m is LocalMessage))
ScheduleAfterChildren(() => scroll.ScrollToEnd());
}); });
private void pendingMessageResolved(Message existing, Message updated) => Schedule(() => private void pendingMessageResolved(Message existing, Message updated) => Schedule(() =>
@ -178,8 +172,6 @@ namespace osu.Game.Overlays.Chat
private IEnumerable<ChatLine> chatLines => ChatLineFlow.Children.OfType<ChatLine>(); private IEnumerable<ChatLine> chatLines => ChatLineFlow.Children.OfType<ChatLine>();
private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd());
public class DaySeparator : Container public class DaySeparator : Container
{ {
public float TextSize public float TextSize
@ -243,5 +235,32 @@ namespace osu.Game.Overlays.Chat
}; };
} }
} }
/// <summary>
/// An <see cref="OsuScrollContainer"/> with functionality to automatically scrolls whenever the maximum scrollable distance increases.
/// </summary>
private class ChannelScrollContainer : OsuScrollContainer
{
private const float auto_scroll_leniency = 10f;
private float? lastExtent;
/// <summary>
/// Whether this should automatically scroll to end on the next call to <see cref="UpdateAfterChildren"/>.
/// </summary>
public bool ShouldAutoScroll { get; private set; } = true;
protected override void UpdateAfterChildren()
{
base.UpdateAfterChildren();
if ((lastExtent == null || ScrollableExtent > lastExtent) && ShouldAutoScroll)
ScrollToEnd();
else
ShouldAutoScroll = IsScrolledToEnd(auto_scroll_leniency);
lastExtent = ScrollableExtent;
}
}
} }
} }