From 9930922769f092d5edd3968404bdd266ad8367fa Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 22 Nov 2024 19:51:55 +0900 Subject: [PATCH] Fix chat channel listing not being ordered to expectations - Public channels (and announcements) are now alphabetically ordered. - Private message channels are now ordered by most recent activity. Closes https://github.com/ppy/osu/issues/30835. --- .../Overlays/Chat/ChannelList/ChannelList.cs | 66 ++++++++++++++----- 1 file changed, 51 insertions(+), 15 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 3b657e7056..a2ec385a7e 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -77,10 +77,10 @@ namespace osu.Game.Overlays.Chat.ChannelList RelativeSizeAxes = Axes.X, } }, - announceChannelGroup = new ChannelGroup(ChatStrings.ChannelsListTitleANNOUNCE.ToUpper()), - publicChannelGroup = new ChannelGroup(ChatStrings.ChannelsListTitlePUBLIC.ToUpper()), + announceChannelGroup = new ChannelGroup(ChatStrings.ChannelsListTitleANNOUNCE.ToUpper(), false), + publicChannelGroup = new ChannelGroup(ChatStrings.ChannelsListTitlePUBLIC.ToUpper(), false), selector = new ChannelListItem(ChannelListingChannel), - privateChannelGroup = new ChannelGroup(ChatStrings.ChannelsListTitlePM.ToUpper()), + privateChannelGroup = new ChannelGroup(ChatStrings.ChannelsListTitlePM.ToUpper(), true), }, }, }, @@ -111,9 +111,9 @@ namespace osu.Game.Overlays.Chat.ChannelList item.OnRequestSelect += chan => OnRequestSelect?.Invoke(chan); item.OnRequestLeave += chan => OnRequestLeave?.Invoke(chan); - FillFlowContainer flow = getFlowForChannel(channel); + ChannelGroup group = getGroupFromChannel(channel); channelMap.Add(channel, item); - flow.Add(item); + group.AddChannel(item); updateVisibility(); } @@ -123,10 +123,10 @@ namespace osu.Game.Overlays.Chat.ChannelList if (!channelMap.TryGetValue(channel, out var item)) return; - FillFlowContainer flow = getFlowForChannel(channel); + ChannelGroup group = getGroupFromChannel(channel); channelMap.Remove(channel); - flow.Remove(item, true); + group.RemoveChannel(item); updateVisibility(); } @@ -141,21 +141,21 @@ namespace osu.Game.Overlays.Chat.ChannelList public void ScrollChannelIntoView(Channel channel) => scroll.ScrollIntoView(GetItem(channel)); - private FillFlowContainer getFlowForChannel(Channel channel) + private ChannelGroup getGroupFromChannel(Channel channel) { switch (channel.Type) { case ChannelType.Public: - return publicChannelGroup.ItemFlow; + return publicChannelGroup; case ChannelType.PM: - return privateChannelGroup.ItemFlow; + return privateChannelGroup; case ChannelType.Announce: - return announceChannelGroup.ItemFlow; + return announceChannelGroup; default: - return publicChannelGroup.ItemFlow; + return publicChannelGroup; } } @@ -169,9 +169,9 @@ namespace osu.Game.Overlays.Chat.ChannelList private partial class ChannelGroup : FillFlowContainer { - public readonly FillFlowContainer ItemFlow; + public readonly ChannelListItemFlow ItemFlow; - public ChannelGroup(LocalisableString label) + public ChannelGroup(LocalisableString label, bool sortByRecent) { Direction = FillDirection.Vertical; RelativeSizeAxes = Axes.X; @@ -186,7 +186,7 @@ namespace osu.Game.Overlays.Chat.ChannelList Margin = new MarginPadding { Left = 18, Bottom = 5 }, Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), }, - ItemFlow = new FillFlowContainer + ItemFlow = new ChannelListItemFlow(sortByRecent) { Direction = FillDirection.Vertical, RelativeSizeAxes = Axes.X, @@ -194,6 +194,42 @@ namespace osu.Game.Overlays.Chat.ChannelList }, }; } + + public partial class ChannelListItemFlow : FillFlowContainer + { + private readonly bool sortByRecent; + + public ChannelListItemFlow(bool sortByRecent) + { + this.sortByRecent = sortByRecent; + } + + public void Reflow() => InvalidateLayout(); + + public override IEnumerable FlowingChildren => sortByRecent + ? base.FlowingChildren.OfType().OrderByDescending(i => i.Channel.LastMessageId) + : base.FlowingChildren.OfType().OrderBy(i => i.Channel.Name); + } + + public void AddChannel(ChannelListItem item) + { + ItemFlow.Add(item); + + item.Channel.NewMessagesArrived += newMessagesArrived; + item.Channel.PendingMessageResolved += pendingMessageResolved; + + ItemFlow.Reflow(); + } + + public void RemoveChannel(ChannelListItem item) + { + item.Channel.NewMessagesArrived -= newMessagesArrived; + item.Channel.PendingMessageResolved -= pendingMessageResolved; + ItemFlow.Remove(item, true); + } + + private void pendingMessageResolved(LocalEchoMessage _, Message __) => ItemFlow.Reflow(); + private void newMessagesArrived(IEnumerable _) => ItemFlow.Reflow(); } private partial class ChannelSearchTextBox : BasicSearchTextBox