From 6e812ebd566c1598303fb2e7ccf5a3cd13f4458e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 00:45:33 +0100 Subject: [PATCH 001/157] Reimplement chat settings from stable --- osu.Game/Configuration/OsuConfigManager.cs | 12 ++++++- .../Online/AlertsAndPrivacySettings.cs | 32 +++++++++++++++++++ .../Sections/Online/InGameChatSettings.cs | 29 +++++++++++++++++ .../Settings/Sections/OnlineSection.cs | 4 ++- 4 files changed, 75 insertions(+), 2 deletions(-) create mode 100644 osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs create mode 100644 osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index e26021d930..ed562637d4 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -49,6 +49,12 @@ namespace osu.Game.Configuration Set(OsuSetting.ExternalLinkWarning, true); + Set(OsuSetting.ChatHighlightName, true); + Set(OsuSetting.ChatMessageNotification, true); + + Set(OsuSetting.HighlightWords, string.Empty); + Set(OsuSetting.IgnoreList, string.Empty); + // Audio Set(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01); @@ -180,6 +186,10 @@ namespace osu.Game.Configuration ScalingSizeX, ScalingSizeY, UIScale, - IntroSequence + IntroSequence, + ChatHighlightName, + ChatMessageNotification, + HighlightWords, + IgnoreList } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs new file mode 100644 index 0000000000..d84bf4eb3f --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -0,0 +1,32 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Configuration; + +namespace osu.Game.Overlays.Settings.Sections.Online +{ + public class AlertsAndPrivacySettings : SettingsSubsection + { + protected override string Header => "Alerts and Privacy"; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + Children = new Drawable[] + { + new SettingsCheckbox + { + LabelText = "Show a notification popup when someone says your name", + Bindable = config.GetBindable(OsuSetting.ChatHighlightName) + }, + new SettingsCheckbox + { + LabelText = "Show chat message notifications", + Bindable = config.GetBindable(OsuSetting.ChatMessageNotification) + }, + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs new file mode 100644 index 0000000000..e9cb1477ad --- /dev/null +++ b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs @@ -0,0 +1,29 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Game.Configuration; + +namespace osu.Game.Overlays.Settings.Sections.Online +{ + public class InGameChatSettings : SettingsSubsection + { + protected override string Header => "In-Game Chat"; + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + Children = new Drawable[] + { + new SettingsTextBox + { + LabelText = "Chat ignore list (space-separated list)", + Bindable = config.GetBindable(OsuSetting.IgnoreList) + }, + new SettingsTextBox + { + LabelText = "Chat highlight words (space-separated list)", + Bindable = config.GetBindable(OsuSetting.HighlightWords) + }, + }; + } + } +} diff --git a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs index 80295690c0..67a2e881d0 100644 --- a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs +++ b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs @@ -16,7 +16,9 @@ namespace osu.Game.Overlays.Settings.Sections { Children = new Drawable[] { - new WebSettings() + new WebSettings(), + new AlertsAndPrivacySettings(), + new InGameChatSettings() }; } } From e8180ab153901844621d0877918dd918a43c9c73 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 00:45:55 +0100 Subject: [PATCH 002/157] Add ToString() method to message for better debugging --- osu.Game/Online/Chat/Message.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game/Online/Chat/Message.cs b/osu.Game/Online/Chat/Message.cs index 2e41038a59..3b0507eb0c 100644 --- a/osu.Game/Online/Chat/Message.cs +++ b/osu.Game/Online/Chat/Message.cs @@ -63,5 +63,7 @@ namespace osu.Game.Online.Chat // ReSharper disable once ImpureMethodCallOnReadonlyValueField public override int GetHashCode() => Id.GetHashCode(); + + public override string ToString() => $"[{ChannelId}] ({Id}) {Sender}: {Content}"; } } From 8dfc8929f11ed8b4be09bca362ce8e6bf83ad62b Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 00:48:22 +0100 Subject: [PATCH 003/157] Add chat and notification logic to DrawableChannel with alongside multiple helper methods --- osu.Game/Overlays/Chat/DrawableChannel.cs | 167 +++++++++++++++++++++- 1 file changed, 163 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index f831266b1b..8c5a2e68ef 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -12,6 +12,14 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Online.Chat; +using osu.Game.Overlays.Notifications; +using osu.Game.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Colour; +using osu.Game.Online.API; +using osu.Game.Configuration; +using osu.Framework.Bindables; +using osu.Game.Users; namespace osu.Game.Overlays.Chat { @@ -20,6 +28,22 @@ namespace osu.Game.Overlays.Chat public readonly Channel Channel; protected ChatLineContainer ChatLineFlow; private OsuScrollContainer scroll; + public ColourInfo HighlightColour { get; set; } + + [Resolved(CanBeNull = true)] + private NotificationOverlay notificationOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private ChatOverlay chatOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private ChannelManager channelManager { get; set; } + + private Bindable notifyOnMention; + private Bindable notifyOnChat; + private Bindable highlightWords; + private Bindable ignoreList; + private Bindable localUser; public DrawableChannel(Channel channel) { @@ -28,8 +52,15 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader] - private void load() + private void load(OsuColour colours, OsuConfigManager config, IAPIProvider api) { + notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); + notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); + highlightWords = config.GetBindable(OsuSetting.HighlightWords); + ignoreList = config.GetBindable(OsuSetting.IgnoreList); + localUser = api.LocalUser; + HighlightColour = colours.Blue; + Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, @@ -77,10 +108,14 @@ namespace osu.Game.Overlays.Chat private void newMessagesArrived(IEnumerable newMessages) { // Add up to last Channel.MAX_HISTORY messages - var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory)); + var ignoredWords = getWords(ignoreList.Value); + var displayMessages = newMessages.Where(m => hasCaseInsensitive(getWords(m.Content), ignoredWords) == null); + displayMessages = displayMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MaxHistory)); ChatLineFlow.AddRange(displayMessages.Select(CreateChatLine)); + checkForMentions(displayMessages); + if (scroll.IsScrolledToEnd(10) || !ChatLineFlow.Children.Any() || newMessages.Any(m => m is LocalMessage)) scrollToEnd(); @@ -96,6 +131,63 @@ namespace osu.Game.Overlays.Chat } } + private void checkForMentions(IEnumerable messages) + { + // only send notifications when chat overlay is **closed** + if (chatOverlay?.IsPresent == true && channelManager?.CurrentChannel.Value == Channel) + return; + + foreach (var message in messages) + { + var words = getWords(message.Content); + var username = localUser.Value.Username; + + if (message.Sender.Username == username) + continue; + + if (notifyOnChat.Value && Channel.Type == ChannelType.PM) + { + var notification = new MentionNotification(Channel, message.Sender.Username, () => + { + channelManager.CurrentChannel.Value = Channel; + HighlightMessage(message); + }, true); + + notificationOverlay?.Post(notification); + continue; + } + + if (notifyOnMention.Value && anyCaseInsensitive(words, username)) + { + var notification = new MentionNotification(Channel, message.Sender.Username, () => + { + channelManager.CurrentChannel.Value = Channel; + HighlightMessage(message); + }, false); + + notificationOverlay?.Post(notification); + continue; + } + + if (!string.IsNullOrWhiteSpace(highlightWords.Value)) + { + var matchedWord = hasCaseInsensitive(words, getWords(highlightWords.Value)); + + if (matchedWord != null) + { + var notification = new MentionNotification(Channel, message.Sender.Username, matchedWord, () => + { + channelManager.CurrentChannel.Value = Channel; + HighlightMessage(message); + }); + + notificationOverlay?.Post(notification); + continue; + } + } + } + } + private void pendingMessageResolved(Message existing, Message updated) { var found = ChatLineFlow.Children.LastOrDefault(c => c.Message == existing); @@ -110,13 +202,31 @@ namespace osu.Game.Overlays.Chat } } - private void messageRemoved(Message removed) + public void HighlightMessage(Message message) { - ChatLineFlow.Children.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + var chatLine = findChatLine(message); + scroll.ScrollTo(chatLine); + chatLine.FlashColour(HighlightColour, 5000, Easing.InExpo); } + private void messageRemoved(Message removed) + { + findChatLine(removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + } + + private ChatLine findChatLine(Message message) => ChatLineFlow.Children.FirstOrDefault(c => c.Message == message); + private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd()); + private string[] getWords(string input) => input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + /// + /// Finds the first matching string/word in both and (case-insensitive) + /// + private string hasCaseInsensitive(IEnumerable x, IEnumerable y) => x.FirstOrDefault(x2 => anyCaseInsensitive(y, x2)); + + private bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.InvariantCultureIgnoreCase)); + protected class ChatLineContainer : FillFlowContainer { protected override int Compare(Drawable x, Drawable y) @@ -127,5 +237,54 @@ namespace osu.Game.Overlays.Chat return xC.Message.CompareTo(yC.Message); } } + + private class MentionNotification : SimpleNotification + { + public MentionNotification(Channel channel, string username, Action onClick, bool isPm) : this(channel, onClick) + { + if (isPm) + { + Icon = FontAwesome.Solid.Envelope; + Text = $"You received a private message from '{username}'. Click to read it!"; + } + else + { + Icon = FontAwesome.Solid.At; + Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; + } + } + + public MentionNotification(Channel channel, string highlighter, string word, Action onClick) : this(channel, onClick) + { + Icon = FontAwesome.Solid.Highlighter; + Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; + } + + private MentionNotification(Channel channel, Action onClick) + { + Channel = channel; + this.onClick = onClick; + } + + private readonly Action onClick; + + public Channel Channel { get; } + + public override bool IsImportant => false; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + { + IconBackgound.Colour = colours.PurpleDark; + Activated = delegate + { + notificationOverlay.Hide(); + chatOverlay.Show(); + onClick?.Invoke(); + + return true; + }; + } + } } } From 28d1fb181fae36a2bc35deac327e37a8b8d2e2e6 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 01:14:51 +0100 Subject: [PATCH 004/157] Add missing license header for InGameChatSettings.cs My unit tests fail at a solution filter, let's hope AppVeyor says yes. --- .../Overlays/Settings/Sections/Online/InGameChatSettings.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs index e9cb1477ad..4d8d06e557 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; From 20670730b99604f6b26d7eb653839873a8632030 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 01:57:07 +0100 Subject: [PATCH 005/157] Resolve code formatting --- osu.Game/Overlays/Chat/DrawableChannel.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 7eec3bf18d..66ba2d1076 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -218,7 +218,6 @@ namespace osu.Game.Overlays.Chat }); notificationOverlay?.Post(notification); - continue; } } } @@ -331,7 +330,8 @@ namespace osu.Game.Overlays.Chat private class MentionNotification : SimpleNotification { - public MentionNotification(Channel channel, string username, Action onClick, bool isPm) : this(channel, onClick) + public MentionNotification(Channel channel, string username, Action onClick, bool isPm) + : this(channel, onClick) { if (isPm) { @@ -345,7 +345,8 @@ namespace osu.Game.Overlays.Chat } } - public MentionNotification(Channel channel, string highlighter, string word, Action onClick) : this(channel, onClick) + public MentionNotification(Channel channel, string highlighter, string word, Action onClick) + : this(channel, onClick) { Icon = FontAwesome.Solid.Highlighter; Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; @@ -353,13 +354,13 @@ namespace osu.Game.Overlays.Chat private MentionNotification(Channel channel, Action onClick) { - Channel = channel; + this.channel = channel; this.onClick = onClick; } private readonly Action onClick; - public Channel Channel { get; } + private readonly Channel channel; public override bool IsImportant => false; From 8b14090c950df960194e5f1763fea694ba1c7695 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 02:13:26 +0100 Subject: [PATCH 006/157] Remove unused field --- osu.Game/Overlays/Chat/DrawableChannel.cs | 19 ++++++++----------- 1 file changed, 8 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 66ba2d1076..0ca3129d6c 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -183,7 +183,7 @@ namespace osu.Game.Overlays.Chat if (notifyOnChat.Value && Channel.Type == ChannelType.PM) { - var notification = new MentionNotification(Channel, message.Sender.Username, () => + var notification = new MentionNotification(message.Sender.Username, () => { channelManager.CurrentChannel.Value = Channel; HighlightMessage(message); @@ -195,7 +195,7 @@ namespace osu.Game.Overlays.Chat if (notifyOnMention.Value && anyCaseInsensitive(words, username)) { - var notification = new MentionNotification(Channel, message.Sender.Username, () => + var notification = new MentionNotification(message.Sender.Username, () => { channelManager.CurrentChannel.Value = Channel; HighlightMessage(message); @@ -211,7 +211,7 @@ namespace osu.Game.Overlays.Chat if (matchedWord != null) { - var notification = new MentionNotification(Channel, message.Sender.Username, matchedWord, () => + var notification = new MentionNotification(message.Sender.Username, matchedWord, () => { channelManager.CurrentChannel.Value = Channel; HighlightMessage(message); @@ -330,8 +330,8 @@ namespace osu.Game.Overlays.Chat private class MentionNotification : SimpleNotification { - public MentionNotification(Channel channel, string username, Action onClick, bool isPm) - : this(channel, onClick) + public MentionNotification(string username, Action onClick, bool isPm) + : this(onClick) { if (isPm) { @@ -345,23 +345,20 @@ namespace osu.Game.Overlays.Chat } } - public MentionNotification(Channel channel, string highlighter, string word, Action onClick) - : this(channel, onClick) + public MentionNotification(string highlighter, string word, Action onClick) + : this(onClick) { Icon = FontAwesome.Solid.Highlighter; Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; } - private MentionNotification(Channel channel, Action onClick) + private MentionNotification(Action onClick) { - this.channel = channel; this.onClick = onClick; } private readonly Action onClick; - private readonly Channel channel; - public override bool IsImportant => false; [BackgroundDependencyLoader] From 81d994abeda12ff1e0ddf635c77363f82ae96b4f Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 03:22:14 +0100 Subject: [PATCH 007/157] Change ChatMessageNotification's LabelText --- .../Settings/Sections/Online/AlertsAndPrivacySettings.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index d84bf4eb3f..0898ce3b84 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -23,7 +23,7 @@ namespace osu.Game.Overlays.Settings.Sections.Online }, new SettingsCheckbox { - LabelText = "Show chat message notifications", + LabelText = "Show private message notifications", Bindable = config.GetBindable(OsuSetting.ChatMessageNotification) }, }; From eb3f851ce27eb3496c8f9d8882f81fc0f246630a Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 03:22:55 +0100 Subject: [PATCH 008/157] Split Notification class into three separate ones --- osu.Game/Overlays/Chat/DrawableChannel.cs | 84 ++++++++++++++++------- 1 file changed, 60 insertions(+), 24 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 0ca3129d6c..bbfdb2dece 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -169,7 +169,7 @@ namespace osu.Game.Overlays.Chat private void checkForMentions(IEnumerable messages) { - // only send notifications when chat overlay is **closed** + // only send notifications when the chat overlay is **closed** and the channel is not visible. if (chatOverlay?.IsPresent == true && channelManager?.CurrentChannel.Value == Channel) return; @@ -183,11 +183,11 @@ namespace osu.Game.Overlays.Chat if (notifyOnChat.Value && Channel.Type == ChannelType.PM) { - var notification = new MentionNotification(message.Sender.Username, () => + var notification = new PrivateMessageNotification(message.Sender.Username, () => { channelManager.CurrentChannel.Value = Channel; HighlightMessage(message); - }, true); + }); notificationOverlay?.Post(notification); continue; @@ -199,7 +199,7 @@ namespace osu.Game.Overlays.Chat { channelManager.CurrentChannel.Value = Channel; HighlightMessage(message); - }, false); + }); notificationOverlay?.Post(notification); continue; @@ -211,7 +211,7 @@ namespace osu.Game.Overlays.Chat if (matchedWord != null) { - var notification = new MentionNotification(message.Sender.Username, matchedWord, () => + var notification = new HighlightNotification(message.Sender.Username, matchedWord, () => { channelManager.CurrentChannel.Value = Channel; HighlightMessage(message); @@ -328,32 +328,68 @@ namespace osu.Game.Overlays.Chat } } - private class MentionNotification : SimpleNotification + private class HighlightNotification : SimpleNotification { - public MentionNotification(string username, Action onClick, bool isPm) - : this(onClick) - { - if (isPm) - { - Icon = FontAwesome.Solid.Envelope; - Text = $"You received a private message from '{username}'. Click to read it!"; - } - else - { - Icon = FontAwesome.Solid.At; - Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; - } - } - - public MentionNotification(string highlighter, string word, Action onClick) - : this(onClick) + public HighlightNotification(string highlighter, string word, Action onClick) { Icon = FontAwesome.Solid.Highlighter; Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; + this.onClick = onClick; } - private MentionNotification(Action onClick) + private readonly Action onClick; + + public override bool IsImportant => false; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) { + IconBackgound.Colour = colours.PurpleDark; + Activated = delegate + { + notificationOverlay.Hide(); + chatOverlay.Show(); + onClick?.Invoke(); + + return true; + }; + } + } + + private class PrivateMessageNotification : SimpleNotification + { + public PrivateMessageNotification(string username, Action onClick) + { + Icon = FontAwesome.Solid.Envelope; + Text = $"You received a private message from '{username}'. Click to read it!"; + this.onClick = onClick; + } + + private readonly Action onClick; + + public override bool IsImportant => false; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + { + IconBackgound.Colour = colours.PurpleDark; + Activated = delegate + { + notificationOverlay.Hide(); + chatOverlay.Show(); + onClick?.Invoke(); + + return true; + }; + } + } + + private class MentionNotification : SimpleNotification + { + public MentionNotification(string username, Action onClick) + { + Icon = FontAwesome.Solid.At; + Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; this.onClick = onClick; } From 0225372e8347a4cbafd8aff855ac52e614289691 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 03:24:07 +0100 Subject: [PATCH 009/157] Rename method to ScrollToAndHighlightMessage --- osu.Game/Overlays/Chat/DrawableChannel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index bbfdb2dece..ef4ab25df7 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -186,7 +186,7 @@ namespace osu.Game.Overlays.Chat var notification = new PrivateMessageNotification(message.Sender.Username, () => { channelManager.CurrentChannel.Value = Channel; - HighlightMessage(message); + ScrollToAndHighlightMessage(message); }); notificationOverlay?.Post(notification); @@ -198,7 +198,7 @@ namespace osu.Game.Overlays.Chat var notification = new MentionNotification(message.Sender.Username, () => { channelManager.CurrentChannel.Value = Channel; - HighlightMessage(message); + ScrollToAndHighlightMessage(message); }); notificationOverlay?.Post(notification); @@ -214,7 +214,7 @@ namespace osu.Game.Overlays.Chat var notification = new HighlightNotification(message.Sender.Username, matchedWord, () => { channelManager.CurrentChannel.Value = Channel; - HighlightMessage(message); + ScrollToAndHighlightMessage(message); }); notificationOverlay?.Post(notification); @@ -237,7 +237,7 @@ namespace osu.Game.Overlays.Chat } } - public void HighlightMessage(Message message) + public void ScrollToAndHighlightMessage(Message message) { var chatLine = findChatLine(message); scroll.ScrollTo(chatLine); From 997b51b1f86679239034ff157e72f28cd6cbb118 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 03:26:30 +0100 Subject: [PATCH 010/157] Make messageRemoved use helper method --- osu.Game/Overlays/Chat/DrawableChannel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index ef4ab25df7..6813b3464d 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -246,7 +246,7 @@ namespace osu.Game.Overlays.Chat private void messageRemoved(Message removed) { - chatLines.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + findChatLine(removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); } private IEnumerable chatLines => ChatLineFlow.Children.OfType(); From 1a1253a4aa66d7bc917322f56d05a61fc627bcc2 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 03:27:19 +0100 Subject: [PATCH 011/157] Add null check to ScrollToAndHighlightMessage --- osu.Game/Overlays/Chat/DrawableChannel.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 6813b3464d..1ca65a1da7 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -239,6 +239,9 @@ namespace osu.Game.Overlays.Chat public void ScrollToAndHighlightMessage(Message message) { + if (message is null) + return; + var chatLine = findChatLine(message); scroll.ScrollTo(chatLine); chatLine.FlashColour(HighlightColour, 5000, Easing.InExpo); From bea34e3aab4b37822ee3792b53851a6aba0ffaa5 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 17 Dec 2019 06:55:48 +0100 Subject: [PATCH 012/157] Make it possible to retrieve notifications from NotificationOverlay --- osu.Game/Overlays/NotificationOverlay.cs | 3 +++ osu.Game/Overlays/Notifications/NotificationSection.cs | 2 ++ 2 files changed, 5 insertions(+) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 41160d10ec..2ae17b143a 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -13,6 +13,7 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Threading; +using System.Collections.Generic; namespace osu.Game.Overlays { @@ -22,6 +23,8 @@ namespace osu.Game.Overlays public const float TRANSITION_LENGTH = 600; + public IEnumerable Notifications => sections.Children.SelectMany(s => s.Notifications); + private FlowContainer sections; /// diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 17a2d4cf9f..320c0d6cb1 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -21,6 +21,8 @@ namespace osu.Game.Overlays.Notifications private FlowContainer notifications; + public IEnumerable Notifications => notifications.Children; + public int DisplayedCount => notifications.Count(n => !n.WasClosed); public int UnreadCount => notifications.Count(n => !n.WasClosed && !n.Read); From 02dc70be022a3837f556412d5dbf1b8725a27bee Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 17 Dec 2019 06:56:05 +0100 Subject: [PATCH 013/157] Make it possible to retrieve loaded channel drawables in ChatOverlay --- osu.Game/Overlays/ChatOverlay.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 33bcc4c139..bceb47c484 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -438,6 +438,11 @@ namespace osu.Game.Overlays textbox.Text = string.Empty; } + /// + /// Returns the loaded drawable for a channel. Returns null if not found. + /// + public DrawableChannel GetChannelDrawable(Channel channel) => loadedChannels.Find(drawable => drawable.Channel == channel); + private class TabsArea : Container { // IsHovered is used From b6c31e7764fb339907bcdea63a90e0cbb0f09637 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 17 Dec 2019 06:59:27 +0100 Subject: [PATCH 014/157] Remove ignore list, move code to MessageNotifier and add it to DI This also adds countable private message notifications. --- osu.Game/Configuration/OsuConfigManager.cs | 2 - osu.Game/Online/Chat/ChannelManager.cs | 14 +- osu.Game/Online/Chat/MessageNotifier.cs | 231 ++++++++++++++++++ osu.Game/OsuGame.cs | 3 + osu.Game/Overlays/Chat/DrawableChannel.cs | 177 +------------- .../Sections/Online/InGameChatSettings.cs | 7 +- 6 files changed, 250 insertions(+), 184 deletions(-) create mode 100644 osu.Game/Online/Chat/MessageNotifier.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index cb4feb360c..93d9068a2e 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -53,7 +53,6 @@ namespace osu.Game.Configuration Set(OsuSetting.ChatMessageNotification, true); Set(OsuSetting.HighlightWords, string.Empty); - Set(OsuSetting.IgnoreList, string.Empty); // Audio Set(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01); @@ -198,7 +197,6 @@ namespace osu.Game.Configuration ChatHighlightName, ChatMessageNotification, HighlightWords, - IgnoreList, UIHoldActivationDelay, HitLighting, MenuBackgroundSource diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 1d8c5609d9..937acf2128 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -50,6 +50,9 @@ namespace osu.Game.Online.Chat private IAPIProvider api; + [Resolved] + private MessageNotifier messageNotifier { get; set; } + public readonly BindableBool HighPollRate = new BindableBool(); public ChannelManager() @@ -247,7 +250,16 @@ namespace osu.Game.Online.Chat var channels = JoinedChannels.ToList(); foreach (var group in messages.GroupBy(m => m.ChannelId)) - channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); + { + var channel = channels.Find(c => c.Id == group.Key); + + if (channel == null) + continue; + + var groupArray = group.ToArray(); + channel.AddNewMessages(groupArray); + messageNotifier.HandleMessages(channel, groupArray); + } } private void initializeChannels() diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs new file mode 100644 index 0000000000..61ec7351c4 --- /dev/null +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -0,0 +1,231 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Sprites; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Online.API; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; +using osu.Game.Users; + +namespace osu.Game.Online.Chat +{ + /// + /// Component that handles creating and posting notifications for incoming messages. + /// + public class MessageNotifier : Component + { + [Resolved(CanBeNull = true)] + private NotificationOverlay notificationOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private ChatOverlay chatOverlay { get; set; } + + [Resolved(CanBeNull = true)] + private ChannelManager channelManager { get; set; } + + [Resolved] + private OsuColour colours { get; set; } + + private Bindable notifyOnMention; + private Bindable notifyOnChat; + private Bindable highlightWords; + private Bindable localUser; + + /// + /// Determines if the user is able to see incoming messages. + /// + public bool IsActive => chatOverlay?.IsPresent == true; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, OsuConfigManager config, IAPIProvider api) + { + notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); + notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); + highlightWords = config.GetBindable(OsuSetting.HighlightWords); + localUser = api.LocalUser; + } + + public void HandleMessages(Channel channel, IEnumerable messages) + { + // don't show if visible or not visible + if (IsActive && channelManager.CurrentChannel.Value == channel) + return; + + var channelDrawable = chatOverlay.GetChannelDrawable(channel); + if (channelDrawable == null) + return; + + foreach (var message in messages) + { + var words = getWords(message.Content); + var localUsername = localUser.Value.Username; + + if (message.Sender.Username == localUsername) + continue; + + void onClick() + { + if (channelManager != null) + channelManager.CurrentChannel.Value = channel; + + channelDrawable.ScrollToAndHighlightMessage(message); + } + + if (notifyOnChat.Value && channel.Type == ChannelType.PM) + { + var username = message.Sender.Username; + var existingNotification = notificationOverlay.Notifications.OfType().FirstOrDefault(n => n.Username == username); + + if (existingNotification == null) + { + var notification = new PrivateMessageNotification(username, onClick); + notificationOverlay?.Post(notification); + } + else + { + existingNotification.MessageCount++; + } + + continue; + } + if (notifyOnMention.Value && anyCaseInsensitive(words, localUsername)) + { + var notification = new MentionNotification(message.Sender.Username, onClick); + notificationOverlay?.Post(notification); + + continue; + } + if (!string.IsNullOrWhiteSpace(highlightWords.Value)) + { + var matchedWord = hasCaseInsensitive(words, getWords(highlightWords.Value)); + + if (matchedWord != null) + { + var notification = new HighlightNotification(message.Sender.Username, matchedWord, onClick); + notificationOverlay?.Post(notification); + } + } + } + } + + private static string[] getWords(string input) => input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + + /// + /// Finds the first matching string/word in both and (case-insensitive) + /// + private static string hasCaseInsensitive(IEnumerable x, IEnumerable y) => x.FirstOrDefault(x2 => anyCaseInsensitive(y, x2)); + + private static bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.InvariantCultureIgnoreCase)); + + private class HighlightNotification : SimpleNotification + { + public HighlightNotification(string highlighter, string word, Action onClick) + { + Icon = FontAwesome.Solid.Highlighter; + Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; + this.onClick = onClick; + } + + private readonly Action onClick; + + public override bool IsImportant => false; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + { + IconBackgound.Colour = colours.PurpleDark; + Activated = delegate + { + notificationOverlay.Hide(); + chatOverlay.Show(); + onClick?.Invoke(); + + return true; + }; + } + } + + private class PrivateMessageNotification : SimpleNotification + { + public PrivateMessageNotification(string username, Action onClick) + { + Icon = FontAwesome.Solid.Envelope; + Username = username; + MessageCount = 1; + this.onClick = onClick; + } + + private int messageCount = 0; + + public int MessageCount + { + get => messageCount; + set + { + messageCount = value; + if (messageCount > 1) + { + Text = $"You received {messageCount} private messages from '{Username}'. Click to read it!"; + } + else + { + Text = $"You received a private message from '{Username}'. Click to read it!"; + } + } + } + + public string Username { get; set; } + + private readonly Action onClick; + + public override bool IsImportant => false; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + { + IconBackgound.Colour = colours.PurpleDark; + Activated = delegate + { + notificationOverlay.Hide(); + chatOverlay.Show(); + onClick?.Invoke(); + + return true; + }; + } + } + + private class MentionNotification : SimpleNotification + { + public MentionNotification(string username, Action onClick) + { + Icon = FontAwesome.Solid.At; + Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; + this.onClick = onClick; + } + + private readonly Action onClick; + + public override bool IsImportant => false; + + [BackgroundDependencyLoader] + private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + { + IconBackgound.Colour = colours.PurpleDark; + Activated = delegate + { + notificationOverlay.Hide(); + chatOverlay.Show(); + onClick?.Invoke(); + + return true; + }; + } + } + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index c7c746bed3..d89109e9b9 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -58,6 +58,8 @@ namespace osu.Game private ChannelManager channelManager; + private MessageNotifier messageNotifier; + private NotificationOverlay notifications; private DirectOverlay direct; @@ -589,6 +591,7 @@ namespace osu.Game loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true); loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); + loadComponentSingleFile(messageNotifier = new MessageNotifier(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 1ca65a1da7..74aac2a7cf 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -33,21 +33,6 @@ namespace osu.Game.Overlays.Chat private OsuScrollContainer scroll; public ColourInfo HighlightColour { get; set; } - [Resolved(CanBeNull = true)] - private NotificationOverlay notificationOverlay { get; set; } - - [Resolved(CanBeNull = true)] - private ChatOverlay chatOverlay { get; set; } - - [Resolved(CanBeNull = true)] - private ChannelManager channelManager { get; set; } - - private Bindable notifyOnMention; - private Bindable notifyOnChat; - private Bindable highlightWords; - private Bindable ignoreList; - private Bindable localUser; - [Resolved] private OsuColour colours { get; set; } @@ -58,13 +43,8 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader] - private void load(OsuColour colours, OsuConfigManager config, IAPIProvider api) + private void load(OsuColour colours) { - notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); - notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); - highlightWords = config.GetBindable(OsuSetting.HighlightWords); - ignoreList = config.GetBindable(OsuSetting.IgnoreList); - localUser = api.LocalUser; HighlightColour = colours.Blue; Child = new OsuContextMenuContainer @@ -122,14 +102,10 @@ namespace osu.Game.Overlays.Chat bool shouldScrollToEnd = scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage); // Add up to last Channel.MAX_HISTORY messages - var ignoredWords = getWords(ignoreList.Value); - var displayMessages = newMessages.Where(m => hasCaseInsensitive(getWords(m.Content), ignoredWords) == null); - displayMessages = displayMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); + var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY)); Message lastMessage = chatLines.LastOrDefault()?.Message; - checkForMentions(displayMessages); - foreach (var message in displayMessages) { if (lastMessage == null || lastMessage.Timestamp.ToLocalTime().Date != message.Timestamp.ToLocalTime().Date) @@ -167,62 +143,6 @@ namespace osu.Game.Overlays.Chat scrollToEnd(); } - private void checkForMentions(IEnumerable messages) - { - // only send notifications when the chat overlay is **closed** and the channel is not visible. - if (chatOverlay?.IsPresent == true && channelManager?.CurrentChannel.Value == Channel) - return; - - foreach (var message in messages) - { - var words = getWords(message.Content); - var username = localUser.Value.Username; - - if (message.Sender.Username == username) - continue; - - if (notifyOnChat.Value && Channel.Type == ChannelType.PM) - { - var notification = new PrivateMessageNotification(message.Sender.Username, () => - { - channelManager.CurrentChannel.Value = Channel; - ScrollToAndHighlightMessage(message); - }); - - notificationOverlay?.Post(notification); - continue; - } - - if (notifyOnMention.Value && anyCaseInsensitive(words, username)) - { - var notification = new MentionNotification(message.Sender.Username, () => - { - channelManager.CurrentChannel.Value = Channel; - ScrollToAndHighlightMessage(message); - }); - - notificationOverlay?.Post(notification); - continue; - } - - if (!string.IsNullOrWhiteSpace(highlightWords.Value)) - { - var matchedWord = hasCaseInsensitive(words, getWords(highlightWords.Value)); - - if (matchedWord != null) - { - var notification = new HighlightNotification(message.Sender.Username, matchedWord, () => - { - channelManager.CurrentChannel.Value = Channel; - ScrollToAndHighlightMessage(message); - }); - - notificationOverlay?.Post(notification); - } - } - } - } - private void pendingMessageResolved(Message existing, Message updated) { var found = chatLines.LastOrDefault(c => c.Message == existing); @@ -256,15 +176,6 @@ namespace osu.Game.Overlays.Chat private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd()); - private string[] getWords(string input) => input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); - - /// - /// Finds the first matching string/word in both and (case-insensitive) - /// - private string hasCaseInsensitive(IEnumerable x, IEnumerable y) => x.FirstOrDefault(x2 => anyCaseInsensitive(y, x2)); - - private bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.InvariantCultureIgnoreCase)); - private ChatLine findChatLine(Message message) => chatLines.FirstOrDefault(c => c.Message == message); public class DaySeparator : Container @@ -330,89 +241,5 @@ namespace osu.Game.Overlays.Chat }; } } - - private class HighlightNotification : SimpleNotification - { - public HighlightNotification(string highlighter, string word, Action onClick) - { - Icon = FontAwesome.Solid.Highlighter; - Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; - this.onClick = onClick; - } - - private readonly Action onClick; - - public override bool IsImportant => false; - - [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) - { - IconBackgound.Colour = colours.PurpleDark; - Activated = delegate - { - notificationOverlay.Hide(); - chatOverlay.Show(); - onClick?.Invoke(); - - return true; - }; - } - } - - private class PrivateMessageNotification : SimpleNotification - { - public PrivateMessageNotification(string username, Action onClick) - { - Icon = FontAwesome.Solid.Envelope; - Text = $"You received a private message from '{username}'. Click to read it!"; - this.onClick = onClick; - } - - private readonly Action onClick; - - public override bool IsImportant => false; - - [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) - { - IconBackgound.Colour = colours.PurpleDark; - Activated = delegate - { - notificationOverlay.Hide(); - chatOverlay.Show(); - onClick?.Invoke(); - - return true; - }; - } - } - - private class MentionNotification : SimpleNotification - { - public MentionNotification(string username, Action onClick) - { - Icon = FontAwesome.Solid.At; - Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; - this.onClick = onClick; - } - - private readonly Action onClick; - - public override bool IsImportant => false; - - [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) - { - IconBackgound.Colour = colours.PurpleDark; - Activated = delegate - { - notificationOverlay.Hide(); - chatOverlay.Show(); - onClick?.Invoke(); - - return true; - }; - } - } } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs index 4d8d06e557..781aa10618 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs @@ -16,16 +16,11 @@ namespace osu.Game.Overlays.Settings.Sections.Online { Children = new Drawable[] { - new SettingsTextBox - { - LabelText = "Chat ignore list (space-separated list)", - Bindable = config.GetBindable(OsuSetting.IgnoreList) - }, new SettingsTextBox { LabelText = "Chat highlight words (space-separated list)", Bindable = config.GetBindable(OsuSetting.HighlightWords) - }, + } }; } } From 7bdfd2e23ce1083cc52db42d021e6a125bba97a5 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 17 Dec 2019 07:04:55 +0100 Subject: [PATCH 015/157] All copyright goes to peppy --- osu.Game/Online/Chat/MessageNotifier.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 61ec7351c4..9ee5e90be8 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -1,4 +1,7 @@ -using System; +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; using System.Collections.Generic; using System.Linq; using osu.Framework.Allocation; From 0d812bce9f90a8a77cd413386e9a6c4cdea90c44 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 26 Dec 2019 03:32:40 +0100 Subject: [PATCH 016/157] WIP changes for code review --- osu.Game/Online/Chat/Channel.cs | 27 ++++++---- osu.Game/Online/Chat/ChannelManager.cs | 5 -- osu.Game/Online/Chat/MessageNotifier.cs | 65 +++++++++++++++++------ osu.Game/Overlays/Chat/DrawableChannel.cs | 6 +-- osu.Game/Overlays/ChatOverlay.cs | 41 ++++++++++++-- 5 files changed, 105 insertions(+), 39 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 451174a73c..3e2a247d7f 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -44,7 +44,7 @@ namespace osu.Game.Online.Chat /// /// An event that fires when new messages arrived. /// - public event Action> NewMessagesArrived; + public event Action, bool> NewMessagesArrived; /// /// An event that fires when a pending message gets resolved. @@ -58,6 +58,11 @@ namespace osu.Game.Online.Chat public bool ReadOnly => false; //todo not yet used. + /// + /// Determines if the channel's previous messages have been loaded. + /// + public bool Populated { get; set; } = false; + public override string ToString() => Name; [JsonProperty(@"name")] @@ -105,7 +110,7 @@ namespace osu.Game.Online.Chat pendingMessages.Add(message); Messages.Add(message); - NewMessagesArrived?.Invoke(new[] { message }); + NewMessagesArrived?.Invoke(new[] { message }, Populated); } public bool MessagesLoaded; @@ -118,17 +123,21 @@ namespace osu.Game.Online.Chat { messages = messages.Except(Messages).ToArray(); - if (messages.Length == 0) return; + if (messages.Length != 0) + { + Messages.AddRange(messages); - Messages.AddRange(messages); + var maxMessageId = messages.Max(m => m.Id); + if (maxMessageId > LastMessageId) + LastMessageId = maxMessageId; - var maxMessageId = messages.Max(m => m.Id); - if (maxMessageId > LastMessageId) - LastMessageId = maxMessageId; + purgeOldMessages(); - purgeOldMessages(); + NewMessagesArrived?.Invoke(messages, Populated); + } - NewMessagesArrived?.Invoke(messages); + if (!Populated) + Populated = true; } /// diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 937acf2128..1bee12d8c8 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -49,10 +49,6 @@ namespace osu.Game.Online.Chat public IBindableList AvailableChannels => availableChannels; private IAPIProvider api; - - [Resolved] - private MessageNotifier messageNotifier { get; set; } - public readonly BindableBool HighPollRate = new BindableBool(); public ChannelManager() @@ -258,7 +254,6 @@ namespace osu.Game.Online.Chat var groupArray = group.ToArray(); channel.AddNewMessages(groupArray); - messageNotifier.HandleMessages(channel, groupArray); } } diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 9ee5e90be8..de079ce636 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -8,6 +8,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; +using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.API; @@ -31,9 +32,6 @@ namespace osu.Game.Online.Chat [Resolved(CanBeNull = true)] private ChannelManager channelManager { get; set; } - [Resolved] - private OsuColour colours { get; set; } - private Bindable notifyOnMention; private Bindable notifyOnChat; private Bindable highlightWords; @@ -45,12 +43,53 @@ namespace osu.Game.Online.Chat public bool IsActive => chatOverlay?.IsPresent == true; [BackgroundDependencyLoader] - private void load(OsuColour colours, OsuConfigManager config, IAPIProvider api) + private void load(OsuConfigManager config, IAPIProvider api) { notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); highlightWords = config.GetBindable(OsuSetting.HighlightWords); localUser = api.LocalUser; + + // Listen for new messages + + channelManager.JoinedChannels.ItemsAdded += (joinedChannels) => + { + foreach (var channel in joinedChannels) + channel.NewMessagesArrived += channel_NewMessagesArrived; + }; + + channelManager.JoinedChannels.ItemsRemoved += (leftChannels) => + { + foreach (var channel in leftChannels) + channel.NewMessagesArrived -= channel_NewMessagesArrived; + }; + } + + private void channel_NewMessagesArrived(IEnumerable messages, bool populated) + { + if (messages == null || !messages.Any()) + return; + + if (!populated) + return; + + HandleMessages(messages.First().ChannelId, messages); + } + + /// + /// Resolves the channel id + /// + public void HandleMessages(long channelId, IEnumerable messages) + { + var channel = channelManager.JoinedChannels.FirstOrDefault(c => c.Id == channelId); + + if (channel == null) + { + Logger.Log($"Couldn't resolve channel id {channelId}", LoggingTarget.Information); + return; + } + + HandleMessages(channel, messages); } public void HandleMessages(Channel channel, IEnumerable messages) @@ -59,10 +98,6 @@ namespace osu.Game.Online.Chat if (IsActive && channelManager.CurrentChannel.Value == channel) return; - var channelDrawable = chatOverlay.GetChannelDrawable(channel); - if (channelDrawable == null) - return; - foreach (var message in messages) { var words = getWords(message.Content); @@ -73,20 +108,17 @@ namespace osu.Game.Online.Chat void onClick() { - if (channelManager != null) - channelManager.CurrentChannel.Value = channel; - - channelDrawable.ScrollToAndHighlightMessage(message); + chatOverlay.ScrollToAndHighlightMessage(channel, message); + chatOverlay.Show(); } if (notifyOnChat.Value && channel.Type == ChannelType.PM) { - var username = message.Sender.Username; - var existingNotification = notificationOverlay.Notifications.OfType().FirstOrDefault(n => n.Username == username); + var existingNotification = notificationOverlay.Notifications.OfType().FirstOrDefault(n => n.Username == message.Sender.Username); if (existingNotification == null) { - var notification = new PrivateMessageNotification(username, onClick); + var notification = new PrivateMessageNotification(message.Sender.Username, onClick); notificationOverlay?.Post(notification); } else @@ -139,13 +171,12 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + private void load(OsuColour colours, NotificationOverlay notificationOverlay) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { notificationOverlay.Hide(); - chatOverlay.Show(); onClick?.Invoke(); return true; diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 74aac2a7cf..57ce7fed7c 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -67,7 +67,7 @@ namespace osu.Game.Overlays.Chat }, }; - newMessagesArrived(Channel.Messages); + newMessagesArrived(Channel.Messages, Channel.Populated); Channel.NewMessagesArrived += newMessagesArrived; Channel.MessageRemoved += messageRemoved; @@ -97,7 +97,7 @@ namespace osu.Game.Overlays.Chat Colour = colours.ChatBlue.Lighten(0.7f), }; - private void newMessagesArrived(IEnumerable newMessages) + private void newMessagesArrived(IEnumerable newMessages, bool populated) { bool shouldScrollToEnd = scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage); @@ -164,7 +164,7 @@ namespace osu.Game.Overlays.Chat var chatLine = findChatLine(message); scroll.ScrollTo(chatLine); - chatLine.FlashColour(HighlightColour, 5000, Easing.InExpo); + chatLine.FlashColour(HighlightColour, 7500, Easing.InExpo); } private void messageRemoved(Message removed) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index bceb47c484..ab74439f9a 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -22,6 +22,7 @@ using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; using osuTK.Input; using osu.Framework.Graphics.Sprites; +using System; namespace osu.Game.Overlays { @@ -60,6 +61,8 @@ namespace osu.Game.Overlays private Container channelSelectionContainer; protected ChannelSelectionOverlay ChannelSelectionOverlay; + private Message highlightingMessage { get; set; } + public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceivePositionalInputAt(screenSpacePos) || (ChannelSelectionOverlay.State.Value == Visibility.Visible && ChannelSelectionOverlay.ReceivePositionalInputAt(screenSpacePos)); @@ -252,15 +255,14 @@ namespace osu.Game.Overlays if (ChannelTabControl.Current.Value != e.NewValue) Scheduler.Add(() => ChannelTabControl.Current.Value = e.NewValue); - var loaded = loadedChannels.Find(d => d.Channel == e.NewValue); + var loaded = GetChannelDrawable(e.NewValue); if (loaded == null) { currentChannelContainer.FadeOut(500, Easing.OutQuint); loading.Show(); - loaded = new DrawableChannel(e.NewValue); - loadedChannels.Add(loaded); + loaded = loadChannelDrawable(e.NewValue); LoadComponentAsync(loaded, l => { if (currentChannel.Value != e.NewValue) @@ -271,6 +273,12 @@ namespace osu.Game.Overlays currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); currentChannelContainer.FadeIn(500, Easing.OutQuint); + + if (highlightingMessage != null && highlightingMessage.ChannelId == e.NewValue.Id) + { + loaded.ScrollToAndHighlightMessage(highlightingMessage); + highlightingMessage = null; + } }); } else @@ -439,9 +447,32 @@ namespace osu.Game.Overlays } /// - /// Returns the loaded drawable for a channel. Returns null if not found. + /// Returns the loaded drawable for a channel. Creates new instance if is true. Otherwise returns null if not found. /// - public DrawableChannel GetChannelDrawable(Channel channel) => loadedChannels.Find(drawable => drawable.Channel == channel); + public DrawableChannel GetChannelDrawable(Channel channel, bool createIfUnloaded = false) + { + var result = loadedChannels.Find(drawable => drawable.Channel == channel); + + if (createIfUnloaded && result == null) + { + result = loadChannelDrawable(channel); + } + + return result; + } + + private DrawableChannel loadChannelDrawable(Channel channel) + { + var loaded = new DrawableChannel(channel); + loadedChannels.Add(loaded); + return loaded; + } + + public void ScrollToAndHighlightMessage(Channel channel, Message message) + { + highlightingMessage = message; + channelManager.CurrentChannel.Value = channel; + } private class TabsArea : Container { From 1b53c0ff7479ec59711882fa21086be4d9cd5cfe Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 16 Jan 2020 23:15:30 +0100 Subject: [PATCH 017/157] Remove populated property, and other changes --- osu.Game/Online/Chat/Channel.cs | 14 +--- osu.Game/Online/Chat/MessageNotifier.cs | 90 ++++++++++++++++------- osu.Game/Overlays/Chat/DrawableChannel.cs | 19 +---- osu.Game/Overlays/ChatOverlay.cs | 43 +---------- 4 files changed, 71 insertions(+), 95 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 3e2a247d7f..3257774a27 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -44,7 +44,7 @@ namespace osu.Game.Online.Chat /// /// An event that fires when new messages arrived. /// - public event Action, bool> NewMessagesArrived; + public event Action> NewMessagesArrived; /// /// An event that fires when a pending message gets resolved. @@ -58,11 +58,6 @@ namespace osu.Game.Online.Chat public bool ReadOnly => false; //todo not yet used. - /// - /// Determines if the channel's previous messages have been loaded. - /// - public bool Populated { get; set; } = false; - public override string ToString() => Name; [JsonProperty(@"name")] @@ -110,7 +105,7 @@ namespace osu.Game.Online.Chat pendingMessages.Add(message); Messages.Add(message); - NewMessagesArrived?.Invoke(new[] { message }, Populated); + NewMessagesArrived?.Invoke(new[] { message }); } public bool MessagesLoaded; @@ -133,11 +128,8 @@ namespace osu.Game.Online.Chat purgeOldMessages(); - NewMessagesArrived?.Invoke(messages, Populated); + NewMessagesArrived?.Invoke(messages); } - - if (!Populated) - Populated = true; } /// diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index de079ce636..8663cf4793 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -51,7 +51,6 @@ namespace osu.Game.Online.Chat localUser = api.LocalUser; // Listen for new messages - channelManager.JoinedChannels.ItemsAdded += (joinedChannels) => { foreach (var channel in joinedChannels) @@ -65,14 +64,11 @@ namespace osu.Game.Online.Chat }; } - private void channel_NewMessagesArrived(IEnumerable messages, bool populated) + private void channel_NewMessagesArrived(IEnumerable messages) { if (messages == null || !messages.Any()) return; - if (!populated) - return; - HandleMessages(messages.First().ChannelId, messages); } @@ -94,7 +90,7 @@ namespace osu.Game.Online.Chat public void HandleMessages(Channel channel, IEnumerable messages) { - // don't show if visible or not visible + // don't show if the ChatOverlay and the channel is visible. if (IsActive && channelManager.CurrentChannel.Value == channel) return; @@ -108,26 +104,36 @@ namespace osu.Game.Online.Chat void onClick() { - chatOverlay.ScrollToAndHighlightMessage(channel, message); + notificationOverlay.Hide(); chatOverlay.Show(); + channelManager.CurrentChannel.Value = channel; } + + if (notifyOnChat.Value && channel.Type == ChannelType.PM) { - var existingNotification = notificationOverlay.Notifications.OfType().FirstOrDefault(n => n.Username == message.Sender.Username); + // Scheduling because of possible "race-condition" (NotificationOverlay didn't add the notification yet). + Schedule(() => + { + var existingNotification = notificationOverlay.Notifications.OfType() + .FirstOrDefault(n => n.Username == message.Sender.Username); - if (existingNotification == null) - { - var notification = new PrivateMessageNotification(message.Sender.Username, onClick); - notificationOverlay?.Post(notification); - } - else - { - existingNotification.MessageCount++; - } + if (existingNotification == null) + { + var notification = new PrivateMessageNotification(message.Sender.Username, onClick); + notificationOverlay?.Post(notification); + } + else + { + existingNotification.MessageCount++; + } + }); + continue; } + if (notifyOnMention.Value && anyCaseInsensitive(words, localUsername)) { var notification = new MentionNotification(message.Sender.Username, onClick); @@ -135,6 +141,7 @@ namespace osu.Game.Online.Chat continue; } + if (!string.IsNullOrWhiteSpace(highlightWords.Value)) { var matchedWord = hasCaseInsensitive(words, getWords(highlightWords.Value)); @@ -146,6 +153,40 @@ namespace osu.Game.Online.Chat } } } + + //making sure if the notification drawer bugs out, we merge it afterwards again. + Schedule(() => mergeNotifications()); + } + + /// + /// Checks current notifications if they aren't merged, and merges them together again. + /// + private void mergeNotifications() + { + if (notificationOverlay == null) + { + return; + } + + var pmn = notificationOverlay.Notifications.OfType(); + + foreach (var notification in pmn) + { + var duplicates = pmn.Where(n => n.Username == notification.Username); + + if (duplicates.Count() < 2) + continue; + + var first = duplicates.First(); + foreach (var notification2 in duplicates) + { + if (notification2 == first) + continue; + + first.MessageCount += notification2.MessageCount; + notification2.Close(); + } + } } private static string[] getWords(string input) => input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); @@ -171,14 +212,12 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay) + private void load(OsuColour colours) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { - notificationOverlay.Hide(); onClick?.Invoke(); - return true; }; } @@ -202,6 +241,7 @@ namespace osu.Game.Online.Chat set { messageCount = value; + if (messageCount > 1) { Text = $"You received {messageCount} private messages from '{Username}'. Click to read it!"; @@ -220,15 +260,12 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + private void load(OsuColour colours) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { - notificationOverlay.Hide(); - chatOverlay.Show(); onClick?.Invoke(); - return true; }; } @@ -248,15 +285,12 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, NotificationOverlay notificationOverlay, ChatOverlay chatOverlay) + private void load(OsuColour colours) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { - notificationOverlay.Hide(); - chatOverlay.Show(); onClick?.Invoke(); - return true; }; } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 57ce7fed7c..9c75e89249 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -8,17 +8,12 @@ using System.Linq; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Cursor; using osu.Game.Online.Chat; -using osu.Game.Overlays.Notifications; using osu.Game.Graphics; -using osu.Game.Online.API; -using osu.Game.Configuration; -using osu.Game.Users; using osu.Game.Graphics.Sprites; using osu.Framework.Graphics; using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Allocation; -using osu.Framework.Bindables; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Sprites; @@ -67,7 +62,7 @@ namespace osu.Game.Overlays.Chat }, }; - newMessagesArrived(Channel.Messages, Channel.Populated); + newMessagesArrived(Channel.Messages); Channel.NewMessagesArrived += newMessagesArrived; Channel.MessageRemoved += messageRemoved; @@ -97,7 +92,7 @@ namespace osu.Game.Overlays.Chat Colour = colours.ChatBlue.Lighten(0.7f), }; - private void newMessagesArrived(IEnumerable newMessages, bool populated) + private void newMessagesArrived(IEnumerable newMessages) { bool shouldScrollToEnd = scroll.IsScrolledToEnd(10) || !chatLines.Any() || newMessages.Any(m => m is LocalMessage); @@ -157,16 +152,6 @@ namespace osu.Game.Overlays.Chat } } - public void ScrollToAndHighlightMessage(Message message) - { - if (message is null) - return; - - var chatLine = findChatLine(message); - scroll.ScrollTo(chatLine); - chatLine.FlashColour(HighlightColour, 7500, Easing.InExpo); - } - private void messageRemoved(Message removed) { findChatLine(removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index ab74439f9a..c2716cd585 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -22,7 +22,6 @@ using osu.Game.Overlays.Chat.Selection; using osu.Game.Overlays.Chat.Tabs; using osuTK.Input; using osu.Framework.Graphics.Sprites; -using System; namespace osu.Game.Overlays { @@ -61,8 +60,6 @@ namespace osu.Game.Overlays private Container channelSelectionContainer; protected ChannelSelectionOverlay ChannelSelectionOverlay; - private Message highlightingMessage { get; set; } - public override bool Contains(Vector2 screenSpacePos) => chatContainer.ReceivePositionalInputAt(screenSpacePos) || (ChannelSelectionOverlay.State.Value == Visibility.Visible && ChannelSelectionOverlay.ReceivePositionalInputAt(screenSpacePos)); @@ -255,14 +252,16 @@ namespace osu.Game.Overlays if (ChannelTabControl.Current.Value != e.NewValue) Scheduler.Add(() => ChannelTabControl.Current.Value = e.NewValue); - var loaded = GetChannelDrawable(e.NewValue); + var loaded = loadedChannels.Find(drawable => drawable.Channel == e.NewValue); if (loaded == null) { currentChannelContainer.FadeOut(500, Easing.OutQuint); loading.Show(); - loaded = loadChannelDrawable(e.NewValue); + loaded = new DrawableChannel(e.NewValue); + loadedChannels.Add(loaded); + LoadComponentAsync(loaded, l => { if (currentChannel.Value != e.NewValue) @@ -273,12 +272,6 @@ namespace osu.Game.Overlays currentChannelContainer.Clear(false); currentChannelContainer.Add(loaded); currentChannelContainer.FadeIn(500, Easing.OutQuint); - - if (highlightingMessage != null && highlightingMessage.ChannelId == e.NewValue.Id) - { - loaded.ScrollToAndHighlightMessage(highlightingMessage); - highlightingMessage = null; - } }); } else @@ -446,34 +439,6 @@ namespace osu.Game.Overlays textbox.Text = string.Empty; } - /// - /// Returns the loaded drawable for a channel. Creates new instance if is true. Otherwise returns null if not found. - /// - public DrawableChannel GetChannelDrawable(Channel channel, bool createIfUnloaded = false) - { - var result = loadedChannels.Find(drawable => drawable.Channel == channel); - - if (createIfUnloaded && result == null) - { - result = loadChannelDrawable(channel); - } - - return result; - } - - private DrawableChannel loadChannelDrawable(Channel channel) - { - var loaded = new DrawableChannel(channel); - loadedChannels.Add(loaded); - return loaded; - } - - public void ScrollToAndHighlightMessage(Channel channel, Message message) - { - highlightingMessage = message; - channelManager.CurrentChannel.Value = channel; - } - private class TabsArea : Container { // IsHovered is used From 5d244f48f7553a862b7f9435c7f62941eb7ec53b Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Fri, 17 Jan 2020 00:00:10 +0100 Subject: [PATCH 018/157] Use instance list instead of exposing NotifcationOverlay's notifications --- osu.Game/Online/Chat/MessageNotifier.cs | 31 ++++++++++++------- osu.Game/Overlays/NotificationOverlay.cs | 2 -- .../Notifications/NotificationSection.cs | 2 -- 3 files changed, 20 insertions(+), 15 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 8663cf4793..c850fb4519 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -42,6 +42,8 @@ namespace osu.Game.Online.Chat /// public bool IsActive => chatOverlay?.IsPresent == true; + private List privateMessageNotifications = new List(); + [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) { @@ -96,12 +98,17 @@ namespace osu.Game.Online.Chat foreach (var message in messages) { - var words = getWords(message.Content); + // ignore messages that already have been read + if (message.Id < channel.LastReadId) + return; + var localUsername = localUser.Value.Username; if (message.Sender.Username == localUsername) continue; + var words = getWords(message.Content); + void onClick() { notificationOverlay.Hide(); @@ -109,20 +116,19 @@ namespace osu.Game.Online.Chat channelManager.CurrentChannel.Value = channel; } - - if (notifyOnChat.Value && channel.Type == ChannelType.PM) { // Scheduling because of possible "race-condition" (NotificationOverlay didn't add the notification yet). Schedule(() => { - var existingNotification = notificationOverlay.Notifications.OfType() - .FirstOrDefault(n => n.Username == message.Sender.Username); + var existingNotification = privateMessageNotifications.OfType() + .FirstOrDefault(n => n.Username == message.Sender.Username); if (existingNotification == null) { var notification = new PrivateMessageNotification(message.Sender.Username, onClick); notificationOverlay?.Post(notification); + privateMessageNotifications.Add(notification); } else { @@ -130,7 +136,6 @@ namespace osu.Game.Online.Chat } }); - continue; } @@ -196,9 +201,9 @@ namespace osu.Game.Online.Chat /// private static string hasCaseInsensitive(IEnumerable x, IEnumerable y) => x.FirstOrDefault(x2 => anyCaseInsensitive(y, x2)); - private static bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.InvariantCultureIgnoreCase)); + private static bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.OrdinalIgnoreCase)); - private class HighlightNotification : SimpleNotification + public class HighlightNotification : SimpleNotification { public HighlightNotification(string highlighter, string word, Action onClick) { @@ -223,7 +228,7 @@ namespace osu.Game.Online.Chat } } - private class PrivateMessageNotification : SimpleNotification + public class PrivateMessageNotification : SimpleNotification { public PrivateMessageNotification(string username, Action onClick) { @@ -260,18 +265,22 @@ namespace osu.Game.Online.Chat public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, MessageNotifier notifier) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { onClick?.Invoke(); + + if (notifier.privateMessageNotifications.Contains(this)) + notifier.privateMessageNotifications.Remove(this); + return true; }; } } - private class MentionNotification : SimpleNotification + public class MentionNotification : SimpleNotification { public MentionNotification(string username, Action onClick) { diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index 2ae17b143a..f36c13ab70 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -23,8 +23,6 @@ namespace osu.Game.Overlays public const float TRANSITION_LENGTH = 600; - public IEnumerable Notifications => sections.Children.SelectMany(s => s.Notifications); - private FlowContainer sections; /// diff --git a/osu.Game/Overlays/Notifications/NotificationSection.cs b/osu.Game/Overlays/Notifications/NotificationSection.cs index 320c0d6cb1..17a2d4cf9f 100644 --- a/osu.Game/Overlays/Notifications/NotificationSection.cs +++ b/osu.Game/Overlays/Notifications/NotificationSection.cs @@ -21,8 +21,6 @@ namespace osu.Game.Overlays.Notifications private FlowContainer notifications; - public IEnumerable Notifications => notifications.Children; - public int DisplayedCount => notifications.Count(n => !n.WasClosed); public int UnreadCount => notifications.Count(n => !n.WasClosed && !n.Read); From f55cf03bd0f09c770e84c85f8d856c85a65bc255 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 18 Jan 2020 14:17:26 +0100 Subject: [PATCH 019/157] Remove unnecessary changes after rework --- osu.Game/Online/Chat/MessageNotifier.cs | 64 +++++-------------------- 1 file changed, 13 insertions(+), 51 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index c850fb4519..2715c42a95 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -118,24 +118,20 @@ namespace osu.Game.Online.Chat if (notifyOnChat.Value && channel.Type == ChannelType.PM) { - // Scheduling because of possible "race-condition" (NotificationOverlay didn't add the notification yet). - Schedule(() => - { - var existingNotification = privateMessageNotifications.OfType() - .FirstOrDefault(n => n.Username == message.Sender.Username); + var existingNotification = privateMessageNotifications.OfType() + .FirstOrDefault(n => n.Username == message.Sender.Username); + + if (existingNotification == null) + { + var notification = new PrivateMessageNotification(message.Sender.Username, onClick); + notificationOverlay?.Post(notification); + privateMessageNotifications.Add(notification); + } + else + { + existingNotification.MessageCount++; + } - if (existingNotification == null) - { - var notification = new PrivateMessageNotification(message.Sender.Username, onClick); - notificationOverlay?.Post(notification); - privateMessageNotifications.Add(notification); - } - else - { - existingNotification.MessageCount++; - } - }); - continue; } @@ -158,40 +154,6 @@ namespace osu.Game.Online.Chat } } } - - //making sure if the notification drawer bugs out, we merge it afterwards again. - Schedule(() => mergeNotifications()); - } - - /// - /// Checks current notifications if they aren't merged, and merges them together again. - /// - private void mergeNotifications() - { - if (notificationOverlay == null) - { - return; - } - - var pmn = notificationOverlay.Notifications.OfType(); - - foreach (var notification in pmn) - { - var duplicates = pmn.Where(n => n.Username == notification.Username); - - if (duplicates.Count() < 2) - continue; - - var first = duplicates.First(); - foreach (var notification2 in duplicates) - { - if (notification2 == first) - continue; - - first.MessageCount += notification2.MessageCount; - notification2.Close(); - } - } } private static string[] getWords(string input) => input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); From bc6f71fe97d150e2dc1911efececb14edce39de0 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 18 Jan 2020 15:27:55 +0100 Subject: [PATCH 020/157] Preserve current channel if ChatOverlay is being loaded in --- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 7 ++++--- osu.Game/Overlays/ChatOverlay.cs | 8 +++++++- 2 files changed, 11 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 4b1d595b44..e30c1678d5 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -59,15 +59,16 @@ namespace osu.Game.Overlays.Chat.Tabs /// /// Adds a channel to the ChannelTabControl. - /// The first channel added will automaticly selected. + /// The first channel added will automaticly selected if is true. /// /// The channel that is going to be added. - public void AddChannel(Channel channel) + /// If the current channel should be changed if none was selected before + public void AddChannel(Channel channel, bool setChannel = true) { if (!Items.Contains(channel)) AddItem(channel); - if (Current.Value == null) + if (Current.Value == null && setChannel) Current.Value = channel; } diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 44772da3c1..4e69e4c9fc 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -221,8 +221,14 @@ namespace osu.Game.Overlays // TODO: consider scheduling bindable callbacks to not perform when overlay is not present. channelManager.JoinedChannels.ItemsAdded += onChannelAddedToJoinedChannels; channelManager.JoinedChannels.ItemsRemoved += onChannelRemovedFromJoinedChannels; + + bool channelSelected = channelManager.CurrentChannel.Value != null; + foreach (Channel channel in channelManager.JoinedChannels) - ChannelTabControl.AddChannel(channel); + ChannelTabControl.AddChannel(channel, !channelSelected); + + if (channelSelected) + ChannelTabControl.Current.Value = channelManager.CurrentChannel.Value; channelManager.AvailableChannels.ItemsAdded += availableChannelsChanged; channelManager.AvailableChannels.ItemsRemoved += availableChannelsChanged; From 8ddd36596e5cfd4b3933abbad5d5fc59179f6506 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 18 Jan 2020 15:40:55 +0100 Subject: [PATCH 021/157] Revert useless changes varying from properties, naming changes etc. --- osu.Game/Online/Chat/Channel.cs | 17 ++++++++--------- osu.Game/Online/Chat/ChannelManager.cs | 11 ++--------- osu.Game/Overlays/Chat/DrawableChannel.cs | 3 --- osu.Game/Overlays/ChatOverlay.cs | 3 +-- osu.Game/Overlays/NotificationOverlay.cs | 1 - 5 files changed, 11 insertions(+), 24 deletions(-) diff --git a/osu.Game/Online/Chat/Channel.cs b/osu.Game/Online/Chat/Channel.cs index 1dea38f422..6f67a95f53 100644 --- a/osu.Game/Online/Chat/Channel.cs +++ b/osu.Game/Online/Chat/Channel.cs @@ -126,18 +126,17 @@ namespace osu.Game.Online.Chat { messages = messages.Except(Messages).ToArray(); - if (messages.Length != 0) - { - Messages.AddRange(messages); + if (messages.Length == 0) return; - var maxMessageId = messages.Max(m => m.Id); - if (maxMessageId > LastMessageId) - LastMessageId = maxMessageId; + Messages.AddRange(messages); - purgeOldMessages(); + var maxMessageId = messages.Max(m => m.Id); + if (maxMessageId > LastMessageId) + LastMessageId = maxMessageId; - NewMessagesArrived?.Invoke(messages); - } + purgeOldMessages(); + + NewMessagesArrived?.Invoke(messages); } /// diff --git a/osu.Game/Online/Chat/ChannelManager.cs b/osu.Game/Online/Chat/ChannelManager.cs index 45c0df0677..4b5ec1cad0 100644 --- a/osu.Game/Online/Chat/ChannelManager.cs +++ b/osu.Game/Online/Chat/ChannelManager.cs @@ -49,6 +49,7 @@ namespace osu.Game.Online.Chat public IBindableList AvailableChannels => availableChannels; private IAPIProvider api; + public readonly BindableBool HighPollRate = new BindableBool(); public ChannelManager() @@ -246,15 +247,7 @@ namespace osu.Game.Online.Chat var channels = JoinedChannels.ToList(); foreach (var group in messages.GroupBy(m => m.ChannelId)) - { - var channel = channels.Find(c => c.Id == group.Key); - - if (channel == null) - continue; - - var groupArray = group.ToArray(); - channel.AddNewMessages(groupArray); - } + channels.Find(c => c.Id == group.Key)?.AddNewMessages(group.ToArray()); } private void initializeChannels() diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index 9c75e89249..a85b157175 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -26,7 +26,6 @@ namespace osu.Game.Overlays.Chat public readonly Channel Channel; protected FillFlowContainer ChatLineFlow; private OsuScrollContainer scroll; - public ColourInfo HighlightColour { get; set; } [Resolved] private OsuColour colours { get; set; } @@ -40,8 +39,6 @@ namespace osu.Game.Overlays.Chat [BackgroundDependencyLoader] private void load(OsuColour colours) { - HighlightColour = colours.Blue; - Child = new OsuContextMenuContainer { RelativeSizeAxes = Axes.Both, diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 4e69e4c9fc..9bd9f89665 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -259,7 +259,7 @@ namespace osu.Game.Overlays if (ChannelTabControl.Current.Value != e.NewValue) Scheduler.Add(() => ChannelTabControl.Current.Value = e.NewValue); - var loaded = loadedChannels.Find(drawable => drawable.Channel == e.NewValue); + var loaded = loadedChannels.Find(d => d.Channel == e.NewValue); if (loaded == null) { @@ -268,7 +268,6 @@ namespace osu.Game.Overlays loaded = new DrawableChannel(e.NewValue); loadedChannels.Add(loaded); - LoadComponentAsync(loaded, l => { if (currentChannel.Value != e.NewValue) diff --git a/osu.Game/Overlays/NotificationOverlay.cs b/osu.Game/Overlays/NotificationOverlay.cs index f36c13ab70..41160d10ec 100644 --- a/osu.Game/Overlays/NotificationOverlay.cs +++ b/osu.Game/Overlays/NotificationOverlay.cs @@ -13,7 +13,6 @@ using System; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Threading; -using System.Collections.Generic; namespace osu.Game.Overlays { From 64fe9692ed2abd4411affa6fe39d5525085dbe8a Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 18 Jan 2020 15:57:51 +0100 Subject: [PATCH 022/157] Resolve CA errors --- osu.Game/Online/Chat/MessageNotifier.cs | 26 +++++++------------------ osu.Game/OsuGame.cs | 4 +--- 2 files changed, 8 insertions(+), 22 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 2715c42a95..a2d6759863 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -53,13 +53,13 @@ namespace osu.Game.Online.Chat localUser = api.LocalUser; // Listen for new messages - channelManager.JoinedChannels.ItemsAdded += (joinedChannels) => + channelManager.JoinedChannels.ItemsAdded += joinedChannels => { foreach (var channel in joinedChannels) channel.NewMessagesArrived += channel_NewMessagesArrived; }; - channelManager.JoinedChannels.ItemsRemoved += (leftChannels) => + channelManager.JoinedChannels.ItemsRemoved += leftChannels => { foreach (var channel in leftChannels) channel.NewMessagesArrived -= channel_NewMessagesArrived; @@ -92,7 +92,7 @@ namespace osu.Game.Online.Chat public void HandleMessages(Channel channel, IEnumerable messages) { - // don't show if the ChatOverlay and the channel is visible. + // don't show if the ChatOverlay and the target channel is visible. if (IsActive && channelManager.CurrentChannel.Value == channel) return; @@ -118,8 +118,7 @@ namespace osu.Game.Online.Chat if (notifyOnChat.Value && channel.Type == ChannelType.PM) { - var existingNotification = privateMessageNotifications.OfType() - .FirstOrDefault(n => n.Username == message.Sender.Username); + var existingNotification = privateMessageNotifications.FirstOrDefault(n => n.Username == message.Sender.Username); if (existingNotification == null) { @@ -200,24 +199,13 @@ namespace osu.Game.Online.Chat this.onClick = onClick; } - private int messageCount = 0; + private int messageCount; public int MessageCount { get => messageCount; - set - { - messageCount = value; - - if (messageCount > 1) - { - Text = $"You received {messageCount} private messages from '{Username}'. Click to read it!"; - } - else - { - Text = $"You received a private message from '{Username}'. Click to read it!"; - } - } + set => Text = (messageCount = value) > 1 ? $"You received {messageCount} private messages from '{Username}'. Click to read it!" + : $"You received a private message from '{Username}'. Click to read it!"; } public string Username { get; set; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index ff23375556..40b65b50e6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -59,8 +59,6 @@ namespace osu.Game private ChannelManager channelManager; - private MessageNotifier messageNotifier; - private NotificationOverlay notifications; private NowPlayingOverlay nowPlaying; @@ -615,7 +613,7 @@ namespace osu.Game loadComponentSingleFile(direct = new DirectOverlay(), overlayContent.Add, true); loadComponentSingleFile(social = new SocialOverlay(), overlayContent.Add, true); loadComponentSingleFile(channelManager = new ChannelManager(), AddInternal, true); - loadComponentSingleFile(messageNotifier = new MessageNotifier(), AddInternal, true); + loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); From 8a9c90c5e61b6b16b1f96c9f3fd225b58e923226 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 18 Jan 2020 16:18:17 +0100 Subject: [PATCH 023/157] Resolve CA errors #2 --- osu.Game/Online/Chat/MessageNotifier.cs | 5 ++--- osu.Game/Overlays/Chat/DrawableChannel.cs | 1 - 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index a2d6759863..1637d2c2fe 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -42,7 +42,7 @@ namespace osu.Game.Online.Chat /// public bool IsActive => chatOverlay?.IsPresent == true; - private List privateMessageNotifications = new List(); + private readonly List privateMessageNotifications = new List(); [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) @@ -204,8 +204,7 @@ namespace osu.Game.Online.Chat public int MessageCount { get => messageCount; - set => Text = (messageCount = value) > 1 ? $"You received {messageCount} private messages from '{Username}'. Click to read it!" - : $"You received a private message from '{Username}'. Click to read it!"; + set => Text = (messageCount = value) > 1 ? $"You received {messageCount} private messages from '{Username}'. Click to read it!" : $"You received a private message from '{Username}'. Click to read it!"; } public string Username { get; set; } diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index a85b157175..b6c5a05c62 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -15,7 +15,6 @@ using osuTK.Graphics; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; -using osu.Framework.Graphics.Colour; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.Shapes; From 32c20235171b7a873e7fbe7fe4f8c9fc4738da73 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 17:20:54 +0100 Subject: [PATCH 024/157] Remove refactor in DrawableChannel --- osu.Game/Overlays/Chat/DrawableChannel.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index b6c5a05c62..d5f4d6c6d6 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -150,15 +150,13 @@ namespace osu.Game.Overlays.Chat private void messageRemoved(Message removed) { - findChatLine(removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); + chatLines.FirstOrDefault(c => c.Message == removed)?.FadeColour(Color4.Red, 400).FadeOut(600).Expire(); } private IEnumerable chatLines => ChatLineFlow.Children.OfType(); private void scrollToEnd() => ScheduleAfterChildren(() => scroll.ScrollToEnd()); - private ChatLine findChatLine(Message message) => chatLines.FirstOrDefault(c => c.Message == message); - public class DaySeparator : Container { public float TextSize From dd5478fe1ff3fe39bbc353e5eebff1aa00f6f460 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 17:26:43 +0100 Subject: [PATCH 025/157] Remove highlighted/mentioned words --- osu.Game/Configuration/OsuConfigManager.cs | 2 -- osu.Game/Online/Chat/MessageNotifier.cs | 34 ------------------- .../Sections/Online/InGameChatSettings.cs | 27 --------------- .../Settings/Sections/OnlineSection.cs | 3 +- 4 files changed, 1 insertion(+), 65 deletions(-) delete mode 100644 osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 93d9068a2e..2968dadb40 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -52,8 +52,6 @@ namespace osu.Game.Configuration Set(OsuSetting.ChatHighlightName, true); Set(OsuSetting.ChatMessageNotification, true); - Set(OsuSetting.HighlightWords, string.Empty); - // Audio Set(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01); diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 1637d2c2fe..0e6da54e8d 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -141,17 +141,6 @@ namespace osu.Game.Online.Chat continue; } - - if (!string.IsNullOrWhiteSpace(highlightWords.Value)) - { - var matchedWord = hasCaseInsensitive(words, getWords(highlightWords.Value)); - - if (matchedWord != null) - { - var notification = new HighlightNotification(message.Sender.Username, matchedWord, onClick); - notificationOverlay?.Post(notification); - } - } } } @@ -164,30 +153,7 @@ namespace osu.Game.Online.Chat private static bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.OrdinalIgnoreCase)); - public class HighlightNotification : SimpleNotification - { - public HighlightNotification(string highlighter, string word, Action onClick) - { - Icon = FontAwesome.Solid.Highlighter; - Text = $"'{word}' was mentioned in chat by '{highlighter}'. Click to find out why!"; - this.onClick = onClick; - } - private readonly Action onClick; - - public override bool IsImportant => false; - - [BackgroundDependencyLoader] - private void load(OsuColour colours) - { - IconBackgound.Colour = colours.PurpleDark; - Activated = delegate - { - onClick?.Invoke(); - return true; - }; - } - } public class PrivateMessageNotification : SimpleNotification { diff --git a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs b/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs deleted file mode 100644 index 781aa10618..0000000000 --- a/osu.Game/Overlays/Settings/Sections/Online/InGameChatSettings.cs +++ /dev/null @@ -1,27 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Game.Configuration; - -namespace osu.Game.Overlays.Settings.Sections.Online -{ - public class InGameChatSettings : SettingsSubsection - { - protected override string Header => "In-Game Chat"; - - [BackgroundDependencyLoader] - private void load(OsuConfigManager config) - { - Children = new Drawable[] - { - new SettingsTextBox - { - LabelText = "Chat highlight words (space-separated list)", - Bindable = config.GetBindable(OsuSetting.HighlightWords) - } - }; - } - } -} diff --git a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs index 67a2e881d0..77aa81b429 100644 --- a/osu.Game/Overlays/Settings/Sections/OnlineSection.cs +++ b/osu.Game/Overlays/Settings/Sections/OnlineSection.cs @@ -17,8 +17,7 @@ namespace osu.Game.Overlays.Settings.Sections Children = new Drawable[] { new WebSettings(), - new AlertsAndPrivacySettings(), - new InGameChatSettings() + new AlertsAndPrivacySettings() }; } } From 86ecaf223d4c92369330c525067b5328df08eb58 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 17:36:38 +0100 Subject: [PATCH 026/157] Improve getWords() --- osu.Game/Online/Chat/MessageNotifier.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 0e6da54e8d..606882507f 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Linq; +using System.Text.RegularExpressions; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -144,7 +145,7 @@ namespace osu.Game.Online.Chat } } - private static string[] getWords(string input) => input.Split(new[] { ' ' }, StringSplitOptions.RemoveEmptyEntries); + private static IEnumerable getWords(string input) => Regex.Matches(input, @"\w+").Select(c => c.Value); /// /// Finds the first matching string/word in both and (case-insensitive) From 4feae82434a33472ea17856fc00827aa0fd9c96e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 17:55:17 +0100 Subject: [PATCH 027/157] Split HandleMessages method --- osu.Game/Online/Chat/MessageNotifier.cs | 93 ++++++++++++++----------- 1 file changed, 51 insertions(+), 42 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 606882507f..431cc7bb00 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -103,48 +103,52 @@ namespace osu.Game.Online.Chat if (message.Id < channel.LastReadId) return; + // ignore messages from yourself var localUsername = localUser.Value.Username; if (message.Sender.Username == localUsername) continue; - var words = getWords(message.Content); - - void onClick() - { - notificationOverlay.Hide(); - chatOverlay.Show(); - channelManager.CurrentChannel.Value = channel; - } - - if (notifyOnChat.Value && channel.Type == ChannelType.PM) - { - var existingNotification = privateMessageNotifications.FirstOrDefault(n => n.Username == message.Sender.Username); - - if (existingNotification == null) - { - var notification = new PrivateMessageNotification(message.Sender.Username, onClick); - notificationOverlay?.Post(notification); - privateMessageNotifications.Add(notification); - } - else - { - existingNotification.MessageCount++; - } - + if (checkForPMs(channel, message)) continue; - } - if (notifyOnMention.Value && anyCaseInsensitive(words, localUsername)) - { - var notification = new MentionNotification(message.Sender.Username, onClick); - notificationOverlay?.Post(notification); - - continue; - } + // change output to bool again if another "message processor" is added. + checkForMentions(channel, message, localUsername); } } + private bool checkForPMs(Channel channel, Message message) + { + if (!notifyOnChat.Value || channel.Type != ChannelType.PM) + return false; + + var existingNotification = privateMessageNotifications.FirstOrDefault(n => n.Username == message.Sender.Username); + + if (existingNotification == null) + { + var notification = new PrivateMessageNotification(message.Sender.Username, channel); + notificationOverlay?.Post(notification); + privateMessageNotifications.Add(notification); + } + else + { + existingNotification.MessageCount++; + } + + return true; + } + + private void checkForMentions(Channel channel, Message message, string username) + { + var words = getWords(message.Content); + + if (!notifyOnMention.Value || !anyCaseInsensitive(words, username)) + return; + + var notification = new MentionNotification(message.Sender.Username, channel); + notificationOverlay?.Post(notification); + } + private static IEnumerable getWords(string input) => Regex.Matches(input, @"\w+").Select(c => c.Value); /// @@ -158,12 +162,12 @@ namespace osu.Game.Online.Chat public class PrivateMessageNotification : SimpleNotification { - public PrivateMessageNotification(string username, Action onClick) + public PrivateMessageNotification(string username, Channel channel) { Icon = FontAwesome.Solid.Envelope; Username = username; MessageCount = 1; - this.onClick = onClick; + Channel = channel; } private int messageCount; @@ -176,17 +180,19 @@ namespace osu.Game.Online.Chat public string Username { get; set; } - private readonly Action onClick; + public Channel Channel { get; set; } public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, MessageNotifier notifier) + private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager, MessageNotifier notifier) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { - onClick?.Invoke(); + notificationOverlay.Hide(); + chatOverlay.Show(); + channelManager.CurrentChannel.Value = Channel; if (notifier.privateMessageNotifications.Contains(this)) notifier.privateMessageNotifications.Remove(this); @@ -198,24 +204,27 @@ namespace osu.Game.Online.Chat public class MentionNotification : SimpleNotification { - public MentionNotification(string username, Action onClick) + public MentionNotification(string username, Channel channel) { Icon = FontAwesome.Solid.At; Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; - this.onClick = onClick; + Channel = channel; } - private readonly Action onClick; + public Channel Channel { get; set; } public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager) { IconBackgound.Colour = colours.PurpleDark; Activated = delegate { - onClick?.Invoke(); + notificationOverlay.Hide(); + chatOverlay.Show(); + channelManager.CurrentChannel.Value = Channel; + return true; }; } From 5f96940b7d8fb778991e9e9d3bfb3b445484cb96 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 17:56:01 +0100 Subject: [PATCH 028/157] Remove unused injection --- osu.Game/Overlays/Chat/DrawableChannel.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Chat/DrawableChannel.cs b/osu.Game/Overlays/Chat/DrawableChannel.cs index d5f4d6c6d6..4c196f758d 100644 --- a/osu.Game/Overlays/Chat/DrawableChannel.cs +++ b/osu.Game/Overlays/Chat/DrawableChannel.cs @@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Chat } [BackgroundDependencyLoader] - private void load(OsuColour colours) + private void load() { Child = new OsuContextMenuContainer { From 1681e167383b54561b4fb4a86ecf35bf6b7a29e8 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 18:20:42 +0100 Subject: [PATCH 029/157] Rework ChannelTabControl's AddChannel method to not auto select and let ChatOverlay handle this --- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 7 +------ osu.Game/Overlays/ChatOverlay.cs | 7 ++----- 2 files changed, 3 insertions(+), 11 deletions(-) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index e30c1678d5..4e6bc48b8a 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -59,17 +59,12 @@ namespace osu.Game.Overlays.Chat.Tabs /// /// Adds a channel to the ChannelTabControl. - /// The first channel added will automaticly selected if is true. /// /// The channel that is going to be added. - /// If the current channel should be changed if none was selected before - public void AddChannel(Channel channel, bool setChannel = true) + public void AddChannel(Channel channel) { if (!Items.Contains(channel)) AddItem(channel); - - if (Current.Value == null && setChannel) - Current.Value = channel; } /// diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 9bd9f89665..3eba0811e3 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -222,13 +222,10 @@ namespace osu.Game.Overlays channelManager.JoinedChannels.ItemsAdded += onChannelAddedToJoinedChannels; channelManager.JoinedChannels.ItemsRemoved += onChannelRemovedFromJoinedChannels; - bool channelSelected = channelManager.CurrentChannel.Value != null; - foreach (Channel channel in channelManager.JoinedChannels) - ChannelTabControl.AddChannel(channel, !channelSelected); + ChannelTabControl.AddChannel(channel); - if (channelSelected) - ChannelTabControl.Current.Value = channelManager.CurrentChannel.Value; + ChannelTabControl.Current.Value = channelManager.CurrentChannel.Value ?? channelManager.JoinedChannels.First(); channelManager.AvailableChannels.ItemsAdded += availableChannelsChanged; channelManager.AvailableChannels.ItemsRemoved += availableChannelsChanged; From 4b871f61e38de3a5b0c9dd507e9a5e0b30e496c8 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 18:23:12 +0100 Subject: [PATCH 030/157] Use Humanizer for counting PMs in text --- osu.Game/Online/Chat/MessageNotifier.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 431cc7bb00..b7fc41e57f 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; +using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -175,7 +176,11 @@ namespace osu.Game.Online.Chat public int MessageCount { get => messageCount; - set => Text = (messageCount = value) > 1 ? $"You received {messageCount} private messages from '{Username}'. Click to read it!" : $"You received a private message from '{Username}'. Click to read it!"; + set + { + messageCount = value; + Text = $"You received {"private message".ToQuantity(messageCount)} from '{Username}'. Click to read it!"; + } } public string Username { get; set; } From 7d1fc388ce2eef2b55f1ebdfd8e22c23b64e0815 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 18:34:48 +0100 Subject: [PATCH 031/157] Resolve code quality errors --- osu.Game/Online/Chat/MessageNotifier.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index b7fc41e57f..2e6d1befd2 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -36,7 +36,6 @@ namespace osu.Game.Online.Chat private Bindable notifyOnMention; private Bindable notifyOnChat; - private Bindable highlightWords; private Bindable localUser; /// @@ -159,8 +158,6 @@ namespace osu.Game.Online.Chat private static bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.OrdinalIgnoreCase)); - - public class PrivateMessageNotification : SimpleNotification { public PrivateMessageNotification(string username, Channel channel) From be2a88c8a503fe31539872014a77473635f653b8 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 18:40:17 +0100 Subject: [PATCH 032/157] Remove left over config entry --- osu.Game/Configuration/OsuConfigManager.cs | 1 - osu.Game/Online/Chat/MessageNotifier.cs | 1 - 2 files changed, 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 2968dadb40..42b757c326 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -194,7 +194,6 @@ namespace osu.Game.Configuration IntroSequence, ChatHighlightName, ChatMessageNotification, - HighlightWords, UIHoldActivationDelay, HitLighting, MenuBackgroundSource diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 2e6d1befd2..58a3dd51a9 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -50,7 +50,6 @@ namespace osu.Game.Online.Chat { notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); - highlightWords = config.GetBindable(OsuSetting.HighlightWords); localUser = api.LocalUser; // Listen for new messages From f98347b3bba3a9f5f84d388709aecff51c12645e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sun, 19 Jan 2020 18:56:15 +0100 Subject: [PATCH 033/157] Allow no channels to be present --- osu.Game/Overlays/ChatOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/ChatOverlay.cs b/osu.Game/Overlays/ChatOverlay.cs index 3eba0811e3..f49f5ef18b 100644 --- a/osu.Game/Overlays/ChatOverlay.cs +++ b/osu.Game/Overlays/ChatOverlay.cs @@ -225,7 +225,7 @@ namespace osu.Game.Overlays foreach (Channel channel in channelManager.JoinedChannels) ChannelTabControl.AddChannel(channel); - ChannelTabControl.Current.Value = channelManager.CurrentChannel.Value ?? channelManager.JoinedChannels.First(); + ChannelTabControl.Current.Value = channelManager.CurrentChannel.Value ?? channelManager.JoinedChannels.FirstOrDefault(); channelManager.AvailableChannels.ItemsAdded += availableChannelsChanged; channelManager.AvailableChannels.ItemsRemoved += availableChannelsChanged; From 63c8ae8211b548dec9cc8bbf3b86504d81d0098f Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 21 Jan 2020 23:42:15 +0100 Subject: [PATCH 034/157] Use IDs for checking against message author --- osu.Game/Online/Chat/MessageNotifier.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 58a3dd51a9..5739054750 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -103,16 +103,14 @@ namespace osu.Game.Online.Chat return; // ignore messages from yourself - var localUsername = localUser.Value.Username; - - if (message.Sender.Username == localUsername) + if (message.Sender.Id == localUser.Value.Id) continue; if (checkForPMs(channel, message)) continue; // change output to bool again if another "message processor" is added. - checkForMentions(channel, message, localUsername); + checkForMentions(channel, message, localUser.Value.Username); } } From 4d6ff31134b481e6d537c3d94a6161701bde793c Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Tue, 21 Jan 2020 23:43:21 +0100 Subject: [PATCH 035/157] Wrap getWords() with anyCaseInsensitive() --- osu.Game/Online/Chat/MessageNotifier.cs | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 5739054750..58941044c7 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -137,9 +137,7 @@ namespace osu.Game.Online.Chat private void checkForMentions(Channel channel, Message message, string username) { - var words = getWords(message.Content); - - if (!notifyOnMention.Value || !anyCaseInsensitive(words, username)) + if (!notifyOnMention.Value || !anyCaseInsensitive(getWords(message.Content), username)) return; var notification = new MentionNotification(message.Sender.Username, channel); From 47a92a13b0745ff9c3f927bd66edc69c33fd8b62 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:13:07 +0100 Subject: [PATCH 036/157] Change code comments --- osu.Game/Online/Chat/MessageNotifier.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 58941044c7..22d5ef303f 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -92,7 +92,7 @@ namespace osu.Game.Online.Chat public void HandleMessages(Channel channel, IEnumerable messages) { - // don't show if the ChatOverlay and the target channel is visible. + // Only send notifications, if ChatOverlay and the target channel aren't visible. if (IsActive && channelManager.CurrentChannel.Value == channel) return; @@ -102,7 +102,6 @@ namespace osu.Game.Online.Chat if (message.Id < channel.LastReadId) return; - // ignore messages from yourself if (message.Sender.Id == localUser.Value.Id) continue; From 9fd494b057597b28c8e9708ec26b469891a37bea Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:27:46 +0100 Subject: [PATCH 037/157] Fix order where messages are checked in --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 22d5ef303f..302600b687 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -96,7 +96,7 @@ namespace osu.Game.Online.Chat if (IsActive && channelManager.CurrentChannel.Value == channel) return; - foreach (var message in messages) + foreach (var message in messages.OrderByDescending(m => m.Id)) { // ignore messages that already have been read if (message.Id < channel.LastReadId) From 699547e1a214c226c96593acf2ef1eace1b67398 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:28:08 +0100 Subject: [PATCH 038/157] Also exclude last read message --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 302600b687..a941b970fb 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -99,7 +99,7 @@ namespace osu.Game.Online.Chat foreach (var message in messages.OrderByDescending(m => m.Id)) { // ignore messages that already have been read - if (message.Id < channel.LastReadId) + if (message.Id <= channel.LastReadId) return; if (message.Sender.Id == localUser.Value.Id) From 5978e2c0e222e64736199df9a84f39c128fe8b52 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:28:59 +0100 Subject: [PATCH 039/157] Redo how instances of PM notifications are removed --- osu.Game/Online/Chat/MessageNotifier.cs | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index a941b970fb..9819754b85 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -122,7 +122,8 @@ namespace osu.Game.Online.Chat if (existingNotification == null) { - var notification = new PrivateMessageNotification(message.Sender.Username, channel); + var notification = new PrivateMessageNotification(message.Sender.Username, channel, (n) => privateMessageNotifications.Remove(n)); + notificationOverlay?.Post(notification); privateMessageNotifications.Add(notification); } @@ -154,12 +155,13 @@ namespace osu.Game.Online.Chat public class PrivateMessageNotification : SimpleNotification { - public PrivateMessageNotification(string username, Channel channel) + public PrivateMessageNotification(string username, Channel channel, Action onRemove) { Icon = FontAwesome.Solid.Envelope; Username = username; MessageCount = 1; Channel = channel; + OnRemove = onRemove; } private int messageCount; @@ -178,23 +180,28 @@ namespace osu.Game.Online.Chat public Channel Channel { get; set; } + public Action OnRemove { get; set; } + public override bool IsImportant => false; [BackgroundDependencyLoader] - private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager, MessageNotifier notifier) + private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager) { IconBackgound.Colour = colours.PurpleDark; + Activated = delegate { notificationOverlay.Hide(); chatOverlay.Show(); channelManager.CurrentChannel.Value = Channel; - if (notifier.privateMessageNotifications.Contains(this)) - notifier.privateMessageNotifications.Remove(this); - return true; }; + + Closed += delegate + { + OnRemove.Invoke(this); + }; } } @@ -215,6 +222,7 @@ namespace osu.Game.Online.Chat private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager) { IconBackgound.Colour = colours.PurpleDark; + Activated = delegate { notificationOverlay.Hide(); From 795051e25699fa9d4b3c9f6f1df73ef9db92358d Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:29:12 +0100 Subject: [PATCH 040/157] Prevent channel duplicates --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 9819754b85..c2ea94a279 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -79,7 +79,7 @@ namespace osu.Game.Online.Chat /// public void HandleMessages(long channelId, IEnumerable messages) { - var channel = channelManager.JoinedChannels.FirstOrDefault(c => c.Id == channelId); + var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == channelId); if (channel == null) { From 88ea1138b6fbabba95abad898beda23e1faa96d9 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:31:44 +0100 Subject: [PATCH 041/157] Compile regex --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index c2ea94a279..7dc19e1370 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -144,7 +144,7 @@ namespace osu.Game.Online.Chat notificationOverlay?.Post(notification); } - private static IEnumerable getWords(string input) => Regex.Matches(input, @"\w+").Select(c => c.Value); + private static IEnumerable getWords(string input) => Regex.Matches(input, @"\w+", RegexOptions.Compiled).Select(c => c.Value); /// /// Finds the first matching string/word in both and (case-insensitive) From d29694d788e988fe47e22120cd2ff42445d2e2fb Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:41:46 +0100 Subject: [PATCH 042/157] Add additional comment to explain the code order --- osu.Game/Online/Chat/MessageNotifier.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 7dc19e1370..c832259338 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -105,6 +105,7 @@ namespace osu.Game.Online.Chat if (message.Sender.Id == localUser.Value.Id) continue; + // check for private messages first, if true, skip checking mentions to prevent duplicate notifications about the same message. if (checkForPMs(channel, message)) continue; From 73d4b6a6be2d5e1a396670bb863fc2114365c779 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 00:53:49 +0100 Subject: [PATCH 043/157] Remove redundant lambda signature parentheses :/ --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index c832259338..21e92c98e4 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -123,7 +123,7 @@ namespace osu.Game.Online.Chat if (existingNotification == null) { - var notification = new PrivateMessageNotification(message.Sender.Username, channel, (n) => privateMessageNotifications.Remove(n)); + var notification = new PrivateMessageNotification(message.Sender.Username, channel, n => privateMessageNotifications.Remove(n)); notificationOverlay?.Post(notification); privateMessageNotifications.Add(notification); From e4accb3344fd275692105b4de6eb025a0393918b Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 10:47:51 +0100 Subject: [PATCH 044/157] Remove IsActive property as it never really made sense to have it in the first place --- osu.Game/Online/Chat/MessageNotifier.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 21e92c98e4..8cdafdfd9c 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -38,11 +38,6 @@ namespace osu.Game.Online.Chat private Bindable notifyOnChat; private Bindable localUser; - /// - /// Determines if the user is able to see incoming messages. - /// - public bool IsActive => chatOverlay?.IsPresent == true; - private readonly List privateMessageNotifications = new List(); [BackgroundDependencyLoader] @@ -93,7 +88,7 @@ namespace osu.Game.Online.Chat public void HandleMessages(Channel channel, IEnumerable messages) { // Only send notifications, if ChatOverlay and the target channel aren't visible. - if (IsActive && channelManager.CurrentChannel.Value == channel) + if (chatOverlay?.IsPresent == true && channelManager.CurrentChannel.Value == channel) return; foreach (var message in messages.OrderByDescending(m => m.Id)) From 771155e88251c948370921a456adfc972159123f Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 10:48:55 +0100 Subject: [PATCH 045/157] No notification "debouncing" --- osu.Game/Online/Chat/MessageNotifier.cs | 38 +++---------------------- 1 file changed, 4 insertions(+), 34 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 8cdafdfd9c..745bf43c02 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -38,8 +38,6 @@ namespace osu.Game.Online.Chat private Bindable notifyOnChat; private Bindable localUser; - private readonly List privateMessageNotifications = new List(); - [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) { @@ -114,19 +112,9 @@ namespace osu.Game.Online.Chat if (!notifyOnChat.Value || channel.Type != ChannelType.PM) return false; - var existingNotification = privateMessageNotifications.FirstOrDefault(n => n.Username == message.Sender.Username); + var notification = new PrivateMessageNotification(message.Sender.Username, channel); - if (existingNotification == null) - { - var notification = new PrivateMessageNotification(message.Sender.Username, channel, n => privateMessageNotifications.Remove(n)); - - notificationOverlay?.Post(notification); - privateMessageNotifications.Add(notification); - } - else - { - existingNotification.MessageCount++; - } + notificationOverlay?.Post(notification); return true; } @@ -151,25 +139,12 @@ namespace osu.Game.Online.Chat public class PrivateMessageNotification : SimpleNotification { - public PrivateMessageNotification(string username, Channel channel, Action onRemove) + public PrivateMessageNotification(string username, Channel channel) { Icon = FontAwesome.Solid.Envelope; Username = username; - MessageCount = 1; Channel = channel; - OnRemove = onRemove; - } - - private int messageCount; - - public int MessageCount - { - get => messageCount; - set - { - messageCount = value; - Text = $"You received {"private message".ToQuantity(messageCount)} from '{Username}'. Click to read it!"; - } + Text = $"You received a private message from '{Username}'. Click to read it!"; } public string Username { get; set; } @@ -193,11 +168,6 @@ namespace osu.Game.Online.Chat return true; }; - - Closed += delegate - { - OnRemove.Invoke(this); - }; } } From 3d2625836ac0dd63b83401ccb90ad27ae03b33f1 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 10:50:27 +0100 Subject: [PATCH 046/157] Remove static from getWords method --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 745bf43c02..71139c81b7 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -128,7 +128,7 @@ namespace osu.Game.Online.Chat notificationOverlay?.Post(notification); } - private static IEnumerable getWords(string input) => Regex.Matches(input, @"\w+", RegexOptions.Compiled).Select(c => c.Value); + private IEnumerable getWords(string input) => Regex.Matches(input, @"\w+", RegexOptions.Compiled).Select(c => c.Value); /// /// Finds the first matching string/word in both and (case-insensitive) From c6f450f93295f5ee65696ed179efd68706d2f0b6 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 22 Jan 2020 11:23:27 +0100 Subject: [PATCH 047/157] Resolve code analysis errors --- osu.Game/Online/Chat/MessageNotifier.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 71139c81b7..f6f1b9cb7d 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -5,7 +5,6 @@ using System; using System.Collections.Generic; using System.Linq; using System.Text.RegularExpressions; -using Humanizer; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -147,9 +146,9 @@ namespace osu.Game.Online.Chat Text = $"You received a private message from '{Username}'. Click to read it!"; } - public string Username { get; set; } + public string Username { get; } - public Channel Channel { get; set; } + public Channel Channel { get; } public Action OnRemove { get; set; } @@ -180,7 +179,7 @@ namespace osu.Game.Online.Chat Channel = channel; } - public Channel Channel { get; set; } + public Channel Channel { get; } public override bool IsImportant => false; From 158b9690526846546755f5de6f572d0c540441e9 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 14:40:16 +0100 Subject: [PATCH 048/157] Remove XML doc from HandleMessages --- osu.Game/Online/Chat/MessageNotifier.cs | 3 --- 1 file changed, 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index f6f1b9cb7d..a4fbb6fef3 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -66,9 +66,6 @@ namespace osu.Game.Online.Chat HandleMessages(messages.First().ChannelId, messages); } - /// - /// Resolves the channel id - /// public void HandleMessages(long channelId, IEnumerable messages) { var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == channelId); From 00da45ead4d9a4a36b1379e19a2f82863da6add2 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 14:40:53 +0100 Subject: [PATCH 049/157] Matching strings instead of splitting --- osu.Game/Online/Chat/MessageNotifier.cs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index a4fbb6fef3..074b171022 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -4,7 +4,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Text.RegularExpressions; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; @@ -117,21 +116,25 @@ namespace osu.Game.Online.Chat private void checkForMentions(Channel channel, Message message, string username) { - if (!notifyOnMention.Value || !anyCaseInsensitive(getWords(message.Content), username)) + if (!notifyOnMention.Value || !isMentioning(message.Content, username)) return; var notification = new MentionNotification(message.Sender.Username, channel); notificationOverlay?.Post(notification); } - private IEnumerable getWords(string input) => Regex.Matches(input, @"\w+", RegexOptions.Compiled).Select(c => c.Value); - /// - /// Finds the first matching string/word in both and (case-insensitive) + /// Checks if contains , if not, retries making spaces into underscores. /// - private static string hasCaseInsensitive(IEnumerable x, IEnumerable y) => x.FirstOrDefault(x2 => anyCaseInsensitive(y, x2)); + /// If the mentions the + private bool isMentioning(string message, string username) + { + // sanitize input to handle casing + message = message.ToLower(); + username = username.ToLower(); - private static bool anyCaseInsensitive(IEnumerable x, string y) => x.Any(x2 => x2.Equals(y, StringComparison.OrdinalIgnoreCase)); + return message.Contains(username) || message.Contains(username.Replace(' ', '_')); + } public class PrivateMessageNotification : SimpleNotification { From 16c500d0b0dd29191466608bcd8f7fa970e3419c Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 16:41:45 +0100 Subject: [PATCH 050/157] Add mention tests --- osu.Game.Tests/Chat/MessageNotifierTests.cs | 27 +++++++++++++++++++++ 1 file changed, 27 insertions(+) create mode 100644 osu.Game.Tests/Chat/MessageNotifierTests.cs diff --git a/osu.Game.Tests/Chat/MessageNotifierTests.cs b/osu.Game.Tests/Chat/MessageNotifierTests.cs new file mode 100644 index 0000000000..d46e18b0b4 --- /dev/null +++ b/osu.Game.Tests/Chat/MessageNotifierTests.cs @@ -0,0 +1,27 @@ +using NUnit.Framework; +using osu.Game.Online.Chat; + +namespace osu.Game.Tests.Chat +{ + [TestFixture] + public class MessageNotifierTests + { + private readonly MessageNotifier messageNotifier = new MessageNotifier(); + + [Test] + public void TestMentions() + { + // Message (with mention, different casing) + Assert.IsTrue(messageNotifier.IsMentioning("Hey, Somebody Playing OSU!", "Somebody playing osu!")); + + // Message (with mention, underscores) + Assert.IsTrue(messageNotifier.IsMentioning("Hey, Somebody_playing_osu!", "Somebody playing osu!")); + + // Message (with mention, different casing, underscores) + Assert.IsTrue(messageNotifier.IsMentioning("Hey, Somebody_Playing_OSU!", "Somebody playing osu!")); + + // Message (without mention) + Assert.IsTrue(!messageNotifier.IsMentioning("peppy, can you please fix this?", "Cookiezi")); + } + } +} From e0ef6725494e75be59325183149d0ab8ed256f03 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 16:43:51 +0100 Subject: [PATCH 051/157] Use binded list --- osu.Game/Online/Chat/MessageNotifier.cs | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 074b171022..4d371f655d 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -35,6 +35,7 @@ namespace osu.Game.Online.Chat private Bindable notifyOnMention; private Bindable notifyOnChat; private Bindable localUser; + private BindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) @@ -43,14 +44,16 @@ namespace osu.Game.Online.Chat notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); localUser = api.LocalUser; + channelManager.JoinedChannels.BindTo(joinedChannels); + // Listen for new messages - channelManager.JoinedChannels.ItemsAdded += joinedChannels => + joinedChannels.ItemsAdded += joinedChannels => { foreach (var channel in joinedChannels) channel.NewMessagesArrived += channel_NewMessagesArrived; }; - channelManager.JoinedChannels.ItemsRemoved += leftChannels => + joinedChannels.ItemsRemoved += leftChannels => { foreach (var channel in leftChannels) channel.NewMessagesArrived -= channel_NewMessagesArrived; @@ -116,7 +119,7 @@ namespace osu.Game.Online.Chat private void checkForMentions(Channel channel, Message message, string username) { - if (!notifyOnMention.Value || !isMentioning(message.Content, username)) + if (!notifyOnMention.Value || !IsMentioning(message.Content, username)) return; var notification = new MentionNotification(message.Sender.Username, channel); From f9def8355237dcc540cb4336c7132b7a4efa8a65 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 16:44:45 +0100 Subject: [PATCH 052/157] Make IsMentioning public to allow it to be used for testing --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 4d371f655d..9f14a0fc21 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -130,7 +130,7 @@ namespace osu.Game.Online.Chat /// Checks if contains , if not, retries making spaces into underscores. /// /// If the mentions the - private bool isMentioning(string message, string username) + public bool IsMentioning(string message, string username) { // sanitize input to handle casing message = message.ToLower(); From 9e6fde7d09ebc8376df331f9b4e629bf34fe54f5 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 16:50:12 +0100 Subject: [PATCH 053/157] Add license header --- osu.Game.Tests/Chat/MessageNotifierTests.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Chat/MessageNotifierTests.cs b/osu.Game.Tests/Chat/MessageNotifierTests.cs index d46e18b0b4..b5a9a63961 100644 --- a/osu.Game.Tests/Chat/MessageNotifierTests.cs +++ b/osu.Game.Tests/Chat/MessageNotifierTests.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; using osu.Game.Online.Chat; namespace osu.Game.Tests.Chat From 65644731e0d2e86280ed7b73a5c0bd9b06be1ff2 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 25 Jan 2020 17:03:39 +0100 Subject: [PATCH 054/157] Make field readonly --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 9f14a0fc21..41df7e7291 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -35,7 +35,7 @@ namespace osu.Game.Online.Chat private Bindable notifyOnMention; private Bindable notifyOnChat; private Bindable localUser; - private BindableList joinedChannels = new BindableList(); + private readonly BindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) From 5e91a3f0f8ac53c66e3d77897e607956a50f4149 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 29 Jan 2020 01:59:52 +0100 Subject: [PATCH 055/157] Use IndexOf --- osu.Game/Online/Chat/MessageNotifier.cs | 9 +-------- 1 file changed, 1 insertion(+), 8 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 41df7e7291..30784c9934 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -130,14 +130,7 @@ namespace osu.Game.Online.Chat /// Checks if contains , if not, retries making spaces into underscores. /// /// If the mentions the - public bool IsMentioning(string message, string username) - { - // sanitize input to handle casing - message = message.ToLower(); - username = username.ToLower(); - - return message.Contains(username) || message.Contains(username.Replace(' ', '_')); - } + public bool IsMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; public class PrivateMessageNotification : SimpleNotification { From d7a52aa80109cbb34b73f220ede35fa2e789a88b Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 29 Jan 2020 02:06:10 +0100 Subject: [PATCH 056/157] Use test scenes --- osu.Game.Tests/Chat/MessageNotifierTests.cs | 30 ------ .../Visual/Online/TestSceneMessageNotifier.cs | 99 +++++++++++++++++++ 2 files changed, 99 insertions(+), 30 deletions(-) delete mode 100644 osu.Game.Tests/Chat/MessageNotifierTests.cs create mode 100644 osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs diff --git a/osu.Game.Tests/Chat/MessageNotifierTests.cs b/osu.Game.Tests/Chat/MessageNotifierTests.cs deleted file mode 100644 index b5a9a63961..0000000000 --- a/osu.Game.Tests/Chat/MessageNotifierTests.cs +++ /dev/null @@ -1,30 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Game.Online.Chat; - -namespace osu.Game.Tests.Chat -{ - [TestFixture] - public class MessageNotifierTests - { - private readonly MessageNotifier messageNotifier = new MessageNotifier(); - - [Test] - public void TestMentions() - { - // Message (with mention, different casing) - Assert.IsTrue(messageNotifier.IsMentioning("Hey, Somebody Playing OSU!", "Somebody playing osu!")); - - // Message (with mention, underscores) - Assert.IsTrue(messageNotifier.IsMentioning("Hey, Somebody_playing_osu!", "Somebody playing osu!")); - - // Message (with mention, different casing, underscores) - Assert.IsTrue(messageNotifier.IsMentioning("Hey, Somebody_Playing_OSU!", "Somebody playing osu!")); - - // Message (without mention) - Assert.IsTrue(!messageNotifier.IsMentioning("peppy, can you please fix this?", "Cookiezi")); - } - } -} diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs new file mode 100644 index 0000000000..632f66354c --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -0,0 +1,99 @@ +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.Chat; +using osu.Game.Overlays; +using osu.Game.Users; + +namespace osu.Game.Tests.Visual.Online +{ + public class TestSceneMessageNotifier : OsuTestScene + { + private User friend; + private Channel publicChannel; + private Channel privateMesssageChannel; + private TestContainer testContainer; + + private int messageIdCounter; + + [SetUp] + public void Setup() + { + friend = new User() { Id = 0, Username = "Friend" }; + publicChannel = new Channel() { Id = 1, Name = "osu" }; + privateMesssageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; + + Child = testContainer = new TestContainer(new Channel[] { publicChannel, privateMesssageChannel }) + { + RelativeSizeAxes = Axes.Both, + }; + + testContainer.ChatOverlay.Show(); + } + + [Test] + public void TestPublicChannelMention() + { + AddStep("Switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMesssageChannel); + + AddStep("Send regular message", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { + Content = "Hello everyone!", + Sender = friend, + ChannelId = publicChannel.Id + })); + AddAssert("Expect no notifications", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + + AddStep("Send message containing mention", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { + Content = $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!", + Sender = friend, + ChannelId = publicChannel.Id + })); + AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + } + + [Test] + public void TestPrivateMessageNotification() + { + AddStep("Send PM", () => privateMesssageChannel.AddNewMessages(new Message(messageIdCounter++) + { + Content = $"Hello {API.LocalUser.Value.Username}!", + Sender = friend, + ChannelId = privateMesssageChannel.Id + })); + AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + } + + private class TestContainer : Container + { + private Channel[] channels; + + public TestContainer(Channel[] channels) => this.channels = channels; + + [Cached] + public ChannelManager ChannelManager { get; } = new ChannelManager(); + + [Cached] + public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay(); + + [Cached] + public MessageNotifier MessageNotifier { get; } = new MessageNotifier(); + + [Cached] + public ChatOverlay ChatOverlay { get; } = new ChatOverlay(); + + [BackgroundDependencyLoader] + private void load() + { + AddRange(new Drawable[] { ChannelManager, NotificationOverlay }); + + ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); + + AddRange(new Drawable[] { ChatOverlay, MessageNotifier }); + + ((BindableList)ChannelManager.JoinedChannels).AddRange(channels); + } + } + } +} From 48231317d28880bd334b836da4d00ba7971e9494 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 29 Jan 2020 02:07:08 +0100 Subject: [PATCH 057/157] Make IsMentioning private --- osu.Game/Online/Chat/MessageNotifier.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 30784c9934..0e79a13917 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -119,7 +119,7 @@ namespace osu.Game.Online.Chat private void checkForMentions(Channel channel, Message message, string username) { - if (!notifyOnMention.Value || !IsMentioning(message.Content, username)) + if (!notifyOnMention.Value || !isMentioning(message.Content, username)) return; var notification = new MentionNotification(message.Sender.Username, channel); @@ -130,7 +130,7 @@ namespace osu.Game.Online.Chat /// Checks if contains , if not, retries making spaces into underscores. /// /// If the mentions the - public bool IsMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; + private bool isMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; public class PrivateMessageNotification : SimpleNotification { From e7881bd3811ed8eda28d8b4b51c1f4a93059dd94 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 29 Jan 2020 02:13:32 +0100 Subject: [PATCH 058/157] Single lines. --- .../Visual/Online/TestSceneMessageNotifier.cs | 12 ++---------- 1 file changed, 2 insertions(+), 10 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 632f66354c..51d5f837fc 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -38,18 +38,10 @@ namespace osu.Game.Tests.Visual.Online { AddStep("Switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMesssageChannel); - AddStep("Send regular message", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { - Content = "Hello everyone!", - Sender = friend, - ChannelId = publicChannel.Id - })); + AddStep("Send regular message", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { Content = "Hello everyone!", Sender = friend, ChannelId = publicChannel.Id })); AddAssert("Expect no notifications", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); - AddStep("Send message containing mention", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { - Content = $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!", - Sender = friend, - ChannelId = publicChannel.Id - })); + AddStep("Send message containing mention", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!", Sender = friend, ChannelId = publicChannel.Id })); AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); } From 4f109c02d31e90dc525f92ffa4291a1a15529592 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 29 Jan 2020 02:18:46 +0100 Subject: [PATCH 059/157] Add license header --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 51d5f837fc..df0611d33f 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -1,4 +1,7 @@ -using NUnit.Framework; +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; From 738f1f0c565f56b6f36cfa2dddcfba46411566cd Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 29 Jan 2020 02:27:07 +0100 Subject: [PATCH 060/157] Turn lines into another single line --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index df0611d33f..64a3a75eda 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -51,12 +51,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestPrivateMessageNotification() { - AddStep("Send PM", () => privateMesssageChannel.AddNewMessages(new Message(messageIdCounter++) - { - Content = $"Hello {API.LocalUser.Value.Username}!", - Sender = friend, - ChannelId = privateMesssageChannel.Id - })); + AddStep("Send PM", () => privateMesssageChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username}!", Sender = friend, ChannelId = privateMesssageChannel.Id })); AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); } From 25b080c78df4e842f759bbd9587daec28381116a Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 30 Jan 2020 03:41:21 +0100 Subject: [PATCH 061/157] Resolve CI/CA errors --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 64a3a75eda..1dcff4b017 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -24,11 +24,11 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void Setup() { - friend = new User() { Id = 0, Username = "Friend" }; - publicChannel = new Channel() { Id = 1, Name = "osu" }; + friend = new User { Id = 0, Username = "Friend" }; + publicChannel = new Channel { Id = 1, Name = "osu" }; privateMesssageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; - Child = testContainer = new TestContainer(new Channel[] { publicChannel, privateMesssageChannel }) + Child = testContainer = new TestContainer(new[] { publicChannel, privateMesssageChannel }) { RelativeSizeAxes = Axes.Both, }; @@ -57,7 +57,7 @@ namespace osu.Game.Tests.Visual.Online private class TestContainer : Container { - private Channel[] channels; + private readonly Channel[] channels; public TestContainer(Channel[] channels) => this.channels = channels; From 8523e3d205fcd8bff4ecf36566ac69ac11f3a040 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 30 Jan 2020 05:24:26 +0100 Subject: [PATCH 062/157] Schedule child updating --- .../Visual/Online/TestSceneMessageNotifier.cs | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 1dcff4b017..4afa013345 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -28,12 +28,15 @@ namespace osu.Game.Tests.Visual.Online publicChannel = new Channel { Id = 1, Name = "osu" }; privateMesssageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; - Child = testContainer = new TestContainer(new[] { publicChannel, privateMesssageChannel }) + Schedule(() => { - RelativeSizeAxes = Axes.Both, - }; + Child = testContainer = new TestContainer(new[] { publicChannel, privateMesssageChannel }) + { + RelativeSizeAxes = Axes.Both, + }; - testContainer.ChatOverlay.Show(); + testContainer.ChatOverlay.Show(); + }); } [Test] From 79f47fe7d791b57872158456a264cab4782ae35e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 22:08:01 +0100 Subject: [PATCH 063/157] Fix typo MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-Authored-By: Bartłomiej Dach --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 4afa013345..33af4568ca 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -16,7 +16,7 @@ namespace osu.Game.Tests.Visual.Online { private User friend; private Channel publicChannel; - private Channel privateMesssageChannel; + private Channel privateMessageChannel; private TestContainer testContainer; private int messageIdCounter; From 176e1e7ec2b742bf079818646f3d5aaeffbdc932 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 22:19:55 +0100 Subject: [PATCH 064/157] Rename references --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 33af4568ca..981aaf5b17 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -26,11 +26,11 @@ namespace osu.Game.Tests.Visual.Online { friend = new User { Id = 0, Username = "Friend" }; publicChannel = new Channel { Id = 1, Name = "osu" }; - privateMesssageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; + privateMessageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; Schedule(() => { - Child = testContainer = new TestContainer(new[] { publicChannel, privateMesssageChannel }) + Child = testContainer = new TestContainer(new[] { publicChannel, privateMessageChannel }) { RelativeSizeAxes = Axes.Both, }; @@ -42,7 +42,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestPublicChannelMention() { - AddStep("Switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMesssageChannel); + AddStep("Switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel); AddStep("Send regular message", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { Content = "Hello everyone!", Sender = friend, ChannelId = publicChannel.Id })); AddAssert("Expect no notifications", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); @@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestPrivateMessageNotification() { - AddStep("Send PM", () => privateMesssageChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username}!", Sender = friend, ChannelId = privateMesssageChannel.Id })); + AddStep("Send PM", () => privateMessageChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username}!", Sender = friend, ChannelId = privateMessageChannel.Id })); AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); } From 2936f83fd95eb62bae3f0737fd0c8445178226cc Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 23:00:29 +0100 Subject: [PATCH 065/157] Improve load order --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 981aaf5b17..a935851282 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -79,12 +79,9 @@ namespace osu.Game.Tests.Visual.Online [BackgroundDependencyLoader] private void load() { - AddRange(new Drawable[] { ChannelManager, NotificationOverlay }); + AddRange(new Drawable[] { ChannelManager, ChatOverlay, NotificationOverlay, MessageNotifier }); ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); - - AddRange(new Drawable[] { ChatOverlay, MessageNotifier }); - ((BindableList)ChannelManager.JoinedChannels).AddRange(channels); } } From 835d4f25ffbaefa3a79c04b778ef2cff5648eb82 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 23:02:58 +0100 Subject: [PATCH 066/157] Add notification testing to tests and show notification overlay while testing --- .../Visual/Online/TestSceneMessageNotifier.cs | 28 ++++++++++++++++++- 1 file changed, 27 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index a935851282..1490331266 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -1,18 +1,22 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; using osu.Game.Online.Chat; using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using osu.Game.Users; +using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public class TestSceneMessageNotifier : OsuTestScene + public class TestSceneMessageNotifier : ManualInputManagerTestScene { private User friend; private Channel publicChannel; @@ -49,13 +53,35 @@ namespace osu.Game.Tests.Visual.Online AddStep("Send message containing mention", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!", Sender = friend, ChannelId = publicChannel.Id })); AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + + AddStep("Open notification overlay", () => testContainer.NotificationOverlay.Show()); + AddStep("Click notification", clickNotification); + + AddAssert("Expect ChatOverlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible); + AddAssert("Expect the public channel to be selected", () => testContainer.ChannelManager.CurrentChannel.Value == publicChannel); } [Test] public void TestPrivateMessageNotification() { + AddStep("Switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel); + AddStep("Send PM", () => privateMessageChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username}!", Sender = friend, ChannelId = privateMessageChannel.Id })); AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + + AddStep("Open notification overlay", () => testContainer.NotificationOverlay.Show()); + AddStep("Click notification", clickNotification); + + AddAssert("Expect ChatOverlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible); + AddAssert("Expect the PM channel to be selected", () => testContainer.ChannelManager.CurrentChannel.Value == privateMessageChannel); + } + + private void clickNotification() where T : Notification + { + var notification = testContainer.NotificationOverlay.ChildrenOfType().Single(); + + InputManager.MoveMouseTo(notification); + InputManager.Click(MouseButton.Left); } private class TestContainer : Container From 4eedd82032b0be8599128d852a5d176881035fbc Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 23:03:27 +0100 Subject: [PATCH 067/157] Don't unnecessarily expose properties --- osu.Game/Online/Chat/MessageNotifier.cs | 20 +++++++++----------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 0e79a13917..4f04a78adc 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -137,16 +137,14 @@ namespace osu.Game.Online.Chat public PrivateMessageNotification(string username, Channel channel) { Icon = FontAwesome.Solid.Envelope; - Username = username; - Channel = channel; - Text = $"You received a private message from '{Username}'. Click to read it!"; + this.username = username; + this.channel = channel; + Text = $"You received a private message from '{this.username}'. Click to read it!"; } - public string Username { get; } + private readonly string username; - public Channel Channel { get; } - - public Action OnRemove { get; set; } + private readonly Channel channel; public override bool IsImportant => false; @@ -159,7 +157,7 @@ namespace osu.Game.Online.Chat { notificationOverlay.Hide(); chatOverlay.Show(); - channelManager.CurrentChannel.Value = Channel; + channelManager.CurrentChannel.Value = channel; return true; }; @@ -172,10 +170,10 @@ namespace osu.Game.Online.Chat { Icon = FontAwesome.Solid.At; Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; - Channel = channel; + this.channel = channel; } - public Channel Channel { get; } + private readonly Channel channel; public override bool IsImportant => false; @@ -188,7 +186,7 @@ namespace osu.Game.Online.Chat { notificationOverlay.Hide(); chatOverlay.Show(); - channelManager.CurrentChannel.Value = Channel; + channelManager.CurrentChannel.Value = channel; return true; }; From ea5eaba0a96cb3060e743952157ac4388854fa08 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 23:05:46 +0100 Subject: [PATCH 068/157] Use ChannelManager.JoinChannel() --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 1490331266..ecd5892468 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -108,7 +108,9 @@ namespace osu.Game.Tests.Visual.Online AddRange(new Drawable[] { ChannelManager, ChatOverlay, NotificationOverlay, MessageNotifier }); ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); - ((BindableList)ChannelManager.JoinedChannels).AddRange(channels); + + foreach (var channel in channels) + ChannelManager.JoinChannel(channel); } } } From f16b90a152a3fdb885dff743f31eee6f1f7178aa Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 3 Feb 2020 23:56:23 +0100 Subject: [PATCH 069/157] Remove username data from PrivateMessageNotification --- osu.Game/Online/Chat/MessageNotifier.cs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 4f04a78adc..0d821dff32 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -137,13 +137,10 @@ namespace osu.Game.Online.Chat public PrivateMessageNotification(string username, Channel channel) { Icon = FontAwesome.Solid.Envelope; - this.username = username; + Text = $"You received a private message from '{username}'. Click to read it!"; this.channel = channel; - Text = $"You received a private message from '{this.username}'. Click to read it!"; } - private readonly string username; - private readonly Channel channel; public override bool IsImportant => false; From a66fd17691182f862e80d5fc7507002edfbad2bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 4 Feb 2020 19:23:46 +0100 Subject: [PATCH 070/157] Expand test coverage --- .../Visual/Online/TestSceneMessageNotifier.cs | 96 +++++++++++++++---- 1 file changed, 80 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index ecd5892468..5e0a3994e1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -46,36 +46,100 @@ namespace osu.Game.Tests.Visual.Online [Test] public void TestPublicChannelMention() { - AddStep("Switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel); + AddStep("switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel); - AddStep("Send regular message", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { Content = "Hello everyone!", Sender = friend, ChannelId = publicChannel.Id })); - AddAssert("Expect no notifications", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + AddStep("receive public message", () => receiveMessage(friend, publicChannel, "Hello everyone")); + AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); - AddStep("Send message containing mention", () => publicChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!", Sender = friend, ChannelId = publicChannel.Id })); - AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + AddStep("receive message containing mention", () => receiveMessage(friend, publicChannel, $"Hello {API.LocalUser.Value.Username.ToLowerInvariant()}!")); + AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); - AddStep("Open notification overlay", () => testContainer.NotificationOverlay.Show()); - AddStep("Click notification", clickNotification); + AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show()); + AddStep("click notification", clickNotification); - AddAssert("Expect ChatOverlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible); - AddAssert("Expect the public channel to be selected", () => testContainer.ChannelManager.CurrentChannel.Value == publicChannel); + AddAssert("chat overlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible); + AddAssert("public channel is selected", () => testContainer.ChannelManager.CurrentChannel.Value == publicChannel); } [Test] public void TestPrivateMessageNotification() { - AddStep("Switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel); + AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel); - AddStep("Send PM", () => privateMessageChannel.AddNewMessages(new Message(messageIdCounter++) { Content = $"Hello {API.LocalUser.Value.Username}!", Sender = friend, ChannelId = privateMessageChannel.Id })); - AddAssert("Expect 1 notification", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + AddStep("receive PM", () => receiveMessage(friend, privateMessageChannel, $"Hello {API.LocalUser.Value.Username}")); + AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); - AddStep("Open notification overlay", () => testContainer.NotificationOverlay.Show()); - AddStep("Click notification", clickNotification); + AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show()); + AddStep("click notification", clickNotification); - AddAssert("Expect ChatOverlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible); - AddAssert("Expect the PM channel to be selected", () => testContainer.ChannelManager.CurrentChannel.Value == privateMessageChannel); + AddAssert("chat overlay is open", () => testContainer.ChatOverlay.State.Value == Visibility.Visible); + AddAssert("PM channel is selected", () => testContainer.ChannelManager.CurrentChannel.Value == privateMessageChannel); } + [Test] + public void TestNoNotificationWhenPMChannelOpen() + { + AddStep("switch to PMs", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel); + + AddStep("receive PM", () => receiveMessage(friend, privateMessageChannel, "you're reading this, right?")); + + AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + } + + [Test] + public void TestNoNotificationWhenMentionedInOpenPublicChannel() + { + AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel); + + AddStep("receive mention", () => receiveMessage(friend, publicChannel, $"{API.LocalUser.Value.Username.ToUpperInvariant()} has been reading this")); + + AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + } + + [Test] + public void TestNoNotificationOnSelfMention() + { + AddStep("switch to PM channel", () => testContainer.ChannelManager.CurrentChannel.Value = privateMessageChannel); + + AddStep("receive self-mention", () => receiveMessage(API.LocalUser.Value, publicChannel, $"my name is {API.LocalUser.Value.Username}")); + + AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + } + + [Test] + public void TestNoNotificationOnPMFromSelf() + { + AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel); + + AddStep("receive PM from self", () => receiveMessage(API.LocalUser.Value, privateMessageChannel, "hey hey")); + + AddAssert("no notifications fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 0); + } + + [Test] + public void TestNotificationsNotFiredTwice() + { + AddStep("switch to public channel", () => testContainer.ChannelManager.CurrentChannel.Value = publicChannel); + + AddStep("receive same PM twice", () => + { + var message = createMessage(friend, privateMessageChannel, "hey hey"); + privateMessageChannel.AddNewMessages(message, message); + }); + + AddStep("open notification overlay", () => testContainer.NotificationOverlay.Show()); + AddAssert("1 notification fired", () => testContainer.NotificationOverlay.UnreadCount.Value == 1); + } + + private void receiveMessage(User sender, Channel channel, string content) => channel.AddNewMessages(createMessage(sender, channel, content)); + + private Message createMessage(User sender, Channel channel, string content) => new Message(messageIdCounter++) + { + Content = content, + Sender = sender, + ChannelId = channel.Id + }; + private void clickNotification() where T : Notification { var notification = testContainer.NotificationOverlay.ChildrenOfType().Single(); From 9378b216e6879414566f63fc2b7c23f17337232b Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Wed, 5 Feb 2020 19:01:51 +0100 Subject: [PATCH 071/157] Lowercase the N inside channel_NewMessagesArrived --- osu.Game/Online/Chat/MessageNotifier.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 0d821dff32..166a073512 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -50,17 +50,17 @@ namespace osu.Game.Online.Chat joinedChannels.ItemsAdded += joinedChannels => { foreach (var channel in joinedChannels) - channel.NewMessagesArrived += channel_NewMessagesArrived; + channel.NewMessagesArrived += channel_newMessagesArrived; }; joinedChannels.ItemsRemoved += leftChannels => { foreach (var channel in leftChannels) - channel.NewMessagesArrived -= channel_NewMessagesArrived; + channel.NewMessagesArrived -= channel_newMessagesArrived; }; } - private void channel_NewMessagesArrived(IEnumerable messages) + private void channel_newMessagesArrived(IEnumerable messages) { if (messages == null || !messages.Any()) return; From 5875f2158c34ff169a2c85573a5f06d3db1f4d91 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Wed, 5 Feb 2020 19:20:16 +0100 Subject: [PATCH 072/157] Properly rename event handler --- osu.Game/Online/Chat/MessageNotifier.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 166a073512..016c25d8ab 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -50,17 +50,17 @@ namespace osu.Game.Online.Chat joinedChannels.ItemsAdded += joinedChannels => { foreach (var channel in joinedChannels) - channel.NewMessagesArrived += channel_newMessagesArrived; + channel.NewMessagesArrived += newMessagesArrived; }; joinedChannels.ItemsRemoved += leftChannels => { foreach (var channel in leftChannels) - channel.NewMessagesArrived -= channel_newMessagesArrived; + channel.NewMessagesArrived -= newMessagesArrived; }; } - private void channel_newMessagesArrived(IEnumerable messages) + private void newMessagesArrived(IEnumerable messages) { if (messages == null || !messages.Any()) return; From 7cd228db07f50d1f489bcf8e3514f48061dc168e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Fri, 7 Feb 2020 16:50:22 +0100 Subject: [PATCH 073/157] Change notifyOnChat to notifyOnPM --- osu.Game/Online/Chat/MessageNotifier.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 166a073512..3b000675ac 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.Chat private ChannelManager channelManager { get; set; } private Bindable notifyOnMention; - private Bindable notifyOnChat; + private Bindable notifyOnPM; private Bindable localUser; private readonly BindableList joinedChannels = new BindableList(); @@ -41,7 +41,7 @@ namespace osu.Game.Online.Chat private void load(OsuConfigManager config, IAPIProvider api) { notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); - notifyOnChat = config.GetBindable(OsuSetting.ChatMessageNotification); + notifyOnPM = config.GetBindable(OsuSetting.ChatMessageNotification); localUser = api.LocalUser; channelManager.JoinedChannels.BindTo(joinedChannels); @@ -107,7 +107,7 @@ namespace osu.Game.Online.Chat private bool checkForPMs(Channel channel, Message message) { - if (!notifyOnChat.Value || channel.Type != ChannelType.PM) + if (!notifyOnPM.Value || channel.Type != ChannelType.PM) return false; var notification = new PrivateMessageNotification(message.Sender.Username, channel); From dd86443264fb3861ee90a453f67eb013afcacd61 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Fri, 7 Feb 2020 16:51:37 +0100 Subject: [PATCH 074/157] Make isMentioning static --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 3b000675ac..975df9714e 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -130,7 +130,7 @@ namespace osu.Game.Online.Chat /// Checks if contains , if not, retries making spaces into underscores. /// /// If the mentions the - private bool isMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; + private static bool isMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; public class PrivateMessageNotification : SimpleNotification { From 41915df1f37fdd5bc9015a35b939f344d5ce0f42 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Fri, 7 Feb 2020 16:52:53 +0100 Subject: [PATCH 075/157] Change comment --- osu.Game/Online/Chat/MessageNotifier.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 975df9714e..8c92892a1e 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -96,7 +96,8 @@ namespace osu.Game.Online.Chat if (message.Sender.Id == localUser.Value.Id) continue; - // check for private messages first, if true, skip checking mentions to prevent duplicate notifications about the same message. + // check for private messages first, + // to avoid both posting two notifications about the same message if (checkForPMs(channel, message)) continue; From 88bdd8a7b767552c16f676e64f25585aecb41ff6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 26 May 2021 16:01:20 +0900 Subject: [PATCH 076/157] Update some out of date code pieces --- osu.Game/Configuration/OsuConfigManager.cs | 4 ++-- .../Settings/Sections/Online/AlertsAndPrivacySettings.cs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index e74ae1aeee..1c92c16333 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -61,8 +61,8 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ShowOnlineExplicitContent, false); - Set(OsuSetting.ChatHighlightName, true); - Set(OsuSetting.ChatMessageNotification, true); + SetDefault(OsuSetting.ChatHighlightName, true); + SetDefault(OsuSetting.ChatMessageNotification, true); // Audio SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01); diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index 0898ce3b84..f9f5b927b7 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -19,12 +19,12 @@ namespace osu.Game.Overlays.Settings.Sections.Online new SettingsCheckbox { LabelText = "Show a notification popup when someone says your name", - Bindable = config.GetBindable(OsuSetting.ChatHighlightName) + Current = config.GetBindable(OsuSetting.ChatHighlightName) }, new SettingsCheckbox { LabelText = "Show private message notifications", - Bindable = config.GetBindable(OsuSetting.ChatMessageNotification) + Current = config.GetBindable(OsuSetting.ChatMessageNotification) }, }; } From d47370bac93ad869c7505c58bfdf003b133c2745 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 27 May 2021 00:59:29 +0200 Subject: [PATCH 077/157] Locally bind to LocalUser --- osu.Game/Online/Chat/MessageNotifier.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 05ffcb03a2..a8ade8e771 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -35,7 +35,7 @@ namespace osu.Game.Online.Chat private Bindable notifyOnMention; private Bindable notifyOnPM; - private IBindable localUser; + private IBindable localUser = new Bindable(); private readonly BindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] @@ -43,9 +43,9 @@ namespace osu.Game.Online.Chat { notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); notifyOnPM = config.GetBindable(OsuSetting.ChatMessageNotification); - localUser = api.LocalUser; channelManager.JoinedChannels.BindTo(joinedChannels); + api.LocalUser.BindTo(localUser); // Listen for new messages joinedChannels.CollectionChanged += channelsChanged; From cf39e58ce733fdd2288bd88b8157fe3a74decef5 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 27 May 2021 01:00:08 +0200 Subject: [PATCH 078/157] Subscribe to CollectionChanged before binding to JoinedChannels --- osu.Game/Online/Chat/MessageNotifier.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index a8ade8e771..1f3fc0946b 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -43,12 +43,12 @@ namespace osu.Game.Online.Chat { notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); notifyOnPM = config.GetBindable(OsuSetting.ChatMessageNotification); - - channelManager.JoinedChannels.BindTo(joinedChannels); api.LocalUser.BindTo(localUser); // Listen for new messages joinedChannels.CollectionChanged += channelsChanged; + + channelManager.JoinedChannels.BindTo(joinedChannels); } private void channelsChanged(object sender, NotifyCollectionChangedEventArgs e) From a679efac1c3b85e036965ca6cf7a8ba2558f9b77 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 27 May 2021 01:00:26 +0200 Subject: [PATCH 079/157] Reduce duplicate notification code by making a base class --- osu.Game/Online/Chat/MessageNotifier.cs | 39 +++++++++---------------- 1 file changed, 13 insertions(+), 26 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 1f3fc0946b..47758673bb 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -142,12 +142,10 @@ namespace osu.Game.Online.Chat /// If the mentions the private static bool isMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; - public class PrivateMessageNotification : SimpleNotification + public class OpenChannelNotification : SimpleNotification { - public PrivateMessageNotification(string username, Channel channel) + public OpenChannelNotification(Channel channel) { - Icon = FontAwesome.Solid.Envelope; - Text = $"You received a private message from '{username}'. Click to read it!"; this.channel = channel; } @@ -171,32 +169,21 @@ namespace osu.Game.Online.Chat } } - public class MentionNotification : SimpleNotification + public class PrivateMessageNotification : OpenChannelNotification { - public MentionNotification(string username, Channel channel) + public PrivateMessageNotification(string username, Channel channel) : base(channel) + { + Icon = FontAwesome.Solid.Envelope; + Text = $"You received a private message from '{username}'. Click to read it!"; + } + } + + public class MentionNotification : OpenChannelNotification + { + public MentionNotification(string username, Channel channel) : base(channel) { Icon = FontAwesome.Solid.At; Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; - this.channel = channel; - } - - private readonly Channel channel; - - public override bool IsImportant => false; - - [BackgroundDependencyLoader] - private void load(OsuColour colours, ChatOverlay chatOverlay, NotificationOverlay notificationOverlay, ChannelManager channelManager) - { - IconBackgound.Colour = colours.PurpleDark; - - Activated = delegate - { - notificationOverlay.Hide(); - chatOverlay.Show(); - channelManager.CurrentChannel.Value = channel; - - return true; - }; } } } From 2166ab87c6a5a6d8d19c9b9c24eef6da8eebd0cf Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 27 May 2021 01:47:00 +0200 Subject: [PATCH 080/157] Change base type of tests Fixes missing API property --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 5e0a3994e1..26b0063178 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -16,7 +16,7 @@ using osuTK.Input; namespace osu.Game.Tests.Visual.Online { - public class TestSceneMessageNotifier : ManualInputManagerTestScene + public class TestSceneMessageNotifier : OsuManualInputManagerTestScene { private User friend; private Channel publicChannel; From 0b17af81f186c2f248307d185fb760ec2688e2bf Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 27 May 2021 09:48:30 +0000 Subject: [PATCH 081/157] Use Contains instead of IndexOf Co-authored-by: Berkan Diler --- osu.Game/Online/Chat/MessageNotifier.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 47758673bb..5b3293f7ee 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -140,7 +140,7 @@ namespace osu.Game.Online.Chat /// Checks if contains , if not, retries making spaces into underscores. /// /// If the mentions the - private static bool isMentioning(string message, string username) => message.IndexOf(username, StringComparison.OrdinalIgnoreCase) != -1 || message.IndexOf(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase) != -1; + private static bool isMentioning(string message, string username) => message.Contains(username, StringComparison.OrdinalIgnoreCase) || message.Contains(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase); public class OpenChannelNotification : SimpleNotification { From 13b2b7c14893d2e150085c32eacc27edbf0f3262 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Thu, 27 May 2021 21:58:54 +0200 Subject: [PATCH 082/157] Fix formatting --- osu.Game/Online/Chat/MessageNotifier.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 47758673bb..2e4dc7b0aa 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -35,7 +35,7 @@ namespace osu.Game.Online.Chat private Bindable notifyOnMention; private Bindable notifyOnPM; - private IBindable localUser = new Bindable(); + private readonly IBindable localUser = new Bindable(); private readonly BindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] @@ -171,7 +171,8 @@ namespace osu.Game.Online.Chat public class PrivateMessageNotification : OpenChannelNotification { - public PrivateMessageNotification(string username, Channel channel) : base(channel) + public PrivateMessageNotification(string username, Channel channel) + : base(channel) { Icon = FontAwesome.Solid.Envelope; Text = $"You received a private message from '{username}'. Click to read it!"; @@ -180,7 +181,8 @@ namespace osu.Game.Online.Chat public class MentionNotification : OpenChannelNotification { - public MentionNotification(string username, Channel channel) : base(channel) + public MentionNotification(string username, Channel channel) + : base(channel) { Icon = FontAwesome.Solid.At; Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; From b746fe7c03c3ca863ddd9825111b3b9b95d9de14 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 11:03:49 +0200 Subject: [PATCH 083/157] Fix binding order --- osu.Game/Online/Chat/MessageNotifier.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 25d6795ffa..c70e678843 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -36,19 +36,18 @@ namespace osu.Game.Online.Chat private Bindable notifyOnMention; private Bindable notifyOnPM; private readonly IBindable localUser = new Bindable(); - private readonly BindableList joinedChannels = new BindableList(); + private readonly IBindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) { notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); notifyOnPM = config.GetBindable(OsuSetting.ChatMessageNotification); - api.LocalUser.BindTo(localUser); + localUser.BindTo(api.LocalUser); // Listen for new messages joinedChannels.CollectionChanged += channelsChanged; - - channelManager.JoinedChannels.BindTo(joinedChannels); + joinedChannels.BindTo(channelManager.JoinedChannels); } private void channelsChanged(object sender, NotifyCollectionChangedEventArgs e) From 6e40af756b71bc9544b000ca310174be17bc8da6 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 11:10:16 +0200 Subject: [PATCH 084/157] Add request handler for dummy API --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 26b0063178..a1c68d34d1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -8,6 +8,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; +using osu.Game.Online.API; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -28,6 +29,14 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void Setup() { + // We blindly mark every request as success so that ChannelManager doesn't remove our channel again. + if (API is DummyAPIAccess daa) + { + daa.HandleRequest = (request) => { + return true; + }; + } + friend = new User { Id = 0, Username = "Friend" }; publicChannel = new Channel { Id = 1, Name = "osu" }; privateMessageChannel = new Channel(friend) { Id = 2, Name = friend.Username, Type = ChannelType.PM }; From ce4bcda8032d19d9364cad23b5882536d411886b Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 14:02:48 +0200 Subject: [PATCH 085/157] Use separate method for fetching channel objects Resolves a pull request review --- osu.Game/Online/Chat/MessageNotifier.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index c70e678843..c52a1876b1 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -76,9 +76,18 @@ namespace osu.Game.Online.Chat HandleMessages(messages.First().ChannelId, messages); } + /// + /// Searches for a channel with the matching , returns when none found. + /// + private Channel fetchJoinedChannel(long channelId) + { + return channelManager.JoinedChannels.SingleOrDefault(c => c.Id == channelId); + } + public void HandleMessages(long channelId, IEnumerable messages) { - var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == channelId); + // Fetch channel object + var channel = fetchJoinedChannel(channelId); if (channel == null) { @@ -86,11 +95,6 @@ namespace osu.Game.Online.Chat return; } - HandleMessages(channel, messages); - } - - public void HandleMessages(Channel channel, IEnumerable messages) - { // Only send notifications, if ChatOverlay and the target channel aren't visible. if (chatOverlay?.IsPresent == true && channelManager.CurrentChannel.Value == channel) return; From 5e44329e0b0e7f5221c90e69baed3f73664084cc Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 14:42:16 +0200 Subject: [PATCH 086/157] Add DummyAPIAccess request handler Make CreateChannelRequest.channel public --- .../Visual/Online/TestSceneMessageNotifier.cs | 34 ++++++++++++++++--- .../API/Requests/CreateChannelRequest.cs | 6 ++-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index a1c68d34d1..fada645632 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System.Collections.Generic; using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; @@ -9,6 +10,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Testing; using osu.Game.Online.API; +using osu.Game.Online.API.Requests; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Online.Chat; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; @@ -29,12 +32,9 @@ namespace osu.Game.Tests.Visual.Online [SetUp] public void Setup() { - // We blindly mark every request as success so that ChannelManager doesn't remove our channel again. if (API is DummyAPIAccess daa) { - daa.HandleRequest = (request) => { - return true; - }; + daa.HandleRequest = dummyAPIHandleRequest; } friend = new User { Id = 0, Username = "Friend" }; @@ -52,6 +52,32 @@ namespace osu.Game.Tests.Visual.Online }); } + private bool dummyAPIHandleRequest(APIRequest request) + { + switch (request) + { + case GetMessagesRequest messagesRequest: + messagesRequest.TriggerSuccess(new List(0)); + return true; + + case CreateChannelRequest createChannelRequest: + var apiChatChannel = new APIChatChannel + { + RecentMessages = new List(0), + ChannelID = (int)createChannelRequest.Channel.Id + }; + createChannelRequest.TriggerSuccess(apiChatChannel); + return true; + + case ListChannelsRequest listChannelsRequest: + listChannelsRequest.TriggerSuccess(new List(1) { publicChannel }); + return true; + + default: + return false; + } + } + [Test] public void TestPublicChannelMention() { diff --git a/osu.Game/Online/API/Requests/CreateChannelRequest.cs b/osu.Game/Online/API/Requests/CreateChannelRequest.cs index 42cb201969..041ad26267 100644 --- a/osu.Game/Online/API/Requests/CreateChannelRequest.cs +++ b/osu.Game/Online/API/Requests/CreateChannelRequest.cs @@ -11,11 +11,11 @@ namespace osu.Game.Online.API.Requests { public class CreateChannelRequest : APIRequest { - private readonly Channel channel; + public readonly Channel Channel; public CreateChannelRequest(Channel channel) { - this.channel = channel; + Channel = channel; } protected override WebRequest CreateWebRequest() @@ -24,7 +24,7 @@ namespace osu.Game.Online.API.Requests req.Method = HttpMethod.Post; req.AddParameter("type", $"{ChannelType.PM}"); - req.AddParameter("target_id", $"{channel.Users.First().Id}"); + req.AddParameter("target_id", $"{Channel.Users.First().Id}"); return req; } From 248e90df6d492baebd808188b1fa47f96527f7f7 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 15:55:58 +0200 Subject: [PATCH 087/157] Add more request handling code --- .../Visual/Online/TestSceneMessageNotifier.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index fada645632..28ec3e91a1 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -73,6 +73,18 @@ namespace osu.Game.Tests.Visual.Online listChannelsRequest.TriggerSuccess(new List(1) { publicChannel }); return true; + case GetUpdatesRequest updatesRequest: + updatesRequest.TriggerSuccess(new GetUpdatesResponse + { + Messages = new List(0), + Presence = new List(0) + }); + return true; + + case JoinChannelRequest joinChannelRequest: + joinChannelRequest.TriggerSuccess(); + return true; + default: return false; } From 4925a7d59e36f10e3b089287e0700a09362df8ce Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 15:57:14 +0200 Subject: [PATCH 088/157] Minor code quality changes --- osu.Game/Online/Chat/MessageNotifier.cs | 27 ++++++++++++++++++++----- 1 file changed, 22 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index c52a1876b1..53bd3c61c3 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -113,30 +113,47 @@ namespace osu.Game.Online.Chat if (checkForPMs(channel, message)) continue; - // change output to bool again if another "message processor" is added. - checkForMentions(channel, message, localUser.Value.Username); + _ = checkForMentions(channel, message, localUser.Value.Username); } } + /// + /// Checks whether the user enabled private message notifications and whether specified is a direct message. + /// + /// The channel associated to the + /// The message to be checked private bool checkForPMs(Channel channel, Message message) { if (!notifyOnPM.Value || channel.Type != ChannelType.PM) return false; - var notification = new PrivateMessageNotification(message.Sender.Username, channel); + if (channel.Id != message.ChannelId) + throw new ArgumentException("The provided channel doesn't match with the channel id provided by the message parameter.", nameof(channel)); + var notification = new PrivateMessageNotification(message.Sender.Username, channel); notificationOverlay?.Post(notification); return true; } - private void checkForMentions(Channel channel, Message message, string username) + /// + /// Checks whether the user enabled mention notifications and whether specified mentions the provided . + /// + /// The channel associated to the + /// The message to be checked + /// The username that will be checked for + private bool checkForMentions(Channel channel, Message message, string username) { if (!notifyOnMention.Value || !isMentioning(message.Content, username)) - return; + return false; + + if (channel.Id != message.ChannelId) + throw new ArgumentException("The provided channel doesn't match with the channel id provided by the message parameter.", nameof(channel)); var notification = new MentionNotification(message.Sender.Username, channel); notificationOverlay?.Post(notification); + + return true; } /// From b97f31f31414a8cc6c284ce2239d2cdecaf64500 Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Sat, 5 Jun 2021 19:03:11 +0200 Subject: [PATCH 089/157] Revert deletion of xmldoc summary line --- osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs index 001520b507..c0de093425 100644 --- a/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs +++ b/osu.Game/Overlays/Chat/Tabs/ChannelTabControl.cs @@ -60,6 +60,7 @@ namespace osu.Game.Overlays.Chat.Tabs /// /// Adds a channel to the ChannelTabControl. + /// The first channel added will automaticly selected. /// /// The channel that is going to be added. public void AddChannel(Channel channel) From 8d0840020b4048839bcfd5f7676cd79ef24bd1be Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 15:33:13 +0900 Subject: [PATCH 090/157] Specify legacy skin version of old-skin testing skin Old-style catcher sprite is not supported for all versions --- osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini | 2 ++ 1 file changed, 2 insertions(+) create mode 100644 osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini diff --git a/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini b/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini new file mode 100644 index 0000000000..1596c95912 --- /dev/null +++ b/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini @@ -0,0 +1,2 @@ +[General] +Version: 1.0 From 7f7c2c73e002177f7518ca876e75b735024ebaea Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 15:39:06 +0900 Subject: [PATCH 091/157] Move catcher movement logic of `Catcher` to `CatcherArea` --- osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs | 6 +- osu.Game.Rulesets.Catch/UI/Catcher.cs | 76 ++++-------------- osu.Game.Rulesets.Catch/UI/CatcherArea.cs | 78 +++++++++++++++++-- osu.Game.Rulesets.Catch/UI/Direction.cs | 11 +++ 4 files changed, 99 insertions(+), 72 deletions(-) create mode 100644 osu.Game.Rulesets.Catch/UI/Direction.cs diff --git a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs index 1e42c6a240..73b60f51a4 100644 --- a/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs +++ b/osu.Game.Rulesets.Catch/Mods/CatchModRelax.cs @@ -33,13 +33,13 @@ namespace osu.Game.Rulesets.Catch.Mods private class MouseInputHelper : Drawable, IKeyBindingHandler, IRequireHighFrequencyMousePosition { - private readonly Catcher catcher; + private readonly CatcherArea catcherArea; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; public MouseInputHelper(CatchPlayfield playfield) { - catcher = playfield.CatcherArea.MovableCatcher; + catcherArea = playfield.CatcherArea; RelativeSizeAxes = Axes.Both; } @@ -52,7 +52,7 @@ namespace osu.Game.Rulesets.Catch.Mods protected override bool OnMouseMove(MouseMoveEvent e) { - catcher.UpdatePosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH); + catcherArea.SetCatcherPosition(e.MousePosition.X / DrawSize.X * CatchPlayfield.WIDTH); return base.OnMouseMove(e); } } diff --git a/osu.Game.Rulesets.Catch/UI/Catcher.cs b/osu.Game.Rulesets.Catch/UI/Catcher.cs index 4af2243ed4..ee2986c73c 100644 --- a/osu.Game.Rulesets.Catch/UI/Catcher.cs +++ b/osu.Game.Rulesets.Catch/UI/Catcher.cs @@ -10,7 +10,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Pooling; using osu.Framework.Graphics.Textures; -using osu.Framework.Input.Bindings; using osu.Framework.Utils; using osu.Game.Beatmaps; using osu.Game.Configuration; @@ -26,7 +25,7 @@ using osuTK.Graphics; namespace osu.Game.Rulesets.Catch.UI { - public class Catcher : SkinReloadableDrawable, IKeyBindingHandler + public class Catcher : SkinReloadableDrawable { /// /// The default colour used to tint hyper-dash fruit, along with the moving catcher, its trail @@ -54,6 +53,11 @@ namespace osu.Game.Rulesets.Catch.UI /// public const double BASE_SPEED = 1.0; + /// + /// The current speed of the catcher. + /// + public double Speed => (Dashing ? 1 : 0.5) * BASE_SPEED * hyperDashModifier; + /// /// The amount by which caught fruit should be offset from the plate surface to make them look visually "caught". /// @@ -96,7 +100,7 @@ namespace osu.Game.Rulesets.Catch.UI public bool Dashing { get => dashing; - protected set + set { if (value == dashing) return; @@ -106,6 +110,12 @@ namespace osu.Game.Rulesets.Catch.UI } } + public Direction VisualDirection + { + get => Scale.X > 0 ? Direction.Right : Direction.Left; + set => Scale = new Vector2((value == Direction.Right ? 1 : -1) * Math.Abs(Scale.X), Scale.Y); + } + /// /// Width of the area that can be used to attempt catches during gameplay. /// @@ -116,8 +126,6 @@ namespace osu.Game.Rulesets.Catch.UI private Color4 hyperDashColour = DEFAULT_HYPER_DASH_COLOUR; private Color4 hyperDashEndGlowColour = DEFAULT_HYPER_DASH_COLOUR; - private int currentDirection; - private double hyperDashModifier = 1; private int hyperDashDirection; private float hyperDashTargetPosition; @@ -315,55 +323,6 @@ namespace osu.Game.Rulesets.Catch.UI } } - public void UpdatePosition(float position) - { - position = Math.Clamp(position, 0, CatchPlayfield.WIDTH); - - if (position == X) - return; - - Scale = new Vector2(Math.Abs(Scale.X) * (position > X ? 1 : -1), Scale.Y); - X = position; - } - - public bool OnPressed(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection--; - return true; - - case CatchAction.MoveRight: - currentDirection++; - return true; - - case CatchAction.Dash: - Dashing = true; - return true; - } - - return false; - } - - public void OnReleased(CatchAction action) - { - switch (action) - { - case CatchAction.MoveLeft: - currentDirection++; - break; - - case CatchAction.MoveRight: - currentDirection--; - break; - - case CatchAction.Dash: - Dashing = false; - break; - } - } - /// /// Drop any fruit off the plate. /// @@ -405,15 +364,6 @@ namespace osu.Game.Rulesets.Catch.UI { base.Update(); - if (currentDirection == 0) return; - - var direction = Math.Sign(currentDirection); - - var dashModifier = Dashing ? 1 : 0.5; - var speed = BASE_SPEED * dashModifier * hyperDashModifier; - - UpdatePosition((float)(X + direction * Clock.ElapsedFrameTime * speed)); - // Correct overshooting. if ((hyperDashDirection > 0 && hyperDashTargetPosition < X) || (hyperDashDirection < 0 && hyperDashTargetPosition > X)) diff --git a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs index 44adbd5512..cdb15c2b4c 100644 --- a/osu.Game.Rulesets.Catch/UI/CatcherArea.cs +++ b/osu.Game.Rulesets.Catch/UI/CatcherArea.cs @@ -1,8 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input.Bindings; using osu.Game.Beatmaps; using osu.Game.Rulesets.Catch.Judgements; using osu.Game.Rulesets.Catch.Objects.Drawables; @@ -14,13 +16,20 @@ using osuTK; namespace osu.Game.Rulesets.Catch.UI { - public class CatcherArea : Container + public class CatcherArea : Container, IKeyBindingHandler { public const float CATCHER_SIZE = 106.75f; public readonly Catcher MovableCatcher; private readonly CatchComboDisplay comboDisplay; + /// + /// -1 when only left button is pressed. + /// 1 when only right button is pressed. + /// 0 when none or both left and right buttons are pressed. + /// + private int currentDirection; + public CatcherArea(Container droppedObjectContainer, BeatmapDifficulty difficulty = null) { Size = new Vector2(CatchPlayfield.WIDTH, CATCHER_SIZE); @@ -63,16 +72,73 @@ namespace osu.Game.Rulesets.Catch.UI MovableCatcher.OnRevertResult(hitObject, result); } + protected override void Update() + { + base.Update(); + + var replayState = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState; + + SetCatcherPosition( + replayState?.CatcherX ?? + (float)(MovableCatcher.X + MovableCatcher.Speed * currentDirection * Clock.ElapsedFrameTime)); + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); - var state = (GetContainingInputManager().CurrentState as RulesetInputManagerInputState)?.LastReplayState as CatchFramedReplayInputHandler.CatchReplayState; - - if (state?.CatcherX != null) - MovableCatcher.X = state.CatcherX.Value; - comboDisplay.X = MovableCatcher.X; } + + public void SetCatcherPosition(float X) + { + float lastPosition = MovableCatcher.X; + float newPosition = Math.Clamp(X, 0, CatchPlayfield.WIDTH); + + MovableCatcher.X = newPosition; + + if (lastPosition < newPosition) + MovableCatcher.VisualDirection = Direction.Right; + else if (lastPosition > newPosition) + MovableCatcher.VisualDirection = Direction.Left; + } + + public bool OnPressed(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection--; + return true; + + case CatchAction.MoveRight: + currentDirection++; + return true; + + case CatchAction.Dash: + MovableCatcher.Dashing = true; + return true; + } + + return false; + } + + public void OnReleased(CatchAction action) + { + switch (action) + { + case CatchAction.MoveLeft: + currentDirection++; + break; + + case CatchAction.MoveRight: + currentDirection--; + break; + + case CatchAction.Dash: + MovableCatcher.Dashing = false; + break; + } + } } } diff --git a/osu.Game.Rulesets.Catch/UI/Direction.cs b/osu.Game.Rulesets.Catch/UI/Direction.cs new file mode 100644 index 0000000000..65f064b7fb --- /dev/null +++ b/osu.Game.Rulesets.Catch/UI/Direction.cs @@ -0,0 +1,11 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Rulesets.Catch.UI +{ + public enum Direction + { + Right = 1, + Left = -1 + } +} From 33aec57238bd02076635d3894d0e1dc5f6bd4747 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 15:45:34 +0900 Subject: [PATCH 092/157] Replace 1.0 version in old skin test assets with none --- osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini | 2 +- osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini | 4 ++-- osu.Game.Tests/Resources/old-skin/skin.ini | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini b/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini index 1596c95912..94c6b5b58d 100644 --- a/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini +++ b/osu.Game.Rulesets.Catch.Tests/Resources/old-skin/skin.ini @@ -1,2 +1,2 @@ [General] -Version: 1.0 +// no version specified means v1 diff --git a/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini b/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini index 89bcd68343..06dfa6b7be 100644 --- a/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini +++ b/osu.Game.Rulesets.Osu.Tests/Resources/old-skin/skin.ini @@ -1,6 +1,6 @@ [General] -Version: 1.0 +// no version specified means v1 [Fonts] HitCircleOverlap: 3 -ScoreOverlap: 3 \ No newline at end of file +ScoreOverlap: 3 diff --git a/osu.Game.Tests/Resources/old-skin/skin.ini b/osu.Game.Tests/Resources/old-skin/skin.ini index 5369de24e9..94c6b5b58d 100644 --- a/osu.Game.Tests/Resources/old-skin/skin.ini +++ b/osu.Game.Tests/Resources/old-skin/skin.ini @@ -1,2 +1,2 @@ [General] -Version: 1.0 \ No newline at end of file +// no version specified means v1 From c00f9ae4b750d905a7165d3d7bd8b69782f95433 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:11:37 +0900 Subject: [PATCH 093/157] Reword settings text --- .../Settings/Sections/Online/AlertsAndPrivacySettings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index f9f5b927b7..9f70d23c27 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -18,12 +18,12 @@ namespace osu.Game.Overlays.Settings.Sections.Online { new SettingsCheckbox { - LabelText = "Show a notification popup when someone says your name", + LabelText = "Show a notification when someone mentions your name", Current = config.GetBindable(OsuSetting.ChatHighlightName) }, new SettingsCheckbox { - LabelText = "Show private message notifications", + LabelText = "Show a notification when you receive a private message", Current = config.GetBindable(OsuSetting.ChatMessageNotification) }, }; From f00967388a5296f5d6a1dc193bf324ba279466a8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:17:42 +0900 Subject: [PATCH 094/157] Refactor tests a bit --- .../Visual/Online/TestSceneMessageNotifier.cs | 24 ++++++++++++------- 1 file changed, 16 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 28ec3e91a1..80c0c86fa3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -197,26 +197,34 @@ namespace osu.Game.Tests.Visual.Online private class TestContainer : Container { - private readonly Channel[] channels; - - public TestContainer(Channel[] channels) => this.channels = channels; - [Cached] public ChannelManager ChannelManager { get; } = new ChannelManager(); [Cached] public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay(); - [Cached] - public MessageNotifier MessageNotifier { get; } = new MessageNotifier(); - [Cached] public ChatOverlay ChatOverlay { get; } = new ChatOverlay(); + private readonly MessageNotifier messageNotifier = new MessageNotifier(); + + private readonly Channel[] channels; + + public TestContainer(Channel[] channels) + { + this.channels = channels; + } + [BackgroundDependencyLoader] private void load() { - AddRange(new Drawable[] { ChannelManager, ChatOverlay, NotificationOverlay, MessageNotifier }); + Children = new Drawable[] + { + ChannelManager, + ChatOverlay, + NotificationOverlay, + messageNotifier, + }; ((BindableList)ChannelManager.AvailableChannels).AddRange(channels); From 16e3a197380524a86031383e7eded8069681f40a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:18:51 +0900 Subject: [PATCH 095/157] Fix notification overlay not being in correct place in test scene --- osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs index 80c0c86fa3..d193856217 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneMessageNotifier.cs @@ -201,7 +201,11 @@ namespace osu.Game.Tests.Visual.Online public ChannelManager ChannelManager { get; } = new ChannelManager(); [Cached] - public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay(); + public NotificationOverlay NotificationOverlay { get; } = new NotificationOverlay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + }; [Cached] public ChatOverlay ChatOverlay { get; } = new ChatOverlay(); From 296761ade5ea6912fb39875ff87aea45fa327b56 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 11 Jun 2021 09:18:24 +0200 Subject: [PATCH 096/157] Add missing `CurrentSkin` null check in DHO disposal --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index 5fd2b2493e..7fc35fc778 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -716,7 +716,8 @@ namespace osu.Game.Rulesets.Objects.Drawables if (HitObject != null) HitObject.DefaultsApplied -= onDefaultsApplied; - CurrentSkin.SourceChanged -= skinSourceChanged; + if (CurrentSkin != null) + CurrentSkin.SourceChanged -= skinSourceChanged; } } From 139401a04a4813072362d6807271cc07e01b0e22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:27:31 +0900 Subject: [PATCH 097/157] Inline and refactor overly verbose `MessageNotifier` code --- osu.Game/Online/Chat/MessageNotifier.cs | 23 ++++------------------- 1 file changed, 4 insertions(+), 19 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 53bd3c61c3..685545f08c 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -45,8 +45,7 @@ namespace osu.Game.Online.Chat notifyOnPM = config.GetBindable(OsuSetting.ChatMessageNotification); localUser.BindTo(api.LocalUser); - // Listen for new messages - joinedChannels.CollectionChanged += channelsChanged; + joinedChannels.BindCollectionChanged(channelsChanged); joinedChannels.BindTo(channelManager.JoinedChannels); } @@ -70,28 +69,14 @@ namespace osu.Game.Online.Chat private void newMessagesArrived(IEnumerable messages) { - if (messages == null || !messages.Any()) + if (!messages.Any()) return; - HandleMessages(messages.First().ChannelId, messages); - } - - /// - /// Searches for a channel with the matching , returns when none found. - /// - private Channel fetchJoinedChannel(long channelId) - { - return channelManager.JoinedChannels.SingleOrDefault(c => c.Id == channelId); - } - - public void HandleMessages(long channelId, IEnumerable messages) - { - // Fetch channel object - var channel = fetchJoinedChannel(channelId); + var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == messages.First().ChannelId); if (channel == null) { - Logger.Log($"Couldn't resolve channel id {channelId}", LoggingTarget.Information); + Logger.Log($"Couldn't resolve channel id {messages.First().ChannelId}", LoggingTarget.Information); return; } From 3d645608eb9b46a94c5f3f453c929686b160dfc1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:28:53 +0900 Subject: [PATCH 098/157] Remove nullability of DI dependencies and fix incorrect load order --- osu.Game/Online/Chat/MessageNotifier.cs | 18 +++++++----------- osu.Game/OsuGame.cs | 2 +- 2 files changed, 8 insertions(+), 12 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 685545f08c..2a676738d0 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -24,13 +24,13 @@ namespace osu.Game.Online.Chat /// public class MessageNotifier : Component { - [Resolved(CanBeNull = true)] - private NotificationOverlay notificationOverlay { get; set; } + [Resolved] + private NotificationOverlay notifications { get; set; } - [Resolved(CanBeNull = true)] + [Resolved] private ChatOverlay chatOverlay { get; set; } - [Resolved(CanBeNull = true)] + [Resolved] private ChannelManager channelManager { get; set; } private Bindable notifyOnMention; @@ -81,7 +81,7 @@ namespace osu.Game.Online.Chat } // Only send notifications, if ChatOverlay and the target channel aren't visible. - if (chatOverlay?.IsPresent == true && channelManager.CurrentChannel.Value == channel) + if (chatOverlay.IsPresent && channelManager.CurrentChannel.Value == channel) return; foreach (var message in messages.OrderByDescending(m => m.Id)) @@ -115,9 +115,7 @@ namespace osu.Game.Online.Chat if (channel.Id != message.ChannelId) throw new ArgumentException("The provided channel doesn't match with the channel id provided by the message parameter.", nameof(channel)); - var notification = new PrivateMessageNotification(message.Sender.Username, channel); - notificationOverlay?.Post(notification); - + notifications.Post(new PrivateMessageNotification(message.Sender.Username, channel)); return true; } @@ -135,9 +133,7 @@ namespace osu.Game.Online.Chat if (channel.Id != message.ChannelId) throw new ArgumentException("The provided channel doesn't match with the channel id provided by the message parameter.", nameof(channel)); - var notification = new MentionNotification(message.Sender.Username, channel); - notificationOverlay?.Post(notification); - + notifications.Post(new MentionNotification(message.Sender.Username, channel)); return true; } diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index e753dd1424..0cd31def2e 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -726,8 +726,8 @@ 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(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(chatOverlay = new ChatOverlay(), overlayContent.Add, true); + loadComponentSingleFile(new MessageNotifier(), AddInternal, true); loadComponentSingleFile(Settings = new SettingsOverlay { GetToolbarHeight = () => ToolbarOffset }, leftFloatingOverlayContent.Add, true); var changelogOverlay = loadComponentSingleFile(new ChangelogOverlay(), overlayContent.Add, true); loadComponentSingleFile(userProfile = new UserProfileOverlay(), overlayContent.Add, true); From 20759657def9491b25d49f12d65a6b81d9c8e6c2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:37:31 +0900 Subject: [PATCH 099/157] Rename configuration variables and refactor lots more --- osu.Game/Configuration/OsuConfigManager.cs | 8 +- osu.Game/Online/Chat/MessageNotifier.cs | 96 ++++++++----------- .../Online/AlertsAndPrivacySettings.cs | 4 +- 3 files changed, 46 insertions(+), 62 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 1c92c16333..60a0d5a0ac 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -61,8 +61,8 @@ namespace osu.Game.Configuration SetDefault(OsuSetting.ShowOnlineExplicitContent, false); - SetDefault(OsuSetting.ChatHighlightName, true); - SetDefault(OsuSetting.ChatMessageNotification, true); + SetDefault(OsuSetting.NotifyOnUsernameMentioned, true); + SetDefault(OsuSetting.NotifyOnPrivateMessage, true); // Audio SetDefault(OsuSetting.VolumeInactive, 0.25, 0, 1, 0.01); @@ -262,8 +262,8 @@ namespace osu.Game.Configuration ScalingSizeY, UIScale, IntroSequence, - ChatHighlightName, - ChatMessageNotification, + NotifyOnUsernameMentioned, + NotifyOnPrivateMessage, UIHoldActivationDelay, HitLighting, MenuBackgroundSource, diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index 2a676738d0..b8947d6e47 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -9,7 +9,6 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; -using osu.Framework.Logging; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Online.API; @@ -33,16 +32,18 @@ namespace osu.Game.Online.Chat [Resolved] private ChannelManager channelManager { get; set; } - private Bindable notifyOnMention; - private Bindable notifyOnPM; + private Bindable notifyOnUsername; + private Bindable notifyOnPrivateMessage; + private readonly IBindable localUser = new Bindable(); private readonly IBindableList joinedChannels = new BindableList(); [BackgroundDependencyLoader] private void load(OsuConfigManager config, IAPIProvider api) { - notifyOnMention = config.GetBindable(OsuSetting.ChatHighlightName); - notifyOnPM = config.GetBindable(OsuSetting.ChatMessageNotification); + notifyOnUsername = config.GetBindable(OsuSetting.NotifyOnUsernameMentioned); + notifyOnPrivateMessage = config.GetBindable(OsuSetting.NotifyOnPrivateMessage); + localUser.BindTo(api.LocalUser); joinedChannels.BindCollectionChanged(channelsChanged); @@ -55,19 +56,19 @@ namespace osu.Game.Online.Chat { case NotifyCollectionChangedAction.Add: foreach (var channel in e.NewItems.Cast()) - channel.NewMessagesArrived += newMessagesArrived; + channel.NewMessagesArrived += checkNewMessages; break; case NotifyCollectionChangedAction.Remove: foreach (var channel in e.OldItems.Cast()) - channel.NewMessagesArrived -= newMessagesArrived; + channel.NewMessagesArrived -= checkNewMessages; break; } } - private void newMessagesArrived(IEnumerable messages) + private void checkNewMessages(IEnumerable messages) { if (!messages.Any()) return; @@ -75,10 +76,7 @@ namespace osu.Game.Online.Chat var channel = channelManager.JoinedChannels.SingleOrDefault(c => c.Id == messages.First().ChannelId); if (channel == null) - { - Logger.Log($"Couldn't resolve channel id {messages.First().ChannelId}", LoggingTarget.Information); return; - } // Only send notifications, if ChatOverlay and the target channel aren't visible. if (chatOverlay.IsPresent && channelManager.CurrentChannel.Value == channel) @@ -93,12 +91,11 @@ namespace osu.Game.Online.Chat if (message.Sender.Id == localUser.Value.Id) continue; - // check for private messages first, - // to avoid both posting two notifications about the same message + // check for private messages first to avoid both posting two notifications about the same message if (checkForPMs(channel, message)) continue; - _ = checkForMentions(channel, message, localUser.Value.Username); + checkForMentions(channel, message); } } @@ -107,45 +104,52 @@ namespace osu.Game.Online.Chat /// /// The channel associated to the /// The message to be checked + /// Whether a notification was fired. private bool checkForPMs(Channel channel, Message message) { - if (!notifyOnPM.Value || channel.Type != ChannelType.PM) + if (!notifyOnPrivateMessage.Value || channel.Type != ChannelType.PM) return false; - if (channel.Id != message.ChannelId) - throw new ArgumentException("The provided channel doesn't match with the channel id provided by the message parameter.", nameof(channel)); - notifications.Post(new PrivateMessageNotification(message.Sender.Username, channel)); return true; } - /// - /// Checks whether the user enabled mention notifications and whether specified mentions the provided . - /// - /// The channel associated to the - /// The message to be checked - /// The username that will be checked for - private bool checkForMentions(Channel channel, Message message, string username) + private void checkForMentions(Channel channel, Message message) { - if (!notifyOnMention.Value || !isMentioning(message.Content, username)) - return false; - - if (channel.Id != message.ChannelId) - throw new ArgumentException("The provided channel doesn't match with the channel id provided by the message parameter.", nameof(channel)); + if (!notifyOnUsername.Value || !checkContainsUsername(message.Content, localUser.Value.Username)) return; notifications.Post(new MentionNotification(message.Sender.Username, channel)); - return true; } /// - /// Checks if contains , if not, retries making spaces into underscores. + /// Checks if contains . + /// This will match against the case where underscores are used instead of spaces (which is how osu-stable handles usernames with spaces). /// - /// If the mentions the - private static bool isMentioning(string message, string username) => message.Contains(username, StringComparison.OrdinalIgnoreCase) || message.Contains(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase); + private static bool checkContainsUsername(string message, string username) => message.Contains(username, StringComparison.OrdinalIgnoreCase) || message.Contains(username.Replace(' ', '_'), StringComparison.OrdinalIgnoreCase); - public class OpenChannelNotification : SimpleNotification + public class PrivateMessageNotification : OpenChannelNotification { - public OpenChannelNotification(Channel channel) + public PrivateMessageNotification(string username, Channel channel) + : base(channel) + { + Icon = FontAwesome.Solid.Envelope; + Text = $"You received a private message from '{username}'. Click to read it!"; + } + } + + public class MentionNotification : OpenChannelNotification + { + public MentionNotification(string username, Channel channel) + : base(channel) + { + Icon = FontAwesome.Solid.At; + Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; + } + } + + public abstract class OpenChannelNotification : SimpleNotification + { + protected OpenChannelNotification(Channel channel) { this.channel = channel; } @@ -169,25 +173,5 @@ namespace osu.Game.Online.Chat }; } } - - public class PrivateMessageNotification : OpenChannelNotification - { - public PrivateMessageNotification(string username, Channel channel) - : base(channel) - { - Icon = FontAwesome.Solid.Envelope; - Text = $"You received a private message from '{username}'. Click to read it!"; - } - } - - public class MentionNotification : OpenChannelNotification - { - public MentionNotification(string username, Channel channel) - : base(channel) - { - Icon = FontAwesome.Solid.At; - Text = $"Your name was mentioned in chat by '{username}'. Click to find out why!"; - } - } } } diff --git a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs index 9f70d23c27..b0f6400d4f 100644 --- a/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs +++ b/osu.Game/Overlays/Settings/Sections/Online/AlertsAndPrivacySettings.cs @@ -19,12 +19,12 @@ namespace osu.Game.Overlays.Settings.Sections.Online new SettingsCheckbox { LabelText = "Show a notification when someone mentions your name", - Current = config.GetBindable(OsuSetting.ChatHighlightName) + Current = config.GetBindable(OsuSetting.NotifyOnUsernameMentioned) }, new SettingsCheckbox { LabelText = "Show a notification when you receive a private message", - Current = config.GetBindable(OsuSetting.ChatMessageNotification) + Current = config.GetBindable(OsuSetting.NotifyOnPrivateMessage) }, }; } From 8eab7df9551f150c394a3df174aa228868983082 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 17:51:58 +0900 Subject: [PATCH 100/157] Move `BindCollectionChanged` out of async load --- osu.Game/Online/Chat/MessageNotifier.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/Chat/MessageNotifier.cs b/osu.Game/Online/Chat/MessageNotifier.cs index b8947d6e47..6840c036ff 100644 --- a/osu.Game/Online/Chat/MessageNotifier.cs +++ b/osu.Game/Online/Chat/MessageNotifier.cs @@ -45,11 +45,15 @@ namespace osu.Game.Online.Chat notifyOnPrivateMessage = config.GetBindable(OsuSetting.NotifyOnPrivateMessage); localUser.BindTo(api.LocalUser); - - joinedChannels.BindCollectionChanged(channelsChanged); joinedChannels.BindTo(channelManager.JoinedChannels); } + protected override void LoadComplete() + { + base.LoadComplete(); + joinedChannels.BindCollectionChanged(channelsChanged, true); + } + private void channelsChanged(object sender, NotifyCollectionChangedEventArgs e) { switch (e.Action) From af3f253b2182784c99072e3df362cbb07714c97d Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 18:28:48 +0900 Subject: [PATCH 101/157] Refactor `ScrollingHitObjectContainer` and expose more useful methods --- .../Scrolling/ScrollingHitObjectContainer.cs | 148 +++++++----------- 1 file changed, 57 insertions(+), 91 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index f478e37e3e..d21f30eb30 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -19,6 +19,11 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly IBindable timeRange = new BindableDouble(); private readonly IBindable direction = new Bindable(); + /// + /// 0 for horizontal scroll, 1 for vertical scroll. + /// + private int scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? 0 : 1; + /// /// A set of top-level s which have an up-to-date layout. /// @@ -48,85 +53,65 @@ namespace osu.Game.Rulesets.UI.Scrolling } /// - /// Given a position in screen space, return the time within this column. + /// Given a position along the scrolling axis, return the time within this . /// - public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) + /// The position along the scrolling axis. + /// The time the scrolling speed is used. + public double TimeAtPosition(float position, double referenceTime) { - // convert to local space of column so we can snap and fetch correct location. - Vector2 localPosition = ToLocalSpace(screenSpacePosition); - - float position = 0; - - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - position = localPosition.Y; - break; - - case ScrollingDirection.Right: - case ScrollingDirection.Left: - position = localPosition.X; - break; - } - flipPositionIfRequired(ref position); - - return scrollingInfo.Algorithm.TimeAt(position, Time.Current, scrollingInfo.TimeRange.Value, scrollLength); + return scrollingInfo.Algorithm.TimeAt(position, referenceTime, timeRange.Value, scrollLength); } /// - /// Given a time, return the screen space position within this column. + /// Given a position in screen space, return the time within this . + /// + public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) + { + Vector2 localPosition = ToLocalSpace(screenSpacePosition); + return TimeAtPosition(localPosition[scrollingAxis], Time.Current); + } + + /// + /// Given a time, return the position along the scrolling axis within this at time . + /// + public float PositionAtTime(double time, double currentTime) + { + float pos = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + flipPositionIfRequired(ref pos); + return pos; + } + + /// + /// Given a time, return the position along the scrolling axis within this at the current time. + /// + public float PositionAtTime(double time) => PositionAtTime(time, Time.Current); + + /// + /// Given a time, return the screen space position within this . + /// In the non-scrolling axis, the center of this is returned. /// public Vector2 ScreenSpacePositionAtTime(double time) { - var pos = scrollingInfo.Algorithm.PositionAt(time, Time.Current, scrollingInfo.TimeRange.Value, scrollLength); - - flipPositionIfRequired(ref pos); - - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - return ToScreenSpace(new Vector2(getBreadth() / 2, pos)); - - default: - return ToScreenSpace(new Vector2(pos, getBreadth() / 2)); - } + float position = PositionAtTime(time, Time.Current); + return scrollingAxis == 0 + ? ToScreenSpace(new Vector2(position, DrawHeight / 2)) + : ToScreenSpace(new Vector2(DrawWidth / 2, position)); } - private float scrollLength + /// + /// Given a start time and end time of a scrolling object, return the length of the object along the scrolling axis. + /// + public float LengthAtTime(double startTime, double endTime) { - get - { - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Left: - case ScrollingDirection.Right: - return DrawWidth; - - default: - return DrawHeight; - } - } + return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength); } - private float getBreadth() - { - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - return DrawWidth; - - default: - return DrawHeight; - } - } + private float scrollLength => DrawSize[scrollingAxis]; private void flipPositionIfRequired(ref float position) { - // We're dealing with screen coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. + // We're dealing with coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, // so when scrolling downwards the coordinates need to be flipped. @@ -237,18 +222,11 @@ namespace osu.Game.Rulesets.UI.Scrolling { if (hitObject.HitObject is IHasDuration e) { - switch (direction.Value) - { - case ScrollingDirection.Up: - case ScrollingDirection.Down: - hitObject.Height = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength); - break; - - case ScrollingDirection.Left: - case ScrollingDirection.Right: - hitObject.Width = scrollingInfo.Algorithm.GetLength(hitObject.HitObject.StartTime, e.EndTime, timeRange.Value, scrollLength); - break; - } + float length = LengthAtTime(hitObject.HitObject.StartTime, e.EndTime); + if (scrollingAxis == 0) + hitObject.Width = length; + else + hitObject.Height = length; } foreach (var obj in hitObject.NestedHitObjects) @@ -262,24 +240,12 @@ namespace osu.Game.Rulesets.UI.Scrolling private void updatePosition(DrawableHitObject hitObject, double currentTime) { - switch (direction.Value) - { - case ScrollingDirection.Up: - hitObject.Y = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; + float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); - case ScrollingDirection.Down: - hitObject.Y = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; - - case ScrollingDirection.Left: - hitObject.X = scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; - - case ScrollingDirection.Right: - hitObject.X = -scrollingInfo.Algorithm.PositionAt(hitObject.HitObject.StartTime, currentTime, timeRange.Value, scrollLength); - break; - } + if (scrollingAxis == 0) + hitObject.X = position; + else + hitObject.Y = position; } } } From 15d3b4444d5dc5d1f3523bf5666d4a60366f6641 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 11 Jun 2021 19:34:54 +0900 Subject: [PATCH 102/157] Rename `HoverSounds` and `HoverClickSounds` samples --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 2 +- osu.Game/Graphics/UserInterface/HoverSounds.cs | 12 ++++++------ 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index c1963ce62d..f6f2b270e6 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleClick = audio.Samples.Get($@"UI/generic-select{SampleSet.GetDescription()}"); + sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select"); } } } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index f2e4c6d013..60c9c36be3 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -31,7 +31,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio, SessionStatics statics) { - sampleHover = audio.Samples.Get($@"UI/generic-hover{SampleSet.GetDescription()}"); + sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover"); } public override void PlayHoverSample() @@ -43,19 +43,19 @@ namespace osu.Game.Graphics.UserInterface public enum HoverSampleSet { - [Description("")] + [Description("default")] Loud, - [Description("-soft")] + [Description("soft")] Normal, - [Description("-softer")] + [Description("softer")] Soft, - [Description("-toolbar")] + [Description("toolbar")] Toolbar, - [Description("-songselect")] + [Description("songselect")] SongSelect } } From 4f80a3b66d0e61a9f5049ea52d7150e5eda23248 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 11 Jun 2021 20:14:35 +0900 Subject: [PATCH 103/157] Add fallback-to-default logic for HoverSounds and HoverClickSounds --- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 2 +- osu.Game/Graphics/UserInterface/HoverSounds.cs | 4 ++-- osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index f6f2b270e6..61e0266372 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -45,7 +45,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select"); + sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); } } } diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index 60c9c36be3..e17128ff83 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -31,7 +31,7 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio, SessionStatics statics) { - sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover"); + sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-hover"); } public override void PlayHoverSample() @@ -44,7 +44,7 @@ namespace osu.Game.Graphics.UserInterface public enum HoverSampleSet { [Description("default")] - Loud, + Default, [Description("soft")] Normal, diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index a22c837080..1bd193e247 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface protected Box Background; protected SpriteText SpriteText; - public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Loud) + public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Default) { Height = 40; From 0b95d07390c95fc6242b53592b854d91373cbd07 Mon Sep 17 00:00:00 2001 From: Jamie Taylor Date: Fri, 11 Jun 2021 20:42:10 +0900 Subject: [PATCH 104/157] Change 'default' hover/click samples into 'button' samples and make 'soft' the new 'default' --- osu.Game/Graphics/Containers/OsuClickableContainer.cs | 2 +- osu.Game/Graphics/UserInterface/HoverClickSounds.cs | 2 +- osu.Game/Graphics/UserInterface/HoverSounds.cs | 6 +++--- osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs | 1 + osu.Game/Graphics/UserInterface/OsuButton.cs | 2 +- 5 files changed, 7 insertions(+), 6 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuClickableContainer.cs b/osu.Game/Graphics/Containers/OsuClickableContainer.cs index 1f31e4cdda..60ded8952d 100644 --- a/osu.Game/Graphics/Containers/OsuClickableContainer.cs +++ b/osu.Game/Graphics/Containers/OsuClickableContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Graphics.Containers protected virtual HoverClickSounds CreateHoverClickSounds(HoverSampleSet sampleSet) => new HoverClickSounds(sampleSet); - public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Normal) + public OsuClickableContainer(HoverSampleSet sampleSet = HoverSampleSet.Default) { this.sampleSet = sampleSet; } diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 61e0266372..3273482162 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -28,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface /// Array of button codes which should trigger the click sound. /// If this optional parameter is omitted or set to null, the click sound will only be played on left click. /// - public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal, MouseButton[] buttons = null) + public HoverClickSounds(HoverSampleSet sampleSet = HoverSampleSet.Default, MouseButton[] buttons = null) : base(sampleSet) { this.buttons = buttons ?? new[] { MouseButton.Left }; diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index e17128ff83..ea81ef7d14 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -22,7 +22,7 @@ namespace osu.Game.Graphics.UserInterface protected readonly HoverSampleSet SampleSet; - public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Normal) + public HoverSounds(HoverSampleSet sampleSet = HoverSampleSet.Default) { SampleSet = sampleSet; RelativeSizeAxes = Axes.Both; @@ -46,8 +46,8 @@ namespace osu.Game.Graphics.UserInterface [Description("default")] Default, - [Description("soft")] - Normal, + [Description("button")] + Button, [Description("softer")] Soft, diff --git a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs index cfcf034d1c..70a107ca04 100644 --- a/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuAnimatedButton.cs @@ -44,6 +44,7 @@ namespace osu.Game.Graphics.UserInterface private readonly Box hover; public OsuAnimatedButton() + : base(HoverSampleSet.Button) { base.Content.Add(content = new Container { diff --git a/osu.Game/Graphics/UserInterface/OsuButton.cs b/osu.Game/Graphics/UserInterface/OsuButton.cs index 1bd193e247..cd9ca9f87f 100644 --- a/osu.Game/Graphics/UserInterface/OsuButton.cs +++ b/osu.Game/Graphics/UserInterface/OsuButton.cs @@ -49,7 +49,7 @@ namespace osu.Game.Graphics.UserInterface protected Box Background; protected SpriteText SpriteText; - public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Default) + public OsuButton(HoverSampleSet? hoverSounds = HoverSampleSet.Button) { Height = 40; From 876a357bf29eedd693804a3b6c75f3861f7aad6f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 11 Jun 2021 13:55:38 +0200 Subject: [PATCH 105/157] Add support for animated colour fill in new style legacy health bar --- osu.Game/Skinning/LegacyHealthDisplay.cs | 24 +++++++++++++----------- 1 file changed, 13 insertions(+), 11 deletions(-) diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index 9d3bafd0b1..d463df5f80 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -148,9 +148,9 @@ namespace osu.Game.Skinning } } - internal class LegacyOldStyleFill : LegacyHealthPiece + internal abstract class LegacyFill : LegacyHealthPiece { - public LegacyOldStyleFill(ISkin skin) + protected LegacyFill(ISkin skin) { // required for sizing correctly.. var firstFrame = getTexture(skin, "colour-0"); @@ -166,23 +166,25 @@ namespace osu.Game.Skinning Size = new Vector2(firstFrame.DisplayWidth, firstFrame.DisplayHeight); } - Position = new Vector2(3, 10) * 1.6f; Masking = true; } } - internal class LegacyNewStyleFill : LegacyHealthPiece + internal class LegacyOldStyleFill : LegacyFill + { + public LegacyOldStyleFill(ISkin skin) + : base(skin) + { + Position = new Vector2(3, 10) * 1.6f; + } + } + + internal class LegacyNewStyleFill : LegacyFill { public LegacyNewStyleFill(ISkin skin) + : base(skin) { - InternalChild = new Sprite - { - Texture = getTexture(skin, "colour"), - }; - - Size = InternalChild.Size; Position = new Vector2(7.5f, 7.8f) * 1.6f; - Masking = true; } protected override void Update() From 550d566bf979521e86a16d62db1eb630ee60aca4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 11 Jun 2021 14:03:21 +0200 Subject: [PATCH 106/157] Simplify member access --- osu.Game/Skinning/LegacyHealthDisplay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Skinning/LegacyHealthDisplay.cs b/osu.Game/Skinning/LegacyHealthDisplay.cs index d463df5f80..1da80f6613 100644 --- a/osu.Game/Skinning/LegacyHealthDisplay.cs +++ b/osu.Game/Skinning/LegacyHealthDisplay.cs @@ -162,7 +162,7 @@ namespace osu.Game.Skinning } else { - InternalChild = skin.GetAnimation("scorebar-colour", true, true, startAtCurrentTime: false, applyConfigFrameRate: true) ?? Drawable.Empty(); + InternalChild = skin.GetAnimation("scorebar-colour", true, true, startAtCurrentTime: false, applyConfigFrameRate: true) ?? Empty(); Size = new Vector2(firstFrame.DisplayWidth, firstFrame.DisplayHeight); } From d3a255fd8113eafeaa6de763ac8bcb99a85d6e99 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Fri, 11 Jun 2021 14:21:54 +0200 Subject: [PATCH 107/157] Add animated assets for legacy health display test --- .../Resources/special-skin/scorebar-bg.png | Bin 0 -> 250 bytes .../Resources/special-skin/scorebar-colour-0.png | Bin 0 -> 1285 bytes .../Resources/special-skin/scorebar-colour-1.png | Bin 0 -> 1288 bytes .../Resources/special-skin/scorebar-colour-2.png | Bin 0 -> 1287 bytes .../Resources/special-skin/scorebar-colour-3.png | Bin 0 -> 1286 bytes .../Resources/special-skin/scorebar-marker.png | Bin 0 -> 126 bytes 6 files changed, 0 insertions(+), 0 deletions(-) create mode 100644 osu.Game.Tests/Resources/special-skin/scorebar-bg.png create mode 100644 osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png create mode 100644 osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png create mode 100644 osu.Game.Tests/Resources/special-skin/scorebar-colour-2.png create mode 100644 osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png create mode 100644 osu.Game.Tests/Resources/special-skin/scorebar-marker.png diff --git a/osu.Game.Tests/Resources/special-skin/scorebar-bg.png b/osu.Game.Tests/Resources/special-skin/scorebar-bg.png new file mode 100644 index 0000000000000000000000000000000000000000..1a25274ed8bb9a3a5ea2cfd01445141b5f774292 GIT binary patch literal 250 zcmeAS@N?(olHy`uVBq!ia0y~yU}6Wd)j8OJ21sKV{?Q5ip7re$fgPYWH+;45_&F_S!~X1_c4;jR%s> zoJ$F)cW<6B!PaS33=>cZe(+&qTGQ{eO=}nqWIz7!efLTRhC&904rT@i83u+&3=9J7 m3=I|x3`ZCl6!>r(w2Ig9Ig`kdJJ$<9YCK*2T-G@yGywqnV>P1y literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png b/osu.Game.Tests/Resources/special-skin/scorebar-colour-0.png new file mode 100644 index 0000000000000000000000000000000000000000..3c15449b039fe44b372fdb9b538be1601f6655d6 GIT binary patch literal 1285 zcmV+g1^W7lP)000vR1^@s6X5jw>00006VoOIv00000 z008+zyMF)x010qNS#tmYE+YT{E+YYWr9XB6000McNliruTa zK~#9!?b*MN9n}@U@$WfzX5M@I|jp zl!++lkdTmLBrI@ZyvW9Dd;NaS%)RGO%mX7jL=i1IpX$zNW_0Jw`B4mn5JCtcgb+dq zA%qY@2qAoo@5#C)fG-!+(J&*^JZ0lD1vpW)u-Xa1m4-Trm}PwkB*% zD(a>tC8bJ^Z zQ3+Hk{Nd6rvlg!3YB@X@adc&myEEtdac12sDv-@-t)~kgCMixZ?2q zgeEDe8cJu`6&BeLb?!fGSPsYbMYOR=6hB}&PdD#jdo-u-GbpGibzPHGNlEC7(RT$9%%R|j>*gDP;HU^qqcpXG2<}eF z&N>^V4EI(FRnj5vajY1nfMJ{38|r@ZR+z!49{QkT!+T_>;J8~6_q+f2=z|gi{WtK3 z|MrMN2qA?3r?>z5-o<}@^uc#O9&3aogb+eFd(22bKaPPOLI@$8K_wSrpob7b2xr_c z|NX{54+|EL?MI_ vLI@#*5JCtcgb+dqA%qY@2qA+nqUV>8`c00000NkvXXu0mjfBN9_U literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png b/osu.Game.Tests/Resources/special-skin/scorebar-colour-1.png new file mode 100644 index 0000000000000000000000000000000000000000..a444723ef4023391257479a66c443a3e593dd019 GIT binary patch literal 1288 zcmV+j1^4=iP)000vR1^@s6X5jw>00006VoOIv00000 z008+zyMF)x010qNS#tmYE+YT{E+YYWr9XB6000McNliruXb2&M5JCtc zgb+dqA%qY@2qAUE0-!>c&f&-AxY3p+=>}ZQktZggQ~EzT{CWKN-4O*sICCvWZvQisj5&_9?VAIf9s;4hTqY1&uW`NUK=7-gqB#A4R_qlLx!oj%_hI4Y-Qmc@v#MZdt z@ce`(DXAJtXW11N*${Oe{Lr$Px6GC;i*-hUzBk^z_6@gBmQ)Q%-P33(V8{g%G&%FxoTjN5jkY;DdV!lauhaF03MfLC zdn{*C5{hL`A1$zAOs5mF^@s~e1WiirdobJNVvkTrRYOyaX#198J#|Wyk}*}1SGYMM zLNVv+)jxCe$IJZlU+*Dm2ud+SR7faVCq|<&nuOWxlv14ee8K*?9mE||#oc)2#UqZ7 zzvu4#6GqL1R42OilDzreBFe#ZhbzxKjR0nbs&nz+fKe?xm@W9~yE_=pg}vRMb4^un zE0mJ??%qSdxpMhQ9An*ee17XLx9&dR`R6Y4#n<0rRyIvcQJ|QyTDOcx4XQfiu|rcO zUVZUd{_@guT)Hsj>BIBvPbX9gZPzoKuju+hw!)-om~PcnqX|_dtR9{+-5GQD`x&ar ze6{A^U)<;Z!zCxDOV)jlnGN+(h92RY#J6IM#}gLoCF}W;zrOl1D)8xN|6$!_%pC*z zuF!TpW<%dC#XyC3Nr9r7N>icty}wyC|L?l*6R8I0~ryM|KL1yA^T2_u>2Rlo;s0 zf`9wAM-)N`A^ev9_U4xtKYIV2J3k$3gd~IzLO6TONdJ2r13iQgLO6p;F2q0&A%qal zxc~q68v{Lr5JLDJh=CqL2qBz75(7Pi5JEWn`fM@KLkJ;+vu@Sq80aB{5W-n!g+~#E y5JCtcgb+dqA%qY@2qA21sKV{?Q;n6f@tTAC=V433S;uunK>+Mb3e%Ys@2R{C{ zJb&g+_4lXiu4|u3N9aoU*_lVy_qJANF|6aOalO})W#sl-%=rHAD8-x_5k(!u zoVz-s4HtWQO%^E*5G~u5eazQaleJvps;I)8GtqYxLPb}dYOXxJ%Xp1Q+4k%^MzPm7 zM|}NqG{Z#E;wDdl)#;k;QIk~)-=4A)Kj&*r`_C?y78RGh407O=ihsD?&PFZLORWn2Xj4m1aB)I-j1Gpy!B1L_AQwYiS_S{Y&@rIJ00Siv}^bAhr#|uuj`LHGYbT) zEb!l9y)TnHt#7yTDuv7)0YZyRm3G}M{hBOXm{YvIL1Gnel&MG17OBNa5B_d&Jg>m& zSdiG!o?gIQUvo}Xk@XI*&jGHmsxAp8XT2E04%*6L-#+I`eFMh81_p@}@y#Pkn z7e)O~eY~7Do_V>LHLT}liPJW@LdDJno+oSh(`LuK5#(B#m9a`N_kPft<$j$(M$5cD zahbcjXgu5V>lL@m--lf9_x=}L)V4sx*rl~)QE8Hi)MC#WXZ^)fz59S=49$(-5 zFy_YXzlPUCShqWA&RqZAmSs+M_`D;A*J6*0Z+~C(`yKPV>Tg`;`+wP|rCvTF!rCRd zy7Y9#l?AJu<*ZFYA8i$1|7rR3c~393YEI`rzuA6nfaaFi^Evw#z2?5jHF;U$uF&9K zwUDVBswz&Eq@TH)pT0ut^VM1P_xGIt+wSe>H+{`-Ib-Qpi+OAhnRn(NmFQR3x#oTC zvub_a+tiQ;o9q8hFP&~!&huio)9tS_cx$(dFpGZsw(N}D*_Xe0xU{@tud9Rx3H?g? z63fU^tYPtJ*H1PD3oWP18op~4nsx_o+I-GU^YGrOPE$)xRLf|)X(rrQ_N{H#{XL>- z2CLfbUflQ~cT>~iUD%Po_wL*MTX4kTzvv(P_0=xG40|a5rT+W4eLueU+y8jhp4>YD zl!w#%C0{N-Zg{~Nn5B(ZJaOXr0u+4M^ZV!i`w}len%+A=gm@-F_&2YocQ?ubOMp40 stIdu(@B`JHv(mQd(m*Q_VB8zopr0M~s-fB*mh literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png b/osu.Game.Tests/Resources/special-skin/scorebar-colour-3.png new file mode 100644 index 0000000000000000000000000000000000000000..a3a5ca4716d3898929332a54b631ee604c017390 GIT binary patch literal 1286 zcmeAS@N?(olHy`uVBq!ia0y~yVEh7P3v;jm$+QRmS%4H21sKV{?Q;W1RpeUik$z%tp>#WAGf*4vx5{jyI*4}AP@ zdH&3u>hDk2UDrO7)SS}85V@wMXMuyFtjQDZB@36FJ^mngNvDP;vuCHvLq1MU$!MlV z;m59KakIbH&Yk((QvGO5!4$qgm+o`xtI|x2tDc>y)MRtwP;3!EB^VS0o8sTUwf~!X zYkJ+Ph7P4gE3_U&==m$X?)$x=j9t(%#L~jX-*%PdzUroq2Nto>JAVAx{O9N2@)>^H zcmBKSYxna-uz>39!d(%UwrSt#QDWlIYwBv&UUul*wU)J>u6M62SrVc-(M7^vDrC;C zpl{{dBXy$l?(8^SbT{y7^0BisPG75v6rD%qgU&6{kKNh51-AQ zcDPy4J^b4a`{F#g^lN(;G2NVVt;$Q#L9ozE?@3UB`L%Azd)qstcg7Ze4LYiQ{#t~Y z3g@oQXv4*xUXw+N14PTVWgqkP)nqM~xGJhJ=S=h+g;3E|rw&)1-etT-q-=Zk9i!Om znm!tvR6E2(VkwwTwiofRgv`$ug?Llu&OQzCTG1F3r@~F|IEbqXvUVa7cXkx*;U%S&OF3H zaMzt=%gK`hbc%mfG>Rr$&7H8;J;p;RBdF+p^G!AJ>K3O}QnRvLZf_TPy)t;wl%AE7 z_8dAZDA;A0zwf7(yMFAm_4U847qu-AF?MNfSyY;2BDL6a##ukjqchKoznOpA@s45W zonG^GvV}E&l)uZ(G00L|Vs&xt^e1P(iv{v6vyQ3#XUSq<95T0?oxLaP;lrGR+wcEx zco=iz_FvWOA*|b-G-tklZ_hMm_4N7246nr=zh3^X@cBLGxSEGX_iMiApE%TUfgV$Jk5 z&%OWsxb}L*f#>lxM|Yi`Va@g>cH!HqGj02#yBfKwtAo?}pMR-kV-;PxE_;%eCTFeT zuXPMfmLf8RcWamhWJDKcPFWTvaPY3?&B*k{Qy$*)TIgl<#I{d#v4}xVaJBQ@{Cix+ z5?7t&OL8ju--yVRYd@;{FE3vok+k4HTb*pb1~9+=sIU6o{9W(g=g0i@KYm6is{k|c zp_|EWzurHVcmZNdh7>8XRRQyM!Lh&Z_uq#IzIWjH0?g|Vc_u;lH?OC6H_8Ds|D4j* tX2%`)ff~@23MQ{KB literal 0 HcmV?d00001 diff --git a/osu.Game.Tests/Resources/special-skin/scorebar-marker.png b/osu.Game.Tests/Resources/special-skin/scorebar-marker.png new file mode 100644 index 0000000000000000000000000000000000000000..b5af0b2148832b745caf04c4e2b5103efa43c913 GIT binary patch literal 126 zcmeAS@N?(olHy`uVBq!ia0vp^j3CUx1|;Q0k8}blwj^(N7a$D;Kb?2i11Zh|kH}&M z20djEW~^9hUj`IpFY)wsWq-=X%_F6M;8)Hypb)pGi(?4K_2dKwCI$vp2F6Efth0f_ N44$rjF6*2UngDK&89D#} literal 0 HcmV?d00001 From dca001a72d6e079e22cf3c8f0e60b3ebd2909a48 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Fri, 11 Jun 2021 22:22:47 +0900 Subject: [PATCH 108/157] Upgraed localisation analyser packages --- .config/dotnet-tools.json | 4 ++-- osu.Game/osu.Game.csproj | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index b51ecb4f7e..84673fe2ba 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -33,10 +33,10 @@ ] }, "ppy.localisationanalyser.tools": { - "version": "2021.524.0", + "version": "2021.608.0", "commands": [ "localisation" ] } } -} \ No newline at end of file +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2ee8ed527f..ed299456de 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -30,7 +30,7 @@ - + all runtime; build; native; contentfiles; analyzers; buildtransitive From 97bb3de1c9024ef77798739981ee0615a5c4c7cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 23:03:27 +0900 Subject: [PATCH 109/157] Update resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 0d3fafd19f..ba8b8b32ba 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 2ee8ed527f..6d3a1d5226 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 7832aaaf2d..e382a804c8 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 5887b4a27cc585bb20cb3e9bb3954f19e40de3be Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 23:46:42 +0900 Subject: [PATCH 110/157] Update stand-alone usage of hover/select sounds in `DrawableOsuMenuItem` --- .../UserInterface/DrawableOsuMenuItem.cs | 16 ++-------------- 1 file changed, 2 insertions(+), 14 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs index 8df2c1c2fd..fea84998cf 100644 --- a/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/DrawableOsuMenuItem.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -23,9 +22,6 @@ namespace osu.Game.Graphics.UserInterface private const int text_size = 17; private const int transition_length = 80; - private Sample sampleClick; - private Sample sampleHover; - private TextContainer text; public DrawableOsuMenuItem(MenuItem item) @@ -36,12 +32,11 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleHover = audio.Samples.Get(@"UI/generic-hover"); - sampleClick = audio.Samples.Get(@"UI/generic-select"); - BackgroundColour = Color4.Transparent; BackgroundColourHover = Color4Extensions.FromHex(@"172023"); + AddInternal(new HoverClickSounds()); + updateTextColour(); Item.Action.BindDisabledChanged(_ => updateState(), true); @@ -84,7 +79,6 @@ namespace osu.Game.Graphics.UserInterface if (IsHovered && !Item.Action.Disabled) { - sampleHover.Play(); text.BoldText.FadeIn(transition_length, Easing.OutQuint); text.NormalText.FadeOut(transition_length, Easing.OutQuint); } @@ -95,12 +89,6 @@ namespace osu.Game.Graphics.UserInterface } } - protected override bool OnClick(ClickEvent e) - { - sampleClick.Play(); - return base.OnClick(e); - } - protected sealed override Drawable CreateContent() => text = CreateTextContainer(); protected virtual TextContainer CreateTextContainer() => new TextContainer(); From e098cac1cffb9388f5c2124eb5e0b6bac953ba20 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 23:49:14 +0900 Subject: [PATCH 111/157] Minor code reformatting / moving --- .../UserInterface/HoverClickSounds.cs | 3 ++- .../Graphics/UserInterface/HoverSampleSet.cs | 25 +++++++++++++++++++ .../Graphics/UserInterface/HoverSounds.cs | 22 ++-------------- 3 files changed, 29 insertions(+), 21 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/HoverSampleSet.cs diff --git a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs index 3273482162..12819840e5 100644 --- a/osu.Game/Graphics/UserInterface/HoverClickSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverClickSounds.cs @@ -45,7 +45,8 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio) { - sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); + sampleClick = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-select") + ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-select"); } } } diff --git a/osu.Game/Graphics/UserInterface/HoverSampleSet.cs b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs new file mode 100644 index 0000000000..c74ac90a4c --- /dev/null +++ b/osu.Game/Graphics/UserInterface/HoverSampleSet.cs @@ -0,0 +1,25 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.ComponentModel; + +namespace osu.Game.Graphics.UserInterface +{ + public enum HoverSampleSet + { + [Description("default")] + Default, + + [Description("button")] + Button, + + [Description("softer")] + Soft, + + [Description("toolbar")] + Toolbar, + + [Description("songselect")] + SongSelect + } +} diff --git a/osu.Game/Graphics/UserInterface/HoverSounds.cs b/osu.Game/Graphics/UserInterface/HoverSounds.cs index ea81ef7d14..c0ef5cb3fc 100644 --- a/osu.Game/Graphics/UserInterface/HoverSounds.cs +++ b/osu.Game/Graphics/UserInterface/HoverSounds.cs @@ -1,7 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.ComponentModel; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -31,7 +30,8 @@ namespace osu.Game.Graphics.UserInterface [BackgroundDependencyLoader] private void load(AudioManager audio, SessionStatics statics) { - sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover") ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-hover"); + sampleHover = audio.Samples.Get($@"UI/{SampleSet.GetDescription()}-hover") + ?? audio.Samples.Get($@"UI/{HoverSampleSet.Default.GetDescription()}-hover"); } public override void PlayHoverSample() @@ -40,22 +40,4 @@ namespace osu.Game.Graphics.UserInterface sampleHover.Play(); } } - - public enum HoverSampleSet - { - [Description("default")] - Default, - - [Description("button")] - Button, - - [Description("softer")] - Soft, - - [Description("toolbar")] - Toolbar, - - [Description("songselect")] - SongSelect - } } From d9ea8d64d4855feda54c3512b054344c86352d2e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Jun 2021 00:05:49 +0900 Subject: [PATCH 112/157] Remove weird local sample logic in `ChangelogOverlay` --- osu.Game/Overlays/ChangelogOverlay.cs | 5 ----- 1 file changed, 5 deletions(-) diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index e7d68853ad..67d83980ef 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -25,8 +25,6 @@ namespace osu.Game.Overlays public readonly Bindable Current = new Bindable(); - private Sample sampleBack; - private List builds; protected List Streams; @@ -41,8 +39,6 @@ namespace osu.Game.Overlays { Header.Build.BindTarget = Current; - sampleBack = audio.Samples.Get(@"UI/generic-select-soft"); - Current.BindValueChanged(e => { if (e.NewValue != null) @@ -108,7 +104,6 @@ namespace osu.Game.Overlays else { Current.Value = null; - sampleBack?.Play(); } return true; From 0dbe5dd2190f030e76a875bca0845cd67856d29d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Jun 2021 00:05:49 +0900 Subject: [PATCH 113/157] Remove unused using statement --- osu.Game/Overlays/ChangelogOverlay.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Overlays/ChangelogOverlay.cs b/osu.Game/Overlays/ChangelogOverlay.cs index 67d83980ef..a8f2e654d7 100644 --- a/osu.Game/Overlays/ChangelogOverlay.cs +++ b/osu.Game/Overlays/ChangelogOverlay.cs @@ -8,7 +8,6 @@ using System.Threading.Tasks; using JetBrains.Annotations; using osu.Framework.Allocation; using osu.Framework.Audio; -using osu.Framework.Audio.Sample; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Game.Input.Bindings; From 121df57dca7e5f66458ac952920b927861113f0e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Jun 2021 00:26:33 +0900 Subject: [PATCH 114/157] Fix focused overlays playing their "appear" sound when not necessarily changing state --- .../Containers/OsuFocusedOverlayContainer.cs | 13 +++++-------- 1 file changed, 5 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs index c0518247a9..b9b098df80 100644 --- a/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs +++ b/osu.Game/Graphics/Containers/OsuFocusedOverlayContainer.cs @@ -107,10 +107,10 @@ namespace osu.Game.Graphics.Containers { } - private bool playedPopInSound; - protected override void UpdateState(ValueChangedEvent state) { + bool didChange = state.NewValue != state.OldValue; + switch (state.NewValue) { case Visibility.Visible: @@ -121,18 +121,15 @@ namespace osu.Game.Graphics.Containers return; } - samplePopIn?.Play(); - playedPopInSound = true; + if (didChange) + samplePopIn?.Play(); if (BlockScreenWideMouse && DimMainContent) game?.AddBlockingOverlay(this); break; case Visibility.Hidden: - if (playedPopInSound) - { + if (didChange) samplePopOut?.Play(); - playedPopInSound = false; - } if (BlockScreenWideMouse) game?.RemoveBlockingOverlay(this); break; From f773ea475d08fa0758e436db9ead42e97ad227d0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sat, 12 Jun 2021 01:37:13 +0900 Subject: [PATCH 115/157] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index ba8b8b32ba..13d45835be 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 877ae94a5e..7eb3c84582 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,7 +34,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index e382a804c8..3e8facaf6e 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From fe39a47797d9d754c59c86414d90bd237a02e9cb Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 12 Jun 2021 00:34:53 +0200 Subject: [PATCH 116/157] Add `OsuModSettingsTextBox` and `OsuModSettingsNumberBox` --- .../UserInterface/OsuModSettingsNumberBox.cs | 10 +++++ .../UserInterface/OsuModSettingsTextBox.cs | 44 +++++++++++++++++++ osu.Game/Overlays/Settings/SettingsTextBox.cs | 2 +- osu.Game/Rulesets/Mods/ModRandom.cs | 4 +- 4 files changed, 57 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs create mode 100644 osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs diff --git a/osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs b/osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs new file mode 100644 index 0000000000..4ec4165c0e --- /dev/null +++ b/osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs @@ -0,0 +1,10 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Graphics.UserInterface +{ + public class OsuModSettingsNumberBox : OsuModSettingsTextBox + { + protected override bool CanAddCharacter(char character) => char.IsNumber(character); + } +} diff --git a/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs b/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs new file mode 100644 index 0000000000..6720727b7a --- /dev/null +++ b/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs @@ -0,0 +1,44 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics.Colour; +using osu.Framework.Input.Events; + +namespace osu.Game.Graphics.UserInterface +{ + public class OsuModSettingsTextBox : OsuTextBox + { + private const float border_thickness = 3; + + private SRGBColour borderColourFocused; + private SRGBColour borderColourUnfocused; + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + borderColourUnfocused = colour.Gray4.Opacity(0.5f); + borderColourFocused = BorderColour; + + BorderThickness = border_thickness; + BorderColour = borderColourUnfocused; + } + + protected override void OnFocus(FocusEvent e) + { + base.OnFocus(e); + + BorderThickness = border_thickness; + BorderColour = borderColourFocused; + } + + protected override void OnFocusLost(FocusLostEvent e) + { + base.OnFocusLost(e); + + BorderThickness = border_thickness; + BorderColour = borderColourUnfocused; + } + } +} diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index 5e700a1d6b..43bc8e87f8 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -8,7 +8,7 @@ namespace osu.Game.Overlays.Settings { public class SettingsTextBox : SettingsItem { - protected override Drawable CreateControl() => new OsuTextBox + protected override Drawable CreateControl() => new OsuModSettingsTextBox { Margin = new MarginPadding { Top = 5 }, RelativeSizeAxes = Axes.X, diff --git a/osu.Game/Rulesets/Mods/ModRandom.cs b/osu.Game/Rulesets/Mods/ModRandom.cs index 3f14263420..450b2a0680 100644 --- a/osu.Game/Rulesets/Mods/ModRandom.cs +++ b/osu.Game/Rulesets/Mods/ModRandom.cs @@ -50,7 +50,7 @@ namespace osu.Game.Rulesets.Mods } } - private readonly OsuNumberBox seedNumberBox; + private readonly OsuModSettingsNumberBox seedNumberBox; public SeedControl() { @@ -76,7 +76,7 @@ namespace osu.Game.Rulesets.Mods { new Drawable[] { - seedNumberBox = new OsuNumberBox + seedNumberBox = new OsuModSettingsNumberBox { RelativeSizeAxes = Axes.X, CommitOnFocusLost = true From bb661abfa65d44f1fb15f6d351f3fbcbb8e3984a Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 12 Jun 2021 17:25:22 +0200 Subject: [PATCH 117/157] Clean up `OsuModSettingsTextBox` --- .../UserInterface/OsuModSettingsTextBox.cs | 19 +++++++++++-------- 1 file changed, 11 insertions(+), 8 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs b/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs index 6720727b7a..11b7ed33d0 100644 --- a/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs +++ b/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs @@ -3,8 +3,8 @@ using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Graphics.Colour; using osu.Framework.Input.Events; +using osuTK.Graphics; namespace osu.Game.Graphics.UserInterface { @@ -12,8 +12,8 @@ namespace osu.Game.Graphics.UserInterface { private const float border_thickness = 3; - private SRGBColour borderColourFocused; - private SRGBColour borderColourUnfocused; + private Color4 borderColourFocused; + private Color4 borderColourUnfocused; [BackgroundDependencyLoader] private void load(OsuColour colour) @@ -21,24 +21,27 @@ namespace osu.Game.Graphics.UserInterface borderColourUnfocused = colour.Gray4.Opacity(0.5f); borderColourFocused = BorderColour; - BorderThickness = border_thickness; - BorderColour = borderColourUnfocused; + updateBorder(); } protected override void OnFocus(FocusEvent e) { base.OnFocus(e); - BorderThickness = border_thickness; - BorderColour = borderColourFocused; + updateBorder(); } protected override void OnFocusLost(FocusLostEvent e) { base.OnFocusLost(e); + updateBorder(); + } + + private void updateBorder() + { BorderThickness = border_thickness; - BorderColour = borderColourUnfocused; + BorderColour = HasFocus ? borderColourFocused : borderColourUnfocused; } } } From 29f38804156b58aee0b6f31c71a28f7dec856b17 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 12 Jun 2021 17:34:02 +0200 Subject: [PATCH 118/157] Move classes into `SettingsTextBox` --- .../UserInterface/OsuModSettingsNumberBox.cs | 10 ---- .../UserInterface/OsuModSettingsTextBox.cs | 47 ------------------- osu.Game/Overlays/Settings/SettingsTextBox.cs | 47 +++++++++++++++++++ osu.Game/Rulesets/Mods/ModRandom.cs | 5 +- 4 files changed, 49 insertions(+), 60 deletions(-) delete mode 100644 osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs delete mode 100644 osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs diff --git a/osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs b/osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs deleted file mode 100644 index 4ec4165c0e..0000000000 --- a/osu.Game/Graphics/UserInterface/OsuModSettingsNumberBox.cs +++ /dev/null @@ -1,10 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -namespace osu.Game.Graphics.UserInterface -{ - public class OsuModSettingsNumberBox : OsuModSettingsTextBox - { - protected override bool CanAddCharacter(char character) => char.IsNumber(character); - } -} diff --git a/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs b/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs deleted file mode 100644 index 11b7ed33d0..0000000000 --- a/osu.Game/Graphics/UserInterface/OsuModSettingsTextBox.cs +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Input.Events; -using osuTK.Graphics; - -namespace osu.Game.Graphics.UserInterface -{ - public class OsuModSettingsTextBox : OsuTextBox - { - private const float border_thickness = 3; - - private Color4 borderColourFocused; - private Color4 borderColourUnfocused; - - [BackgroundDependencyLoader] - private void load(OsuColour colour) - { - borderColourUnfocused = colour.Gray4.Opacity(0.5f); - borderColourFocused = BorderColour; - - updateBorder(); - } - - protected override void OnFocus(FocusEvent e) - { - base.OnFocus(e); - - updateBorder(); - } - - protected override void OnFocusLost(FocusLostEvent e) - { - base.OnFocusLost(e); - - updateBorder(); - } - - private void updateBorder() - { - BorderThickness = border_thickness; - BorderColour = HasFocus ? borderColourFocused : borderColourUnfocused; - } - } -} diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index 43bc8e87f8..4e96573538 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -1,8 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; +using osu.Framework.Input.Events; +using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; +using osuTK.Graphics; namespace osu.Game.Overlays.Settings { @@ -14,5 +19,47 @@ namespace osu.Game.Overlays.Settings RelativeSizeAxes = Axes.X, CommitOnFocusLost = true, }; + + public class OsuModSettingsTextBox : OsuTextBox + { + private const float border_thickness = 3; + + private Color4 borderColourFocused; + private Color4 borderColourUnfocused; + + [BackgroundDependencyLoader] + private void load(OsuColour colour) + { + borderColourUnfocused = colour.Gray4.Opacity(0.5f); + borderColourFocused = BorderColour; + + updateBorder(); + } + + protected override void OnFocus(FocusEvent e) + { + base.OnFocus(e); + + updateBorder(); + } + + protected override void OnFocusLost(FocusLostEvent e) + { + base.OnFocusLost(e); + + updateBorder(); + } + + private void updateBorder() + { + BorderThickness = border_thickness; + BorderColour = HasFocus ? borderColourFocused : borderColourUnfocused; + } + } + + public class OsuModSettingsNumberBox : OsuModSettingsTextBox + { + protected override bool CanAddCharacter(char character) => char.IsNumber(character); + } } } diff --git a/osu.Game/Rulesets/Mods/ModRandom.cs b/osu.Game/Rulesets/Mods/ModRandom.cs index 450b2a0680..7220580b9f 100644 --- a/osu.Game/Rulesets/Mods/ModRandom.cs +++ b/osu.Game/Rulesets/Mods/ModRandom.cs @@ -8,7 +8,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Configuration; using osu.Game.Graphics; -using osu.Game.Graphics.UserInterface; using osu.Game.Overlays.Settings; namespace osu.Game.Rulesets.Mods @@ -50,7 +49,7 @@ namespace osu.Game.Rulesets.Mods } } - private readonly OsuModSettingsNumberBox seedNumberBox; + private readonly SettingsTextBox.OsuModSettingsNumberBox seedNumberBox; public SeedControl() { @@ -76,7 +75,7 @@ namespace osu.Game.Rulesets.Mods { new Drawable[] { - seedNumberBox = new OsuModSettingsNumberBox + seedNumberBox = new SettingsTextBox.OsuModSettingsNumberBox { RelativeSizeAxes = Axes.X, CommitOnFocusLost = true From c728f673d6dffc3e24d3d1b0163034922b45544e Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 12 Jun 2021 17:37:01 +0200 Subject: [PATCH 119/157] Rename classes --- osu.Game/Overlays/Settings/SettingsTextBox.cs | 6 +++--- osu.Game/Rulesets/Mods/ModRandom.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index 4e96573538..f895a66128 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -13,14 +13,14 @@ namespace osu.Game.Overlays.Settings { public class SettingsTextBox : SettingsItem { - protected override Drawable CreateControl() => new OsuModSettingsTextBox + protected override Drawable CreateControl() => new OsuSettingsTextBox { Margin = new MarginPadding { Top = 5 }, RelativeSizeAxes = Axes.X, CommitOnFocusLost = true, }; - public class OsuModSettingsTextBox : OsuTextBox + public class OsuSettingsTextBox : OsuTextBox { private const float border_thickness = 3; @@ -57,7 +57,7 @@ namespace osu.Game.Overlays.Settings } } - public class OsuModSettingsNumberBox : OsuModSettingsTextBox + public class OsuSettingsNumberBox : OsuSettingsTextBox { protected override bool CanAddCharacter(char character) => char.IsNumber(character); } diff --git a/osu.Game/Rulesets/Mods/ModRandom.cs b/osu.Game/Rulesets/Mods/ModRandom.cs index 7220580b9f..cef1814ee6 100644 --- a/osu.Game/Rulesets/Mods/ModRandom.cs +++ b/osu.Game/Rulesets/Mods/ModRandom.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mods } } - private readonly SettingsTextBox.OsuModSettingsNumberBox seedNumberBox; + private readonly SettingsTextBox.OsuSettingsNumberBox seedNumberBox; public SeedControl() { @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Mods { new Drawable[] { - seedNumberBox = new SettingsTextBox.OsuModSettingsNumberBox + seedNumberBox = new SettingsTextBox.OsuSettingsNumberBox { RelativeSizeAxes = Axes.X, CommitOnFocusLost = true From b79d57b68c4586ca174b702b6c50396a0262bb72 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 12 Jun 2021 17:57:40 +0200 Subject: [PATCH 120/157] Move `OsuSettingsNumberBox` into `SettingsNumberBox` --- osu.Game/Overlays/Settings/SettingsNumberBox.cs | 8 ++++++-- osu.Game/Overlays/Settings/SettingsTextBox.cs | 5 ----- osu.Game/Rulesets/Mods/ModRandom.cs | 4 ++-- 3 files changed, 8 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsNumberBox.cs b/osu.Game/Overlays/Settings/SettingsNumberBox.cs index cb7e63ae6f..20de35ed87 100644 --- a/osu.Game/Overlays/Settings/SettingsNumberBox.cs +++ b/osu.Game/Overlays/Settings/SettingsNumberBox.cs @@ -2,16 +2,20 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Settings { public class SettingsNumberBox : SettingsItem { - protected override Drawable CreateControl() => new OsuNumberBox + protected override Drawable CreateControl() => new OsuSettingsNumberBox { Margin = new MarginPadding { Top = 5 }, RelativeSizeAxes = Axes.X, }; + + public class OsuSettingsNumberBox : SettingsTextBox.OsuSettingsTextBox + { + protected override bool CanAddCharacter(char character) => char.IsNumber(character); + } } } diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index f895a66128..efcfb0ec5b 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -56,10 +56,5 @@ namespace osu.Game.Overlays.Settings BorderColour = HasFocus ? borderColourFocused : borderColourUnfocused; } } - - public class OsuSettingsNumberBox : OsuSettingsTextBox - { - protected override bool CanAddCharacter(char character) => char.IsNumber(character); - } } } diff --git a/osu.Game/Rulesets/Mods/ModRandom.cs b/osu.Game/Rulesets/Mods/ModRandom.cs index cef1814ee6..49e5ec0cbc 100644 --- a/osu.Game/Rulesets/Mods/ModRandom.cs +++ b/osu.Game/Rulesets/Mods/ModRandom.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mods } } - private readonly SettingsTextBox.OsuSettingsNumberBox seedNumberBox; + private readonly SettingsNumberBox.OsuSettingsNumberBox seedNumberBox; public SeedControl() { @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Mods { new Drawable[] { - seedNumberBox = new SettingsTextBox.OsuSettingsNumberBox + seedNumberBox = new SettingsNumberBox.OsuSettingsNumberBox { RelativeSizeAxes = Axes.X, CommitOnFocusLost = true From ef9cb2c95836a1ff7eeffe0d46f6cc5afe72b6e7 Mon Sep 17 00:00:00 2001 From: Pasi4K5 Date: Sat, 12 Jun 2021 18:37:31 +0200 Subject: [PATCH 121/157] Rename nested classes --- osu.Game/Overlays/Settings/SettingsNumberBox.cs | 4 ++-- osu.Game/Overlays/Settings/SettingsTextBox.cs | 4 ++-- osu.Game/Rulesets/Mods/ModRandom.cs | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/Settings/SettingsNumberBox.cs b/osu.Game/Overlays/Settings/SettingsNumberBox.cs index 20de35ed87..ca9a8e9c08 100644 --- a/osu.Game/Overlays/Settings/SettingsNumberBox.cs +++ b/osu.Game/Overlays/Settings/SettingsNumberBox.cs @@ -7,13 +7,13 @@ namespace osu.Game.Overlays.Settings { public class SettingsNumberBox : SettingsItem { - protected override Drawable CreateControl() => new OsuSettingsNumberBox + protected override Drawable CreateControl() => new NumberBox { Margin = new MarginPadding { Top = 5 }, RelativeSizeAxes = Axes.X, }; - public class OsuSettingsNumberBox : SettingsTextBox.OsuSettingsTextBox + public class NumberBox : SettingsTextBox.TextBox { protected override bool CanAddCharacter(char character) => char.IsNumber(character); } diff --git a/osu.Game/Overlays/Settings/SettingsTextBox.cs b/osu.Game/Overlays/Settings/SettingsTextBox.cs index efcfb0ec5b..25424e85a1 100644 --- a/osu.Game/Overlays/Settings/SettingsTextBox.cs +++ b/osu.Game/Overlays/Settings/SettingsTextBox.cs @@ -13,14 +13,14 @@ namespace osu.Game.Overlays.Settings { public class SettingsTextBox : SettingsItem { - protected override Drawable CreateControl() => new OsuSettingsTextBox + protected override Drawable CreateControl() => new TextBox { Margin = new MarginPadding { Top = 5 }, RelativeSizeAxes = Axes.X, CommitOnFocusLost = true, }; - public class OsuSettingsTextBox : OsuTextBox + public class TextBox : OsuTextBox { private const float border_thickness = 3; diff --git a/osu.Game/Rulesets/Mods/ModRandom.cs b/osu.Game/Rulesets/Mods/ModRandom.cs index 49e5ec0cbc..e0c3008ae8 100644 --- a/osu.Game/Rulesets/Mods/ModRandom.cs +++ b/osu.Game/Rulesets/Mods/ModRandom.cs @@ -49,7 +49,7 @@ namespace osu.Game.Rulesets.Mods } } - private readonly SettingsNumberBox.OsuSettingsNumberBox seedNumberBox; + private readonly SettingsNumberBox.NumberBox seedNumberBox; public SeedControl() { @@ -75,7 +75,7 @@ namespace osu.Game.Rulesets.Mods { new Drawable[] { - seedNumberBox = new SettingsNumberBox.OsuSettingsNumberBox + seedNumberBox = new SettingsNumberBox.NumberBox { RelativeSizeAxes = Axes.X, CommitOnFocusLost = true From 17347401cf29d825686ab775a471698c5fb68304 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 11:27:45 +0900 Subject: [PATCH 122/157] Remove unused `RankingType` enum We have `BeatmapLeaderboardScope` instead. --- osu.Game/Configuration/RankingType.cs | 20 -------------------- 1 file changed, 20 deletions(-) delete mode 100644 osu.Game/Configuration/RankingType.cs diff --git a/osu.Game/Configuration/RankingType.cs b/osu.Game/Configuration/RankingType.cs deleted file mode 100644 index 7701e1dd1d..0000000000 --- a/osu.Game/Configuration/RankingType.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using System.ComponentModel; - -namespace osu.Game.Configuration -{ - public enum RankingType - { - Local, - - [Description("Global")] - Top, - - [Description("Selected Mods")] - SelectedMod, - Friends, - Country - } -} From 8cf44547802fff912ec0a9ce42032e51df1ac0f3 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 23:50:41 +0900 Subject: [PATCH 123/157] Use `Direction` enum instead of `int` The property is named `scrollingAxis` to distinguish from `direction`, which is of `ScrollingDirection` type (unfortunate name crash). --- .../Scrolling/ScrollingHitObjectContainer.cs | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index d21f30eb30..b2c549244d 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -20,9 +20,9 @@ namespace osu.Game.Rulesets.UI.Scrolling private readonly IBindable direction = new Bindable(); /// - /// 0 for horizontal scroll, 1 for vertical scroll. + /// Whether the scrolling direction is horizontal or vertical. /// - private int scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? 0 : 1; + private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical; /// /// A set of top-level s which have an up-to-date layout. @@ -68,8 +68,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) { - Vector2 localPosition = ToLocalSpace(screenSpacePosition); - return TimeAtPosition(localPosition[scrollingAxis], Time.Current); + Vector2 position = ToLocalSpace(screenSpacePosition); + return TimeAtPosition(scrollingAxis == Direction.Horizontal ? position.X : position.Y, Time.Current); } /// @@ -77,9 +77,9 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public float PositionAtTime(double time, double currentTime) { - float pos = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); - flipPositionIfRequired(ref pos); - return pos; + float position = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + flipPositionIfRequired(ref position); + return position; } /// @@ -94,7 +94,7 @@ namespace osu.Game.Rulesets.UI.Scrolling public Vector2 ScreenSpacePositionAtTime(double time) { float position = PositionAtTime(time, Time.Current); - return scrollingAxis == 0 + return scrollingAxis == Direction.Horizontal ? ToScreenSpace(new Vector2(position, DrawHeight / 2)) : ToScreenSpace(new Vector2(DrawWidth / 2, position)); } @@ -107,7 +107,7 @@ namespace osu.Game.Rulesets.UI.Scrolling return scrollingInfo.Algorithm.GetLength(startTime, endTime, timeRange.Value, scrollLength); } - private float scrollLength => DrawSize[scrollingAxis]; + private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; private void flipPositionIfRequired(ref float position) { @@ -223,7 +223,7 @@ namespace osu.Game.Rulesets.UI.Scrolling if (hitObject.HitObject is IHasDuration e) { float length = LengthAtTime(hitObject.HitObject.StartTime, e.EndTime); - if (scrollingAxis == 0) + if (scrollingAxis == Direction.Horizontal) hitObject.Width = length; else hitObject.Height = length; @@ -242,7 +242,7 @@ namespace osu.Game.Rulesets.UI.Scrolling { float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); - if (scrollingAxis == 0) + if (scrollingAxis == Direction.Horizontal) hitObject.X = position; else hitObject.Y = position; From fdb09ef4d7a7a6791f887f84b4b91ed517fd2b59 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 23:53:01 +0900 Subject: [PATCH 124/157] Simplify `flipPositionIfRequired` using `scrollLength` --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index b2c549244d..283d84e8df 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -114,17 +114,8 @@ namespace osu.Game.Rulesets.UI.Scrolling // We're dealing with coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, // so when scrolling downwards the coordinates need to be flipped. - - switch (scrollingInfo.Direction.Value) - { - case ScrollingDirection.Down: - position = DrawHeight - position; - break; - - case ScrollingDirection.Right: - position = DrawWidth - position; - break; - } + if (direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right) + position = scrollLength - position; } protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable) From 09f1cbde7eb13b8a72f9965ac0ee9ef933d622e3 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 14 Jun 2021 12:41:44 +0900 Subject: [PATCH 125/157] Fix `TimeAtPosition` doc comment --- .../UI/Scrolling/ScrollingHitObjectContainer.cs | 16 ++++++++++------ 1 file changed, 10 insertions(+), 6 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 283d84e8df..061c9aa948 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -53,19 +53,23 @@ namespace osu.Game.Rulesets.UI.Scrolling } /// - /// Given a position along the scrolling axis, return the time within this . + /// Given a position at , return the time of the object corresponding the position. /// - /// The position along the scrolling axis. - /// The time the scrolling speed is used. - public double TimeAtPosition(float position, double referenceTime) + /// + /// If there are multiple valid time values, one arbitrary time is returned. + /// + public double TimeAtPosition(float position, double currentTime) { flipPositionIfRequired(ref position); - return scrollingInfo.Algorithm.TimeAt(position, referenceTime, timeRange.Value, scrollLength); + return scrollingInfo.Algorithm.TimeAt(position, currentTime, timeRange.Value, scrollLength); } /// - /// Given a position in screen space, return the time within this . + /// Given a position at the current time in screen space, return the time of the object corresponding the position. /// + /// + /// If there are multiple valid time values, one arbitrary time is returned. + /// public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) { Vector2 position = ToLocalSpace(screenSpacePosition); From 660bf50dc7ce71115a64a4a8168826bd5cc6cf90 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Mon, 14 Jun 2021 13:10:07 +0900 Subject: [PATCH 126/157] Clarify multiple coordinate systems - Fix wrong position is set for DHOs for down/right scrolling direction. --- .../Scrolling/ScrollingHitObjectContainer.cs | 43 +++++++++---------- 1 file changed, 21 insertions(+), 22 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index 061c9aa948..d75954d77f 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -24,6 +24,11 @@ namespace osu.Game.Rulesets.UI.Scrolling /// private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical; + /// + /// Whether the scrolling direction is the positive-to-negative direction in the local coordinate. + /// + private bool axisInverted => direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right; + /// /// A set of top-level s which have an up-to-date layout. /// @@ -58,10 +63,10 @@ namespace osu.Game.Rulesets.UI.Scrolling /// /// If there are multiple valid time values, one arbitrary time is returned. /// - public double TimeAtPosition(float position, double currentTime) + public double TimeAtPosition(float localPosition, double currentTime) { - flipPositionIfRequired(ref position); - return scrollingInfo.Algorithm.TimeAt(position, currentTime, timeRange.Value, scrollLength); + float scrollPosition = axisInverted ? scrollLength - localPosition : localPosition; + return scrollingInfo.Algorithm.TimeAt(scrollPosition, currentTime, timeRange.Value, scrollLength); } /// @@ -72,8 +77,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public double TimeAtScreenSpacePosition(Vector2 screenSpacePosition) { - Vector2 position = ToLocalSpace(screenSpacePosition); - return TimeAtPosition(scrollingAxis == Direction.Horizontal ? position.X : position.Y, Time.Current); + Vector2 localPosition = ToLocalSpace(screenSpacePosition); + return TimeAtPosition(scrollingAxis == Direction.Horizontal ? localPosition.X : localPosition.Y, Time.Current); } /// @@ -81,9 +86,8 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public float PositionAtTime(double time, double currentTime) { - float position = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); - flipPositionIfRequired(ref position); - return position; + float scrollPosition = scrollingInfo.Algorithm.PositionAt(time, currentTime, timeRange.Value, scrollLength); + return axisInverted ? scrollLength - scrollPosition : scrollPosition; } /// @@ -97,10 +101,10 @@ namespace osu.Game.Rulesets.UI.Scrolling /// public Vector2 ScreenSpacePositionAtTime(double time) { - float position = PositionAtTime(time, Time.Current); + float localPosition = PositionAtTime(time, Time.Current); return scrollingAxis == Direction.Horizontal - ? ToScreenSpace(new Vector2(position, DrawHeight / 2)) - : ToScreenSpace(new Vector2(DrawWidth / 2, position)); + ? ToScreenSpace(new Vector2(localPosition, DrawHeight / 2)) + : ToScreenSpace(new Vector2(DrawWidth / 2, localPosition)); } /// @@ -113,15 +117,6 @@ namespace osu.Game.Rulesets.UI.Scrolling private float scrollLength => scrollingAxis == Direction.Horizontal ? DrawWidth : DrawHeight; - private void flipPositionIfRequired(ref float position) - { - // We're dealing with coordinates in which the position decreases towards the centre of the screen resulting in an increase in start time. - // The scrolling algorithm instead assumes a top anchor meaning an increase in time corresponds to an increase in position, - // so when scrolling downwards the coordinates need to be flipped. - if (direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right) - position = scrollLength - position; - } - protected override void AddDrawable(HitObjectLifetimeEntry entry, DrawableHitObject drawable) { base.AddDrawable(entry, drawable); @@ -237,10 +232,14 @@ namespace osu.Game.Rulesets.UI.Scrolling { float position = PositionAtTime(hitObject.HitObject.StartTime, currentTime); + // The position returned from `PositionAtTime` is assuming the `TopLeft` anchor. + // A correction is needed because the hit objects are using a different anchor for each direction (e.g. `BottomCentre` for `Bottom` direction). + float anchorCorrection = axisInverted ? scrollLength : 0; + if (scrollingAxis == Direction.Horizontal) - hitObject.X = position; + hitObject.X = position - anchorCorrection; else - hitObject.Y = position; + hitObject.Y = position - anchorCorrection; } } } From 564682270a9bb0d49faf095bbad1a919e0915f42 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 13:18:52 +0900 Subject: [PATCH 127/157] Revert "Add nested `PlatformActionContainer` to allow testing of platform actions in visual tests" This reverts commit be91203c92ba7004f0f03b32878b3a4182092584. --- osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index c7edc0174a..01dd7a25c8 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -4,7 +4,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input; using osu.Framework.Testing.Input; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.Sprites; @@ -49,7 +48,7 @@ namespace osu.Game.Tests.Visual InputManager = new ManualInputManager { UseParentInput = true, - Child = new PlatformActionContainer().WithChild(mainContent) + Child = mainContent }, new Container { From 8dd48d48f683823fe511f68fafe29b778a8393fc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:20:23 +0900 Subject: [PATCH 128/157] Add support for song select leaderboard to handle newly imported scores --- osu.Game/Online/Leaderboards/Leaderboard.cs | 6 +++--- .../Select/Leaderboards/BeatmapLeaderboard.cs | 21 ++++++++++++++++++- 2 files changed, 23 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index d18f189a70..c7610e0ba6 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -44,9 +44,9 @@ namespace osu.Game.Online.Leaderboards protected override Container Content => content; - private IEnumerable scores; + private ICollection scores; - public IEnumerable Scores + public ICollection Scores { get => scores; set @@ -290,7 +290,7 @@ namespace osu.Game.Online.Leaderboards getScoresRequest = FetchScores(scores => Schedule(() => { - Scores = scores; + Scores = scores.ToArray(); PlaceholderState = Scores.Any() ? PlaceholderState.Successful : PlaceholderState.NoScores; })); diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 8ddae67dba..2bbcb6678f 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -44,6 +44,8 @@ namespace osu.Game.Screens.Select.Leaderboards private IBindable> itemRemoved; + private IBindable> itemAdded; + /// /// Whether to apply the game's currently selected mods as a filter when retrieving scores. /// @@ -85,6 +87,9 @@ namespace osu.Game.Screens.Select.Leaderboards itemRemoved = scoreManager.ItemRemoved.GetBoundCopy(); itemRemoved.BindValueChanged(onScoreRemoved); + + itemAdded = scoreManager.ItemUpdated.GetBoundCopy(); + itemAdded.BindValueChanged(onScoreAdded); } protected override void Reset() @@ -93,7 +98,21 @@ namespace osu.Game.Screens.Select.Leaderboards TopScore = null; } - private void onScoreRemoved(ValueChangedEvent> score) => Schedule(RefreshScores); + private void onScoreRemoved(ValueChangedEvent> score) + { + if (Scope != BeatmapLeaderboardScope.Local) + return; + + Scheduler.AddOnce(RefreshScores); + } + + private void onScoreAdded(ValueChangedEvent> score) + { + if (Scope != BeatmapLeaderboardScope.Local) + return; + + Scheduler.AddOnce(RefreshScores); + } protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; From fc442713bbd46e072c8166db9fd0dc19fdea03c8 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:26:40 +0900 Subject: [PATCH 129/157] Debounce schedule at base class --- osu.Game/Online/Leaderboards/Leaderboard.cs | 10 +++++----- .../Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 4 ++-- 2 files changed, 7 insertions(+), 7 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index c7610e0ba6..70e38e421d 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -126,7 +126,7 @@ namespace osu.Game.Online.Leaderboards return; scope = value; - UpdateScores(); + RefreshScores(); } } @@ -154,7 +154,7 @@ namespace osu.Game.Online.Leaderboards case PlaceholderState.NetworkFailure: replacePlaceholder(new ClickablePlaceholder(@"Couldn't fetch scores!", FontAwesome.Solid.Sync) { - Action = UpdateScores, + Action = RefreshScores }); break; @@ -254,8 +254,6 @@ namespace osu.Game.Online.Leaderboards apiState.BindValueChanged(onlineStateChanged, true); } - public void RefreshScores() => UpdateScores(); - private APIRequest getScoresRequest; protected abstract bool IsOnlineScope { get; } @@ -267,12 +265,14 @@ namespace osu.Game.Online.Leaderboards case APIState.Online: case APIState.Offline: if (IsOnlineScope) - UpdateScores(); + RefreshScores(); break; } }); + public void RefreshScores() => Scheduler.AddOnce(UpdateScores); + protected void UpdateScores() { // don't display any scores or placeholder until the first Scores_Set has been called. diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 2bbcb6678f..d6967c17a8 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -103,7 +103,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (Scope != BeatmapLeaderboardScope.Local) return; - Scheduler.AddOnce(RefreshScores); + RefreshScores(); } private void onScoreAdded(ValueChangedEvent> score) @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (Scope != BeatmapLeaderboardScope.Local) return; - Scheduler.AddOnce(RefreshScores); + RefreshScores(); } protected override bool IsOnlineScope => Scope != BeatmapLeaderboardScope.Local; From f8b09b7c81bfa370ed4765133c1231f520b21163 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:26:54 +0900 Subject: [PATCH 130/157] Avoid refresh if score is not related to current display --- .../Select/Leaderboards/BeatmapLeaderboard.cs | 20 +++++++++++-------- 1 file changed, 12 insertions(+), 8 deletions(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index d6967c17a8..587a35c480 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -98,18 +98,22 @@ namespace osu.Game.Screens.Select.Leaderboards TopScore = null; } - private void onScoreRemoved(ValueChangedEvent> score) + private void onScoreRemoved(ValueChangedEvent> score) => + scoreStoreChanged(score); + + private void onScoreAdded(ValueChangedEvent> score) => + scoreStoreChanged(score); + + private void scoreStoreChanged(ValueChangedEvent> score) { if (Scope != BeatmapLeaderboardScope.Local) return; - RefreshScores(); - } - - private void onScoreAdded(ValueChangedEvent> score) - { - if (Scope != BeatmapLeaderboardScope.Local) - return; + if (score.NewValue.TryGetTarget(out var scoreInfo)) + { + if (Beatmap.ID != scoreInfo.BeatmapInfoID) + return; + } RefreshScores(); } From b06477a1f59fbf00546dd84fce6af2b187cf4bb0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 14:35:24 +0900 Subject: [PATCH 131/157] Split out tests into individual test methods --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 22 ++++++++++++++++++- 1 file changed, 21 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 67cd720260..2a4ad48568 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Beatmaps; @@ -37,18 +38,37 @@ namespace osu.Game.Tests.Visual.SongSelect Size = new Vector2(550f, 450f), Scope = BeatmapLeaderboardScope.Global, }); + } + [Test] + public void TestScoresDisplay() + { AddStep(@"New Scores", newScores); + } + + [Test] + public void TestPersonalBest() + { AddStep(@"Show personal best", showPersonalBest); + AddStep("null personal best position", showPersonalBestWithNullPosition); + } + + [Test] + public void TestPlaceholderStates() + { AddStep(@"Empty Scores", () => leaderboard.SetRetrievalState(PlaceholderState.NoScores)); AddStep(@"Network failure", () => leaderboard.SetRetrievalState(PlaceholderState.NetworkFailure)); AddStep(@"No supporter", () => leaderboard.SetRetrievalState(PlaceholderState.NotSupporter)); AddStep(@"Not logged in", () => leaderboard.SetRetrievalState(PlaceholderState.NotLoggedIn)); AddStep(@"Unavailable", () => leaderboard.SetRetrievalState(PlaceholderState.Unavailable)); AddStep(@"None selected", () => leaderboard.SetRetrievalState(PlaceholderState.NoneSelected)); + } + + [Test] + public void TestBeatmapStates() + { foreach (BeatmapSetOnlineStatus status in Enum.GetValues(typeof(BeatmapSetOnlineStatus))) AddStep($"{status} beatmap", () => showBeatmapWithStatus(status)); - AddStep("null personal best position", showPersonalBestWithNullPosition); } private void showPersonalBestWithNullPosition() From 83402a70db9088e6ddf160b8ceb3de483aedcc28 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 15:06:24 +0900 Subject: [PATCH 132/157] Fix potential null ref when no beatmap is selected --- osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs index 587a35c480..a86a614a05 100644 --- a/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs +++ b/osu.Game/Screens/Select/Leaderboards/BeatmapLeaderboard.cs @@ -111,7 +111,7 @@ namespace osu.Game.Screens.Select.Leaderboards if (score.NewValue.TryGetTarget(out var scoreInfo)) { - if (Beatmap.ID != scoreInfo.BeatmapInfoID) + if (Beatmap?.ID != scoreInfo.BeatmapInfoID) return; } From fcb0b8d825c887cb78937471e8877e2fec86c043 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 15:06:33 +0900 Subject: [PATCH 133/157] Add test coverage --- .../SongSelect/TestSceneBeatmapLeaderboard.cs | 110 +++++++++++++++--- 1 file changed, 94 insertions(+), 16 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs index 2a4ad48568..184a2e59da 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestSceneBeatmapLeaderboard.cs @@ -2,16 +2,22 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using NUnit.Framework; using osu.Framework.Allocation; +using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Platform; +using osu.Framework.Testing; using osu.Game.Beatmaps; using osu.Game.Online.Leaderboards; using osu.Game.Overlays; +using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; using osu.Game.Rulesets.Osu.Mods; using osu.Game.Scoring; using osu.Game.Screens.Select.Leaderboards; +using osu.Game.Tests.Resources; using osu.Game.Users; using osuTK; @@ -24,26 +30,73 @@ namespace osu.Game.Tests.Visual.SongSelect [Cached] private readonly DialogOverlay dialogOverlay; + private ScoreManager scoreManager; + + private RulesetStore rulesetStore; + private BeatmapManager beatmapManager; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + { + var dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + + dependencies.Cache(rulesetStore = new RulesetStore(ContextFactory)); + dependencies.Cache(beatmapManager = new BeatmapManager(LocalStorage, ContextFactory, rulesetStore, null, dependencies.Get(), Resources, dependencies.Get(), Beatmap.Default)); + dependencies.Cache(scoreManager = new ScoreManager(rulesetStore, () => beatmapManager, LocalStorage, null, ContextFactory)); + + return dependencies; + } + public TestSceneBeatmapLeaderboard() { - Add(dialogOverlay = new DialogOverlay + AddRange(new Drawable[] { - Depth = -1 - }); - - Add(leaderboard = new FailableLeaderboard - { - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - Size = new Vector2(550f, 450f), - Scope = BeatmapLeaderboardScope.Global, + dialogOverlay = new DialogOverlay + { + Depth = -1 + }, + leaderboard = new FailableLeaderboard + { + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + Size = new Vector2(550f, 450f), + Scope = BeatmapLeaderboardScope.Global, + } }); } [Test] - public void TestScoresDisplay() + public void TestLocalScoresDisplay() { - AddStep(@"New Scores", newScores); + BeatmapInfo beatmapInfo = null; + + AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Local); + + AddStep(@"Set beatmap", () => + { + beatmapManager.Import(TestResources.GetQuickTestBeatmapForImport()).Wait(); + beatmapInfo = beatmapManager.GetAllUsableBeatmapSets().First().Beatmaps.First(); + + leaderboard.Beatmap = beatmapInfo; + }); + + clearScores(); + checkCount(0); + + loadMoreScores(() => beatmapInfo); + checkCount(10); + + loadMoreScores(() => beatmapInfo); + checkCount(20); + + clearScores(); + checkCount(0); + } + + [Test] + public void TestGlobalScoresDisplay() + { + AddStep(@"Set scope", () => leaderboard.Scope = BeatmapLeaderboardScope.Global); + AddStep(@"New Scores", () => leaderboard.Scores = generateSampleScores(null)); } [Test] @@ -116,9 +169,26 @@ namespace osu.Game.Tests.Visual.SongSelect }; } - private void newScores() + private void loadMoreScores(Func beatmapInfo) { - var scores = new[] + AddStep(@"Load new scores via manager", () => + { + foreach (var score in generateSampleScores(beatmapInfo())) + scoreManager.Import(score).Wait(); + }); + } + + private void clearScores() + { + AddStep("Clear all scores", () => scoreManager.Delete(scoreManager.GetAllUsableScores())); + } + + private void checkCount(int expected) => + AddUntilStep("Correct count displayed", () => leaderboard.ChildrenOfType().Count() == expected); + + private static ScoreInfo[] generateSampleScores(BeatmapInfo beatmap) + { + return new[] { new ScoreInfo { @@ -127,6 +197,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 6602580, @@ -145,6 +216,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 4608074, @@ -163,6 +235,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 1014222, @@ -181,6 +254,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 1541390, @@ -199,6 +273,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 2243452, @@ -217,6 +292,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 2705430, @@ -235,6 +311,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 7151382, @@ -253,6 +330,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 2051389, @@ -271,6 +349,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 6169483, @@ -289,6 +368,7 @@ namespace osu.Game.Tests.Visual.SongSelect MaxCombo = 244, TotalScore = 1707827, //Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), }, + Beatmap = beatmap, User = new User { Id = 6702666, @@ -301,8 +381,6 @@ namespace osu.Game.Tests.Visual.SongSelect }, }, }; - - leaderboard.Scores = scores; } private void showBeatmapWithStatus(BeatmapSetOnlineStatus status) From aa5dae84b2ad3c20580d0a5f7a44aa880c9c1603 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 14 Jun 2021 16:51:17 +0900 Subject: [PATCH 134/157] Make all localisation class strings verbatim --- osu.Game/Localisation/ChatStrings.cs | 6 +++--- osu.Game/Localisation/CommonStrings.cs | 4 ++-- osu.Game/Localisation/Language.cs | 4 ++-- osu.Game/Localisation/NotificationsStrings.cs | 6 +++--- osu.Game/Localisation/NowPlayingStrings.cs | 6 +++--- osu.Game/Localisation/SettingsStrings.cs | 6 +++--- 6 files changed, 16 insertions(+), 16 deletions(-) diff --git a/osu.Game/Localisation/ChatStrings.cs b/osu.Game/Localisation/ChatStrings.cs index daddb602ad..636351470b 100644 --- a/osu.Game/Localisation/ChatStrings.cs +++ b/osu.Game/Localisation/ChatStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class ChatStrings { - private const string prefix = "osu.Game.Localisation.Chat"; + private const string prefix = @"osu.Game.Localisation.Chat"; /// /// "chat" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "chat"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"chat"); /// /// "join the real-time discussion" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "join the real-time discussion"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"join the real-time discussion"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index f448158191..ced0d80955 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -7,12 +7,12 @@ namespace osu.Game.Localisation { public static class CommonStrings { - private const string prefix = "osu.Game.Localisation.Common"; + private const string prefix = @"osu.Game.Localisation.Common"; /// /// "Cancel" /// - public static LocalisableString Cancel => new TranslatableString(getKey("cancel"), "Cancel"); + public static LocalisableString Cancel => new TranslatableString(getKey(@"cancel"), @"Cancel"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/Language.cs b/osu.Game/Localisation/Language.cs index edcf264c7f..a3e845f229 100644 --- a/osu.Game/Localisation/Language.cs +++ b/osu.Game/Localisation/Language.cs @@ -7,10 +7,10 @@ namespace osu.Game.Localisation { public enum Language { - [Description("English")] + [Description(@"English")] en, - [Description("日本語")] + [Description(@"日本語")] ja } } diff --git a/osu.Game/Localisation/NotificationsStrings.cs b/osu.Game/Localisation/NotificationsStrings.cs index 092eec3a6b..ba28ef5560 100644 --- a/osu.Game/Localisation/NotificationsStrings.cs +++ b/osu.Game/Localisation/NotificationsStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class NotificationsStrings { - private const string prefix = "osu.Game.Localisation.Notifications"; + private const string prefix = @"osu.Game.Localisation.Notifications"; /// /// "notifications" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "notifications"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"notifications"); /// /// "waiting for 'ya" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "waiting for 'ya"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"waiting for 'ya"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/NowPlayingStrings.cs b/osu.Game/Localisation/NowPlayingStrings.cs index d742a56895..47646b0f68 100644 --- a/osu.Game/Localisation/NowPlayingStrings.cs +++ b/osu.Game/Localisation/NowPlayingStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class NowPlayingStrings { - private const string prefix = "osu.Game.Localisation.NowPlaying"; + private const string prefix = @"osu.Game.Localisation.NowPlaying"; /// /// "now playing" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "now playing"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"now playing"); /// /// "manage the currently playing track" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "manage the currently playing track"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"manage the currently playing track"); private static string getKey(string key) => $"{prefix}:{key}"; } diff --git a/osu.Game/Localisation/SettingsStrings.cs b/osu.Game/Localisation/SettingsStrings.cs index cfbd392691..f4b417fa28 100644 --- a/osu.Game/Localisation/SettingsStrings.cs +++ b/osu.Game/Localisation/SettingsStrings.cs @@ -7,17 +7,17 @@ namespace osu.Game.Localisation { public static class SettingsStrings { - private const string prefix = "osu.Game.Localisation.Settings"; + private const string prefix = @"osu.Game.Localisation.Settings"; /// /// "settings" /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey("header_title"), "settings"); + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"settings"); /// /// "change the way osu! behaves" /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey("header_description"), "change the way osu! behaves"); + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"change the way osu! behaves"); private static string getKey(string key) => $"{prefix}:{key}"; } From b327baa4dea5812234c8ef9754c61a0bfbfcba61 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Mon, 14 Jun 2021 17:47:31 +0900 Subject: [PATCH 135/157] Match any arbitrary assembly for localisations --- .../ResourceManagerLocalisationStore.cs | 25 ++++++++++++++++++- 1 file changed, 24 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs index 7b21e1af42..a35ce7a9c8 100644 --- a/osu.Game/Localisation/ResourceManagerLocalisationStore.cs +++ b/osu.Game/Localisation/ResourceManagerLocalisationStore.cs @@ -5,6 +5,7 @@ using System; using System.Collections.Generic; using System.Globalization; using System.IO; +using System.Linq; using System.Resources; using System.Threading.Tasks; using osu.Framework.Localisation; @@ -34,7 +35,29 @@ namespace osu.Game.Localisation lock (resourceManagers) { if (!resourceManagers.TryGetValue(ns, out var manager)) - resourceManagers[ns] = manager = new ResourceManager(ns, GetType().Assembly); + { + var loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies(); + + // Traverse backwards through periods in the namespace to find a matching assembly. + string assemblyName = ns; + + while (!string.IsNullOrEmpty(assemblyName)) + { + var matchingAssembly = loadedAssemblies.FirstOrDefault(asm => asm.GetName().Name == assemblyName); + + if (matchingAssembly != null) + { + resourceManagers[ns] = manager = new ResourceManager(ns, matchingAssembly); + break; + } + + int lastIndex = Math.Max(0, assemblyName.LastIndexOf('.')); + assemblyName = assemblyName.Substring(0, lastIndex); + } + } + + if (manager == null) + return null; try { From 13d0eaa9fe9b7d418d544cf35ea7d0fef55ab04f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 14 Jun 2021 19:03:31 +0900 Subject: [PATCH 136/157] Update framework --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index 13d45835be..c020b1d783 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -52,6 +52,6 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 7eb3c84582..a7bd5f2e9f 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -34,7 +34,7 @@ all runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 3e8facaf6e..5b3efb4ba4 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -70,7 +70,7 @@ - + @@ -93,7 +93,7 @@ - + From cb1e2e3d9785748718a37c43f4b01c8e9c704342 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Jun 2021 21:51:32 +0200 Subject: [PATCH 137/157] Improve xmldoc --- .../Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs index d75954d77f..94cc7ed095 100644 --- a/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs +++ b/osu.Game/Rulesets/UI/Scrolling/ScrollingHitObjectContainer.cs @@ -25,8 +25,12 @@ namespace osu.Game.Rulesets.UI.Scrolling private Direction scrollingAxis => direction.Value == ScrollingDirection.Left || direction.Value == ScrollingDirection.Right ? Direction.Horizontal : Direction.Vertical; /// - /// Whether the scrolling direction is the positive-to-negative direction in the local coordinate. + /// The scrolling axis is inverted if objects temporally farther in the future have a smaller position value across the scrolling axis. /// + /// + /// is inverted, because given two objects, one of which is at the current time and one of which is 1000ms in the future, + /// in the current time instant the future object is spatially above the current object, and therefore has a smaller value of the Y coordinate of its position. + /// private bool axisInverted => direction.Value == ScrollingDirection.Down || direction.Value == ScrollingDirection.Right; /// @@ -58,7 +62,7 @@ namespace osu.Game.Rulesets.UI.Scrolling } /// - /// Given a position at , return the time of the object corresponding the position. + /// Given a position at , return the time of the object corresponding to the position. /// /// /// If there are multiple valid time values, one arbitrary time is returned. From 9d9c5902bbe616ffcfdc53b116f907cdb3644f42 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 14 Jun 2021 22:46:56 +0200 Subject: [PATCH 138/157] Temporarily disable `dotnet format` to unblock CI --- appveyor.yml | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/appveyor.yml b/appveyor.yml index a4a0cedc66..845751ef07 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -17,7 +17,11 @@ build: publish_nuget: true after_build: - ps: dotnet tool restore - - ps: dotnet format --dry-run --check + + # Temporarily disabled until the tool is upgraded to 5.0. + # The version specified in .config/dotnet-tools.json (3.1.37601) won't run on .NET hosts >=5.0.7. + # - ps: dotnet format --dry-run --check + - ps: .\InspectCode.ps1 test: assemblies: From f6c6eea6dce32a50514fb3713f4ef301c0f1c1ba Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 11:14:35 +0900 Subject: [PATCH 139/157] Make PresentScore() only consider replay hash --- osu.Game/OsuGame.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 019d3b3cd0..1466d685d6 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -426,9 +426,8 @@ namespace osu.Game { // The given ScoreInfo may have missing properties if it was retrieved from online data. Re-retrieve it from the database // to ensure all the required data for presenting a replay are present. - var databasedScoreInfo = score.OnlineScoreID != null - ? ScoreManager.Query(s => s.OnlineScoreID == score.OnlineScoreID) - : ScoreManager.Query(s => s.Hash == score.Hash); + // Todo: This should use the OnlineScoreID if available, however lazer scores are imported without an OnlineScoreID for the time being (see Player.ImportScore()). + var databasedScoreInfo = ScoreManager.Query(s => s.Hash == score.Hash); if (databasedScoreInfo == null) { From eb4c093371267c6446d6d37ed8a51cfb42690db6 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 14:06:17 +0900 Subject: [PATCH 140/157] Use hash as fallback --- osu.Game/OsuGame.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 1466d685d6..b226932555 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -427,7 +427,12 @@ namespace osu.Game // The given ScoreInfo may have missing properties if it was retrieved from online data. Re-retrieve it from the database // to ensure all the required data for presenting a replay are present. // Todo: This should use the OnlineScoreID if available, however lazer scores are imported without an OnlineScoreID for the time being (see Player.ImportScore()). - var databasedScoreInfo = ScoreManager.Query(s => s.Hash == score.Hash); + ScoreInfo databasedScoreInfo = null; + + if (score.OnlineScoreID != null) + databasedScoreInfo = ScoreManager.Query(s => s.OnlineScoreID == score.OnlineScoreID); + + databasedScoreInfo ??= ScoreManager.Query(s => s.Hash == score.Hash); if (databasedScoreInfo == null) { From 579a4aa9c8032da0c18fda6f7de4ea34abd33157 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 14:10:09 +0900 Subject: [PATCH 141/157] Remove comment --- osu.Game/OsuGame.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index b226932555..da104852e3 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -426,7 +426,6 @@ namespace osu.Game { // The given ScoreInfo may have missing properties if it was retrieved from online data. Re-retrieve it from the database // to ensure all the required data for presenting a replay are present. - // Todo: This should use the OnlineScoreID if available, however lazer scores are imported without an OnlineScoreID for the time being (see Player.ImportScore()). ScoreInfo databasedScoreInfo = null; if (score.OnlineScoreID != null) From f39dbb8b6e3dcdbc838d42a9a7a9a69bf1b0fe05 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 21:42:09 +0900 Subject: [PATCH 142/157] Upgrade cfs --- .config/dotnet-tools.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 84673fe2ba..e72bed602e 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -27,7 +27,7 @@ ] }, "codefilesanity": { - "version": "15.0.0", + "version": "0.0.36", "commands": [ "CodeFileSanity" ] @@ -39,4 +39,4 @@ ] } } -} +} \ No newline at end of file From e29e2328f89d14f79bcf1d09fce5b7126098b90a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 21:45:02 +0900 Subject: [PATCH 143/157] Inline inspection actions into appveyor.yml --- appveyor.yml | 21 ++++++++++++++------- 1 file changed, 14 insertions(+), 7 deletions(-) diff --git a/appveyor.yml b/appveyor.yml index 845751ef07..accc913bf5 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -1,28 +1,35 @@ clone_depth: 1 version: '{branch}-{build}' image: Visual Studio 2019 +cache: + - '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml' + dotnet_csproj: patch: true file: 'osu.Game\osu.Game.csproj' # Use wildcard when it's able to exclude Xamarin projects version: '0.0.{build}' -cache: - - '%LOCALAPPDATA%\NuGet\v3-cache -> appveyor.yml' + before_build: - - ps: dotnet --info # Useful when version mismatch between CI and local - - ps: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects + - cmd: dotnet --info # Useful when version mismatch between CI and local + - cmd: nuget restore -verbosity quiet # Only nuget.exe knows both new (.NET Core) and old (Xamarin) projects + build: project: osu.sln parallel: true verbosity: minimal publish_nuget: true + after_build: - - ps: dotnet tool restore + - cmd: dotnet tool restore # Temporarily disabled until the tool is upgraded to 5.0. # The version specified in .config/dotnet-tools.json (3.1.37601) won't run on .NET hosts >=5.0.7. - # - ps: dotnet format --dry-run --check + # - cmd: dotnet format --dry-run --check + + - cmd: dotnet CodeFileSanity + - cmd: dotnet jb inspectcode "osu.Desktop.slnf" --output="temp/inspectcodereport.xml" --caches-home="temp/inspectcode" --verbosity=WARN + - cmd: dotnet nvika parsereport "temp/inspectcodereport.xml" --treatwarningsaserrors - - ps: .\InspectCode.ps1 test: assemblies: except: From 9fcf10536435688241f783ef2f39160e0141f529 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 21:46:23 +0900 Subject: [PATCH 144/157] Remove cake --- .config/dotnet-tools.json | 6 ------ .vscode/launch.json | 14 ------------- InspectCode.ps1 | 27 -------------------------- build/Desktop.proj | 17 ---------------- build/InspectCode.cake | 41 --------------------------------------- cake.config | 5 ----- 6 files changed, 110 deletions(-) delete mode 100644 InspectCode.ps1 delete mode 100644 build/Desktop.proj delete mode 100644 build/InspectCode.cake delete mode 100644 cake.config diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index e72bed602e..1dca8b3859 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -2,12 +2,6 @@ "version": 1, "isRoot": true, "tools": { - "cake.tool": { - "version": "0.35.0", - "commands": [ - "dotnet-cake" - ] - }, "dotnet-format": { "version": "3.1.37601", "commands": [ diff --git a/.vscode/launch.json b/.vscode/launch.json index afd997f91d..1b590008cd 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -113,20 +113,6 @@ "cwd": "${workspaceRoot}", "preLaunchTask": "Build benchmarks", "console": "internalConsole" - }, - { - "name": "Cake: Debug Script", - "type": "coreclr", - "request": "launch", - "program": "${workspaceRoot}/build/tools/Cake.CoreCLR/0.30.0/Cake.dll", - "args": [ - "${workspaceRoot}/build/build.cake", - "--debug", - "--verbosity=diagnostic" - ], - "cwd": "${workspaceRoot}/build", - "stopAtEntry": true, - "externalConsole": false } ] } diff --git a/InspectCode.ps1 b/InspectCode.ps1 deleted file mode 100644 index 6ed935fdbb..0000000000 --- a/InspectCode.ps1 +++ /dev/null @@ -1,27 +0,0 @@ -[CmdletBinding()] -Param( - [string]$Target, - [string]$Configuration, - [ValidateSet("Quiet", "Minimal", "Normal", "Verbose", "Diagnostic")] - [string]$Verbosity, - [switch]$ShowDescription, - [Alias("WhatIf", "Noop")] - [switch]$DryRun, - [Parameter(Position = 0, Mandatory = $false, ValueFromRemainingArguments = $true)] - [string[]]$ScriptArgs -) - -# Build Cake arguments -$cakeArguments = ""; -if ($Target) { $cakeArguments += "-target=$Target" } -if ($Configuration) { $cakeArguments += "-configuration=$Configuration" } -if ($Verbosity) { $cakeArguments += "-verbosity=$Verbosity" } -if ($ShowDescription) { $cakeArguments += "-showdescription" } -if ($DryRun) { $cakeArguments += "-dryrun" } -if ($Experimental) { $cakeArguments += "-experimental" } -$cakeArguments += $ScriptArgs - -dotnet tool restore -dotnet cake ./build/InspectCode.cake --bootstrap -dotnet cake ./build/InspectCode.cake $cakeArguments -exit $LASTEXITCODE \ No newline at end of file diff --git a/build/Desktop.proj b/build/Desktop.proj deleted file mode 100644 index b1c6b065e8..0000000000 --- a/build/Desktop.proj +++ /dev/null @@ -1,17 +0,0 @@ - - - - - - - - - - - - - - - - - \ No newline at end of file diff --git a/build/InspectCode.cake b/build/InspectCode.cake deleted file mode 100644 index 6836d9071b..0000000000 --- a/build/InspectCode.cake +++ /dev/null @@ -1,41 +0,0 @@ -#addin "nuget:?package=CodeFileSanity&version=0.0.36" - -/////////////////////////////////////////////////////////////////////////////// -// ARGUMENTS -/////////////////////////////////////////////////////////////////////////////// - -var target = Argument("target", "CodeAnalysis"); -var configuration = Argument("configuration", "Release"); - -var rootDirectory = new DirectoryPath(".."); -var sln = rootDirectory.CombineWithFilePath("osu.sln"); -var desktopSlnf = rootDirectory.CombineWithFilePath("osu.Desktop.slnf"); - -/////////////////////////////////////////////////////////////////////////////// -// TASKS -/////////////////////////////////////////////////////////////////////////////// - -Task("InspectCode") - .Does(() => { - var inspectcodereport = "inspectcodereport.xml"; - var cacheDir = "inspectcode"; - var verbosity = AppVeyor.IsRunningOnAppVeyor ? "WARN" : "INFO"; // Don't flood CI output - - DotNetCoreTool(rootDirectory.FullPath, - "jb", $@"inspectcode ""{desktopSlnf}"" --output=""{inspectcodereport}"" --caches-home=""{cacheDir}"" --verbosity={verbosity}"); - DotNetCoreTool(rootDirectory.FullPath, "nvika", $@"parsereport ""{inspectcodereport}"" --treatwarningsaserrors"); - }); - -Task("CodeFileSanity") - .Does(() => { - ValidateCodeSanity(new ValidateCodeSanitySettings { - RootDirectory = rootDirectory.FullPath, - IsAppveyorBuild = AppVeyor.IsRunningOnAppVeyor - }); - }); - -Task("CodeAnalysis") - .IsDependentOn("CodeFileSanity") - .IsDependentOn("InspectCode"); - -RunTarget(target); \ No newline at end of file diff --git a/cake.config b/cake.config deleted file mode 100644 index 187d825591..0000000000 --- a/cake.config +++ /dev/null @@ -1,5 +0,0 @@ - -[Nuget] -Source=https://api.nuget.org/v3/index.json -UseInProcessClient=true -LoadDependencies=true From 04e8703eeea79e71790a4f0efc8c1ece02a788f0 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 21:59:18 +0900 Subject: [PATCH 145/157] Add github actions workflows --- .config/.github/workflows/ci.yml | 95 ++++++++++++++++++++++ .config/.github/workflows/report-nunit.yml | 31 +++++++ 2 files changed, 126 insertions(+) create mode 100644 .config/.github/workflows/ci.yml create mode 100644 .config/.github/workflows/report-nunit.yml diff --git a/.config/.github/workflows/ci.yml b/.config/.github/workflows/ci.yml new file mode 100644 index 0000000000..0be3f64ab3 --- /dev/null +++ b/.config/.github/workflows/ci.yml @@ -0,0 +1,95 @@ +on: [push, pull_request] +name: Continuous Integration + +jobs: + test: + name: Test + runs-on: ${{matrix.os.fullname}} + env: + OSU_EXECUTION_MODE: ${{matrix.threadingMode}} + strategy: + fail-fast: false + matrix: + os: + - { prettyname: Windows, fullname: windows-latest } + - { prettyname: macOS, fullname: macos-latest } + - { prettyname: Linux, fullname: ubuntu-latest } + threadingMode: ['SingleThread', 'MultiThreaded'] + steps: + - name: Checkout + uses: actions/checkout@v2 + + - name: Install .NET 5.0.x + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "5.0.x" + + # FIXME: libavformat is not included in Ubuntu. Let's fix that. + # https://github.com/ppy/osu-framework/issues/4349 + # Remove this once https://github.com/actions/virtual-environments/issues/3306 has been resolved. + - name: Install libavformat-dev + if: ${{matrix.os.fullname == 'ubuntu-latest'}} + run: | + sudo apt-get update && \ + sudo apt-get -y install libavformat-dev + + - name: Compile + run: dotnet build -c Debug -warnaserror osu.Desktop.slnf + + - name: Test + run: dotnet test $pwd/*.Tests/bin/Debug/*/*.Tests.dll --logger "trx;LogFileName=TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx" + shell: pwsh + + # Attempt to upload results even if test fails. + # https://docs.github.com/en/actions/reference/context-and-expression-syntax-for-github-actions#always + - name: Upload Test Results + uses: actions/upload-artifact@v2 + if: ${{ always() }} + with: + name: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}} + path: ${{github.workspace}}/TestResults/TestResults-${{matrix.os.prettyname}}-${{matrix.threadingMode}}.trx + + inspect-code: + name: Code Quality + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@v2 + + # FIXME: Tools won't run in .NET 5.0 unless you install 3.1.x LTS side by side. + # https://itnext.io/how-to-support-multiple-net-sdks-in-github-actions-workflows-b988daa884e + - name: Install .NET 3.1.x LTS + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "3.1.x" + + - name: Install .NET 5.0.x + uses: actions/setup-dotnet@v1 + with: + dotnet-version: "5.0.x" + + - name: Restore Tools + run: dotnet tool restore + + - name: Restore Packages + run: dotnet restore + + - name: CodeFileSanity + run: | + # TODO: Add ignore filters and GitHub Workflow Command Reporting in CFS. That way we don't have to do this workaround. + # FIXME: Suppress warnings from templates project + dotnet codefilesanity | while read -r line; do + echo "::warning::$line" + done + + # Temporarily disabled due to test failures, but it won't work anyway until the tool is upgraded. + # - name: .NET Format (Dry Run) + # run: dotnet format --dry-run --check + + - name: InspectCode + run: dotnet jb inspectcode $(pwd)/osu.Desktop.slnf --output=$(pwd)/inspectcodereport.xml --cachesDir=$(pwd)/inspectcode --verbosity=WARN + + - name: ReSharper + uses: glassechidna/resharper-action@master + with: + report: ${{github.workspace}}/inspectcodereport.xml diff --git a/.config/.github/workflows/report-nunit.yml b/.config/.github/workflows/report-nunit.yml new file mode 100644 index 0000000000..381d2d49c5 --- /dev/null +++ b/.config/.github/workflows/report-nunit.yml @@ -0,0 +1,31 @@ +# This is a workaround to allow PRs to report their coverage. This will run inside the base repository. +# See: +# * https://github.com/dorny/test-reporter#recommended-setup-for-public-repositories +# * https://docs.github.com/en/actions/reference/authentication-in-a-workflow#permissions-for-the-github_token +name: Annotate CI run with test results +on: + workflow_run: + workflows: ["Continuous Integration"] + types: + - completed +jobs: + annotate: + name: Annotate CI run with test results + runs-on: ubuntu-latest + if: ${{ github.event.workflow_run.conclusion != 'cancelled' }} + strategy: + fail-fast: false + matrix: + os: + - { prettyname: Windows } + - { prettyname: macOS } + - { prettyname: Linux } + threadingMode: ['SingleThread', 'MultiThreaded'] + steps: + - name: Annotate CI run with test results + uses: dorny/test-reporter@v1.4.2 + with: + artifact: osu-test-results-${{matrix.os.prettyname}}-${{matrix.threadingMode}} + name: Test Results (${{matrix.os.prettyname}}, ${{matrix.threadingMode}}) + path: "*.trx" + reporter: dotnet-trx From 5283948a6d2021d208609003fab4c553f4af9ffa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 22:05:13 +0900 Subject: [PATCH 146/157] Fix incorrect directory --- {.config/.github => .github}/workflows/ci.yml | 0 {.config/.github => .github}/workflows/report-nunit.yml | 0 2 files changed, 0 insertions(+), 0 deletions(-) rename {.config/.github => .github}/workflows/ci.yml (100%) rename {.config/.github => .github}/workflows/report-nunit.yml (100%) diff --git a/.config/.github/workflows/ci.yml b/.github/workflows/ci.yml similarity index 100% rename from .config/.github/workflows/ci.yml rename to .github/workflows/ci.yml diff --git a/.config/.github/workflows/report-nunit.yml b/.github/workflows/report-nunit.yml similarity index 100% rename from .config/.github/workflows/report-nunit.yml rename to .github/workflows/report-nunit.yml From a85a592f70245b01f8bde3db136f913912da67c4 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 15 Jun 2021 16:16:25 +0300 Subject: [PATCH 147/157] Add lookup for spinner background colour --- osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs b/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs index 4e6d3ef0e4..f7ba8b9fc4 100644 --- a/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs +++ b/osu.Game.Rulesets.Osu/Skinning/OsuSkinColour.cs @@ -7,6 +7,7 @@ namespace osu.Game.Rulesets.Osu.Skinning { SliderTrackOverride, SliderBorder, - SliderBall + SliderBall, + SpinnerBackground, } } From 52145c9237815f56c211f9e6d7780b646ee98a58 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Tue, 15 Jun 2021 16:17:05 +0300 Subject: [PATCH 148/157] Assign skinnable colour to `spinner-background` with correct default --- osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs index 19cb55c16e..d80e061662 100644 --- a/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs +++ b/osu.Game.Rulesets.Osu/Skinning/Legacy/LegacyOldStyleSpinner.cs @@ -12,6 +12,7 @@ using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.Objects.Drawables; using osu.Game.Skinning; using osuTK; +using osuTK.Graphics; namespace osu.Game.Rulesets.Osu.Skinning.Legacy { @@ -40,6 +41,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Legacy Anchor = Anchor.TopCentre, Origin = Anchor.Centre, Texture = source.GetTexture("spinner-background"), + Colour = source.GetConfig(OsuSkinColour.SpinnerBackground)?.Value ?? new Color4(100, 100, 100, 255), Scale = new Vector2(SPRITE_SCALE), Y = SPINNER_Y_CENTRE, }, From a4c4867d6a6b49db710b467ead9b2ec5afef0f0e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 22:40:31 +0900 Subject: [PATCH 149/157] Add scripts for running inspections locally --- InspectCode.ps1 | 11 +++++++++++ InspectCode.sh | 6 ++++++ appveyor.yml | 10 +--------- 3 files changed, 18 insertions(+), 9 deletions(-) create mode 100644 InspectCode.ps1 create mode 100755 InspectCode.sh diff --git a/InspectCode.ps1 b/InspectCode.ps1 new file mode 100644 index 0000000000..8316f48ff3 --- /dev/null +++ b/InspectCode.ps1 @@ -0,0 +1,11 @@ +dotnet tool restore + +# Temporarily disabled until the tool is upgraded to 5.0. + # The version specified in .config/dotnet-tools.json (3.1.37601) won't run on .NET hosts >=5.0.7. + # - cmd: dotnet format --dry-run --check + +dotnet CodeFileSanity +dotnet jb inspectcode "osu.Desktop.slnf" --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN +dotnet nvika parsereport "inspectcodereport.xml" --treatwarningsaserrors + +exit $LASTEXITCODE diff --git a/InspectCode.sh b/InspectCode.sh new file mode 100755 index 0000000000..cf2bc18175 --- /dev/null +++ b/InspectCode.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +dotnet tool restore +dotnet CodeFileSanity +dotnet jb inspectcode "osu.Desktop.slnf" --output="inspectcodereport.xml" --caches-home="inspectcode" --verbosity=WARN +dotnet nvika parsereport "inspectcodereport.xml" --treatwarningsaserrors diff --git a/appveyor.yml b/appveyor.yml index accc913bf5..5be73f9875 100644 --- a/appveyor.yml +++ b/appveyor.yml @@ -20,15 +20,7 @@ build: publish_nuget: true after_build: - - cmd: dotnet tool restore - - # Temporarily disabled until the tool is upgraded to 5.0. - # The version specified in .config/dotnet-tools.json (3.1.37601) won't run on .NET hosts >=5.0.7. - # - cmd: dotnet format --dry-run --check - - - cmd: dotnet CodeFileSanity - - cmd: dotnet jb inspectcode "osu.Desktop.slnf" --output="temp/inspectcodereport.xml" --caches-home="temp/inspectcode" --verbosity=WARN - - cmd: dotnet nvika parsereport "temp/inspectcodereport.xml" --treatwarningsaserrors + - ps: .\InspectCode.ps1 test: assemblies: From e79e1bbcc0c694fc179c63018a59bc1df15e3a71 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Tue, 15 Jun 2021 22:53:43 +0900 Subject: [PATCH 150/157] Fix malformed database test failing in single-threaded mode --- osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs index a47631a83b..8f5ebf53bd 100644 --- a/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs +++ b/osu.Game.Tests/Collections/IO/ImportCollectionsTest.cs @@ -113,7 +113,6 @@ namespace osu.Game.Tests.Collections.IO await importCollectionsFromStream(osu, ms); } - Assert.That(host.UpdateThread.Running, Is.True); Assert.That(exceptionThrown, Is.False); Assert.That(osu.CollectionManager.Collections.Count, Is.EqualTo(0)); } From 30703d518c055e3f6e5656f5bdd23952dbbc0c4f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 15 Jun 2021 23:19:33 +0200 Subject: [PATCH 151/157] Add failing assert for seasonal background equality --- .../Visual/Background/TestSceneSeasonalBackgroundLoader.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs index dc5a4f4a3e..0bd1263076 100644 --- a/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs +++ b/osu.Game.Tests/Visual/Background/TestSceneSeasonalBackgroundLoader.cs @@ -161,15 +161,18 @@ namespace osu.Game.Tests.Visual.Background private void loadNextBackground() { + SeasonalBackground previousBackground = null; SeasonalBackground background = null; AddStep("create next background", () => { + previousBackground = (SeasonalBackground)backgroundContainer.SingleOrDefault(); background = backgroundLoader.LoadNextBackground(); LoadComponentAsync(background, bg => backgroundContainer.Child = bg); }); AddUntilStep("background loaded", () => background.IsLoaded); + AddAssert("background is different", () => !background.Equals(previousBackground)); } private void assertAnyBackground() From 022b1a28d5d491bad38676eb961ad12f491c74bb Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 15 Jun 2021 23:21:48 +0200 Subject: [PATCH 152/157] Add missing equality implementation for seasonal backgrounds The equality operator is used to determine whether the next background in the cycle should be loaded, to avoid pointless loads of the same background several times (see #13362 and #13393). Its omission in the latter pull caused seasonal backgrounds to no longer cycle. Closes #13508. --- .../Graphics/Backgrounds/SeasonalBackgroundLoader.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs index a48da37804..f01a26a3a8 100644 --- a/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs +++ b/osu.Game/Graphics/Backgrounds/SeasonalBackgroundLoader.cs @@ -99,5 +99,14 @@ namespace osu.Game.Graphics.Backgrounds // ensure we're not loading in without a transition. this.FadeInFromZero(200, Easing.InOutSine); } + + public override bool Equals(Background other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return other.GetType() == GetType() + && ((SeasonalBackground)other).url == url; + } } } From 6be41e497a2a9556ac4fc8334e9a5bc90fe4193a Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Jun 2021 11:25:00 +0900 Subject: [PATCH 153/157] Fix possible nullref in difficulty recommender --- osu.Game/Beatmaps/DifficultyRecommender.cs | 18 ++++++++++++++---- 1 file changed, 14 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/DifficultyRecommender.cs b/osu.Game/Beatmaps/DifficultyRecommender.cs index 340c47d89b..ca910e70b8 100644 --- a/osu.Game/Beatmaps/DifficultyRecommender.cs +++ b/osu.Game/Beatmaps/DifficultyRecommender.cs @@ -101,10 +101,20 @@ namespace osu.Game.Beatmaps /// Rulesets ordered descending by their respective recommended difficulties. /// The currently selected ruleset will always be first. /// - private IEnumerable orderedRulesets => - recommendedDifficultyMapping - .OrderByDescending(pair => pair.Value).Select(pair => pair.Key).Where(r => !r.Equals(ruleset.Value)) - .Prepend(ruleset.Value); + private IEnumerable orderedRulesets + { + get + { + if (LoadState < LoadState.Ready || ruleset.Value == null) + return Enumerable.Empty(); + + return recommendedDifficultyMapping + .OrderByDescending(pair => pair.Value) + .Select(pair => pair.Key) + .Where(r => !r.Equals(ruleset.Value)) + .Prepend(ruleset.Value); + } + } private void onlineStateChanged(ValueChangedEvent state) => Schedule(() => { From a5261f0cb3c7209bfc36ba157c02c80020ec18fa Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Jun 2021 11:48:41 +0900 Subject: [PATCH 154/157] Add difficulty recommender instantly --- osu.Game/OsuGame.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 019d3b3cd0..7f23dfc7f8 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -712,7 +712,6 @@ namespace osu.Game PostNotification = n => notifications.Post(n), }, Add, true); - loadComponentSingleFile(difficultyRecommender, Add); loadComponentSingleFile(stableImportManager, Add); loadComponentSingleFile(screenshotManager, Add); @@ -755,6 +754,7 @@ namespace osu.Game chatOverlay.State.ValueChanged += state => channelManager.HighPollRate.Value = state.NewValue == Visibility.Visible; + Add(difficultyRecommender); Add(externalLinkOpener = new ExternalLinkOpener()); Add(new MusicKeyBindingHandler()); From 451ce04d19126a4c38c096e90fa97a94231e81dd Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Jun 2021 13:22:46 +0900 Subject: [PATCH 155/157] Make Resharper inspections fail CI job As per https://github.com/ppy/osu-framework/pull/4514. --- .config/dotnet-tools.json | 4 ++-- .github/workflows/ci.yml | 6 ++---- 2 files changed, 4 insertions(+), 6 deletions(-) diff --git a/.config/dotnet-tools.json b/.config/dotnet-tools.json index 1dca8b3859..b3f7c67c51 100644 --- a/.config/dotnet-tools.json +++ b/.config/dotnet-tools.json @@ -14,8 +14,8 @@ "jb" ] }, - "nvika": { - "version": "2.0.0", + "smoogipoo.nvika": { + "version": "1.0.1", "commands": [ "nvika" ] diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 0be3f64ab3..ed3e99cb61 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -89,7 +89,5 @@ jobs: - name: InspectCode run: dotnet jb inspectcode $(pwd)/osu.Desktop.slnf --output=$(pwd)/inspectcodereport.xml --cachesDir=$(pwd)/inspectcode --verbosity=WARN - - name: ReSharper - uses: glassechidna/resharper-action@master - with: - report: ${{github.workspace}}/inspectcodereport.xml + - name: NVika + run: dotnet nvika parsereport "${{github.workspace}}/inspectcodereport.xml" --treatwarningsaserrors From fa00d07107a9079af55ef6d2ea4a9a3c16c7e29e Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Jun 2021 13:26:36 +0900 Subject: [PATCH 156/157] Upgrade osu-resources --- osu.Android.props | 2 +- osu.Game/osu.Game.csproj | 2 +- osu.iOS.props | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Android.props b/osu.Android.props index c020b1d783..490e43b5e6 100644 --- a/osu.Android.props +++ b/osu.Android.props @@ -51,7 +51,7 @@ - + diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index a7bd5f2e9f..8eeaad1127 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -35,7 +35,7 @@ runtime; build; native; contentfiles; analyzers; buildtransitive - + diff --git a/osu.iOS.props b/osu.iOS.props index 5b3efb4ba4..db442238ce 100644 --- a/osu.iOS.props +++ b/osu.iOS.props @@ -71,7 +71,7 @@ - + From 4c5268694efca63bed526a5f0a2b57ecef4a3699 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 16 Jun 2021 13:46:13 +0900 Subject: [PATCH 157/157] Localise some of the BeatmapListingOverlay --- .../BeatmapListingSearchControl.cs | 17 +++++----- .../BeatmapListing/BeatmapSearchFilterRow.cs | 6 ++-- ...BeatmapSearchMultipleSelectionFilterRow.cs | 5 +-- .../BeatmapSearchRulesetFilterRow.cs | 3 +- .../BeatmapSearchScoreFilterRow.cs | 32 +++++++++++++++---- .../Overlays/BeatmapListing/FilterTabItem.cs | 3 +- osu.Game/Overlays/BeatmapListingOverlay.cs | 3 +- 7 files changed, 47 insertions(+), 22 deletions(-) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs index 97ccb66599..0626f236b8 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapListingSearchControl.cs @@ -14,6 +14,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; +using osu.Game.Resources.Localisation.Web; using osuTK.Graphics; using osu.Game.Rulesets; using osu.Game.Scoring; @@ -126,15 +127,15 @@ namespace osu.Game.Overlays.BeatmapListing Padding = new MarginPadding { Horizontal = 10 }, Children = new Drawable[] { - generalFilter = new BeatmapSearchMultipleSelectionFilterRow(@"General"), + generalFilter = new BeatmapSearchMultipleSelectionFilterRow(BeatmapsStrings.ListingSearchFiltersGeneral), modeFilter = new BeatmapSearchRulesetFilterRow(), - categoryFilter = new BeatmapSearchFilterRow(@"Categories"), - genreFilter = new BeatmapSearchFilterRow(@"Genre"), - languageFilter = new BeatmapSearchFilterRow(@"Language"), - extraFilter = new BeatmapSearchMultipleSelectionFilterRow(@"Extra"), + categoryFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersStatus), + genreFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersGenre), + languageFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersLanguage), + extraFilter = new BeatmapSearchMultipleSelectionFilterRow(BeatmapsStrings.ListingSearchFiltersExtra), ranksFilter = new BeatmapSearchScoreFilterRow(), - playedFilter = new BeatmapSearchFilterRow(@"Played"), - explicitContentFilter = new BeatmapSearchFilterRow(@"Explicit Content"), + playedFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersPlayed), + explicitContentFilter = new BeatmapSearchFilterRow(BeatmapsStrings.ListingSearchFiltersNsfw), } } } @@ -172,7 +173,7 @@ namespace osu.Game.Overlays.BeatmapListing public BeatmapSearchTextBox() { - PlaceholderText = @"type in keywords..."; + PlaceholderText = BeatmapsStrings.ListingSearchPrompt; } protected override bool OnKeyDown(KeyDownEvent e) diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs index 01bcbd3244..4c831543fe 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchFilterRow.cs @@ -11,8 +11,8 @@ using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osuTK; -using Humanizer; using osu.Framework.Extensions.EnumExtensions; +using osu.Framework.Localisation; namespace osu.Game.Overlays.BeatmapListing { @@ -26,7 +26,7 @@ namespace osu.Game.Overlays.BeatmapListing set => current.Current = value; } - public BeatmapSearchFilterRow(string headerName) + public BeatmapSearchFilterRow(LocalisableString header) { Drawable filter; AutoSizeAxes = Axes.Y; @@ -53,7 +53,7 @@ namespace osu.Game.Overlays.BeatmapListing Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, Font = OsuFont.GetFont(size: 13), - Text = headerName.Titleize() + Text = header }, filter = CreateFilter() } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs index 5dfa8e6109..e0632ace58 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchMultipleSelectionFilterRow.cs @@ -9,6 +9,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osuTK; namespace osu.Game.Overlays.BeatmapListing @@ -19,8 +20,8 @@ namespace osu.Game.Overlays.BeatmapListing private MultipleSelectionFilter filter; - public BeatmapSearchMultipleSelectionFilterRow(string headerName) - : base(headerName) + public BeatmapSearchMultipleSelectionFilterRow(LocalisableString header) + : base(header) { Current.BindTo(filter.Current); } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs index a8dc088e52..c2d0eea80c 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchRulesetFilterRow.cs @@ -3,6 +3,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; +using osu.Game.Resources.Localisation.Web; using osu.Game.Rulesets; namespace osu.Game.Overlays.BeatmapListing @@ -10,7 +11,7 @@ namespace osu.Game.Overlays.BeatmapListing public class BeatmapSearchRulesetFilterRow : BeatmapSearchFilterRow { public BeatmapSearchRulesetFilterRow() - : base(@"Mode") + : base(BeatmapsStrings.ListingSearchFiltersMode) { } diff --git a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs index 804962adfb..abfffe907f 100644 --- a/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs +++ b/osu.Game/Overlays/BeatmapListing/BeatmapSearchScoreFilterRow.cs @@ -1,9 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using System; using System.Collections.Generic; using System.Linq; -using osu.Framework.Extensions; +using osu.Framework.Localisation; +using osu.Game.Resources.Localisation.Web; using osu.Game.Scoring; namespace osu.Game.Overlays.BeatmapListing @@ -11,7 +13,7 @@ namespace osu.Game.Overlays.BeatmapListing public class BeatmapSearchScoreFilterRow : BeatmapSearchMultipleSelectionFilterRow { public BeatmapSearchScoreFilterRow() - : base(@"Rank Achieved") + : base(BeatmapsStrings.ListingSearchFiltersRank) { } @@ -31,18 +33,36 @@ namespace osu.Game.Overlays.BeatmapListing { } - protected override string LabelFor(ScoreRank value) + protected override LocalisableString LabelFor(ScoreRank value) { switch (value) { case ScoreRank.XH: - return @"Silver SS"; + return BeatmapsStrings.RankXH; + + case ScoreRank.X: + return BeatmapsStrings.RankX; case ScoreRank.SH: - return @"Silver S"; + return BeatmapsStrings.RankSH; + + case ScoreRank.S: + return BeatmapsStrings.RankS; + + case ScoreRank.A: + return BeatmapsStrings.RankA; + + case ScoreRank.B: + return BeatmapsStrings.RankB; + + case ScoreRank.C: + return BeatmapsStrings.RankC; + + case ScoreRank.D: + return BeatmapsStrings.RankD; default: - return value.GetDescription(); + throw new ArgumentException("Unsupported value.", nameof(value)); } } } diff --git a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs index f02b515755..d64ee59682 100644 --- a/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs +++ b/osu.Game/Overlays/BeatmapListing/FilterTabItem.cs @@ -7,6 +7,7 @@ using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; @@ -66,7 +67,7 @@ namespace osu.Game.Overlays.BeatmapListing /// /// Returns the label text to be used for the supplied . /// - protected virtual string LabelFor(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); + protected virtual LocalisableString LabelFor(T value) => (value as Enum)?.GetDescription() ?? value.ToString(); private void updateState() { diff --git a/osu.Game/Overlays/BeatmapListingOverlay.cs b/osu.Game/Overlays/BeatmapListingOverlay.cs index 5df7a4650e..5e65cd9488 100644 --- a/osu.Game/Overlays/BeatmapListingOverlay.cs +++ b/osu.Game/Overlays/BeatmapListingOverlay.cs @@ -18,6 +18,7 @@ using osu.Game.Beatmaps; using osu.Game.Graphics.Sprites; using osu.Game.Overlays.BeatmapListing; using osu.Game.Overlays.BeatmapListing.Panels; +using osu.Game.Resources.Localisation.Web; using osuTK; using osuTK.Graphics; @@ -232,7 +233,7 @@ namespace osu.Game.Overlays { Anchor = Anchor.Centre, Origin = Anchor.Centre, - Text = @"... nope, nothing found.", + Text = BeatmapsStrings.ListingSearchNotFoundQuote, } } });