From 6e812ebd566c1598303fb2e7ccf5a3cd13f4458e Mon Sep 17 00:00:00 2001 From: Craftplacer Date: Mon, 16 Dec 2019 00:45:33 +0100 Subject: [PATCH 001/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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/100] 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 7f7c2c73e002177f7518ca876e75b735024ebaea Mon Sep 17 00:00:00 2001 From: ekrctb Date: Fri, 11 Jun 2021 15:39:06 +0900 Subject: [PATCH 090/100] 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 c00f9ae4b750d905a7165d3d7bd8b69782f95433 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:11:37 +0900 Subject: [PATCH 091/100] 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 092/100] 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 093/100] 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 139401a04a4813072362d6807271cc07e01b0e22 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 11 Jun 2021 16:27:31 +0900 Subject: [PATCH 094/100] 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 095/100] 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 096/100] 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 097/100] 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 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 098/100] 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 099/100] 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 100/100] 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