From 58d39734d07c0fdd90c2310b68186b82df4ac6c0 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 23 May 2022 20:23:50 +0100 Subject: [PATCH 01/14] Integrate `ChatOverlayV2` into main game --- osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs | 2 +- osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs | 2 +- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/OsuGame.cs | 4 ++-- osu.Game/Overlays/ChatOverlayV2.cs | 10 ++++++++-- .../Profile/Header/Components/MessageUserButton.cs | 2 +- osu.Game/Overlays/Toolbar/ToolbarChatButton.cs | 2 +- 7 files changed, 15 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs index e4871f611e..c8ea692bb2 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneOsuGame.cs @@ -40,7 +40,7 @@ namespace osu.Game.Tests.Visual.Navigation typeof(DashboardOverlay), typeof(NewsOverlay), typeof(ChannelManager), - typeof(ChatOverlay), + typeof(ChatOverlayV2), typeof(SettingsOverlay), typeof(UserProfileOverlay), typeof(BeatmapSetOverlay), diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs index e27db00003..7268dd31f6 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs @@ -63,7 +63,7 @@ namespace osu.Game.Tests.Visual.Online Children = new Drawable[] { channelManager, - chatOverlay = new TestChatOverlayV2 { RelativeSizeAxes = Axes.Both }, + chatOverlay = new TestChatOverlayV2(), }, }; }); diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 20d555c16c..69e7dee1a5 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -46,7 +46,7 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.RandomSelectAlgorithm, RandomSelectAlgorithm.RandomPermutation); - SetDefault(OsuSetting.ChatDisplayHeight, ChatOverlay.DEFAULT_HEIGHT, 0.2f, 1f); + SetDefault(OsuSetting.ChatDisplayHeight, ChatOverlayV2.DEFAULT_HEIGHT, 0.2f, 1f); SetDefault(OsuSetting.BeatmapListingCardSize, BeatmapCardSize.Normal); diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 785881d97a..402bd94f31 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -75,7 +75,7 @@ namespace osu.Game public Toolbar Toolbar; - private ChatOverlay chatOverlay; + private ChatOverlayV2 chatOverlay; private ChannelManager channelManager; @@ -848,7 +848,7 @@ namespace osu.Game loadComponentSingleFile(news = new NewsOverlay(), overlayContent.Add, true); var rankingsOverlay = loadComponentSingleFile(new RankingsOverlay(), overlayContent.Add, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); - loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); + loadComponentSingleFile(chatOverlay = new ChatOverlayV2(), overlayContent.Add, true); loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(Settings = new SettingsOverlay(), leftFloatingOverlayContent.Add, true); loadComponentSingleFile(changelogOverlay = new ChangelogOverlay(), overlayContent.Add, true); diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index ef479ea21b..441042432a 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -47,8 +47,9 @@ namespace osu.Game.Overlays private bool isDraggingTopBar; private float dragStartChatHeight; + public const float DEFAULT_HEIGHT = 0.4f; + private const int transition_length = 500; - private const float default_chat_height = 0.4f; private const float top_bar_height = 40; private const float side_bar_width = 190; private const float chat_bar_height = 60; @@ -70,7 +71,7 @@ namespace osu.Game.Overlays public ChatOverlayV2() { - Height = default_chat_height; + Height = DEFAULT_HEIGHT; Masking = true; @@ -82,6 +83,7 @@ namespace osu.Game.Overlays Margin = new MarginPadding { Bottom = -corner_radius }; Padding = new MarginPadding { Bottom = corner_radius }; + RelativeSizeAxes = Axes.Both; Anchor = Anchor.BottomCentre; Origin = Anchor.BottomCentre; } @@ -294,6 +296,10 @@ namespace osu.Game.Overlays }); } } + + // Mark channel as read when channel switched + if (newChannel.Messages.Any()) + channelManager.MarkChannelAsRead(newChannel); } protected virtual ChatOverlayDrawableChannel CreateDrawableChannel(Channel newChannel) => new ChatOverlayDrawableChannel(newChannel); diff --git a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs index e3dc5f818a..eafb453f75 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MessageUserButton.cs @@ -27,7 +27,7 @@ namespace osu.Game.Overlays.Profile.Header.Components private UserProfileOverlay userOverlay { get; set; } [Resolved(CanBeNull = true)] - private ChatOverlay chatOverlay { get; set; } + private ChatOverlayV2 chatOverlay { get; set; } [Resolved] private IAPIProvider apiProvider { get; set; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs index 2d3b33e9bc..20f405aae2 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarChatButton.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Toolbar } [BackgroundDependencyLoader(true)] - private void load(ChatOverlay chat) + private void load(ChatOverlayV2 chat) { StateContainer = chat; } From d2a49ca266087d5342fb1c9aa65b45db9204a7a1 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 23 May 2022 20:24:17 +0100 Subject: [PATCH 02/14] Use `ChatOverlayV2` in message notifier and tests --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 2 +- osu.Game/Online/Chat/MessageNotifier.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 79f62a16e3..46f426597a 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -208,7 +208,7 @@ namespace osu.Game.Tests.Visual.Online }; [Cached] - public ChatOverlay ChatOverlay { get; } = new ChatOverlay(); + public ChatOverlayV2 ChatOverlay { get; } = new ChatOverlayV2(); private readonly MessageNotifier messageNotifier = new MessageNotifier(); diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index ca6082e19b..cea3e321fa 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -27,7 +27,7 @@ namespace osu.Game.Online.Chat private INotificationOverlay notifications { get; set; } [Resolved] - private ChatOverlay chatOverlay { get; set; } + private ChatOverlayV2 chatOverlay { get; set; } [Resolved] private ChannelManager channelManager { get; set; } @@ -170,7 +170,7 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, ChatOverlay chatOverlay, INotificationOverlay notificationOverlay) + private void load(OsuColour colours, ChatOverlayV2 chatOverlay, INotificationOverlay notificationOverlay) { IconBackground.Colour = colours.PurpleDark; From 606f3b2bd18bc2ed780441a02f6698ba4bcbe6f0 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 23 May 2022 20:24:49 +0100 Subject: [PATCH 03/14] Use `ChatOverlayV2` in screen navigation tests --- .../Visual/Navigation/TestScenePerformFromScreen.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs index 2ce914ba3d..5d0116f80e 100644 --- a/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs +++ b/osu.Game.Tests/Visual/Navigation/TestScenePerformFromScreen.cs @@ -86,9 +86,9 @@ namespace osu.Game.Tests.Visual.Navigation [Test] public void TestOverlaysAlwaysClosed() { - ChatOverlay chat = null; + ChatOverlayV2 chat = null; AddUntilStep("is at menu", () => Game.ScreenStack.CurrentScreen is MainMenu); - AddUntilStep("wait for chat load", () => (chat = Game.ChildrenOfType().SingleOrDefault()) != null); + AddUntilStep("wait for chat load", () => (chat = Game.ChildrenOfType().SingleOrDefault()) != null); AddStep("show chat", () => InputManager.Key(Key.F8)); From 60b10fca4ec969997f77861beb12d724f0f15297 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Mon, 23 May 2022 20:25:01 +0100 Subject: [PATCH 04/14] Remove redundant caching of overlays in `ChatLink` test --- osu.Game.Tests/Visual/Online/TestSceneChatLink.cs | 6 ------ 1 file changed, 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs index 6818147da4..a28de3be1e 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatLink.cs @@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; -using osu.Game.Overlays; using osu.Game.Overlays.Chat; using osuTK.Graphics; @@ -22,12 +21,10 @@ namespace osu.Game.Tests.Visual.Online public class TestSceneChatLink : OsuTestScene { private readonly TestChatLineContainer textContainer; - private readonly DialogOverlay dialogOverlay; private Color4 linkColour; public TestSceneChatLink() { - Add(dialogOverlay = new DialogOverlay { Depth = float.MinValue }); Add(textContainer = new TestChatLineContainer { Padding = new MarginPadding { Left = 20, Right = 20 }, @@ -47,9 +44,6 @@ namespace osu.Game.Tests.Visual.Online availableChannels.Add(new Channel { Name = "#english" }); availableChannels.Add(new Channel { Name = "#japanese" }); Dependencies.Cache(chatManager); - - Dependencies.Cache(new ChatOverlay()); - Dependencies.CacheAs(dialogOverlay); } [SetUp] From fce527b0dfbcd056dc2b2590448ae2925c803d9e Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 24 May 2022 21:25:27 +0100 Subject: [PATCH 05/14] Schedule channel manager bindable events to ensure they happen after the first poll --- osu.Game/Overlays/ChatOverlayV2.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index 441042432a..3aab81cb04 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -155,13 +155,15 @@ namespace osu.Game.Overlays chatHeight.BindValueChanged(height => { Height = height.NewValue; }, true); currentChannel.BindTo(channelManager.CurrentChannel); - currentChannel.BindValueChanged(currentChannelChanged, true); - joinedChannels.BindTo(channelManager.JoinedChannels); - joinedChannels.BindCollectionChanged(joinedChannelsChanged, true); - availableChannels.BindTo(channelManager.AvailableChannels); - availableChannels.BindCollectionChanged(availableChannelsChanged, true); + + Schedule(() => + { + currentChannel.BindValueChanged(currentChannelChanged, true); + joinedChannels.BindCollectionChanged(joinedChannelsChanged, true); + availableChannels.BindCollectionChanged(availableChannelsChanged, true); + }); channelList.OnRequestSelect += channel => channelManager.CurrentChannel.Value = channel; channelList.OnRequestLeave += channel => channelManager.LeaveChannel(channel); From f6810d3f59d831e02ae1c4a42fe61001746858d8 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Tue, 24 May 2022 23:05:25 +0100 Subject: [PATCH 06/14] Add keyboard shortcuts to `ChatOverlayV2` with tests --- .../Visual/Online/TestSceneChatOverlayV2.cs | 72 +++++++++++++++++++ osu.Game/Overlays/ChatOverlayV2.cs | 52 +++++++++++++- 2 files changed, 122 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs b/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs index 7268dd31f6..0580d20171 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneChatOverlayV2.cs @@ -12,6 +12,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Framework.Logging; using osu.Framework.Testing; using osu.Framework.Utils; @@ -417,6 +418,67 @@ namespace osu.Game.Tests.Visual.Online AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1); } + [Test] + public void TestKeyboardCloseAndRestoreChannel() + { + AddStep("Show overlay with channel 1", () => + { + channelManager.JoinChannel(testChannel1); + chatOverlay.Show(); + }); + AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1); + + AddStep("Press document close keys", () => InputManager.Keys(PlatformAction.DocumentClose)); + AddAssert("Listing is visible", () => listingIsVisible); + + AddStep("Press tab restore keys", () => InputManager.Keys(PlatformAction.TabRestore)); + AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1); + } + + [Test] + public void TestKeyboardNewChannel() + { + AddStep("Show overlay with channel 1", () => + { + channelManager.JoinChannel(testChannel1); + chatOverlay.Show(); + }); + AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1); + + AddStep("Press tab new keys", () => InputManager.Keys(PlatformAction.TabNew)); + AddAssert("Listing is visible", () => listingIsVisible); + } + + [Test] + public void TestKeyboardNextChannel() + { + Channel pmChannel1 = createPrivateChannel(); + Channel pmChannel2 = createPrivateChannel(); + + AddStep("Show overlay with channels", () => + { + channelManager.JoinChannel(testChannel1); + channelManager.JoinChannel(testChannel2); + channelManager.JoinChannel(pmChannel1); + channelManager.JoinChannel(pmChannel2); + chatOverlay.Show(); + }); + + AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1); + + AddStep("Press document next keys", () => InputManager.Keys(PlatformAction.DocumentNext)); + AddAssert("Channel 2 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel2); + + AddStep("Press document next keys", () => InputManager.Keys(PlatformAction.DocumentNext)); + AddAssert("PM Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == pmChannel1); + + AddStep("Press document next keys", () => InputManager.Keys(PlatformAction.DocumentNext)); + AddAssert("PM Channel 2 displayed", () => channelIsVisible && currentDrawableChannel.Channel == pmChannel2); + + AddStep("Press document next keys", () => InputManager.Keys(PlatformAction.DocumentNext)); + AddAssert("Channel 1 displayed", () => channelIsVisible && currentDrawableChannel.Channel == testChannel1); + } + private bool listingIsVisible => chatOverlay.ChildrenOfType().Single().State.Value == Visibility.Visible; @@ -467,6 +529,16 @@ namespace osu.Game.Tests.Visual.Online Type = ChannelType.Public, }; + private Channel createPrivateChannel() + { + int id = RNG.Next(0, 10000); + return new Channel(new APIUser + { + Id = id, + Username = $"test user {id}", + }); + } + private class TestChatOverlayV2 : ChatOverlayV2 { public bool SlowLoading { get; set; } diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index 3aab81cb04..39717b1f31 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -13,6 +13,8 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Framework.Input; +using osu.Framework.Input.Bindings; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Configuration; @@ -26,7 +28,7 @@ using osu.Game.Overlays.Chat.Listing; namespace osu.Game.Overlays { - public class ChatOverlayV2 : OsuFocusedOverlayContainer, INamedOverlayComponent + public class ChatOverlayV2 : OsuFocusedOverlayContainer, INamedOverlayComponent, IKeyBindingHandler { public string IconTexture => "Icons/Hexacons/messaging"; public LocalisableString Title => ChatStrings.HeaderTitle; @@ -197,6 +199,35 @@ namespace osu.Game.Overlays Show(); } + public bool OnPressed(KeyBindingPressEvent e) + { + switch (e.Action) + { + case PlatformAction.TabNew: + currentChannel.Value = channelList.ChannelListingChannel; + return true; + + case PlatformAction.DocumentClose: + channelManager.LeaveChannel(currentChannel.Value); + return true; + + case PlatformAction.TabRestore: + channelManager.JoinLastClosedChannel(); + return true; + + case PlatformAction.DocumentNext: + cycleChannel(); + return true; + + default: + return false; + } + } + + public void OnReleased(KeyBindingReleaseEvent e) + { + } + protected override bool OnDragStart(DragStartEvent e) { isDraggingTopBar = topBar.IsHovered; @@ -341,7 +372,7 @@ namespace osu.Game.Overlays private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) => channelListing.UpdateAvailableChannels(channelManager.AvailableChannels); - private IEnumerable filterChannels(IList channels) + private IEnumerable filterChannels(IEnumerable channels) => channels.Cast().Where(c => c.Type == ChannelType.Public || c.Type == ChannelType.PM); private void handleChatMessage(string message) @@ -354,5 +385,22 @@ namespace osu.Game.Overlays else channelManager.PostMessage(message); } + + private void cycleChannel() + { + List overlayChannels = filterChannels(channelManager.JoinedChannels).ToList(); + + if (overlayChannels.Count < 2) + return; + + int currentIdx = overlayChannels.IndexOf(currentChannel.Value); + int nextIdx = currentIdx + 1; + + // Cycle the list when reaching the end + if (nextIdx > overlayChannels.Count - 1) + nextIdx = 0; + + currentChannel.Value = overlayChannels[nextIdx]; + } } } From a92089c443b9cd256f145aef6711b76bd4e18579 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 May 2022 18:42:33 +0900 Subject: [PATCH 07/14] Change filter method to consider all non-system channels as joinable --- osu.Game/Overlays/ChatOverlayV2.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index 39717b1f31..a23595e1c0 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -342,7 +342,7 @@ namespace osu.Game.Overlays switch (args.Action) { case NotifyCollectionChangedAction.Add: - IEnumerable newChannels = filterChannels(args.NewItems); + IEnumerable newChannels = filterToChatChannels(args.NewItems); foreach (var channel in newChannels) channelList.AddChannel(channel); @@ -350,7 +350,7 @@ namespace osu.Game.Overlays break; case NotifyCollectionChangedAction.Remove: - IEnumerable leftChannels = filterChannels(args.OldItems); + IEnumerable leftChannels = filterToChatChannels(args.OldItems); foreach (var channel in leftChannels) { @@ -372,8 +372,6 @@ namespace osu.Game.Overlays private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) => channelListing.UpdateAvailableChannels(channelManager.AvailableChannels); - private IEnumerable filterChannels(IEnumerable channels) - => channels.Cast().Where(c => c.Type == ChannelType.Public || c.Type == ChannelType.PM); private void handleChatMessage(string message) { @@ -402,5 +400,7 @@ namespace osu.Game.Overlays currentChannel.Value = overlayChannels[nextIdx]; } + + private IEnumerable filterToChatChannels(IEnumerable channels) => channels.Cast().Where(c => c.Type != ChannelType.System); } } From 49ab031e75f0398ed321b0664d68acee9aba5b31 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 25 May 2022 18:42:49 +0900 Subject: [PATCH 08/14] Allow traversing in both directions using ctrl-tab shortcuts --- osu.Game/Overlays/ChatOverlayV2.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index a23595e1c0..d0355e0165 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -215,8 +215,12 @@ namespace osu.Game.Overlays channelManager.JoinLastClosedChannel(); return true; + case PlatformAction.DocumentPrevious: + cycleChannel(-1); + return true; + case PlatformAction.DocumentNext: - cycleChannel(); + cycleChannel(1); return true; default: @@ -372,7 +376,6 @@ namespace osu.Game.Overlays private void availableChannelsChanged(object sender, NotifyCollectionChangedEventArgs args) => channelListing.UpdateAvailableChannels(channelManager.AvailableChannels); - private void handleChatMessage(string message) { if (string.IsNullOrWhiteSpace(message)) @@ -384,21 +387,16 @@ namespace osu.Game.Overlays channelManager.PostMessage(message); } - private void cycleChannel() + private void cycleChannel(int direction) { - List overlayChannels = filterChannels(channelManager.JoinedChannels).ToList(); + List overlayChannels = filterToChatChannels(channelManager.JoinedChannels).ToList(); if (overlayChannels.Count < 2) return; - int currentIdx = overlayChannels.IndexOf(currentChannel.Value); - int nextIdx = currentIdx + 1; + int currentIndex = overlayChannels.IndexOf(currentChannel.Value); - // Cycle the list when reaching the end - if (nextIdx > overlayChannels.Count - 1) - nextIdx = 0; - - currentChannel.Value = overlayChannels[nextIdx]; + currentChannel.Value = overlayChannels[(currentIndex + direction + overlayChannels.Count) % overlayChannels.Count]; } private IEnumerable filterToChatChannels(IEnumerable channels) => channels.Cast().Where(c => c.Type != ChannelType.System); From 4a36f3aa4c5f7c6af19627ed38ccc48dc353a39f Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 25 May 2022 12:29:04 +0100 Subject: [PATCH 09/14] Ensure channel traversal shortcut is using visual order --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 7 +++++++ osu.Game/Overlays/ChatOverlayV2.cs | 5 +++-- 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index d1ceae604c..f212f5b162 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -4,6 +4,7 @@ #nullable enable using System; +using System.Linq; using System.Collections.Generic; using osu.Framework.Allocation; using osu.Framework.Graphics; @@ -22,6 +23,8 @@ namespace osu.Game.Overlays.Chat.ChannelList public Action? OnRequestSelect; public Action? OnRequestLeave; + public IEnumerable Channels => publicChannelFlow.Channels.Concat(privateChannelFlow.Channels); + public readonly ChannelListing.ChannelListingChannel ChannelListingChannel = new ChannelListing.ChannelListingChannel(); private readonly Dictionary channelMap = new Dictionary(); @@ -118,6 +121,10 @@ namespace osu.Game.Overlays.Chat.ChannelList private class ChannelListItemFlow : FillFlowContainer { + public IEnumerable Channels => Children.Where(c => c is ChannelListItem) + .Cast() + .Select(c => c.Channel); + public ChannelListItemFlow(string label) { Direction = FillDirection.Vertical; diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index d0355e0165..cc780073ce 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -389,7 +389,7 @@ namespace osu.Game.Overlays private void cycleChannel(int direction) { - List overlayChannels = filterToChatChannels(channelManager.JoinedChannels).ToList(); + List overlayChannels = channelList.Channels.ToList(); if (overlayChannels.Count < 2) return; @@ -399,6 +399,7 @@ namespace osu.Game.Overlays currentChannel.Value = overlayChannels[(currentIndex + direction + overlayChannels.Count) % overlayChannels.Count]; } - private IEnumerable filterToChatChannels(IEnumerable channels) => channels.Cast().Where(c => c.Type != ChannelType.System); + private IEnumerable filterToChatChannels(IEnumerable channels) + => channels.Cast().Where(c => c.Type == ChannelType.PM || c.Type == ChannelType.Public); } } From cd90d2931534bf8210fedfc6a4c2efbb5863d05a Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 25 May 2022 12:37:28 +0100 Subject: [PATCH 10/14] Ensure channel traversal shortcut scrolls channel list item into view --- osu.Game/Overlays/Chat/ChannelList/ChannelList.cs | 5 ++++- osu.Game/Overlays/ChatOverlayV2.cs | 2 ++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index f212f5b162..2798841925 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -29,6 +29,7 @@ namespace osu.Game.Overlays.Chat.ChannelList private readonly Dictionary channelMap = new Dictionary(); + private OsuScrollContainer scroll = null!; private ChannelListItemFlow publicChannelFlow = null!; private ChannelListItemFlow privateChannelFlow = null!; private ChannelListItem selector = null!; @@ -43,7 +44,7 @@ namespace osu.Game.Overlays.Chat.ChannelList RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background6, }, - new OsuScrollContainer + scroll = new OsuScrollContainer { Padding = new MarginPadding { Vertical = 7 }, RelativeSizeAxes = Axes.Both, @@ -104,6 +105,8 @@ namespace osu.Game.Overlays.Chat.ChannelList return channelMap[channel]; } + public void ScrollChannelIntoView(Channel channel) => scroll.ScrollIntoView(this.GetItem(channel)); + private ChannelListItemFlow getFlowForChannel(Channel channel) { switch (channel.Type) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index cc780073ce..ad7a856dbc 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -397,6 +397,8 @@ namespace osu.Game.Overlays int currentIndex = overlayChannels.IndexOf(currentChannel.Value); currentChannel.Value = overlayChannels[(currentIndex + direction + overlayChannels.Count) % overlayChannels.Count]; + + channelList.ScrollChannelIntoView(currentChannel.Value); } private IEnumerable filterToChatChannels(IEnumerable channels) From c0da05dda0454690d11d3d5536d322c80cced4c6 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 25 May 2022 15:15:26 +0100 Subject: [PATCH 11/14] Use an array of channels to exclude from the overlay --- osu.Game/Overlays/ChatOverlayV2.cs | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index ad7a856dbc..9ca4d9cb6c 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -56,6 +56,13 @@ namespace osu.Game.Overlays private const float side_bar_width = 190; private const float chat_bar_height = 60; + private readonly ChannelType[] excluded_channel_types = new[] + { + ChannelType.Multiplayer, + ChannelType.Spectator, + ChannelType.Temporary, + }; + [Resolved] private OsuConfigManager config { get; set; } = null!; @@ -402,6 +409,6 @@ namespace osu.Game.Overlays } private IEnumerable filterToChatChannels(IEnumerable channels) - => channels.Cast().Where(c => c.Type == ChannelType.PM || c.Type == ChannelType.Public); + => channels.Cast().Where(c => !excluded_channel_types.Contains(c.Type)); } } From 997fc716e8609d84e157cf602e468699dff4d04b Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 25 May 2022 15:15:46 +0100 Subject: [PATCH 12/14] Split out the channel list labels from the channel list item flow --- .../Overlays/Chat/ChannelList/ChannelList.cs | 35 ++++++++++--------- 1 file changed, 19 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs index 2798841925..21b2251aca 100644 --- a/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs +++ b/osu.Game/Overlays/Chat/ChannelList/ChannelList.cs @@ -57,12 +57,14 @@ namespace osu.Game.Overlays.Chat.ChannelList AutoSizeAxes = Axes.Y, Children = new Drawable[] { - publicChannelFlow = new ChannelListItemFlow("CHANNELS"), + new ChannelListLabel("CHANNELS"), + publicChannelFlow = new ChannelListItemFlow(), selector = new ChannelListItem(ChannelListingChannel) { Margin = new MarginPadding { Bottom = 10 }, }, - privateChannelFlow = new ChannelListItemFlow("DIRECT MESSAGES"), + new ChannelListLabel("DIRECT MESSAGES"), + privateChannelFlow = new ChannelListItemFlow(), }, }, }, @@ -105,7 +107,7 @@ namespace osu.Game.Overlays.Chat.ChannelList return channelMap[channel]; } - public void ScrollChannelIntoView(Channel channel) => scroll.ScrollIntoView(this.GetItem(channel)); + public void ScrollChannelIntoView(Channel channel) => scroll.ScrollIntoView(GetItem(channel)); private ChannelListItemFlow getFlowForChannel(Channel channel) { @@ -118,28 +120,29 @@ namespace osu.Game.Overlays.Chat.ChannelList return privateChannelFlow; default: - throw new ArgumentOutOfRangeException(); + return publicChannelFlow; } } - private class ChannelListItemFlow : FillFlowContainer + private class ChannelListLabel : OsuSpriteText { - public IEnumerable Channels => Children.Where(c => c is ChannelListItem) - .Cast() - .Select(c => c.Channel); + public ChannelListLabel(string label) + { + Text = label; + Margin = new MarginPadding { Left = 18, Bottom = 5 }; + Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold); + } + } - public ChannelListItemFlow(string label) + private class ChannelListItemFlow : FillFlowContainer + { + public IEnumerable Channels => Children.Select(c => c.Channel); + + public ChannelListItemFlow() { Direction = FillDirection.Vertical; RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; - - Add(new OsuSpriteText - { - Text = label, - Margin = new MarginPadding { Left = 18, Bottom = 5 }, - Font = OsuFont.Torus.With(size: 12, weight: FontWeight.SemiBold), - }); } } } From f94afa5f8cf0b384322ba12a1ca527b36bae1580 Mon Sep 17 00:00:00 2001 From: Jai Sharma Date: Wed, 25 May 2022 18:28:18 +0100 Subject: [PATCH 13/14] Code quality --- osu.Game/Overlays/ChatOverlayV2.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index 9ca4d9cb6c..68199c9d25 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -56,7 +56,7 @@ namespace osu.Game.Overlays private const float side_bar_width = 190; private const float chat_bar_height = 60; - private readonly ChannelType[] excluded_channel_types = new[] + private readonly ChannelType[] excludedChannelTypes = { ChannelType.Multiplayer, ChannelType.Spectator, @@ -409,6 +409,6 @@ namespace osu.Game.Overlays } private IEnumerable filterToChatChannels(IEnumerable channels) - => channels.Cast().Where(c => !excluded_channel_types.Contains(c.Type)); + => channels.Cast().Where(c => !excludedChannelTypes.Contains(c.Type)); } } From a98d0cf0d8b6d8c91cdaff9626cc76859ca71537 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 26 May 2022 18:47:50 +0900 Subject: [PATCH 14/14] Simplify channel filter method --- osu.Game/Overlays/ChatOverlayV2.cs | 30 ++++++++++++++++++------------ 1 file changed, 18 insertions(+), 12 deletions(-) diff --git a/osu.Game/Overlays/ChatOverlayV2.cs b/osu.Game/Overlays/ChatOverlayV2.cs index 68199c9d25..f2ec007b19 100644 --- a/osu.Game/Overlays/ChatOverlayV2.cs +++ b/osu.Game/Overlays/ChatOverlayV2.cs @@ -3,7 +3,6 @@ #nullable enable -using System.Collections; using System.Collections.Generic; using System.Collections.Specialized; using System.Diagnostics; @@ -56,13 +55,6 @@ namespace osu.Game.Overlays private const float side_bar_width = 190; private const float chat_bar_height = 60; - private readonly ChannelType[] excludedChannelTypes = - { - ChannelType.Multiplayer, - ChannelType.Spectator, - ChannelType.Temporary, - }; - [Resolved] private OsuConfigManager config { get; set; } = null!; @@ -353,7 +345,7 @@ namespace osu.Game.Overlays switch (args.Action) { case NotifyCollectionChangedAction.Add: - IEnumerable newChannels = filterToChatChannels(args.NewItems); + IEnumerable newChannels = args.NewItems.OfType().Where(isChatChannel); foreach (var channel in newChannels) channelList.AddChannel(channel); @@ -361,7 +353,7 @@ namespace osu.Game.Overlays break; case NotifyCollectionChangedAction.Remove: - IEnumerable leftChannels = filterToChatChannels(args.OldItems); + IEnumerable leftChannels = args.OldItems.OfType().Where(isChatChannel); foreach (var channel in leftChannels) { @@ -408,7 +400,21 @@ namespace osu.Game.Overlays channelList.ScrollChannelIntoView(currentChannel.Value); } - private IEnumerable filterToChatChannels(IEnumerable channels) - => channels.Cast().Where(c => !excludedChannelTypes.Contains(c.Type)); + /// + /// Whether a channel should be displayed in this overlay, based on its type. + /// + private static bool isChatChannel(Channel channel) + { + switch (channel.Type) + { + case ChannelType.Multiplayer: + case ChannelType.Spectator: + case ChannelType.Temporary: + return false; + + default: + return true; + } + } } }