From 9c611019b37d770355ccee2c23088238ac47d8e9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20K=C3=A4llberg?= Date: Tue, 11 Oct 2022 09:30:32 +0200 Subject: [PATCH 01/83] Toolbar localisation --- osu.Game/Localisation/HomeStrings.cs | 24 +++++++++++++++++++ osu.Game/Localisation/RulesetStrings.cs | 20 ++++++++++++++++ .../Overlays/Toolbar/ToolbarHomeButton.cs | 5 ++-- .../Toolbar/ToolbarRulesetTabButton.cs | 4 +++- 4 files changed, 50 insertions(+), 3 deletions(-) create mode 100644 osu.Game/Localisation/HomeStrings.cs create mode 100644 osu.Game/Localisation/RulesetStrings.cs diff --git a/osu.Game/Localisation/HomeStrings.cs b/osu.Game/Localisation/HomeStrings.cs new file mode 100644 index 0000000000..4a2cea00ca --- /dev/null +++ b/osu.Game/Localisation/HomeStrings.cs @@ -0,0 +1,24 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class HomeStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Home"; + + /// + /// "home" + /// + public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); + + /// + /// "return to the main menu" + /// + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} \ No newline at end of file diff --git a/osu.Game/Localisation/RulesetStrings.cs b/osu.Game/Localisation/RulesetStrings.cs new file mode 100644 index 0000000000..201831cd91 --- /dev/null +++ b/osu.Game/Localisation/RulesetStrings.cs @@ -0,0 +1,20 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class RulesetStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Ruleset"; + + /// + /// "play some" + /// + + public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); + + private static string getKey(string key) => $"{prefix}:{key}"; + } +} \ No newline at end of file diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index f170ec84ac..52fa83e37a 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -5,6 +5,7 @@ using osu.Framework.Allocation; using osu.Game.Input.Bindings; +using osu.Game.Localisation; namespace osu.Game.Overlays.Toolbar { @@ -19,8 +20,8 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load() { - TooltipMain = "home"; - TooltipSub = "return to the main menu"; + TooltipMain = HomeStrings.HeaderTitle; + TooltipSub = HomeStrings.HeaderDescription; SetIcon("Icons/Hexacons/home"); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 31c6802fda..101bba95cc 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -9,6 +9,8 @@ using osu.Game.Rulesets; using osuTK.Graphics; using osu.Framework.Graphics; using osu.Framework.Input.Events; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Overlays.Toolbar { @@ -29,7 +31,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = $"play some {rInstance.Description}"; + ruleset.TooltipSub = LocalisableString.Format("{0} {1}", RulesetStrings.HeaderDescription, ($"{rInstance.Description}")); ruleset.SetIcon(rInstance.CreateIcon()); } From 63e651130af1954d7f8ce5ac1923a95abb2bc926 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Daniel=20K=C3=A4llberg?= Date: Tue, 11 Oct 2022 10:59:07 +0200 Subject: [PATCH 02/83] Grouped localisation strings --- osu.Game/Localisation/HomeStrings.cs | 24 ------------------- osu.Game/Localisation/RulesetStrings.cs | 20 ---------------- osu.Game/Localisation/ToolbarStrings.cs | 16 +++++++++++++ .../Overlays/Toolbar/ToolbarHomeButton.cs | 4 ++-- .../Toolbar/ToolbarRulesetTabButton.cs | 8 +++---- 5 files changed, 22 insertions(+), 50 deletions(-) delete mode 100644 osu.Game/Localisation/HomeStrings.cs delete mode 100644 osu.Game/Localisation/RulesetStrings.cs diff --git a/osu.Game/Localisation/HomeStrings.cs b/osu.Game/Localisation/HomeStrings.cs deleted file mode 100644 index 4a2cea00ca..0000000000 --- a/osu.Game/Localisation/HomeStrings.cs +++ /dev/null @@ -1,24 +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.Localisation; - -namespace osu.Game.Localisation -{ - public static class HomeStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.Home"; - - /// - /// "home" - /// - public static LocalisableString HeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); - - /// - /// "return to the main menu" - /// - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} \ No newline at end of file diff --git a/osu.Game/Localisation/RulesetStrings.cs b/osu.Game/Localisation/RulesetStrings.cs deleted file mode 100644 index 201831cd91..0000000000 --- a/osu.Game/Localisation/RulesetStrings.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Localisation; - -namespace osu.Game.Localisation -{ - public static class RulesetStrings - { - private const string prefix = @"osu.Game.Resources.Localisation.Ruleset"; - - /// - /// "play some" - /// - - public static LocalisableString HeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); - - private static string getKey(string key) => $"{prefix}:{key}"; - } -} \ No newline at end of file diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index 6dc8a1e50c..b76c643332 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -19,6 +19,22 @@ namespace osu.Game.Localisation /// public static LocalisableString Connecting => new TranslatableString(getKey(@"connecting"), @"Connecting..."); + /// + /// "home" + /// + public static LocalisableString HomeHeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); + + /// + /// "return to the main menu" + /// + public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); + + /// + /// "play some" + /// + + public static LocalisableString RulesetHeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs index 52fa83e37a..959706b805 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarHomeButton.cs @@ -20,8 +20,8 @@ namespace osu.Game.Overlays.Toolbar [BackgroundDependencyLoader] private void load() { - TooltipMain = HomeStrings.HeaderTitle; - TooltipSub = HomeStrings.HeaderDescription; + TooltipMain = ToolbarStrings.HomeHeaderTitle; + TooltipSub = ToolbarStrings.HomeHeaderDescription; SetIcon("Icons/Hexacons/home"); } } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index 101bba95cc..bffd8b96e5 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -3,14 +3,14 @@ #nullable disable +using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; -using osu.Game.Rulesets; -using osuTK.Graphics; -using osu.Framework.Graphics; using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Game.Localisation; +using osu.Game.Rulesets; +using osuTK.Graphics; namespace osu.Game.Overlays.Toolbar { @@ -31,7 +31,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = LocalisableString.Format("{0} {1}", RulesetStrings.HeaderDescription, ($"{rInstance.Description}")); + ruleset.TooltipSub = LocalisableString.Format("{0} {1}", ToolbarStrings.RulesetHeaderDescription, ($"{rInstance.Description}")); ruleset.SetIcon(rInstance.CreateIcon()); } From a0690e7ffb1bb1f2ea81ea65090a4b0b890b619b Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Mon, 26 Dec 2022 22:23:31 +0000 Subject: [PATCH 03/83] replay menus remembers expanded state no messing with readonly fields --- .../NonVisual/SessionStaticsTest.cs | 6 ++++++ osu.Game/Configuration/SessionStatics.cs | 4 ++++ .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 19 ++++++++++++++++++- 3 files changed, 28 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs index 5c8254b947..499c0e5d34 100644 --- a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs +++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs @@ -24,12 +24,16 @@ namespace osu.Game.Tests.NonVisual sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true); sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true); sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d); + sessionStatics.SetValue(Static.ReplayPlaybackSettingExpanded, false); + sessionStatics.SetValue(Static.ReplayVisualSettingsExpanded, true); sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) }); Assert.IsFalse(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); sessionStatics.ResetAfterInactivity(); @@ -39,6 +43,8 @@ namespace osu.Game.Tests.NonVisual Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); // some statics should not reset despite inactivity. Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); + Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); } } diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index 12a30a0c84..f08658f182 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -20,6 +20,8 @@ namespace osu.Game.Configuration SetDefault(Static.MutedAudioNotificationShownOnce, false); SetDefault(Static.LowBatteryNotificationShownOnce, false); SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null); + SetDefault(Static.ReplayPlaybackSettingExpanded, true); + SetDefault(Static.ReplayVisualSettingsExpanded, false); SetDefault(Static.SeasonalBackgrounds, null); } @@ -42,6 +44,8 @@ namespace osu.Game.Configuration LoginOverlayDisplayed, MutedAudioNotificationShownOnce, LowBatteryNotificationShownOnce, + ReplayPlaybackSettingExpanded, + ReplayVisualSettingsExpanded, /// /// Info about seasonal backgrounds available fetched from API - see . diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 5f6f040959..c4f07f77cd 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -3,12 +3,15 @@ #nullable disable +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osuTK; using osu.Game.Screens.Play.PlayerSettings; using osuTK.Input; +using osu.Game.Configuration; +using osu.Framework.Allocation; namespace osu.Game.Screens.Play.HUD { @@ -16,6 +19,10 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; + private Bindable playbackMenuExpanded; + + private Bindable visualMenuExpanded; + public bool ReplayLoaded; public readonly PlaybackSettings PlaybackSettings; @@ -42,11 +49,21 @@ namespace osu.Game.Screens.Play.HUD //CollectionSettings = new CollectionSettings(), //DiscussionSettings = new DiscussionSettings(), PlaybackSettings = new PlaybackSettings(), - VisualSettings = new VisualSettings { Expanded = { Value = false } } + VisualSettings = new VisualSettings() } }; } + [BackgroundDependencyLoader] + private void load(SessionStatics statics) + { + playbackMenuExpanded = statics.GetBindable(Static.ReplayPlaybackSettingExpanded); + visualMenuExpanded = statics.GetBindable(Static.ReplayVisualSettingsExpanded); + + PlaybackSettings.Expanded.BindTo(playbackMenuExpanded); + VisualSettings.Expanded.BindTo(visualMenuExpanded); + } + protected override void PopIn() => this.FadeIn(fade_duration); protected override void PopOut() => this.FadeOut(fade_duration); From 768a33bb64a5fef23201c5224bd53336eb80e133 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Fri, 6 Jan 2023 23:31:19 +0300 Subject: [PATCH 04/83] Add request class --- .../Online/API/Requests/CommentPostRequest.cs | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 osu.Game/Online/API/Requests/CommentPostRequest.cs diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs new file mode 100644 index 0000000000..bd69c04bed --- /dev/null +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -0,0 +1,41 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Net.Http; +using osu.Framework.IO.Network; +using osu.Game.Online.API.Requests.Responses; + +namespace osu.Game.Online.API.Requests +{ + public class CommentPostRequest : APIRequest + { + public readonly CommentableType Commentable; + public readonly long CommentableId; + public readonly string Message; + public readonly long? ReplyTo; + + public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? replyTo = null) + { + Commentable = commentable; + CommentableId = commentableId; + Message = message; + ReplyTo = replyTo; + } + + protected override WebRequest CreateWebRequest() + { + var req = base.CreateWebRequest(); + req.Method = HttpMethod.Post; + + req.AddParameter(@"comment[commentable_type]", Commentable.ToString()); + req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); + req.AddParameter(@"comment[message]", Message); + if (ReplyTo.HasValue) + req.AddParameter(@"comment[parent_id]", $"{ReplyTo}"); + + return req; + } + + protected override string Target => "comments"; + } +} From 32e90829e3d0b2df4241ecf9f419446a4d42d587 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 02:59:24 +0300 Subject: [PATCH 05/83] Integrate comment editor into container --- .../Overlays/Comments/CommentsContainer.cs | 68 ++++++++++++++++++- 1 file changed, 67 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 7bd2d6a5e6..c8a2ab39ae 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -17,15 +17,23 @@ using osu.Framework.Extensions.IEnumerableExtensions; using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; +using osu.Framework.Localisation; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; -using APIUser = osu.Game.Online.API.Requests.Responses.APIUser; +using osu.Game.Users.Drawables; +using osuTK; namespace osu.Game.Overlays.Comments { + [Cached] public partial class CommentsContainer : CompositeDrawable { + private const string cid = "commentableId"; + + [Cached] private readonly Bindable type = new Bindable(); + + [Cached(name: cid)] private readonly BindableLong id = new BindableLong(); public readonly Bindable Sort = new Bindable(); @@ -46,12 +54,14 @@ namespace osu.Game.Overlays.Comments private DeletedCommentsCounter deletedCommentsCounter; private CommentsShowMoreButton moreButton; private TotalCommentsCounter commentCounter; + private UpdateableAvatar avatar; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; + AddRangeInternal(new Drawable[] { new Box @@ -86,6 +96,29 @@ namespace osu.Game.Overlays.Comments }, }, }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = 50, Vertical = 20 }, + Children = new Drawable[] + { + avatar = new UpdateableAvatar(api.LocalUser.Value) + { + Size = new Vector2(50), + CornerExponent = 2, + CornerRadius = 25, + Masking = true, + }, + new Container + { + Padding = new MarginPadding { Left = 60 }, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Child = new NewCommentEditor() + } + } + }, new CommentsHeader { Sort = { BindTarget = Sort }, @@ -146,6 +179,7 @@ namespace osu.Game.Overlays.Comments }); User.BindTo(api.LocalUser); + User.BindValueChanged(e => avatar.User = e.NewValue); } protected override void LoadComplete() @@ -336,5 +370,37 @@ namespace osu.Game.Overlays.Comments }); } } + + private partial class NewCommentEditor : CommentEditor + { + [Resolved] + public Bindable CommentableType { get; set; } + + [Resolved(name: cid)] + public BindableLong CommentableId { get; set; } + + protected override LocalisableString FooterText => default; + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + + [Resolved] + private IAPIProvider api { get; set; } + + protected override void OnCommit(string text) + { + CommitButton.IsLoadingSpinnerShown = true; + CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); + req.Failure += _ => Schedule(() => + { + CommitButton.IsLoadingSpinnerShown = false; + }); + req.Success += cb => Schedule(() => + { + CommitButton.IsLoadingSpinnerShown = false; + Current.Value = string.Empty; + }); + api.Queue(req); + } + } } } From 58bf7349eea9cd4a3600f7c71ca6968feb85e776 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 02:59:32 +0300 Subject: [PATCH 06/83] Fix request --- osu.Game/Online/API/Requests/CommentPostRequest.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs index bd69c04bed..7012d479bd 100644 --- a/osu.Game/Online/API/Requests/CommentPostRequest.cs +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -27,7 +27,7 @@ namespace osu.Game.Online.API.Requests var req = base.CreateWebRequest(); req.Method = HttpMethod.Post; - req.AddParameter(@"comment[commentable_type]", Commentable.ToString()); + req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant()); req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); req.AddParameter(@"comment[message]", Message); if (ReplyTo.HasValue) From 927773d56584c1b288642a3b143ef118d6ce4d65 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:15:43 +0300 Subject: [PATCH 07/83] Display submitted comments locally --- .../Overlays/Comments/CommentsContainer.cs | 46 ++++++++++++++++++- 1 file changed, 44 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index c8a2ab39ae..98c186b273 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -3,6 +3,7 @@ #nullable disable +using System; using osu.Framework.Allocation; using osu.Framework.Graphics.Containers; using osu.Game.Online.API; @@ -115,7 +116,10 @@ namespace osu.Game.Overlays.Comments Padding = new MarginPadding { Left = 60 }, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Child = new NewCommentEditor() + Child = new NewCommentEditor + { + OnPost = prependPostedComments + } } } }, @@ -279,7 +283,6 @@ namespace osu.Game.Overlays.Comments { pinnedContent.AddRange(loaded.Where(d => d.Comment.Pinned)); content.AddRange(loaded.Where(d => !d.Comment.Pinned)); - deletedCommentsCounter.Count.Value += topLevelComments.Select(d => d.Comment).Count(c => c.IsDeleted && c.IsTopLevel); if (bundle.HasMore) @@ -322,6 +325,42 @@ namespace osu.Game.Overlays.Comments } } + private void prependPostedComments(CommentBundle bundle) + { + var topLevelComments = new List(); + + foreach (var comment in bundle.Comments) + { + // Exclude possible duplicated comments. + if (CommentDictionary.ContainsKey(comment.Id)) + continue; + + topLevelComments.Add(getDrawableComment(comment)); + } + + if (topLevelComments.Any()) + { + LoadComponentsAsync(topLevelComments, loaded => + { + if (content[0] is NoCommentsPlaceholder placeholder) + content.Remove(placeholder, true); + + foreach (var comment in loaded) + { + int pos = -1; + + if (content.Count > 0) + { + var first = content.FlowingChildren.First(); + pos = (int)(content.GetLayoutPosition(first) - 1); + } + + content.Insert(pos, comment); + } + }, (loadCancellation = new CancellationTokenSource()).Token); + } + } + private DrawableComment getDrawableComment(Comment comment) { if (CommentDictionary.TryGetValue(comment.Id, out var existing)) @@ -386,6 +425,8 @@ namespace osu.Game.Overlays.Comments [Resolved] private IAPIProvider api { get; set; } + public Action OnPost; + protected override void OnCommit(string text) { CommitButton.IsLoadingSpinnerShown = true; @@ -398,6 +439,7 @@ namespace osu.Game.Overlays.Comments { CommitButton.IsLoadingSpinnerShown = false; Current.Value = string.Empty; + OnPost?.Invoke(cb); }); api.Queue(req); } From 49ce50878d2c761fcc0a43132cf1669f9966d687 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:15:53 +0300 Subject: [PATCH 08/83] Add simple test --- .../Online/TestSceneCommentsContainer.cs | 48 +++++++++++++++++++ 1 file changed, 48 insertions(+) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 291ccd634d..86a574cf77 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -11,7 +11,11 @@ using osu.Game.Overlays; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; +using osu.Framework.Utils; +using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; @@ -126,6 +130,24 @@ namespace osu.Game.Tests.Visual.Online commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } + [TestCase] + public void TestPost() + { + setUpCommentsResponse(getExampleComments()); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + setUpPostResponse(); + AddStep("Enter text", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value = "comm"); + AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + AddUntilStep("Comment sent", () => + { + var text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; + return this.ChildrenOfType().Any(x => + { + return x.ChildrenOfType().Any(y => y.Text == text); + }); + }); + } + private void setUpCommentsResponse(CommentBundle commentBundle) => AddStep("set up response", () => { @@ -139,6 +161,32 @@ namespace osu.Game.Tests.Visual.Online }; }); + private void setUpPostResponse() + => AddStep("set up response", () => + { + dummyAPI.HandleRequest = request => + { + if (!(request is CommentPostRequest req)) + return false; + + req.TriggerSuccess(new CommentBundle + { + Comments = new List + { + new Comment + { + Id = 98, + Message = req.Message, + LegacyName = "FirstUser", + CreatedAt = DateTimeOffset.Now, + VotesCount = 98, + } + } + }); + return true; + }; + }); + private CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle From 4baa2670953b4c201f5d70b64149fd6cb064d86d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 7 Jan 2023 04:26:52 +0300 Subject: [PATCH 09/83] warnings --- osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 86a574cf77..e58423241b 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -14,7 +14,6 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Framework.Testing; -using osu.Framework.Utils; using osu.Game.Graphics.UserInterfaceV2; using osu.Game.Online.API; using osu.Game.Online.API.Requests; @@ -140,7 +139,7 @@ namespace osu.Game.Tests.Visual.Online AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); AddUntilStep("Comment sent", () => { - var text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; + string text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; return this.ChildrenOfType().Any(x => { return x.ChildrenOfType().Any(y => y.Text == text); @@ -187,7 +186,7 @@ namespace osu.Game.Tests.Visual.Online }; }); - private CommentBundle getExampleComments(bool withPinned = false) + private static CommentBundle getExampleComments(bool withPinned = false) { var bundle = new CommentBundle { From c2dd822e4a141f787d65200697ba1ea118493909 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 8 Jan 2023 14:08:36 -0800 Subject: [PATCH 10/83] Make pause overlay close with pause gameplay action --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 2 +- osu.Game/Screens/Play/PauseOverlay.cs | 14 ++++++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index c681ef8f96..13f32d3b6a 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -189,7 +189,7 @@ namespace osu.Game.Screens.Play InternalButtons.Add(button); } - public bool OnPressed(KeyBindingPressEvent e) + public virtual bool OnPressed(KeyBindingPressEvent e) { switch (e.Action) { diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index 28044653e6..db2b87dae6 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -8,8 +8,10 @@ using System.Linq; using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Graphics; +using osu.Framework.Input.Events; using osu.Game.Audio; using osu.Game.Graphics; +using osu.Game.Input.Bindings; using osu.Game.Skinning; using osuTK.Graphics; @@ -56,5 +58,17 @@ namespace osu.Game.Screens.Play pauseLoop.VolumeTo(0, TRANSITION_DURATION, Easing.OutQuad).Finally(_ => pauseLoop.Stop()); } + + public override bool OnPressed(KeyBindingPressEvent e) + { + switch (e.Action) + { + case GlobalAction.PauseGameplay: + BackAction.Invoke(); + return true; + } + + return base.OnPressed(e); + } } } From 776b60f3b3b133ecd41bc284e727e333c670f949 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 14:05:08 -0800 Subject: [PATCH 11/83] Fix manual input manager test scenes not matching game input hierarchy Fix popover using on key down Fix popover not expiring when using global action --- osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs | 12 +++++++++++- .../Tests/Visual/OsuManualInputManagerTestScene.cs | 10 ++++++---- 2 files changed, 17 insertions(+), 5 deletions(-) diff --git a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs index e66e48373c..d89322cecd 100644 --- a/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs +++ b/osu.Game/Graphics/UserInterfaceV2/OsuPopover.cs @@ -5,6 +5,7 @@ using JetBrains.Annotations; using osu.Framework.Allocation; +using osu.Framework.Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -14,6 +15,7 @@ using osu.Framework.Input.Events; using osu.Game.Input.Bindings; using osu.Game.Overlays; using osuTK; +using osuTK.Input; namespace osu.Game.Graphics.UserInterfaceV2 { @@ -58,6 +60,14 @@ namespace osu.Game.Graphics.UserInterfaceV2 this.FadeOut(fade_duration, Easing.OutQuint); } + protected override bool OnKeyDown(KeyDownEvent e) + { + if (e.Key == Key.Escape) + return false; // disable the framework-level handling of escape key for conformity (we use GlobalAction.Back). + + return base.OnKeyDown(e); + } + public bool OnPressed(KeyBindingPressEvent e) { if (e.Repeat) @@ -68,7 +78,7 @@ namespace osu.Game.Graphics.UserInterfaceV2 if (e.Action == GlobalAction.Back) { - Hide(); + this.HidePopover(); return true; } diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index b0043b902c..8e0ee896a5 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -46,21 +46,23 @@ namespace osu.Game.Tests.Visual { var mainContent = content = new Container { RelativeSizeAxes = Axes.Both }; + var inputContainer = new Container { RelativeSizeAxes = Axes.Both }; + if (DisplayCursorForManualInput) { var cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }; - cursorDisplay.Add(new OsuTooltipContainer(cursorDisplay.MenuCursor) + cursorDisplay.Add(content = new OsuTooltipContainer(cursorDisplay.MenuCursor) { RelativeSizeAxes = Axes.Both, - Child = mainContent }); - mainContent = cursorDisplay; + inputContainer.Add(cursorDisplay); + mainContent = inputContainer; } if (CreateNestedActionContainer) - mainContent = new GlobalActionContainer(null).WithChild(mainContent); + inputContainer.Add(new GlobalActionContainer(null)); base.Content.AddRange(new Drawable[] { From 51dbe2c3a33fb6033e1af6730cb49b1ba50c9a55 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:43:06 -0800 Subject: [PATCH 12/83] Refactor pause test to actually use back action keybinding --- .../Visual/Gameplay/TestScenePause.cs | 23 +++++++++++-------- 1 file changed, 14 insertions(+), 9 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 7880a849a2..910a6f28cf 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -5,6 +5,7 @@ using System.Linq; using NUnit.Framework; +using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -34,6 +35,12 @@ namespace osu.Game.Tests.Visual.Gameplay base.Content.Add(content = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }); } + [BackgroundDependencyLoader] + private void load() + { + LocalConfig.SetValue(OsuSetting.UIHoldActivationDelay, 0.0); + } + [SetUpSteps] public override void SetUpSteps() { @@ -144,7 +151,7 @@ namespace osu.Game.Tests.Visual.Gameplay { AddStep("disable pause support", () => Player.Configuration.AllowPause = false); - pauseFromUserExitKey(); + pauseViaBackAction(); confirmExited(); } @@ -156,7 +163,7 @@ namespace osu.Game.Tests.Visual.Gameplay pauseAndConfirm(); resume(); - pauseFromUserExitKey(); + pauseViaBackAction(); confirmResumed(); confirmNotExited(); @@ -214,7 +221,7 @@ namespace osu.Game.Tests.Visual.Gameplay confirmClockRunning(false); - AddStep("exit via user pause", () => Player.ExitViaPause()); + pauseViaBackAction(); confirmExited(); } @@ -224,11 +231,11 @@ namespace osu.Game.Tests.Visual.Gameplay AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed); // will finish the fail animation and show the fail/pause screen. - AddStep("attempt exit via pause key", () => Player.ExitViaPause()); + pauseViaBackAction(); AddAssert("fail overlay shown", () => Player.FailOverlayVisible); // will actually exit. - AddStep("exit via pause key", () => Player.ExitViaPause()); + pauseViaBackAction(); confirmExited(); } @@ -327,7 +334,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void pauseAndConfirm() { - pauseFromUserExitKey(); + pauseViaBackAction(); confirmPaused(); } @@ -374,7 +381,7 @@ namespace osu.Game.Tests.Visual.Gameplay } private void restart() => AddStep("restart", () => Player.Restart()); - private void pauseFromUserExitKey() => AddStep("user pause", () => Player.ExitViaPause()); + private void pauseViaBackAction() => AddStep("press escape", () => InputManager.Key(Key.Escape)); private void resume() => AddStep("resume", () => Player.Resume()); private void confirmPauseOverlayShown(bool isShown) => @@ -405,8 +412,6 @@ namespace osu.Game.Tests.Visual.Gameplay public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible; - public void ExitViaPause() => PerformExit(true); - public void ExitViaQuickExit() => PerformExit(false); public override void OnEntering(ScreenTransitionEvent e) From 404d34f5920d8caced05226cc9f234ce585d3b7e Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:43:50 -0800 Subject: [PATCH 13/83] Refactor pause test to actually use quick exit action keybinding --- .../Visual/Gameplay/TestScenePause.cs | 17 ++++++++++++----- 1 file changed, 12 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index 910a6f28cf..ca221b6b1c 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -177,7 +177,7 @@ namespace osu.Game.Tests.Visual.Gameplay pauseAndConfirm(); resume(); - AddStep("pause via exit key", () => Player.ExitViaQuickExit()); + exitViaQuickExitAction(); confirmResumed(); AddAssert("exited", () => !Player.IsCurrentScreen()); @@ -252,7 +252,7 @@ namespace osu.Game.Tests.Visual.Gameplay public void TestQuickExitFromFailedGameplay() { AddUntilStep("wait for fail", () => Player.GameplayState.HasFailed); - AddStep("quick exit", () => Player.GameplayClockContainer.ChildrenOfType().First().Action?.Invoke()); + exitViaQuickExitAction(); confirmExited(); } @@ -268,7 +268,7 @@ namespace osu.Game.Tests.Visual.Gameplay [Test] public void TestQuickExitFromGameplay() { - AddStep("quick exit", () => Player.GameplayClockContainer.ChildrenOfType().First().Action?.Invoke()); + exitViaQuickExitAction(); confirmExited(); } @@ -382,6 +382,15 @@ namespace osu.Game.Tests.Visual.Gameplay private void restart() => AddStep("restart", () => Player.Restart()); private void pauseViaBackAction() => AddStep("press escape", () => InputManager.Key(Key.Escape)); + + private void exitViaQuickExitAction() => AddStep("press ctrl-tilde", () => + { + InputManager.PressKey(Key.ControlLeft); + InputManager.PressKey(Key.Tilde); + InputManager.ReleaseKey(Key.Tilde); + InputManager.ReleaseKey(Key.ControlLeft); + }); + private void resume() => AddStep("resume", () => Player.Resume()); private void confirmPauseOverlayShown(bool isShown) => @@ -412,8 +421,6 @@ namespace osu.Game.Tests.Visual.Gameplay public bool PauseOverlayVisible => PauseOverlay.State.Value == Visibility.Visible; - public void ExitViaQuickExit() => PerformExit(false); - public override void OnEntering(ScreenTransitionEvent e) { base.OnEntering(e); From 974a8d520c0a630d8610447a4112ab73404c3a11 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:51:22 -0800 Subject: [PATCH 14/83] Add basic toggle pause tests --- .../Visual/Gameplay/TestScenePause.cs | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs index ca221b6b1c..f1435094b3 100644 --- a/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs +++ b/osu.Game.Tests/Visual/Gameplay/TestScenePause.cs @@ -50,6 +50,22 @@ namespace osu.Game.Tests.Visual.Gameplay confirmClockRunning(true); } + [Test] + public void TestTogglePauseViaBackAction() + { + pauseViaBackAction(); + pauseViaBackAction(); + confirmPausedWithNoOverlay(); + } + + [Test] + public void TestTogglePauseViaPauseGameplayAction() + { + pauseViaPauseGameplayAction(); + pauseViaPauseGameplayAction(); + confirmPausedWithNoOverlay(); + } + [Test] public void TestPauseWithLargeOffset() { @@ -382,6 +398,7 @@ namespace osu.Game.Tests.Visual.Gameplay private void restart() => AddStep("restart", () => Player.Restart()); private void pauseViaBackAction() => AddStep("press escape", () => InputManager.Key(Key.Escape)); + private void pauseViaPauseGameplayAction() => AddStep("press middle mouse", () => InputManager.Click(MouseButton.Middle)); private void exitViaQuickExitAction() => AddStep("press ctrl-tilde", () => { From b5caa1b778bc9f663e38ba16c5f13ec6907d893f Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 10 Jan 2023 15:53:41 -0800 Subject: [PATCH 15/83] Rename pause gameplay keybind to reflect other behavior --- osu.Game/Localisation/GlobalActionKeyBindingStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs index 14e0bbbced..303dbb6f46 100644 --- a/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs +++ b/osu.Game/Localisation/GlobalActionKeyBindingStrings.cs @@ -155,9 +155,9 @@ namespace osu.Game.Localisation public static LocalisableString ToggleProfile => new TranslatableString(getKey(@"toggle_profile"), @"Toggle profile"); /// - /// "Pause gameplay" + /// "Pause / resume gameplay" /// - public static LocalisableString PauseGameplay => new TranslatableString(getKey(@"pause_gameplay"), @"Pause gameplay"); + public static LocalisableString PauseGameplay => new TranslatableString(getKey(@"pause_gameplay"), @"Pause / resume gameplay"); /// /// "Setup mode" From 1f129d4e163132c6355eb0c397c64d5bfacd8052 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 11 Jan 2023 21:20:56 +0300 Subject: [PATCH 16/83] Add failing test --- .../TestScenePlacementBeforeTrackStart.cs | 30 +++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs diff --git a/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs new file mode 100644 index 0000000000..00dd75ceee --- /dev/null +++ b/osu.Game.Rulesets.Mania.Tests/Editor/TestScenePlacementBeforeTrackStart.cs @@ -0,0 +1,30 @@ +// 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.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Tests.Visual; +using osuTK.Input; + +namespace osu.Game.Rulesets.Mania.Tests.Editor +{ + public partial class TestScenePlacementBeforeTrackStart : EditorTestScene + { + protected override Ruleset CreateEditorRuleset() => new ManiaRuleset(); + + [Test] + public void TestPlacement() + { + AddStep("Seek to 0", () => EditorClock.Seek(0)); + AddStep("Select note", () => InputManager.Key(Key.Number2)); + AddStep("Hover negative span", () => + { + InputManager.MoveMouseTo(this.ChildrenOfType().First(x => x.Name == "Icons").Children[0]); + }); + AddStep("Click", () => InputManager.Click(MouseButton.Left)); + AddAssert("No notes placed", () => EditorBeatmap.HitObjects.All(x => x.StartTime >= 0)); + } + } +} From 03ac2fd7d74b446f62328648c83e857d7aef1cd9 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 12 Jan 2023 03:33:20 +0300 Subject: [PATCH 17/83] More tests --- .../Editing/TestSceneSnappingNearZero.cs | 79 +++++++++++++++++++ 1 file changed, 79 insertions(+) create mode 100644 osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs diff --git a/osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs b/osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs new file mode 100644 index 0000000000..59081215ba --- /dev/null +++ b/osu.Game.Tests/Editing/TestSceneSnappingNearZero.cs @@ -0,0 +1,79 @@ +// 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.Beatmaps.ControlPoints; + +namespace osu.Game.Tests.Editing +{ + [TestFixture] + public class TestSceneSnappingNearZero + { + private readonly ControlPointInfo cpi = new ControlPointInfo(); + + [Test] + public void TestOnZero() + { + test(0, 500, 0, 0); + test(0, 500, 100, 0); + test(0, 500, 250, 500); + test(0, 500, 600, 500); + + test(0, 500, -600, 0); + } + + [Test] + public void TestAlmostOnZero() + { + test(50, 500, 0, 50); + test(50, 500, 50, 50); + test(50, 500, 100, 50); + test(50, 500, 299, 50); + test(50, 500, 300, 550); + + test(50, 500, -500, 50); + } + + [Test] + public void TestAlmostOnOne() + { + test(499, 500, -1, 499); + test(499, 500, 0, 499); + test(499, 500, 1, 499); + test(499, 500, 499, 499); + test(499, 500, 600, 499); + test(499, 500, 800, 999); + } + + [Test] + public void TestOnOne() + { + test(500, 500, -500, 0); + test(500, 500, 0, 0); + test(500, 500, 200, 0); + test(500, 500, 400, 500); + test(500, 500, 500, 500); + test(500, 500, 600, 500); + test(500, 500, 900, 1000); + } + + [Test] + public void TestNegative() + { + test(-600, 500, -600, 400); + test(-600, 500, -100, 400); + test(-600, 500, 0, 400); + test(-600, 500, 200, 400); + test(-600, 500, 400, 400); + test(-600, 500, 600, 400); + test(-600, 500, 1000, 900); + } + + private void test(double pointTime, double beatLength, double from, double expected) + { + cpi.Clear(); + cpi.Add(pointTime, new TimingControlPoint { BeatLength = beatLength }); + Assert.That(cpi.GetClosestSnappedTime(from, 1), Is.EqualTo(expected), $"From: {from}"); + } + } +} From 51e21ee6f00962c396a1987ab248c236e1865f96 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 12 Jan 2023 03:38:57 +0300 Subject: [PATCH 18/83] Make snapped time always positive --- osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs index 29b7191ecf..1a15db98e4 100644 --- a/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs +++ b/osu.Game/Beatmaps/ControlPoints/ControlPointInfo.cs @@ -183,9 +183,15 @@ namespace osu.Game.Beatmaps.ControlPoints private static double getClosestSnappedTime(TimingControlPoint timingPoint, double time, int beatDivisor) { double beatLength = timingPoint.BeatLength / beatDivisor; - int beatLengths = (int)Math.Round((time - timingPoint.Time) / beatLength, MidpointRounding.AwayFromZero); + double beats = (Math.Max(time, 0) - timingPoint.Time) / beatLength; - return timingPoint.Time + beatLengths * beatLength; + int roundedBeats = (int)Math.Round(beats, MidpointRounding.AwayFromZero); + double snappedTime = timingPoint.Time + roundedBeats * beatLength; + + if (snappedTime >= 0) + return snappedTime; + + return snappedTime + beatLength; } /// From e8029e63908fff723cdabe43152ca534a1ed3f5e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Thu, 12 Jan 2023 03:39:27 +0300 Subject: [PATCH 19/83] Fix unrelated tests --- osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs | 8 ++++---- osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs index 6f3fe875e3..8ebf34b1ca 100644 --- a/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs +++ b/osu.Game.Tests/NonVisual/ClosestBeatDivisorTest.cs @@ -17,7 +17,7 @@ namespace osu.Game.Tests.NonVisual public void TestExactDivisors() { var cpi = new ControlPointInfo(); - cpi.Add(-1000, new TimingControlPoint { BeatLength = 1000 }); + cpi.Add(0, new TimingControlPoint { BeatLength = 1000 }); double[] divisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 }; @@ -47,7 +47,7 @@ namespace osu.Game.Tests.NonVisual public void TestExactDivisorsHighBPMStream() { var cpi = new ControlPointInfo(); - cpi.Add(-50, new TimingControlPoint { BeatLength = 50 }); // 1200 BPM 1/4 (limit testing) + cpi.Add(0, new TimingControlPoint { BeatLength = 50 }); // 1200 BPM 1/4 (limit testing) // A 1/4 stream should land on 1/1, 1/2 and 1/4 divisors. double[] divisors = { 4, 4, 4, 4, 4, 4, 4, 4 }; @@ -60,7 +60,7 @@ namespace osu.Game.Tests.NonVisual public void TestApproximateDivisors() { var cpi = new ControlPointInfo(); - cpi.Add(-1000, new TimingControlPoint { BeatLength = 1000 }); + cpi.Add(0, new TimingControlPoint { BeatLength = 1000 }); double[] divisors = { 3.03d, 0.97d, 14, 13, 7.94d, 6.08d, 3.93d, 2.96d, 2.02d, 64 }; double[] closestDivisors = { 3, 1, 16, 12, 8, 6, 4, 3, 2, 1 }; @@ -68,7 +68,7 @@ namespace osu.Game.Tests.NonVisual assertClosestDivisors(divisors, closestDivisors, cpi); } - private void assertClosestDivisors(IReadOnlyList divisors, IReadOnlyList closestDivisors, ControlPointInfo cpi, double step = 1) + private static void assertClosestDivisors(IReadOnlyList divisors, IReadOnlyList closestDivisors, ControlPointInfo cpi, double step = 1) { List hitobjects = new List(); double offset = cpi.TimingPoints[0].Time; diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs index 70118e0b67..b396b382ff 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorSaving.cs @@ -144,7 +144,7 @@ namespace osu.Game.Tests.Visual.Editing double lastStarRating = 0; double lastLength = 0; - AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(500, new TimingControlPoint())); + AddStep("Add timing point", () => EditorBeatmap.ControlPointInfo.Add(200, new TimingControlPoint { BeatLength = 600 })); AddStep("Change to placement mode", () => InputManager.Key(Key.Number2)); AddStep("Move to playfield", () => InputManager.MoveMouseTo(Game.ScreenSpaceDrawQuad.Centre)); AddStep("Place single hitcircle", () => InputManager.Click(MouseButton.Left)); From 403ca05e5e61aeecb19ce9afeb59ca91bf2a49db Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 13 Jan 2023 00:52:14 +0100 Subject: [PATCH 20/83] Enable nullability for song select --- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 + .../OnlinePlay/OnlinePlaySongSelect.cs | 2 +- osu.Game/Screens/Select/SongSelect.cs | 155 ++++++++++-------- 3 files changed, 87 insertions(+), 72 deletions(-) diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 873a1b0d50..6a4ce7aff5 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -105,6 +106,7 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => { + Debug.Assert(Carousel != null); Carousel.AllowSelection = true; }); }); diff --git a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs index b9d8912170..e0ae437d49 100644 --- a/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/OnlinePlaySongSelect.cs @@ -173,7 +173,7 @@ namespace osu.Game.Screens.OnlinePlay IsValidMod = IsValidMod }; - protected override IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() + protected override IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() { var buttons = base.CreateFooterButtons().ToList(); buttons.Insert(buttons.FindIndex(b => b.Item1 is FooterButtonMods) + 1, (new FooterButtonFreeMods { Current = FreeMods }, freeModSelectOverlay)); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index f4804c6a6c..6826dffd5f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Allocation; using osu.Framework.Audio; using osu.Framework.Audio.Sample; @@ -36,7 +34,6 @@ using osu.Framework.Input.Bindings; using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using System.Diagnostics; -using JetBrains.Annotations; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -49,7 +46,7 @@ namespace osu.Game.Screens.Select protected const float BACKGROUND_BLUR = 20; private const float left_area_padding = 20; - public FilterControl FilterControl { get; private set; } + public FilterControl FilterControl { get; private set; } = null!; /// /// Whether this song select instance should take control of the global track, @@ -64,18 +61,18 @@ namespace osu.Game.Screens.Select /// /// Can be null if is false. /// - protected BeatmapOptionsOverlay BeatmapOptions { get; private set; } + protected BeatmapOptionsOverlay BeatmapOptions { get; private set; } = null!; /// /// Can be null if is false. /// - protected Footer Footer { get; private set; } + protected Footer? Footer { get; private set; } /// /// Contains any panel which is triggered by a footer button. /// Helps keep them located beneath the footer itself. /// - protected Container FooterPanels { get; private set; } + protected Container FooterPanels { get; private set; } = null!; /// /// Whether entering editor mode should be allowed. @@ -85,50 +82,49 @@ namespace osu.Game.Screens.Select public bool BeatmapSetsLoaded => IsLoaded && Carousel?.BeatmapSetsLoaded == true; [Resolved] - private Bindable> selectedMods { get; set; } + private Bindable> selectedMods { get; set; } = null!; - protected BeatmapCarousel Carousel { get; private set; } + protected BeatmapCarousel? Carousel { get; private set; } - private ParallaxContainer wedgeBackground; + private ParallaxContainer wedgeBackground = null!; - protected Container LeftArea { get; private set; } + protected Container LeftArea { get; private set; } = null!; - private BeatmapInfoWedge beatmapInfoWedge; - - [Resolved(canBeNull: true)] - private IDialogOverlay dialogOverlay { get; set; } + private BeatmapInfoWedge beatmapInfoWedge = null!; [Resolved] - private BeatmapManager beatmaps { get; set; } + private IDialogOverlay? dialogOverlay { get; set; } - protected ModSelectOverlay ModSelect { get; private set; } + [Resolved] + private BeatmapManager beatmaps { get; set; } = null!; - protected Sample SampleConfirm { get; private set; } + protected ModSelectOverlay ModSelect { get; private set; } = null!; - private Sample sampleChangeDifficulty; - private Sample sampleChangeBeatmap; + protected Sample? SampleConfirm { get; private set; } - private Container carouselContainer; + private Sample sampleChangeDifficulty = null!; + private Sample sampleChangeBeatmap = null!; - protected BeatmapDetailArea BeatmapDetails { get; private set; } + private Container carouselContainer = null!; - private FooterButtonOptions beatmapOptionsButton; + protected BeatmapDetailArea BeatmapDetails { get; private set; } = null!; + + private FooterButtonOptions beatmapOptionsButton = null!; private readonly Bindable decoupledRuleset = new Bindable(); private double audioFeedbackLastPlaybackTime; - [CanBeNull] - private IDisposable modSelectOverlayRegistration; + private IDisposable? modSelectOverlayRegistration; [Resolved] - private MusicController music { get; set; } + private MusicController? music { get; set; } - [Resolved(CanBeNull = true)] - internal IOverlayManager OverlayManager { get; private set; } + [Resolved] + internal IOverlayManager? OverlayManager { get; private set; } [BackgroundDependencyLoader(true)] - private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog manageCollectionsDialog, DifficultyRecommender recommender) + private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). transferRulesetValue(); @@ -273,7 +269,7 @@ namespace osu.Game.Screens.Select BeatmapOptions = new BeatmapOptionsOverlay(), } }, - Footer = new Footer(), + Footer = new Footer() }); } @@ -318,16 +314,20 @@ namespace osu.Game.Screens.Select /// Creates the buttons to be displayed in the footer. /// /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton, OverlayContainer)> CreateFooterButtons() => new (FooterButton, OverlayContainer)[] + protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() { - (new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom + Debug.Assert(Carousel != null); + return new (FooterButton, OverlayContainer?)[] { - NextRandom = () => Carousel.SelectNextRandom(), - PreviousRandom = Carousel.SelectPreviousRandom - }, null), - (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) - }; + (new FooterButtonMods { Current = Mods }, ModSelect), + (new FooterButtonRandom + { + NextRandom = () => Carousel.SelectNextRandom(), + PreviousRandom = Carousel.SelectPreviousRandom + }, null), + (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) + }; + } protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -336,10 +336,11 @@ namespace osu.Game.Screens.Select // if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter). bool shouldDebounce = this.IsCurrentScreen(); + Debug.Assert(Carousel != null); Carousel.Filter(criteria, shouldDebounce); } - private DependencyContainer dependencies; + private DependencyContainer dependencies = null!; protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) { @@ -357,7 +358,7 @@ namespace osu.Game.Screens.Select /// protected abstract BeatmapDetailArea CreateBeatmapDetailArea(); - public void Edit(BeatmapInfo beatmapInfo = null) + public void Edit(BeatmapInfo? beatmapInfo = null) { if (!AllowEditing) throw new InvalidOperationException($"Attempted to edit when {nameof(AllowEditing)} is disabled"); @@ -372,8 +373,10 @@ namespace osu.Game.Screens.Select /// An optional beatmap to override the current carousel selection. /// An optional ruleset to override the current carousel selection. /// An optional custom action to perform instead of . - public void FinaliseSelection(BeatmapInfo beatmapInfo = null, RulesetInfo ruleset = null, Action customStartAction = null) + public void FinaliseSelection(BeatmapInfo? beatmapInfo = null, RulesetInfo? ruleset = null, Action? customStartAction = null) { + Debug.Assert(Carousel != null); + // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) { @@ -419,43 +422,44 @@ namespace osu.Game.Screens.Select /// If a resultant action occurred that takes the user away from SongSelect. protected abstract bool OnStart(); - private ScheduledDelegate selectionChangedDebounce; + private ScheduledDelegate? selectionChangedDebounce; - private void updateCarouselSelection(ValueChangedEvent e = null) + private void updateCarouselSelection(ValueChangedEvent? e = null) { var beatmap = e?.NewValue ?? Beatmap.Value; if (beatmap is DummyWorkingBeatmap || !this.IsCurrentScreen()) return; Logger.Log($"Song select working beatmap updated to {beatmap}"); - if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) + Debug.Assert(Carousel != null); + + if (Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) return; + + // A selection may not have been possible with filters applied. + + // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. + if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) { - // A selection may not have been possible with filters applied. - - // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. - if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) - { - Ruleset.Value = beatmap.BeatmapInfo.Ruleset; - transferRulesetValue(); - } - - // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), - // we still want to temporarily show the new beatmap, bypassing filters. - // This will be undone the next time the user changes the filter. - var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; - Carousel.Filter(criteria); - - Carousel.SelectBeatmap(beatmap.BeatmapInfo); + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + transferRulesetValue(); } + + // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), + // we still want to temporarily show the new beatmap, bypassing filters. + // This will be undone the next time the user changes the filter. + var criteria = FilterControl.CreateCriteria(); + criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; + Carousel.Filter(criteria); + + Carousel.SelectBeatmap(beatmap.BeatmapInfo); } // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. - private BeatmapInfo beatmapInfoPrevious; - private BeatmapInfo beatmapInfoNoDebounce; - private RulesetInfo rulesetNoDebounce; + private BeatmapInfo? beatmapInfoPrevious; + private BeatmapInfo? beatmapInfoNoDebounce; + private RulesetInfo? rulesetNoDebounce; - private void updateSelectedBeatmap(BeatmapInfo beatmapInfo) + private void updateSelectedBeatmap(BeatmapInfo? beatmapInfo) { if (beatmapInfo == null && beatmapInfoNoDebounce == null) return; @@ -467,7 +471,7 @@ namespace osu.Game.Screens.Select performUpdateSelected(); } - private void updateSelectedRuleset(RulesetInfo ruleset) + private void updateSelectedRuleset(RulesetInfo? ruleset) { if (ruleset == null && rulesetNoDebounce == null) return; @@ -485,7 +489,7 @@ namespace osu.Game.Screens.Select private void performUpdateSelected() { var beatmap = beatmapInfoNoDebounce; - var ruleset = rulesetNoDebounce; + RulesetInfo? ruleset = rulesetNoDebounce; selectionChangedDebounce?.Cancel(); @@ -518,6 +522,7 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { + Debug.Assert(Carousel != null); // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). @@ -604,6 +609,7 @@ namespace osu.Game.Screens.Select ModSelect.SelectedMods.Disabled = false; ModSelect.SelectedMods.BindTo(selectedMods); + Debug.Assert(Carousel != null); Carousel.AllowSelection = true; BeatmapDetails.Refresh(); @@ -620,6 +626,7 @@ namespace osu.Game.Screens.Select { // restart playback on returning to song select, regardless. // not sure this should be a permanent thing (we may want to leave a user pause paused even on returning) + Debug.Assert(music != null); music.ResetTrackAdjustments(); music.Play(requestedByUser: true); } @@ -665,6 +672,7 @@ namespace osu.Game.Screens.Select BeatmapOptions.Hide(); + Debug.Assert(Carousel != null); Carousel.AllowSelection = false; endLooping(); @@ -694,6 +702,8 @@ namespace osu.Game.Screens.Select isHandlingLooping = true; ensureTrackLooping(Beatmap.Value, TrackChangeDirection.None); + + Debug.Assert(music != null); music.TrackChanged += ensureTrackLooping; } @@ -703,6 +713,7 @@ namespace osu.Game.Screens.Select if (!isHandlingLooping) return; + Debug.Assert(music != null); music.CurrentTrack.Looping = isHandlingLooping = false; music.TrackChanged -= ensureTrackLooping; @@ -763,7 +774,7 @@ namespace osu.Game.Screens.Select } } - private readonly WeakReference lastTrack = new WeakReference(null); + private readonly WeakReference lastTrack = new WeakReference(null); /// /// Ensures some music is playing for the current track. @@ -774,6 +785,7 @@ namespace osu.Game.Screens.Select if (!ControlGlobalMusic) return; + Debug.Assert(music != null); ITrack track = music.CurrentTrack; bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; @@ -791,6 +803,7 @@ namespace osu.Game.Screens.Select { bindBindables(); + Debug.Assert(Carousel != null); Carousel.AllowSelection = true; // If a selection was already obtained, do not attempt to update the selected beatmap. @@ -868,14 +881,14 @@ namespace osu.Game.Screens.Select return true; } - private void delete(BeatmapSetInfo beatmap) + private void delete(BeatmapSetInfo? beatmap) { if (beatmap == null) return; dialogOverlay?.Push(new BeatmapDeleteDialog(beatmap)); } - private void clearScores(BeatmapInfo beatmapInfo) + private void clearScores(BeatmapInfo? beatmapInfo) { if (beatmapInfo == null) return; @@ -950,7 +963,7 @@ namespace osu.Game.Screens.Select private partial class ResetScrollContainer : Container { - private readonly Action onHoverAction; + private readonly Action? onHoverAction; public ResetScrollContainer(Action onHoverAction) { From 653376f5f2814476a3a29da545896d8c23badec7 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 13 Jan 2023 09:32:36 +0100 Subject: [PATCH 21/83] Fix test failures --- osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index cfee02dfb8..97ffd896c6 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1151,7 +1151,7 @@ namespace osu.Game.Tests.Visual.SongSelect public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; - public new BeatmapCarousel Carousel => base.Carousel; + public new BeatmapCarousel Carousel => base.Carousel!; public new ModSelectOverlay ModSelect => base.ModSelect; public new void PresentScore(ScoreInfo score) => base.PresentScore(score); From a6b6fb864eaa673e9f5cd325a1965624fb482973 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Fri, 13 Jan 2023 13:10:29 +0100 Subject: [PATCH 22/83] Make carousel non nullable and ensure pre load usages of methods that reference it are protected against failure --- .../SongSelect/TestScenePlaySongSelect.cs | 2 +- .../Multiplayer/MultiplayerMatchSongSelect.cs | 2 -- osu.Game/Screens/Select/SongSelect.cs | 29 +++++++------------ 3 files changed, 11 insertions(+), 22 deletions(-) diff --git a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs index 97ffd896c6..cfee02dfb8 100644 --- a/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs +++ b/osu.Game.Tests/Visual/SongSelect/TestScenePlaySongSelect.cs @@ -1151,7 +1151,7 @@ namespace osu.Game.Tests.Visual.SongSelect public WorkingBeatmap CurrentBeatmap => Beatmap.Value; public IWorkingBeatmap CurrentBeatmapDetailsBeatmap => BeatmapDetails.Beatmap; - public new BeatmapCarousel Carousel => base.Carousel!; + public new BeatmapCarousel Carousel => base.Carousel; public new ModSelectOverlay ModSelect => base.ModSelect; public new void PresentScore(ScoreInfo score) => base.PresentScore(score); diff --git a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs index 6a4ce7aff5..873a1b0d50 100644 --- a/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs +++ b/osu.Game/Screens/OnlinePlay/Multiplayer/MultiplayerMatchSongSelect.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Diagnostics; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -106,7 +105,6 @@ namespace osu.Game.Screens.OnlinePlay.Multiplayer Schedule(() => { - Debug.Assert(Carousel != null); Carousel.AllowSelection = true; }); }); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 6826dffd5f..ef5827fad7 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -79,12 +79,12 @@ namespace osu.Game.Screens.Select /// public virtual bool AllowEditing => true; - public bool BeatmapSetsLoaded => IsLoaded && Carousel?.BeatmapSetsLoaded == true; + public bool BeatmapSetsLoaded => IsLoaded && Carousel.BeatmapSetsLoaded; [Resolved] private Bindable> selectedMods { get; set; } = null!; - protected BeatmapCarousel? Carousel { get; private set; } + protected BeatmapCarousel Carousel { get; private set; } = null!; private ParallaxContainer wedgeBackground = null!; @@ -127,7 +127,7 @@ namespace osu.Game.Screens.Select private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(); + transferRulesetValue(false); LoadComponentAsync(Carousel = new BeatmapCarousel { @@ -314,10 +314,8 @@ namespace osu.Game.Screens.Select /// Creates the buttons to be displayed in the footer. /// /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() - { - Debug.Assert(Carousel != null); - return new (FooterButton, OverlayContainer?)[] + protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() => + new (FooterButton, OverlayContainer?)[] { (new FooterButtonMods { Current = Mods }, ModSelect), (new FooterButtonRandom @@ -327,7 +325,6 @@ namespace osu.Game.Screens.Select }, null), (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) }; - } protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -336,7 +333,6 @@ namespace osu.Game.Screens.Select // if not the current screen, we want to get carousel in a good presentation state before displaying (resume or enter). bool shouldDebounce = this.IsCurrentScreen(); - Debug.Assert(Carousel != null); Carousel.Filter(criteria, shouldDebounce); } @@ -375,8 +371,6 @@ namespace osu.Game.Screens.Select /// An optional custom action to perform instead of . public void FinaliseSelection(BeatmapInfo? beatmapInfo = null, RulesetInfo? ruleset = null, Action? customStartAction = null) { - Debug.Assert(Carousel != null); - // This is very important as we have not yet bound to screen-level bindables before the carousel load is completed. if (!Carousel.BeatmapSetsLoaded) { @@ -431,8 +425,6 @@ namespace osu.Game.Screens.Select Logger.Log($"Song select working beatmap updated to {beatmap}"); - Debug.Assert(Carousel != null); - if (Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) return; // A selection may not have been possible with filters applied. @@ -522,7 +514,6 @@ namespace osu.Game.Screens.Select if (transferRulesetValue()) { - Debug.Assert(Carousel != null); // transferRulesetValue() may trigger a re-filter. If the current selection does not match the new ruleset, we want to switch away from it. // The default logic on WorkingBeatmap change is to switch to a matching ruleset (see workingBeatmapChanged()), but we don't want that here. // We perform an early selection attempt and clear out the beatmap selection to avoid a second ruleset change (revert). @@ -609,7 +600,6 @@ namespace osu.Game.Screens.Select ModSelect.SelectedMods.Disabled = false; ModSelect.SelectedMods.BindTo(selectedMods); - Debug.Assert(Carousel != null); Carousel.AllowSelection = true; BeatmapDetails.Refresh(); @@ -672,7 +662,6 @@ namespace osu.Game.Screens.Select BeatmapOptions.Hide(); - Debug.Assert(Carousel != null); Carousel.AllowSelection = false; endLooping(); @@ -803,7 +792,6 @@ namespace osu.Game.Screens.Select { bindBindables(); - Debug.Assert(Carousel != null); Carousel.AllowSelection = true; // If a selection was already obtained, do not attempt to update the selected beatmap. @@ -867,7 +855,7 @@ namespace osu.Game.Screens.Select /// Will immediately run filter operations if required. /// /// Whether a transfer occurred. - private bool transferRulesetValue() + private bool transferRulesetValue(bool carouselLoaded = true) { if (decoupledRuleset.Value?.Equals(Ruleset.Value) == true) return false; @@ -875,9 +863,12 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; + // We don't want to declare the carousel as nullable, so this check allows us to avoid running the carousel flush during the loading process + if (!carouselLoaded) return true; + // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). - Carousel?.FlushPendingFilterOperations(); + Carousel.FlushPendingFilterOperations(); return true; } From 0b5c89d01fde788848440d474b3d50de8e30383e Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Fri, 13 Jan 2023 23:07:21 +0000 Subject: [PATCH 23/83] revert additions to `SessionStatics` --- osu.Game.Tests/NonVisual/SessionStaticsTest.cs | 6 ------ osu.Game/Configuration/SessionStatics.cs | 4 ---- .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 15 --------------- 3 files changed, 25 deletions(-) diff --git a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs index 499c0e5d34..5c8254b947 100644 --- a/osu.Game.Tests/NonVisual/SessionStaticsTest.cs +++ b/osu.Game.Tests/NonVisual/SessionStaticsTest.cs @@ -24,16 +24,12 @@ namespace osu.Game.Tests.NonVisual sessionStatics.SetValue(Static.MutedAudioNotificationShownOnce, true); sessionStatics.SetValue(Static.LowBatteryNotificationShownOnce, true); sessionStatics.SetValue(Static.LastHoverSoundPlaybackTime, (double?)1d); - sessionStatics.SetValue(Static.ReplayPlaybackSettingExpanded, false); - sessionStatics.SetValue(Static.ReplayVisualSettingsExpanded, true); sessionStatics.SetValue(Static.SeasonalBackgrounds, new APISeasonalBackgrounds { EndDate = new DateTimeOffset(2022, 1, 1, 0, 0, 0, TimeSpan.Zero) }); Assert.IsFalse(sessionStatics.GetBindable(Static.LoginOverlayDisplayed).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.MutedAudioNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); sessionStatics.ResetAfterInactivity(); @@ -43,8 +39,6 @@ namespace osu.Game.Tests.NonVisual Assert.IsTrue(sessionStatics.GetBindable(Static.LowBatteryNotificationShownOnce).IsDefault); // some statics should not reset despite inactivity. Assert.IsFalse(sessionStatics.GetBindable(Static.LastHoverSoundPlaybackTime).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayPlaybackSettingExpanded).IsDefault); - Assert.IsFalse(sessionStatics.GetBindable(Static.ReplayVisualSettingsExpanded).IsDefault); Assert.IsFalse(sessionStatics.GetBindable(Static.SeasonalBackgrounds).IsDefault); } } diff --git a/osu.Game/Configuration/SessionStatics.cs b/osu.Game/Configuration/SessionStatics.cs index f08658f182..12a30a0c84 100644 --- a/osu.Game/Configuration/SessionStatics.cs +++ b/osu.Game/Configuration/SessionStatics.cs @@ -20,8 +20,6 @@ namespace osu.Game.Configuration SetDefault(Static.MutedAudioNotificationShownOnce, false); SetDefault(Static.LowBatteryNotificationShownOnce, false); SetDefault(Static.LastHoverSoundPlaybackTime, (double?)null); - SetDefault(Static.ReplayPlaybackSettingExpanded, true); - SetDefault(Static.ReplayVisualSettingsExpanded, false); SetDefault(Static.SeasonalBackgrounds, null); } @@ -44,8 +42,6 @@ namespace osu.Game.Configuration LoginOverlayDisplayed, MutedAudioNotificationShownOnce, LowBatteryNotificationShownOnce, - ReplayPlaybackSettingExpanded, - ReplayVisualSettingsExpanded, /// /// Info about seasonal backgrounds available fetched from API - see . diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index c4f07f77cd..1edb227a75 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -3,15 +3,12 @@ #nullable disable -using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osuTK; using osu.Game.Screens.Play.PlayerSettings; using osuTK.Input; -using osu.Game.Configuration; -using osu.Framework.Allocation; namespace osu.Game.Screens.Play.HUD { @@ -19,9 +16,6 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; - private Bindable playbackMenuExpanded; - - private Bindable visualMenuExpanded; public bool ReplayLoaded; @@ -54,15 +48,6 @@ namespace osu.Game.Screens.Play.HUD }; } - [BackgroundDependencyLoader] - private void load(SessionStatics statics) - { - playbackMenuExpanded = statics.GetBindable(Static.ReplayPlaybackSettingExpanded); - visualMenuExpanded = statics.GetBindable(Static.ReplayVisualSettingsExpanded); - - PlaybackSettings.Expanded.BindTo(playbackMenuExpanded); - VisualSettings.Expanded.BindTo(visualMenuExpanded); - } protected override void PopIn() => this.FadeIn(fade_duration); protected override void PopOut() => this.FadeOut(fade_duration); From c3c1d77e8e8d0ccab211e461c84b73062c7aeece Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Fri, 13 Jan 2023 23:07:59 +0000 Subject: [PATCH 24/83] make `PlayerSettingsGroup` expand on hover --- .../Screens/Play/HUD/PlayerSettingsOverlay.cs | 6 ++--- .../PlayerSettings/PlayerSettingsGroup.cs | 24 +++++++++++++++++++ 2 files changed, 26 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs index 1edb227a75..019ba53a5e 100644 --- a/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs +++ b/osu.Game/Screens/Play/HUD/PlayerSettingsOverlay.cs @@ -16,7 +16,6 @@ namespace osu.Game.Screens.Play.HUD { private const int fade_duration = 200; - public bool ReplayLoaded; public readonly PlaybackSettings PlaybackSettings; @@ -42,13 +41,12 @@ namespace osu.Game.Screens.Play.HUD { //CollectionSettings = new CollectionSettings(), //DiscussionSettings = new DiscussionSettings(), - PlaybackSettings = new PlaybackSettings(), - VisualSettings = new VisualSettings() + PlaybackSettings = new PlaybackSettings { Expanded = { Value = false } }, + VisualSettings = new VisualSettings { Expanded = { Value = false } } } }; } - protected override void PopIn() => this.FadeIn(fade_duration); protected override void PopOut() => this.FadeOut(fade_duration); diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 6c6f62a8ac..63e081b2ea 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -4,6 +4,7 @@ #nullable disable using osu.Framework.Input.Events; +using osu.Framework.Threading; using osu.Game.Overlays; namespace osu.Game.Screens.Play.PlayerSettings @@ -15,12 +16,35 @@ namespace osu.Game.Screens.Play.PlayerSettings { } + private ScheduledDelegate hoverExpandEvent; + protected override bool OnHover(HoverEvent e) { + updateHoverExpansion(); base.OnHover(e); // Importantly, return true to correctly take focus away from PlayerLoader. return true; } + + protected override void OnHoverLost(HoverLostEvent e) + { + if (hoverExpandEvent == null) return; + + hoverExpandEvent?.Cancel(); + hoverExpandEvent = null; + + Expanded.Value = false; + + base.OnHoverLost(e); + } + + private void updateHoverExpansion() + { + hoverExpandEvent?.Cancel(); + + if (IsHovered && !Expanded.Value) + hoverExpandEvent = Scheduler.AddDelayed(() => Expanded.Value = true, 0); + } } } From 9e7ecbf4a14ebf97459677b128ef70528d0115e2 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 02:41:11 +0300 Subject: [PATCH 25/83] Adapt to changes in base class --- osu.Game/Overlays/Comments/CommentsContainer.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 98c186b273..08542bbcea 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -429,15 +429,15 @@ namespace osu.Game.Overlays.Comments protected override void OnCommit(string text) { - CommitButton.IsLoadingSpinnerShown = true; + ShowLoadingSpinner = true; CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); req.Failure += _ => Schedule(() => { - CommitButton.IsLoadingSpinnerShown = false; + ShowLoadingSpinner = false; }); req.Success += cb => Schedule(() => { - CommitButton.IsLoadingSpinnerShown = false; + ShowLoadingSpinner = false; Current.Value = string.Empty; OnPost?.Invoke(cb); }); From bb8bcd7248153a5bf1ae2c96dcaf0e93bda0502e Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 02:50:30 +0300 Subject: [PATCH 26/83] Move avatar update bind to LoadComplete --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 08542bbcea..9446857f5e 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -183,12 +183,12 @@ namespace osu.Game.Overlays.Comments }); User.BindTo(api.LocalUser); - User.BindValueChanged(e => avatar.User = e.NewValue); } protected override void LoadComplete() { User.BindValueChanged(_ => refetchComments()); + User.BindValueChanged(e => avatar.User = e.NewValue); Sort.BindValueChanged(_ => refetchComments(), true); base.LoadComplete(); } From 2831db53f74088e1fb08e39cf51ded52cd5d76e9 Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Sat, 14 Jan 2023 14:19:02 +0000 Subject: [PATCH 27/83] fix wrong control flow on hover lost --- .../Play/PlayerSettings/PlayerSettingsGroup.cs | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index 63e081b2ea..f4769cd417 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -29,12 +29,13 @@ namespace osu.Game.Screens.Play.PlayerSettings protected override void OnHoverLost(HoverLostEvent e) { - if (hoverExpandEvent == null) return; + if (hoverExpandEvent != null) + { + hoverExpandEvent?.Cancel(); + hoverExpandEvent = null; - hoverExpandEvent?.Cancel(); - hoverExpandEvent = null; - - Expanded.Value = false; + Expanded.Value = false; + } base.OnHoverLost(e); } From fbb674d8e9d809b9a5154525d96e36685e928fac Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 20:15:19 +0300 Subject: [PATCH 28/83] Rename parent comment id field --- osu.Game/Online/API/Requests/CommentPostRequest.cs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Online/API/Requests/CommentPostRequest.cs b/osu.Game/Online/API/Requests/CommentPostRequest.cs index 7012d479bd..45e5eb1a94 100644 --- a/osu.Game/Online/API/Requests/CommentPostRequest.cs +++ b/osu.Game/Online/API/Requests/CommentPostRequest.cs @@ -12,14 +12,14 @@ namespace osu.Game.Online.API.Requests public readonly CommentableType Commentable; public readonly long CommentableId; public readonly string Message; - public readonly long? ReplyTo; + public readonly long? ParentCommentId; - public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? replyTo = null) + public CommentPostRequest(CommentableType commentable, long commentableId, string message, long? parentCommentId = null) { Commentable = commentable; CommentableId = commentableId; Message = message; - ReplyTo = replyTo; + ParentCommentId = parentCommentId; } protected override WebRequest CreateWebRequest() @@ -30,8 +30,8 @@ namespace osu.Game.Online.API.Requests req.AddParameter(@"comment[commentable_type]", Commentable.ToString().ToLowerInvariant()); req.AddParameter(@"comment[commentable_id]", $"{CommentableId}"); req.AddParameter(@"comment[message]", Message); - if (ReplyTo.HasValue) - req.AddParameter(@"comment[parent_id]", $"{ReplyTo}"); + if (ParentCommentId.HasValue) + req.AddParameter(@"comment[parent_id]", $"{ParentCommentId}"); return req; } From 3102044d00a85caaaafd059f77a08022dfd2d7aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 14 Jan 2023 18:46:14 +0100 Subject: [PATCH 29/83] Add failing test for new difficulty creation --- .../Editing/TestSceneEditorBeatmapCreation.cs | 49 +++++++++++++++++++ 1 file changed, 49 insertions(+) diff --git a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs index a40c7814e1..3f89bf9e9c 100644 --- a/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs +++ b/osu.Game.Tests/Visual/Editing/TestSceneEditorBeatmapCreation.cs @@ -20,6 +20,8 @@ using osu.Game.Rulesets.Catch; using osu.Game.Rulesets.Osu; using osu.Game.Rulesets.Osu.Objects; using osu.Game.Rulesets.Osu.UI; +using osu.Game.Rulesets.Taiko; +using osu.Game.Rulesets.Taiko.Objects; using osu.Game.Screens.Edit; using osu.Game.Screens.Edit.Setup; using osu.Game.Storyboards; @@ -395,5 +397,52 @@ namespace osu.Game.Tests.Visual.Editing return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2); }); } + + [Test] + public void TestCreateNewDifficultyForInconvertibleRuleset() + { + Guid setId = Guid.Empty; + + AddStep("retrieve set ID", () => setId = EditorBeatmap.BeatmapInfo.BeatmapSet!.ID); + AddStep("save beatmap", () => Editor.Save()); + AddStep("try to create new taiko difficulty", () => Editor.CreateNewDifficulty(new TaikoRuleset().RulesetInfo)); + + AddUntilStep("wait for created", () => + { + string? difficultyName = Editor.ChildrenOfType().SingleOrDefault()?.BeatmapInfo.DifficultyName; + return difficultyName != null && difficultyName == "New Difficulty"; + }); + AddAssert("new difficulty persisted", () => + { + var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId); + return set != null && set.PerformRead(s => s.Beatmaps.Count == 2 && s.Files.Count == 2); + }); + + AddStep("add timing point", () => EditorBeatmap.ControlPointInfo.Add(0, new TimingControlPoint { BeatLength = 1000 })); + AddStep("add hitobjects", () => EditorBeatmap.AddRange(new[] + { + new Hit + { + StartTime = 0 + }, + new Hit + { + StartTime = 1000 + } + })); + AddStep("save beatmap", () => Editor.Save()); + AddStep("try to create new catch difficulty", () => Editor.CreateNewDifficulty(new CatchRuleset().RulesetInfo)); + + AddUntilStep("wait for created", () => + { + string? difficultyName = Editor.ChildrenOfType().SingleOrDefault()?.BeatmapInfo.DifficultyName; + return difficultyName != null && difficultyName == "New Difficulty (1)"; + }); + AddAssert("new difficulty persisted", () => + { + var set = beatmapManager.QueryBeatmapSet(s => s.ID == setId); + return set != null && set.PerformRead(s => s.Beatmaps.Count == 3 && s.Files.Count == 3); + }); + } } } From 88c3eef8e1b48e01827c50d10cacfca55bebad53 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 20:59:13 +0300 Subject: [PATCH 30/83] Add test case with no existing comments --- .../Online/TestSceneCommentsContainer.cs | 45 ++++++++++++++----- .../Overlays/Comments/CommentsContainer.cs | 2 +- 2 files changed, 36 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index e58423241b..4a41eca898 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -32,13 +32,18 @@ namespace osu.Game.Tests.Visual.Online private CommentsContainer commentsContainer; + private TextBox editorTextBox; + [SetUp] public void SetUp() => Schedule(() => + { Child = new BasicScrollContainer { RelativeSizeAxes = Axes.Both, Child = commentsContainer = new CommentsContainer() - }); + }; + editorTextBox = commentsContainer.ChildrenOfType().First(); + }); [Test] public void TestIdleState() @@ -129,21 +134,41 @@ namespace osu.Game.Tests.Visual.Online commentsContainer.ChildrenOfType().Count(d => d.Comment.Pinned == withPinned) == 1); } - [TestCase] + [Test] public void TestPost() + { + setUpCommentsResponse(new CommentBundle { Comments = new List() }); + AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + AddAssert("no comments placeholder shown", () => commentsContainer.ChildrenOfType().Any()); + + setUpPostResponse(); + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => + { + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().Last(); + return comment.ChildrenOfType().Any(y => y.Text == writtenText); + }); + AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType().Any()); + } + + [Test] + public void TestPostWithExistingComments() { setUpCommentsResponse(getExampleComments()); AddStep("show comments", () => commentsContainer.ShowComments(CommentableType.Beatmapset, 123)); + setUpPostResponse(); - AddStep("Enter text", () => this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value = "comm"); - AddStep("Submit", () => this.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); - AddUntilStep("Comment sent", () => + AddStep("enter text", () => editorTextBox.Current.Value = "comm"); + AddStep("submit", () => commentsContainer.ChildrenOfType().Single().ChildrenOfType().First().TriggerClick()); + + AddUntilStep("comment sent", () => { - string text = this.ChildrenOfType().Single().ChildrenOfType().Single().Current.Value; - return this.ChildrenOfType().Any(x => - { - return x.ChildrenOfType().Any(y => y.Text == text); - }); + string writtenText = editorTextBox.Current.Value; + var comment = commentsContainer.ChildrenOfType().Last(); + return comment.ChildrenOfType().Any(y => y.Text == writtenText); }); } diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 9446857f5e..a8939ffdc6 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -390,7 +390,7 @@ namespace osu.Game.Overlays.Comments base.Dispose(isDisposing); } - private partial class NoCommentsPlaceholder : CompositeDrawable + internal partial class NoCommentsPlaceholder : CompositeDrawable { [BackgroundDependencyLoader] private void load() From e7ab54379933937e8affbb008b0e3dacd3e3c92a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Fri, 13 Jan 2023 16:08:34 -0800 Subject: [PATCH 31/83] Add ability to view converted beatmaps on beatmap set overlay --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ++++ osu.Game/Online/API/Requests/Responses/APIBeatmap.cs | 3 +++ osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 3 +++ osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 5 +++-- osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs | 3 ++- 5 files changed, 15 insertions(+), 3 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 1665ec52fa..41db2399ac 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -13,6 +13,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -116,6 +117,9 @@ namespace osu.Game.Beatmaps.Drawables private Drawable getRulesetIcon() { + if ((beatmap as APIBeatmap)?.Convert == true) + return rulesets.GetRuleset(0)!.CreateInstance().CreateIcon(); + int? onlineID = ruleset.OnlineID; if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs index 27ad2a746c..7d6740ee46 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmap.cs @@ -63,6 +63,9 @@ namespace osu.Game.Online.API.Requests.Responses set => Length = TimeSpan.FromSeconds(value).TotalMilliseconds; } + [JsonProperty(@"convert")] + public bool Convert { get; set; } + [JsonProperty(@"count_circles")] public int CircleCount { get; set; } diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index aeae3edde2..d39ed1e1ed 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -125,6 +125,9 @@ namespace osu.Game.Online.API.Requests.Responses [JsonProperty(@"beatmaps")] public APIBeatmap[] Beatmaps { get; set; } = Array.Empty(); + [JsonProperty(@"converts")] + public APIBeatmap[] Converts { get; set; } = Array.Empty(); + private BeatmapMetadata metadata => new BeatmapMetadata { Title = Title, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 84d12f2611..51b6b14579 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -168,9 +168,10 @@ namespace osu.Game.Overlays.BeatmapSet if (BeatmapSet != null) { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Concat(BeatmapSet.Converts) .Where(b => b.Ruleset.MatchesOnlineID(ruleset.Value)) - .OrderBy(b => b.StarRating) + .OrderBy(b => !b.Convert) + .ThenBy(b => b.StarRating) .Select(b => new DifficultySelectorButton(b) { State = DifficultySelectorState.NotSelected, diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs index f802807c3c..76e2f256b0 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapRulesetTabItem.cs @@ -68,11 +68,12 @@ namespace osu.Game.Overlays.BeatmapSet BeatmapSet.BindValueChanged(setInfo => { int beatmapsCount = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.MatchesOnlineID(Value)) ?? 0; + int osuBeatmaps = setInfo.NewValue?.Beatmaps.Count(b => b.Ruleset.OnlineID == 0) ?? 0; count.Text = beatmapsCount.ToString(); countContainer.FadeTo(beatmapsCount > 0 ? 1 : 0); - Enabled.Value = beatmapsCount > 0; + Enabled.Value = beatmapsCount > 0 || osuBeatmaps > 0; }, true); } } From a9facc076f37fc6663bae5e0b64c5e124bf9e3b5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 14 Jan 2023 19:39:30 +0100 Subject: [PATCH 32/83] Fix difficulty creation flow failing for some ruleset combinations In current `master`, the difficulty creation flow would retrieve a "reference beatmap" to copy metadata and timing points from using `GetPlayableBeatmap()`. But, importantly, it was calling that method using *the ruleset of the new difficulty* rather than the ruleset of the existing one. This would make the difficulty creation flow fail if the beatmap couldn't be converted between rulesets (like taiko to catch). Fixing to use the reference beatmap's actual ruleset would be trivial, but there's no real reason to do all of that work anyway when a `WorkingBeatmap` is available. Because getting a playable beatmap is not required to copy across metadata and timing points, remove the `GetPlayableBeatmap()` step entirely to fix the bug. Closes #22145. --- osu.Game/Beatmaps/BeatmapManager.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Beatmaps/BeatmapManager.cs b/osu.Game/Beatmaps/BeatmapManager.cs index eafd1e96e8..34637501fa 100644 --- a/osu.Game/Beatmaps/BeatmapManager.cs +++ b/osu.Game/Beatmaps/BeatmapManager.cs @@ -136,14 +136,12 @@ namespace osu.Game.Beatmaps /// The ruleset with which the new difficulty should be created. public virtual WorkingBeatmap CreateNewDifficulty(BeatmapSetInfo targetBeatmapSet, WorkingBeatmap referenceWorkingBeatmap, RulesetInfo rulesetInfo) { - var playableBeatmap = referenceWorkingBeatmap.GetPlayableBeatmap(rulesetInfo); - - var newBeatmapInfo = new BeatmapInfo(rulesetInfo, new BeatmapDifficulty(), playableBeatmap.Metadata.DeepClone()) + var newBeatmapInfo = new BeatmapInfo(rulesetInfo, new BeatmapDifficulty(), referenceWorkingBeatmap.Metadata.DeepClone()) { DifficultyName = NamingUtils.GetNextBestName(targetBeatmapSet.Beatmaps.Select(b => b.DifficultyName), "New Difficulty") }; var newBeatmap = new Beatmap { BeatmapInfo = newBeatmapInfo }; - foreach (var timingPoint in playableBeatmap.ControlPointInfo.TimingPoints) + foreach (var timingPoint in referenceWorkingBeatmap.Beatmap.ControlPointInfo.TimingPoints) newBeatmap.ControlPointInfo.Add(timingPoint.Time, timingPoint.DeepClone()); return addDifficultyToSet(targetBeatmapSet, newBeatmap, referenceWorkingBeatmap.Skin); From cdf3aafdddd4c987c2ad8b5aa4ece2a03703f174 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:37:05 +0300 Subject: [PATCH 33/83] Add check for any drawables in content before looking for placeholder --- osu.Game/Overlays/Comments/CommentsContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index a8939ffdc6..58f7a72ee5 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -342,7 +342,7 @@ namespace osu.Game.Overlays.Comments { LoadComponentsAsync(topLevelComments, loaded => { - if (content[0] is NoCommentsPlaceholder placeholder) + if (content.Count > 0 && content[0] is NoCommentsPlaceholder placeholder) content.Remove(placeholder, true); foreach (var comment in loaded) From c2bb0949f52404739cea5dd5d544b3068615efb8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:57:23 +0300 Subject: [PATCH 34/83] Take type and id from container directly on submit --- .../Overlays/Comments/CommentsContainer.cs | 24 ++++++++----------- 1 file changed, 10 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 58f7a72ee5..67db0714dc 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -29,13 +29,10 @@ namespace osu.Game.Overlays.Comments [Cached] public partial class CommentsContainer : CompositeDrawable { - private const string cid = "commentableId"; - - [Cached] private readonly Bindable type = new Bindable(); - - [Cached(name: cid)] private readonly BindableLong id = new BindableLong(); + public IBindable Type => type; + public IBindable Id => id; public readonly Bindable Sort = new Bindable(); public readonly BindableBool ShowDeleted = new BindableBool(); @@ -413,24 +410,23 @@ namespace osu.Game.Overlays.Comments private partial class NewCommentEditor : CommentEditor { [Resolved] - public Bindable CommentableType { get; set; } - - [Resolved(name: cid)] - public BindableLong CommentableId { get; set; } - - protected override LocalisableString FooterText => default; - protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; - protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + private CommentsContainer commentsContainer { get; set; } [Resolved] private IAPIProvider api { get; set; } public Action OnPost; + protected override LocalisableString FooterText => default; + + protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; + + protected override LocalisableString TextBoxPlaceholder => CommentsStrings.PlaceholderNew; + protected override void OnCommit(string text) { ShowLoadingSpinner = true; - CommentPostRequest req = new CommentPostRequest(CommentableType.Value, CommentableId.Value, text); + CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text); req.Failure += _ => Schedule(() => { ShowLoadingSpinner = false; From c36922dd2c630dfb621633e359de61b0636941e7 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 22:57:51 +0300 Subject: [PATCH 35/83] Use clock to obtain a position for comment insertion --- osu.Game/Overlays/Comments/CommentsContainer.cs | 10 +--------- 1 file changed, 1 insertion(+), 9 deletions(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 67db0714dc..c626d1f26c 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -344,15 +344,7 @@ namespace osu.Game.Overlays.Comments foreach (var comment in loaded) { - int pos = -1; - - if (content.Count > 0) - { - var first = content.FlowingChildren.First(); - pos = (int)(content.GetLayoutPosition(first) - 1); - } - - content.Insert(pos, comment); + content.Insert((int)-Clock.CurrentTime, comment); } }, (loadCancellation = new CancellationTokenSource()).Token); } From 58406cae19851cf6910ffb5fbc04aea54af78e42 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 23:42:10 +0300 Subject: [PATCH 36/83] Make test wait for comment loading --- .../Visual/Online/TestSceneCommentsContainer.cs | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs index 4a41eca898..3d8781d902 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneCommentsContainer.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.Linq; @@ -30,9 +28,9 @@ namespace osu.Game.Tests.Visual.Online private DummyAPIAccess dummyAPI => (DummyAPIAccess)API; - private CommentsContainer commentsContainer; + private CommentsContainer commentsContainer = null!; - private TextBox editorTextBox; + private TextBox editorTextBox = null!; [SetUp] public void SetUp() => Schedule(() => @@ -148,8 +146,8 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("comment sent", () => { string writtenText = editorTextBox.Current.Value; - var comment = commentsContainer.ChildrenOfType().Last(); - return comment.ChildrenOfType().Any(y => y.Text == writtenText); + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText); }); AddAssert("no comments placeholder removed", () => !commentsContainer.ChildrenOfType().Any()); } @@ -167,8 +165,8 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("comment sent", () => { string writtenText = editorTextBox.Current.Value; - var comment = commentsContainer.ChildrenOfType().Last(); - return comment.ChildrenOfType().Any(y => y.Text == writtenText); + var comment = commentsContainer.ChildrenOfType().LastOrDefault(); + return comment != null && comment.ChildrenOfType().Any(y => y.Text == writtenText); }); } From 1480c691ae8bbf2ca0fbe4b88acc5eb426f7ffc5 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sat, 14 Jan 2023 23:42:56 +0300 Subject: [PATCH 37/83] Explain empty string in editor's footer --- osu.Game/Overlays/Comments/CommentsContainer.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index c626d1f26c..3639fe1835 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -409,6 +409,7 @@ namespace osu.Game.Overlays.Comments public Action OnPost; + //TODO should match web, left empty due to no multiline support protected override LocalisableString FooterText => default; protected override LocalisableString CommitButtonText => CommonStrings.ButtonsPost; From a68d4fe5d18da32ede6420f50520769e20739106 Mon Sep 17 00:00:00 2001 From: integer <7279624+integerrr@users.noreply.github.com> Date: Sat, 14 Jan 2023 21:18:51 +0000 Subject: [PATCH 38/83] make expansion to not use scheduler --- .../PlayerSettings/PlayerSettingsGroup.cs | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index f4769cd417..55cf69b0f2 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -4,7 +4,6 @@ #nullable disable using osu.Framework.Input.Events; -using osu.Framework.Threading; using osu.Game.Overlays; namespace osu.Game.Screens.Play.PlayerSettings @@ -16,11 +15,16 @@ namespace osu.Game.Screens.Play.PlayerSettings { } - private ScheduledDelegate hoverExpandEvent; + private bool expandedByDefault = true; protected override bool OnHover(HoverEvent e) { - updateHoverExpansion(); + if (IsHovered && !Expanded.Value) + { + Expanded.Value = true; + expandedByDefault = false; + } + base.OnHover(e); // Importantly, return true to correctly take focus away from PlayerLoader. @@ -29,23 +33,10 @@ namespace osu.Game.Screens.Play.PlayerSettings protected override void OnHoverLost(HoverLostEvent e) { - if (hoverExpandEvent != null) - { - hoverExpandEvent?.Cancel(); - hoverExpandEvent = null; - + if (!expandedByDefault) Expanded.Value = false; - } base.OnHoverLost(e); } - - private void updateHoverExpansion() - { - hoverExpandEvent?.Cancel(); - - if (IsHovered && !Expanded.Value) - hoverExpandEvent = Scheduler.AddDelayed(() => Expanded.Value = true, 0); - } } } From 76eefc7573a5267ddf3016517d77e0eea1adf272 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:46:11 +0300 Subject: [PATCH 39/83] Add support for localisation where it was missing --- osu.Game/Graphics/UserInterface/OsuMenuItem.cs | 6 ++---- osu.Game/Graphics/UserInterface/StatefulMenuItem.cs | 11 +++++------ osu.Game/Graphics/UserInterface/ToggleMenuItem.cs | 7 +++---- .../Screens/Edit/Components/Menus/EditorMenuItem.cs | 9 +++++---- .../Components/Menus/EditorScreenSwitcherControl.cs | 5 ----- 5 files changed, 15 insertions(+), 23 deletions(-) diff --git a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs index 9d65d6b8b9..20461de08f 100644 --- a/osu.Game/Graphics/UserInterface/OsuMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/OsuMenuItem.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Graphics.UserInterface; using osu.Framework.Localisation; @@ -13,12 +11,12 @@ namespace osu.Game.Graphics.UserInterface { public readonly MenuItemType Type; - public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard) + public OsuMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } - public OsuMenuItem(LocalisableString text, MenuItemType type, Action action) + public OsuMenuItem(LocalisableString text, MenuItemType type, Action? action) : base(text, action) { Type = type; diff --git a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs index 17266e876c..85efd75a60 100644 --- a/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/StatefulMenuItem.cs @@ -1,11 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Bindables; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterface { @@ -25,7 +24,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) + protected StatefulMenuItem(LocalisableString text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) : this(text, changeStateFunc, type, null) { } @@ -37,7 +36,7 @@ namespace osu.Game.Graphics.UserInterface /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + protected StatefulMenuItem(LocalisableString text, Func? changeStateFunc, MenuItemType type, Action? action) : base(text, type) { Action.Value = () => @@ -69,7 +68,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type = MenuItemType.Standard) + protected StatefulMenuItem(LocalisableString text, Func? changeStateFunc, MenuItemType type = MenuItemType.Standard) : this(text, changeStateFunc, type, null) { } @@ -81,7 +80,7 @@ namespace osu.Game.Graphics.UserInterface /// A function that mutates a state to another state after this is pressed. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - protected StatefulMenuItem(string text, Func changeStateFunc, MenuItemType type, Action action) + protected StatefulMenuItem(LocalisableString text, Func? changeStateFunc, MenuItemType type, Action? action) : base(text, o => changeStateFunc?.Invoke((T)o) ?? o, type, o => action?.Invoke((T)o)) { base.State.BindValueChanged(state => diff --git a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs index 6787e17113..51e1248bc1 100644 --- a/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs +++ b/osu.Game/Graphics/UserInterface/ToggleMenuItem.cs @@ -1,10 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; namespace osu.Game.Graphics.UserInterface { @@ -18,7 +17,7 @@ namespace osu.Game.Graphics.UserInterface /// /// The text to display. /// The type of action which this performs. - public ToggleMenuItem(string text, MenuItemType type = MenuItemType.Standard) + public ToggleMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) : this(text, type, null) { } @@ -29,7 +28,7 @@ namespace osu.Game.Graphics.UserInterface /// The text to display. /// The type of action which this performs. /// A delegate to be invoked when this is pressed. - public ToggleMenuItem(string text, MenuItemType type, Action action) + public ToggleMenuItem(LocalisableString text, MenuItemType type, Action? action) : base(text, value => !value, type, action) { } diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 0a2c073dcd..1bd8979347 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Localisation; using osu.Game.Graphics.UserInterface; namespace osu.Game.Screens.Edit.Components.Menus @@ -10,13 +11,13 @@ namespace osu.Game.Screens.Edit.Components.Menus { private const int min_text_length = 40; - public EditorMenuItem(string text, MenuItemType type = MenuItemType.Standard) - : base(text.PadRight(min_text_length), type) + public EditorMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) + : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type) { } - public EditorMenuItem(string text, MenuItemType type, Action action) - : base(text.PadRight(min_text_length), type, action) + public EditorMenuItem(LocalisableString text, MenuItemType type, Action action) + : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type, action) { } } diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs b/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs index 3d51874082..1f6d61d0ad 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorScreenSwitcherControl.cs @@ -56,11 +56,6 @@ namespace osu.Game.Screens.Edit.Components.Menus Bar.Expire(); } - [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) - { - } - protected override void OnActivated() { base.OnActivated(); From 24df23f42038d890ad645bc7430351baf3314afc Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:49:19 +0300 Subject: [PATCH 40/83] Localise background header --- osu.Game/Localisation/EditorSetupStrings.cs | 26 ++++++++++++++----- .../Edit/Setup/SetupScreenHeaderBackground.cs | 3 ++- 2 files changed, 21 insertions(+), 8 deletions(-) diff --git a/osu.Game/Localisation/EditorSetupStrings.cs b/osu.Game/Localisation/EditorSetupStrings.cs index 0431b9cf76..4ddacf2c5b 100644 --- a/osu.Game/Localisation/EditorSetupStrings.cs +++ b/osu.Game/Localisation/EditorSetupStrings.cs @@ -42,7 +42,8 @@ namespace osu.Game.Localisation /// /// "If enabled, an "Are you ready? 3, 2, 1, GO!" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so." /// - public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); + public static LocalisableString CountdownDescription => new TranslatableString(getKey(@"countdown_description"), + @"If enabled, an ""Are you ready? 3, 2, 1, GO!"" countdown will be inserted at the beginning of the beatmap, assuming there is enough time to do so."); /// /// "Countdown speed" @@ -52,7 +53,8 @@ namespace osu.Game.Localisation /// /// "If the countdown sounds off-time, use this to make it appear one or more beats early." /// - public static LocalisableString CountdownOffsetDescription => new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); + public static LocalisableString CountdownOffsetDescription => + new TranslatableString(getKey(@"countdown_offset_description"), @"If the countdown sounds off-time, use this to make it appear one or more beats early."); /// /// "Countdown offset" @@ -67,7 +69,8 @@ namespace osu.Game.Localisation /// /// "Allows storyboards to use the full screen space, rather than be confined to a 4:3 area." /// - public static LocalisableString WidescreenSupportDescription => new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); + public static LocalisableString WidescreenSupportDescription => + new TranslatableString(getKey(@"widescreen_support_description"), @"Allows storyboards to use the full screen space, rather than be confined to a 4:3 area."); /// /// "Epilepsy warning" @@ -77,7 +80,8 @@ namespace osu.Game.Localisation /// /// "Recommended if the storyboard or video contain scenes with rapidly flashing colours." /// - public static LocalisableString EpilepsyWarningDescription => new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); + public static LocalisableString EpilepsyWarningDescription => + new TranslatableString(getKey(@"epilepsy_warning_description"), @"Recommended if the storyboard or video contain scenes with rapidly flashing colours."); /// /// "Letterbox during breaks" @@ -87,7 +91,8 @@ namespace osu.Game.Localisation /// /// "Adds horizontal letterboxing to give a cinematic look during breaks." /// - public static LocalisableString LetterboxDuringBreaksDescription => new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); + public static LocalisableString LetterboxDuringBreaksDescription => + new TranslatableString(getKey(@"letterbox_during_breaks_description"), @"Adds horizontal letterboxing to give a cinematic look during breaks."); /// /// "Samples match playback rate" @@ -97,7 +102,8 @@ namespace osu.Game.Localisation /// /// "When enabled, all samples will speed up or slow down when rate-changing mods are enabled." /// - public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); + public static LocalisableString SamplesMatchPlaybackRateDescription => new TranslatableString(getKey(@"samples_match_playback_rate_description"), + @"When enabled, all samples will speed up or slow down when rate-changing mods are enabled."); /// /// "The size of all hit objects" @@ -117,7 +123,8 @@ namespace osu.Game.Localisation /// /// "The harshness of hit windows and difficulty of special objects (ie. spinners)" /// - public static LocalisableString OverallDifficultyDescription => new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); + public static LocalisableString OverallDifficultyDescription => + new TranslatableString(getKey(@"overall_difficulty_description"), @"The harshness of hit windows and difficulty of special objects (ie. spinners)"); /// /// "Metadata" @@ -199,6 +206,11 @@ namespace osu.Game.Localisation /// public static LocalisableString DifficultyHeader => new TranslatableString(getKey(@"difficulty_header"), @"Difficulty"); + /// + /// "Drag image here to set beatmap background!" + /// + public static LocalisableString DragToSetBackground => new TranslatableString(getKey(@"drag_to_set_background"), @"Drag image here to set beatmap background!"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs b/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs index 47a7512adf..033e5361bb 100644 --- a/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs +++ b/osu.Game/Screens/Edit/Setup/SetupScreenHeaderBackground.cs @@ -10,6 +10,7 @@ using osu.Game.Beatmaps; using osu.Game.Beatmaps.Drawables; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit.Setup { @@ -61,7 +62,7 @@ namespace osu.Game.Screens.Edit.Setup }, new OsuTextFlowContainer(t => t.Font = OsuFont.Default.With(size: 24)) { - Text = "Drag image here to set beatmap background!", + Text = EditorSetupStrings.DragToSetBackground, Anchor = Anchor.Centre, Origin = Anchor.Centre, AutoSizeAxes = Axes.Both From 78e562903df18bf7c24d31bc640636b4fe029d78 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:50:41 +0300 Subject: [PATCH 41/83] Localise part of editor --- osu.Game/Localisation/EditorStrings.cs | 164 ++++++++++++++++++ .../Screens/Edit/BackgroundDimMenuItem.cs | 13 +- .../Edit/Components/PlaybackControl.cs | 3 +- .../Timelines/Summary/TestGameplayButton.cs | 3 +- .../Components/Timeline/TimelineArea.cs | 7 +- osu.Game/Screens/Edit/Editor.cs | 39 ++--- osu.Game/Screens/Edit/EditorScreenMode.cs | 15 +- .../Screens/Edit/WaveformOpacityMenuItem.cs | 3 +- 8 files changed, 207 insertions(+), 40 deletions(-) create mode 100644 osu.Game/Localisation/EditorStrings.cs diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs new file mode 100644 index 0000000000..32078468c9 --- /dev/null +++ b/osu.Game/Localisation/EditorStrings.cs @@ -0,0 +1,164 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.Editor"; + + /// + /// "File" + /// + public static LocalisableString File => new TranslatableString(getKey(@"file"), @"File"); + + /// + /// "Edit" + /// + public static LocalisableString Edit => new TranslatableString(getKey(@"edit"), @"Edit"); + + /// + /// "Undo" + /// + public static LocalisableString Undo => new TranslatableString(getKey(@"undo"), @"Undo"); + + /// + /// "Redo" + /// + public static LocalisableString Redo => new TranslatableString(getKey(@"redo"), @"Redo"); + + /// + /// "Cut" + /// + public static LocalisableString Cut => new TranslatableString(getKey(@"cut"), @"Cut"); + + /// + /// "Copy" + /// + public static LocalisableString Copy => new TranslatableString(getKey(@"copy"), @"Copy"); + + /// + /// "Paste" + /// + public static LocalisableString Paste => new TranslatableString(getKey(@"paste"), @"Paste"); + + /// + /// "Clone" + /// + public static LocalisableString Clone => new TranslatableString(getKey(@"clone"), @"Clone"); + + /// + /// "View" + /// + public static LocalisableString View => new TranslatableString(getKey(@"view"), @"View"); + + /// + /// "Background dim" + /// + public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"background_dim"), @"Background dim"); + + /// + /// "Waveform opacity" + /// + public static LocalisableString WaveformOpacity => new TranslatableString(getKey(@"waveform_opacity"), @"Waveform opacity"); + + /// + /// "Show hit markers" + /// + public static LocalisableString ShowHitMarkers => new TranslatableString(getKey(@"show_hit_markers"), @"Show hit markers"); + + /// + /// "Timing" + /// + public static LocalisableString Timing => new TranslatableString(getKey(@"timing"), @"Timing"); + + /// + /// "Set preview point to current time" + /// + public static LocalisableString SetPreviewPointToCurrent => new TranslatableString(getKey(@"set_preview_point_to_current"), @"Set preview point to current time"); + + /// + /// "Save" + /// + public static LocalisableString Save => new TranslatableString(getKey(@"save"), @"Save"); + + /// + /// "Export package" + /// + public static LocalisableString ExportPackage => new TranslatableString(getKey(@"export_package"), @"Export package"); + + /// + /// "Create new difficulty" + /// + public static LocalisableString CreateNewDifficulty => new TranslatableString(getKey(@"create_new_difficulty"), @"Create new difficulty"); + + /// + /// "Change difficulty" + /// + public static LocalisableString ChangeDifficulty => new TranslatableString(getKey(@"change_difficulty"), @"Change difficulty"); + + /// + /// "Delete difficulty" + /// + public static LocalisableString DeleteDifficulty => new TranslatableString(getKey(@"delete_difficulty"), @"Delete difficulty"); + + /// + /// "Exit" + /// + public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); + + /// + /// "setup" + /// + public static LocalisableString SetupScreen => new TranslatableString(getKey(@"setup_screen"), @"setup"); + + /// + /// "compose" + /// + public static LocalisableString ComposeScreen => new TranslatableString(getKey(@"compose_screen"), @"compose"); + + /// + /// "design" + /// + public static LocalisableString DesignScreen => new TranslatableString(getKey(@"design_screen"), @"design"); + + /// + /// "timing" + /// + public static LocalisableString TimingScreen => new TranslatableString(getKey(@"timing_screen"), @"timing"); + + /// + /// "verify" + /// + public static LocalisableString VerifyScreen => new TranslatableString(getKey(@"verify_screen"), @"verify"); + + /// + /// "Playback speed" + /// + public static LocalisableString PlaybackSpeed => new TranslatableString(getKey(@"playback_speed"), @"Playback speed"); + + /// + /// "Test!" + /// + public static LocalisableString TestBeatmap => new TranslatableString(getKey(@"test_beatmap"), @"Test!"); + + /// + /// "Waveform" + /// + public static LocalisableString TimelineWaveform => new TranslatableString(getKey(@"timeline_waveform"), @"Waveform"); + + /// + /// "Ticks" + /// + public static LocalisableString TimelineTicks => new TranslatableString(getKey(@"timeline_ticks"), @"Ticks"); + + /// + /// "BPM" + /// + public static LocalisableString TimelineBpm => new TranslatableString(getKey(@"timeline_bpm"), @"BPM"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs index b5a33f06e7..bff01385bb 100644 --- a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -5,17 +5,18 @@ using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { internal class BackgroundDimMenuItem : MenuItem { - private readonly Bindable backgroudDim; + private readonly Bindable backgroundDim; private readonly Dictionary menuItemLookup = new Dictionary(); - public BackgroundDimMenuItem(Bindable backgroudDim) - : base("Background dim") + public BackgroundDimMenuItem(Bindable backgroundDim) + : base(EditorStrings.BackgroundDim) { Items = new[] { @@ -25,8 +26,8 @@ namespace osu.Game.Screens.Edit createMenuItem(0.75f), }; - this.backgroudDim = backgroudDim; - backgroudDim.BindValueChanged(dim => + this.backgroundDim = backgroundDim; + backgroundDim.BindValueChanged(dim => { foreach (var kvp in menuItemLookup) kvp.Value.State.Value = kvp.Key == dim.NewValue ? TernaryState.True : TernaryState.False; @@ -40,6 +41,6 @@ namespace osu.Game.Screens.Edit return item; } - private void updateOpacity(float dim) => backgroudDim.Value = dim; + private void updateOpacity(float dim) => backgroundDim.Value = dim; } } diff --git a/osu.Game/Screens/Edit/Components/PlaybackControl.cs b/osu.Game/Screens/Edit/Components/PlaybackControl.cs index 87cbcb8aff..72c299f443 100644 --- a/osu.Game/Screens/Edit/Components/PlaybackControl.cs +++ b/osu.Game/Screens/Edit/Components/PlaybackControl.cs @@ -16,6 +16,7 @@ using osu.Framework.Input.Events; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osuTK.Input; @@ -47,7 +48,7 @@ namespace osu.Game.Screens.Edit.Components new OsuSpriteText { Origin = Anchor.BottomLeft, - Text = "Playback speed", + Text = EditorStrings.PlaybackSpeed, RelativePositionAxes = Axes.Y, Y = 0.5f, Padding = new MarginPadding { Left = 45 } diff --git a/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs b/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs index 9b45464e81..169e72fe3f 100644 --- a/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs +++ b/osu.Game/Screens/Edit/Components/Timelines/Summary/TestGameplayButton.cs @@ -7,6 +7,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; namespace osu.Game.Screens.Edit.Components.Timelines.Summary @@ -30,7 +31,7 @@ namespace osu.Game.Screens.Edit.Components.Timelines.Summary Content.CornerRadius = 0; - Text = "Test!"; + Text = EditorStrings.TestBeatmap; } } } diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index 615925ff91..f11c7b1d00 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -9,6 +9,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osuTK; @@ -75,17 +76,17 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { waveformCheckbox = new OsuCheckbox { - LabelText = "Waveform", + LabelText = EditorStrings.TimelineWaveform, Current = { Value = true }, }, ticksCheckbox = new OsuCheckbox { - LabelText = "Ticks", + LabelText = EditorStrings.TimelineTicks, Current = { Value = true }, }, controlPointsCheckbox = new OsuCheckbox { - LabelText = "BPM", + LabelText = EditorStrings.TimelineBpm, Current = { Value = true }, }, } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index be4e2f9628..c440cc8285 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,7 +51,6 @@ using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK.Input; -using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Screens.Edit { @@ -294,40 +293,40 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Items = new[] { - new MenuItem("File") + new MenuItem(EditorStrings.File) { Items = createFileMenuItems() }, - new MenuItem(CommonStrings.ButtonsEdit) + new MenuItem(EditorStrings.Edit) { Items = new[] { - undoMenuItem = new EditorMenuItem("Undo", MenuItemType.Standard, Undo), - redoMenuItem = new EditorMenuItem("Redo", MenuItemType.Standard, Redo), + undoMenuItem = new EditorMenuItem(EditorStrings.Undo, MenuItemType.Standard, Undo), + redoMenuItem = new EditorMenuItem(EditorStrings.Redo, MenuItemType.Standard, Redo), new EditorMenuItemSpacer(), - cutMenuItem = new EditorMenuItem("Cut", MenuItemType.Standard, Cut), - copyMenuItem = new EditorMenuItem("Copy", MenuItemType.Standard, Copy), - pasteMenuItem = new EditorMenuItem("Paste", MenuItemType.Standard, Paste), - cloneMenuItem = new EditorMenuItem("Clone", MenuItemType.Standard, Clone), + cutMenuItem = new EditorMenuItem(EditorStrings.Cut, MenuItemType.Standard, Cut), + copyMenuItem = new EditorMenuItem(EditorStrings.Copy, MenuItemType.Standard, Copy), + pasteMenuItem = new EditorMenuItem(EditorStrings.Paste, MenuItemType.Standard, Paste), + cloneMenuItem = new EditorMenuItem(EditorStrings.Clone, MenuItemType.Standard, Clone), } }, - new MenuItem("View") + new MenuItem(EditorStrings.View) { Items = new MenuItem[] { new WaveformOpacityMenuItem(config.GetBindable(OsuSetting.EditorWaveformOpacity)), new BackgroundDimMenuItem(editorBackgroundDim), - new ToggleMenuItem("Show hit markers") + new ToggleMenuItem(EditorStrings.ShowHitMarkers) { State = { BindTarget = editorHitMarkers }, } } }, - new MenuItem("Timing") + new MenuItem(EditorStrings.Timing) { Items = new MenuItem[] { - new EditorMenuItem("Set preview point to current time", MenuItemType.Standard, SetPreviewPointToCurrentTime) + new EditorMenuItem(EditorStrings.SetPreviewPointToCurrent, MenuItemType.Standard, SetPreviewPointToCurrentTime) } } } @@ -716,7 +715,7 @@ namespace osu.Game.Screens.Edit if (!(refetchedBeatmap is DummyWorkingBeatmap)) { - Logger.Log("Editor providing re-fetched beatmap post edit session"); + Logger.Log(@"Editor providing re-fetched beatmap post edit session"); Beatmap.Value = refetchedBeatmap; } } @@ -952,15 +951,15 @@ namespace osu.Game.Screens.Edit private List createFileMenuItems() => new List { - new EditorMenuItem("Save", MenuItemType.Standard, () => Save()), - new EditorMenuItem("Export package", MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, + new EditorMenuItem(EditorStrings.Save, MenuItemType.Standard, () => Save()), + new EditorMenuItem(EditorStrings.ExportPackage, MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, new EditorMenuItemSpacer(), createDifficultyCreationMenu(), createDifficultySwitchMenu(), new EditorMenuItemSpacer(), - new EditorMenuItem("Delete difficulty", MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, + new EditorMenuItem(EditorStrings.DeleteDifficulty, MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, new EditorMenuItemSpacer(), - new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit) + new EditorMenuItem(EditorStrings.Exit, MenuItemType.Standard, this.Exit) }; private void exportBeatmap() @@ -1009,7 +1008,7 @@ namespace osu.Game.Screens.Edit foreach (var ruleset in rulesets.AvailableRulesets) rulesetItems.Add(new EditorMenuItem(ruleset.Name, MenuItemType.Standard, () => CreateNewDifficulty(ruleset))); - return new EditorMenuItem("Create new difficulty") { Items = rulesetItems }; + return new EditorMenuItem(EditorStrings.CreateNewDifficulty) { Items = rulesetItems }; } protected void CreateNewDifficulty(RulesetInfo rulesetInfo) @@ -1045,7 +1044,7 @@ namespace osu.Game.Screens.Edit } } - return new EditorMenuItem("Change difficulty") { Items = difficultyItems }; + return new EditorMenuItem(EditorStrings.ChangeDifficulty) { Items = difficultyItems }; } protected void SwitchToDifficulty(BeatmapInfo nextBeatmap) => loader?.ScheduleSwitchToExistingDifficulty(nextBeatmap, GetState(nextBeatmap.Ruleset)); diff --git a/osu.Game/Screens/Edit/EditorScreenMode.cs b/osu.Game/Screens/Edit/EditorScreenMode.cs index 81fcf23cdf..f787fee1e0 100644 --- a/osu.Game/Screens/Edit/EditorScreenMode.cs +++ b/osu.Game/Screens/Edit/EditorScreenMode.cs @@ -1,27 +1,26 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - -using System.ComponentModel; +using osu.Framework.Localisation; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { public enum EditorScreenMode { - [Description("setup")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.SetupScreen))] SongSetup, - [Description("compose")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.ComposeScreen))] Compose, - [Description("design")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.DesignScreen))] Design, - [Description("timing")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.TimingScreen))] Timing, - [Description("verify")] + [LocalisableDescription(typeof(EditorStrings), nameof(EditorStrings.VerifyScreen))] Verify, } } diff --git a/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs b/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs index 3d3f67e70e..5b1d7142e4 100644 --- a/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs +++ b/osu.Game/Screens/Edit/WaveformOpacityMenuItem.cs @@ -7,6 +7,7 @@ using System.Collections.Generic; using osu.Framework.Bindables; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { @@ -17,7 +18,7 @@ namespace osu.Game.Screens.Edit private readonly Dictionary menuItemLookup = new Dictionary(); public WaveformOpacityMenuItem(Bindable waveformOpacity) - : base("Waveform opacity") + : base(EditorStrings.WaveformOpacity) { Items = new[] { From 87650044bbecc58bcdd74ee4920b3a21603a6f9d Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 01:49:54 +0300 Subject: [PATCH 42/83] Localise create/save dialog --- osu.Game/Localisation/EditorDialogsStrings.cs | 54 +++++++++++++++++++ .../Screens/Edit/CreateNewDifficultyDialog.cs | 11 ++-- osu.Game/Screens/Edit/PromptForSaveDialog.cs | 11 ++-- 3 files changed, 64 insertions(+), 12 deletions(-) create mode 100644 osu.Game/Localisation/EditorDialogsStrings.cs diff --git a/osu.Game/Localisation/EditorDialogsStrings.cs b/osu.Game/Localisation/EditorDialogsStrings.cs new file mode 100644 index 0000000000..fc4c2b7f2a --- /dev/null +++ b/osu.Game/Localisation/EditorDialogsStrings.cs @@ -0,0 +1,54 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class EditorDialogsStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.EditorDialogs"; + + /// + /// "Would you like to create a blank difficulty?" + /// + public static LocalisableString NewDifficultyDialogHeader => new TranslatableString(getKey(@"new_difficulty_dialog_header"), @"Would you like to create a blank difficulty?"); + + /// + /// "Yeah, let's start from scratch!" + /// + public static LocalisableString CreateNew => new TranslatableString(getKey(@"create_new"), @"Yeah, let's start from scratch!"); + + /// + /// "No, create an exact copy of this difficulty" + /// + public static LocalisableString CreateCopy => new TranslatableString(getKey(@"create_copy"), @"No, create an exact copy of this difficulty"); + + /// + /// "I changed my mind, I want to keep editing this difficulty" + /// + public static LocalisableString KeepEditing => new TranslatableString(getKey(@"keep_editing"), @"I changed my mind, I want to keep editing this difficulty"); + + /// + /// "Did you want to save your changes?" + /// + public static LocalisableString SaveDialogHeader => new TranslatableString(getKey(@"save_dialog_header"), @"Did you want to save your changes?"); + + /// + /// "Save my masterpiece!" + /// + public static LocalisableString Save => new TranslatableString(getKey(@"save"), @"Save my masterpiece!"); + + /// + /// "Forget all changes" + /// + public static LocalisableString ForgetAllChanges => new TranslatableString(getKey(@"forget_all_changes"), @"Forget all changes"); + + /// + /// "Oops, continue editing" + /// + public static LocalisableString ContinueEditing => new TranslatableString(getKey(@"continue_editing"), @"Oops, continue editing"); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs b/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs index 85466c5056..811da5236e 100644 --- a/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs +++ b/osu.Game/Screens/Edit/CreateNewDifficultyDialog.cs @@ -1,10 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Graphics.Sprites; using osu.Game.Overlays.Dialog; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { @@ -20,7 +19,7 @@ namespace osu.Game.Screens.Edit public CreateNewDifficultyDialog(CreateNewDifficulty createNewDifficulty) { - HeaderText = "Would you like to create a blank difficulty?"; + HeaderText = EditorDialogsStrings.NewDifficultyDialogHeader; Icon = FontAwesome.Regular.Clone; @@ -28,17 +27,17 @@ namespace osu.Game.Screens.Edit { new PopupDialogOkButton { - Text = "Yeah, let's start from scratch!", + Text = EditorDialogsStrings.CreateNew, Action = () => createNewDifficulty.Invoke(false) }, new PopupDialogCancelButton { - Text = "No, create an exact copy of this difficulty", + Text = EditorDialogsStrings.CreateCopy, Action = () => createNewDifficulty.Invoke(true) }, new PopupDialogCancelButton { - Text = "I changed my mind, I want to keep editing this difficulty", + Text = EditorDialogsStrings.KeepEditing, Action = () => { } } }; diff --git a/osu.Game/Screens/Edit/PromptForSaveDialog.cs b/osu.Game/Screens/Edit/PromptForSaveDialog.cs index 2a2cd019ea..7d78465e6c 100644 --- a/osu.Game/Screens/Edit/PromptForSaveDialog.cs +++ b/osu.Game/Screens/Edit/PromptForSaveDialog.cs @@ -1,11 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using osu.Framework.Graphics.Sprites; using osu.Game.Overlays.Dialog; +using osu.Game.Localisation; namespace osu.Game.Screens.Edit { @@ -13,7 +12,7 @@ namespace osu.Game.Screens.Edit { public PromptForSaveDialog(Action exit, Action saveAndExit, Action cancel) { - HeaderText = "Did you want to save your changes?"; + HeaderText = EditorDialogsStrings.SaveDialogHeader; Icon = FontAwesome.Regular.Save; @@ -21,17 +20,17 @@ namespace osu.Game.Screens.Edit { new PopupDialogOkButton { - Text = @"Save my masterpiece!", + Text = EditorDialogsStrings.Save, Action = saveAndExit }, new PopupDialogDangerousButton { - Text = @"Forget all changes", + Text = EditorDialogsStrings.ForgetAllChanges, Action = exit }, new PopupDialogCancelButton { - Text = @"Oops, continue editing", + Text = EditorDialogsStrings.ContinueEditing, Action = cancel }, }; From 8777d5349bd9e816d9ceff9b0891bc51ca0014ea Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 14:39:34 +0300 Subject: [PATCH 43/83] Use existing strings --- osu.Game/Localisation/EditorStrings.cs | 15 --------------- osu.Game/Screens/Edit/BackgroundDimMenuItem.cs | 2 +- .../Compose/Components/Timeline/TimelineArea.cs | 3 ++- osu.Game/Screens/Edit/Editor.cs | 3 ++- 4 files changed, 5 insertions(+), 18 deletions(-) diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 32078468c9..6b16e43bd3 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -54,11 +54,6 @@ namespace osu.Game.Localisation /// public static LocalisableString View => new TranslatableString(getKey(@"view"), @"View"); - /// - /// "Background dim" - /// - public static LocalisableString BackgroundDim => new TranslatableString(getKey(@"background_dim"), @"Background dim"); - /// /// "Waveform opacity" /// @@ -79,11 +74,6 @@ namespace osu.Game.Localisation /// public static LocalisableString SetPreviewPointToCurrent => new TranslatableString(getKey(@"set_preview_point_to_current"), @"Set preview point to current time"); - /// - /// "Save" - /// - public static LocalisableString Save => new TranslatableString(getKey(@"save"), @"Save"); - /// /// "Export package" /// @@ -154,11 +144,6 @@ namespace osu.Game.Localisation /// public static LocalisableString TimelineTicks => new TranslatableString(getKey(@"timeline_ticks"), @"Ticks"); - /// - /// "BPM" - /// - public static LocalisableString TimelineBpm => new TranslatableString(getKey(@"timeline_bpm"), @"BPM"); - private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs index bff01385bb..2a1159eb27 100644 --- a/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs +++ b/osu.Game/Screens/Edit/BackgroundDimMenuItem.cs @@ -16,7 +16,7 @@ namespace osu.Game.Screens.Edit private readonly Dictionary menuItemLookup = new Dictionary(); public BackgroundDimMenuItem(Bindable backgroundDim) - : base(EditorStrings.BackgroundDim) + : base(GameplaySettingsStrings.BackgroundDim) { Items = new[] { diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs index f11c7b1d00..0b83258f8b 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/TimelineArea.cs @@ -11,6 +11,7 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays; +using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Screens.Edit.Compose.Components.Timeline @@ -86,7 +87,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline }, controlPointsCheckbox = new OsuCheckbox { - LabelText = EditorStrings.TimelineBpm, + LabelText = BeatmapsetsStrings.ShowStatsBpm, Current = { Value = true }, }, } diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index c440cc8285..29be1a3881 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,6 +51,7 @@ using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK.Input; +using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Screens.Edit { @@ -951,7 +952,7 @@ namespace osu.Game.Screens.Edit private List createFileMenuItems() => new List { - new EditorMenuItem(EditorStrings.Save, MenuItemType.Standard, () => Save()), + new EditorMenuItem(CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), new EditorMenuItem(EditorStrings.ExportPackage, MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, new EditorMenuItemSpacer(), createDifficultyCreationMenu(), From 5d2e09137cfed291d842458972c4c8c2e64073be Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 14:40:53 +0300 Subject: [PATCH 44/83] Remove text padding in editor menu for now --- osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs index 1bd8979347..368fe40977 100644 --- a/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs +++ b/osu.Game/Screens/Edit/Components/Menus/EditorMenuItem.cs @@ -9,15 +9,13 @@ namespace osu.Game.Screens.Edit.Components.Menus { public class EditorMenuItem : OsuMenuItem { - private const int min_text_length = 40; - public EditorMenuItem(LocalisableString text, MenuItemType type = MenuItemType.Standard) - : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type) + : base(text, type) { } public EditorMenuItem(LocalisableString text, MenuItemType type, Action action) - : base(LocalisableString.Interpolate($"{text,-min_text_length}"), type, action) + : base(text, type, action) { } } From f7af5a8115d5566a623a9ba8d3b6a5679bc13d29 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Jan 2023 22:35:44 +0900 Subject: [PATCH 45/83] Revert some formatting changes --- osu.Game/Screens/Select/SongSelect.cs | 54 +++++++++++++-------------- 1 file changed, 27 insertions(+), 27 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index ef5827fad7..0e108d3db0 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -314,17 +314,16 @@ namespace osu.Game.Screens.Select /// Creates the buttons to be displayed in the footer. /// /// A set of and an optional which the button opens when pressed. - protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() => - new (FooterButton, OverlayContainer?)[] + protected virtual IEnumerable<(FooterButton, OverlayContainer?)> CreateFooterButtons() => new (FooterButton, OverlayContainer?)[] + { + (new FooterButtonMods { Current = Mods }, ModSelect), + (new FooterButtonRandom { - (new FooterButtonMods { Current = Mods }, ModSelect), - (new FooterButtonRandom - { - NextRandom = () => Carousel.SelectNextRandom(), - PreviousRandom = Carousel.SelectPreviousRandom - }, null), - (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) - }; + NextRandom = () => Carousel.SelectNextRandom(), + PreviousRandom = Carousel.SelectPreviousRandom + }, null), + (beatmapOptionsButton = new FooterButtonOptions(), BeatmapOptions) + }; protected virtual ModSelectOverlay CreateModSelectOverlay() => new SoloModSelectOverlay(); @@ -425,25 +424,26 @@ namespace osu.Game.Screens.Select Logger.Log($"Song select working beatmap updated to {beatmap}"); - if (Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) return; - - // A selection may not have been possible with filters applied. - - // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. - if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) + if (!Carousel.SelectBeatmap(beatmap.BeatmapInfo, false)) { - Ruleset.Value = beatmap.BeatmapInfo.Ruleset; - transferRulesetValue(); + // A selection may not have been possible with filters applied. + + // There was possibly a ruleset mismatch. This is a case we can help things along by updating the game-wide ruleset to match. + if (!beatmap.BeatmapInfo.Ruleset.Equals(decoupledRuleset.Value)) + { + Ruleset.Value = beatmap.BeatmapInfo.Ruleset; + transferRulesetValue(); + } + + // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), + // we still want to temporarily show the new beatmap, bypassing filters. + // This will be undone the next time the user changes the filter. + var criteria = FilterControl.CreateCriteria(); + criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; + Carousel.Filter(criteria); + + Carousel.SelectBeatmap(beatmap.BeatmapInfo); } - - // Even if a ruleset mismatch was not the cause (ie. a text filter is applied), - // we still want to temporarily show the new beatmap, bypassing filters. - // This will be undone the next time the user changes the filter. - var criteria = FilterControl.CreateCriteria(); - criteria.SelectedBeatmapSet = beatmap.BeatmapInfo.BeatmapSet; - Carousel.Filter(criteria); - - Carousel.SelectBeatmap(beatmap.BeatmapInfo); } // We need to keep track of the last selected beatmap ignoring debounce to play the correct selection sounds. From 4cf4a6685802831dee21b6d0cc0047c453ec608b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Sun, 15 Jan 2023 22:43:30 +0900 Subject: [PATCH 46/83] Make `MusicController` a required dependency of `SongSelect` --- osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0e108d3db0..d7c1dbf543 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -34,6 +34,7 @@ using osu.Framework.Input.Bindings; using osu.Game.Collections; using osu.Game.Graphics.UserInterface; using System.Diagnostics; +using osu.Framework.Extensions.ObjectExtensions; using osu.Game.Screens.Play; using osu.Game.Skinning; @@ -118,7 +119,7 @@ namespace osu.Game.Screens.Select private IDisposable? modSelectOverlayRegistration; [Resolved] - private MusicController? music { get; set; } + private MusicController music { get; set; } = null!; [Resolved] internal IOverlayManager? OverlayManager { get; private set; } @@ -616,7 +617,6 @@ namespace osu.Game.Screens.Select { // restart playback on returning to song select, regardless. // not sure this should be a permanent thing (we may want to leave a user pause paused even on returning) - Debug.Assert(music != null); music.ResetTrackAdjustments(); music.Play(requestedByUser: true); } @@ -692,7 +692,6 @@ namespace osu.Game.Screens.Select ensureTrackLooping(Beatmap.Value, TrackChangeDirection.None); - Debug.Assert(music != null); music.TrackChanged += ensureTrackLooping; } @@ -702,7 +701,6 @@ namespace osu.Game.Screens.Select if (!isHandlingLooping) return; - Debug.Assert(music != null); music.CurrentTrack.Looping = isHandlingLooping = false; music.TrackChanged -= ensureTrackLooping; @@ -728,7 +726,7 @@ namespace osu.Game.Screens.Select decoupledRuleset.UnbindAll(); - if (music != null) + if (music.IsNotNull()) music.TrackChanged -= ensureTrackLooping; modSelectOverlayRegistration?.Dispose(); @@ -774,7 +772,6 @@ namespace osu.Game.Screens.Select if (!ControlGlobalMusic) return; - Debug.Assert(music != null); ITrack track = music.CurrentTrack; bool isNewTrack = !lastTrack.TryGetTarget(out var last) || last != track; From 9a29c9ae26a94f35d1a3cc4aff6678ab388847e7 Mon Sep 17 00:00:00 2001 From: mk56-spn Date: Sun, 15 Jan 2023 15:32:53 +0100 Subject: [PATCH 47/83] remove hacky method to check if carousel is null --- osu.Game/Screens/Select/SongSelect.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d7c1dbf543..d4d75d0ad6 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -128,7 +128,7 @@ namespace osu.Game.Screens.Select private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(false); + transferRulesetValue(); LoadComponentAsync(Carousel = new BeatmapCarousel { @@ -852,7 +852,7 @@ namespace osu.Game.Screens.Select /// Will immediately run filter operations if required. /// /// Whether a transfer occurred. - private bool transferRulesetValue(bool carouselLoaded = true) + private bool transferRulesetValue() { if (decoupledRuleset.Value?.Equals(Ruleset.Value) == true) return false; @@ -860,8 +860,8 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // We don't want to declare the carousel as nullable, so this check allows us to avoid running the carousel flush during the loading process - if (!carouselLoaded) return true; + // We want to check for null since this method gets called before the loading of the carousel. + if (Carousel.IsNull()) return true; // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). From 00acea59fca4254630d4a21555be1ab8ffc9fccb Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Sun, 15 Jan 2023 19:37:40 +0300 Subject: [PATCH 48/83] Move some strings to common --- osu.Game/Localisation/CommonStrings.cs | 50 ++++++++++++++++++++++++++ osu.Game/Localisation/EditorStrings.cs | 50 -------------------------- osu.Game/Screens/Edit/Editor.cs | 25 +++++++------ 3 files changed, 62 insertions(+), 63 deletions(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 385ebd0593..10178915a2 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -104,6 +104,56 @@ namespace osu.Game.Localisation /// public static LocalisableString Description => new TranslatableString(getKey(@"description"), @"Description"); + /// + /// "File" + /// + public static LocalisableString MenuBarFile => new TranslatableString(getKey(@"menu_bar_file"), @"File"); + + /// + /// "Edit" + /// + public static LocalisableString MenuBarEdit => new TranslatableString(getKey(@"menu_bar_edit"), @"Edit"); + + /// + /// "View" + /// + public static LocalisableString MenuBarView => new TranslatableString(getKey(@"menu_bar_view"), @"View"); + + /// + /// "Undo" + /// + public static LocalisableString Undo => new TranslatableString(getKey(@"undo"), @"Undo"); + + /// + /// "Redo" + /// + public static LocalisableString Redo => new TranslatableString(getKey(@"redo"), @"Redo"); + + /// + /// "Cut" + /// + public static LocalisableString Cut => new TranslatableString(getKey(@"cut"), @"Cut"); + + /// + /// "Copy" + /// + public static LocalisableString Copy => new TranslatableString(getKey(@"copy"), @"Copy"); + + /// + /// "Paste" + /// + public static LocalisableString Paste => new TranslatableString(getKey(@"paste"), @"Paste"); + + /// + /// "Clone" + /// + public static LocalisableString Clone => new TranslatableString(getKey(@"clone"), @"Clone"); + + /// + /// "Exit" + /// + public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Localisation/EditorStrings.cs b/osu.Game/Localisation/EditorStrings.cs index 6b16e43bd3..96c08aa6f8 100644 --- a/osu.Game/Localisation/EditorStrings.cs +++ b/osu.Game/Localisation/EditorStrings.cs @@ -9,51 +9,6 @@ namespace osu.Game.Localisation { private const string prefix = @"osu.Game.Resources.Localisation.Editor"; - /// - /// "File" - /// - public static LocalisableString File => new TranslatableString(getKey(@"file"), @"File"); - - /// - /// "Edit" - /// - public static LocalisableString Edit => new TranslatableString(getKey(@"edit"), @"Edit"); - - /// - /// "Undo" - /// - public static LocalisableString Undo => new TranslatableString(getKey(@"undo"), @"Undo"); - - /// - /// "Redo" - /// - public static LocalisableString Redo => new TranslatableString(getKey(@"redo"), @"Redo"); - - /// - /// "Cut" - /// - public static LocalisableString Cut => new TranslatableString(getKey(@"cut"), @"Cut"); - - /// - /// "Copy" - /// - public static LocalisableString Copy => new TranslatableString(getKey(@"copy"), @"Copy"); - - /// - /// "Paste" - /// - public static LocalisableString Paste => new TranslatableString(getKey(@"paste"), @"Paste"); - - /// - /// "Clone" - /// - public static LocalisableString Clone => new TranslatableString(getKey(@"clone"), @"Clone"); - - /// - /// "View" - /// - public static LocalisableString View => new TranslatableString(getKey(@"view"), @"View"); - /// /// "Waveform opacity" /// @@ -94,11 +49,6 @@ namespace osu.Game.Localisation /// public static LocalisableString DeleteDifficulty => new TranslatableString(getKey(@"delete_difficulty"), @"Delete difficulty"); - /// - /// "Exit" - /// - public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); - /// /// "setup" /// diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index 29be1a3881..74ea933255 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -51,7 +51,7 @@ using osu.Game.Screens.Edit.Verify; using osu.Game.Screens.Play; using osu.Game.Users; using osuTK.Input; -using CommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; +using WebCommonStrings = osu.Game.Resources.Localisation.Web.CommonStrings; namespace osu.Game.Screens.Edit { @@ -294,24 +294,24 @@ namespace osu.Game.Screens.Edit RelativeSizeAxes = Axes.Both, Items = new[] { - new MenuItem(EditorStrings.File) + new MenuItem(CommonStrings.MenuBarFile) { Items = createFileMenuItems() }, - new MenuItem(EditorStrings.Edit) + new MenuItem(CommonStrings.MenuBarEdit) { Items = new[] { - undoMenuItem = new EditorMenuItem(EditorStrings.Undo, MenuItemType.Standard, Undo), - redoMenuItem = new EditorMenuItem(EditorStrings.Redo, MenuItemType.Standard, Redo), + undoMenuItem = new EditorMenuItem(CommonStrings.Undo, MenuItemType.Standard, Undo), + redoMenuItem = new EditorMenuItem(CommonStrings.Redo, MenuItemType.Standard, Redo), new EditorMenuItemSpacer(), - cutMenuItem = new EditorMenuItem(EditorStrings.Cut, MenuItemType.Standard, Cut), - copyMenuItem = new EditorMenuItem(EditorStrings.Copy, MenuItemType.Standard, Copy), - pasteMenuItem = new EditorMenuItem(EditorStrings.Paste, MenuItemType.Standard, Paste), - cloneMenuItem = new EditorMenuItem(EditorStrings.Clone, MenuItemType.Standard, Clone), + cutMenuItem = new EditorMenuItem(CommonStrings.Cut, MenuItemType.Standard, Cut), + copyMenuItem = new EditorMenuItem(CommonStrings.Copy, MenuItemType.Standard, Copy), + pasteMenuItem = new EditorMenuItem(CommonStrings.Paste, MenuItemType.Standard, Paste), + cloneMenuItem = new EditorMenuItem(CommonStrings.Clone, MenuItemType.Standard, Clone), } }, - new MenuItem(EditorStrings.View) + new MenuItem(CommonStrings.MenuBarView) { Items = new MenuItem[] { @@ -344,7 +344,6 @@ namespace osu.Game.Screens.Edit bottomBar = new BottomBar(), } }); - changeHandler?.CanUndo.BindValueChanged(v => undoMenuItem.Action.Disabled = !v.NewValue, true); changeHandler?.CanRedo.BindValueChanged(v => redoMenuItem.Action.Disabled = !v.NewValue, true); @@ -952,7 +951,7 @@ namespace osu.Game.Screens.Edit private List createFileMenuItems() => new List { - new EditorMenuItem(CommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), + new EditorMenuItem(WebCommonStrings.ButtonsSave, MenuItemType.Standard, () => Save()), new EditorMenuItem(EditorStrings.ExportPackage, MenuItemType.Standard, exportBeatmap) { Action = { Disabled = !RuntimeInfo.IsDesktop } }, new EditorMenuItemSpacer(), createDifficultyCreationMenu(), @@ -960,7 +959,7 @@ namespace osu.Game.Screens.Edit new EditorMenuItemSpacer(), new EditorMenuItem(EditorStrings.DeleteDifficulty, MenuItemType.Standard, deleteDifficulty) { Action = { Disabled = Beatmap.Value.BeatmapSetInfo.Beatmaps.Count < 2 } }, new EditorMenuItemSpacer(), - new EditorMenuItem(EditorStrings.Exit, MenuItemType.Standard, this.Exit) + new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, this.Exit) }; private void exportBeatmap() From 85c1932851bf71202805c9cbcfe133d32ee3088b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 12:46:41 -0800 Subject: [PATCH 49/83] Mark `Converts` as nullable --- osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs | 2 +- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs index d39ed1e1ed..d98715a42d 100644 --- a/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs +++ b/osu.Game/Online/API/Requests/Responses/APIBeatmapSet.cs @@ -126,7 +126,7 @@ namespace osu.Game.Online.API.Requests.Responses public APIBeatmap[] Beatmaps { get; set; } = Array.Empty(); [JsonProperty(@"converts")] - public APIBeatmap[] Converts { get; set; } = Array.Empty(); + public APIBeatmap[]? Converts { get; set; } private BeatmapMetadata metadata => new BeatmapMetadata { diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 51b6b14579..0ee7dfc9bd 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -168,7 +168,7 @@ namespace osu.Game.Overlays.BeatmapSet if (BeatmapSet != null) { - Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Concat(BeatmapSet.Converts) + Difficulties.ChildrenEnumerable = BeatmapSet.Beatmaps.Concat(BeatmapSet.Converts ?? Array.Empty()) .Where(b => b.Ruleset.MatchesOnlineID(ruleset.Value)) .OrderBy(b => !b.Convert) .ThenBy(b => b.StarRating) From b733f46c6fed49d930da4e0cf20d5949c5914ddd Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 14:15:36 -0800 Subject: [PATCH 50/83] Apply NRT to `BeatmapPicker` --- .../TestSceneStartupBeatmapDisplay.cs | 4 +--- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 22 +++++++++---------- 2 files changed, 11 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs index 0c165bc40e..25cef8440a 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneStartupBeatmapDisplay.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using NUnit.Framework; using osu.Framework.Graphics.Containers; @@ -50,7 +48,7 @@ namespace osu.Game.Tests.Visual.Navigation public void TestBeatmapLink() { AddUntilStep("Beatmap overlay displayed", () => Game.ChildrenOfType().FirstOrDefault()?.State.Value == Visibility.Visible); - AddUntilStep("Beatmap overlay showing content", () => Game.ChildrenOfType().FirstOrDefault()?.Beatmap.Value.OnlineID == requested_beatmap_id); + AddUntilStep("Beatmap overlay showing content", () => Game.ChildrenOfType().FirstOrDefault()?.Beatmap.Value?.OnlineID == requested_beatmap_id); } } } diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 0ee7dfc9bd..76fc1bbf53 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Linq; using osu.Framework; @@ -38,10 +36,10 @@ namespace osu.Game.Overlays.BeatmapSet public readonly DifficultiesContainer Difficulties; - public readonly Bindable Beatmap = new Bindable(); - private APIBeatmapSet beatmapSet; + public readonly Bindable Beatmap = new Bindable(); + private APIBeatmapSet? beatmapSet; - public APIBeatmapSet BeatmapSet + public APIBeatmapSet? BeatmapSet { get => beatmapSet; set @@ -142,7 +140,7 @@ namespace osu.Game.Overlays.BeatmapSet } [Resolved] - private IBindable ruleset { get; set; } + private IBindable ruleset { get; set; } = null!; [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -200,9 +198,9 @@ namespace osu.Game.Overlays.BeatmapSet updateDifficultyButtons(); } - private void showBeatmap(IBeatmapInfo beatmapInfo) + private void showBeatmap(IBeatmapInfo? beatmapInfo) { - version.Text = beatmapInfo?.DifficultyName; + version.Text = beatmapInfo?.DifficultyName ?? string.Empty; } private void updateDifficultyButtons() @@ -212,7 +210,7 @@ namespace osu.Game.Overlays.BeatmapSet public partial class DifficultiesContainer : FillFlowContainer { - public Action OnLostHover; + public Action? OnLostHover; protected override void OnHoverLost(HoverLostEvent e) { @@ -233,9 +231,9 @@ namespace osu.Game.Overlays.BeatmapSet public readonly APIBeatmap Beatmap; - public Action OnHovered; - public Action OnClicked; - public event Action StateChanged; + public Action? OnHovered; + public Action? OnClicked; + public event Action? StateChanged; private DifficultySelectorState state; From ae49e724e43ebe449f1229c1efbed7157d00ba23 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 14:17:46 -0800 Subject: [PATCH 51/83] Move converted beatmap icons logic locally --- osu.Game/Beatmaps/Drawables/DifficultyIcon.cs | 4 ---- osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs index 41db2399ac..1665ec52fa 100644 --- a/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs +++ b/osu.Game/Beatmaps/Drawables/DifficultyIcon.cs @@ -13,7 +13,6 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Rulesets; using osuTK; using osuTK.Graphics; @@ -117,9 +116,6 @@ namespace osu.Game.Beatmaps.Drawables private Drawable getRulesetIcon() { - if ((beatmap as APIBeatmap)?.Convert == true) - return rulesets.GetRuleset(0)!.CreateInstance().CreateIcon(); - int? onlineID = ruleset.OnlineID; if (onlineID >= 0 && rulesets.GetRuleset(onlineID.Value)?.CreateInstance() is Ruleset rulesetInstance) diff --git a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs index 76fc1bbf53..585e0dd1a2 100644 --- a/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs +++ b/osu.Game/Overlays/BeatmapSet/BeatmapPicker.cs @@ -170,7 +170,7 @@ namespace osu.Game.Overlays.BeatmapSet .Where(b => b.Ruleset.MatchesOnlineID(ruleset.Value)) .OrderBy(b => !b.Convert) .ThenBy(b => b.StarRating) - .Select(b => new DifficultySelectorButton(b) + .Select(b => new DifficultySelectorButton(b, b.Convert ? new RulesetInfo { OnlineID = 0 } : null) { State = DifficultySelectorState.NotSelected, OnHovered = beatmap => @@ -254,7 +254,7 @@ namespace osu.Game.Overlays.BeatmapSet } } - public DifficultySelectorButton(APIBeatmap beatmapInfo) + public DifficultySelectorButton(APIBeatmap beatmapInfo, IRulesetInfo? ruleset) { Beatmap = beatmapInfo; Size = new Vector2(size); @@ -273,7 +273,7 @@ namespace osu.Game.Overlays.BeatmapSet Alpha = 0.5f } }, - icon = new DifficultyIcon(beatmapInfo) + icon = new DifficultyIcon(beatmapInfo, ruleset) { ShowTooltip = false, Current = { Value = new StarDifficulty(beatmapInfo.StarRating, 0) }, From 0ff143d4c86d7e6ae19f703201046cab5592c01a Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 15:19:06 -0800 Subject: [PATCH 52/83] Add argument for play some ruleset string --- osu.Game/Localisation/ToolbarStrings.cs | 5 ++--- osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs | 3 +-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index b76c643332..02a68a6bdc 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -30,10 +30,9 @@ namespace osu.Game.Localisation public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); /// - /// "play some" + /// "play some {0}" /// - - public static LocalisableString RulesetHeaderDescription => new TranslatableString(getKey(@"header_description"), @"play some"); + public static LocalisableString PlaySomeRuleset(string arg0) => new TranslatableString(getKey(@"play_some_ruleset"), @"play some {0}", arg0); private static string getKey(string key) => $@"{prefix}:{key}"; } diff --git a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs index d603863888..07f7d52545 100644 --- a/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs +++ b/osu.Game/Overlays/Toolbar/ToolbarRulesetTabButton.cs @@ -7,7 +7,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.UserInterface; using osu.Framework.Input.Events; -using osu.Framework.Localisation; using osu.Game.Localisation; using osu.Game.Rulesets; using osuTK.Graphics; @@ -31,7 +30,7 @@ namespace osu.Game.Overlays.Toolbar var rInstance = value.CreateInstance(); ruleset.TooltipMain = rInstance.Description; - ruleset.TooltipSub = LocalisableString.Format("{0} {1}", ToolbarStrings.RulesetHeaderDescription, ($"{rInstance.Description}")); + ruleset.TooltipSub = ToolbarStrings.PlaySomeRuleset(rInstance.Description); ruleset.SetIcon(rInstance.CreateIcon()); } From 6a847faea9ad82990e7aa2ab94eb10eb2767112b Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Sun, 15 Jan 2023 15:19:47 -0800 Subject: [PATCH 53/83] Make home string keys more specific --- osu.Game/Localisation/ToolbarStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/ToolbarStrings.cs b/osu.Game/Localisation/ToolbarStrings.cs index 02a68a6bdc..e71a3fff9b 100644 --- a/osu.Game/Localisation/ToolbarStrings.cs +++ b/osu.Game/Localisation/ToolbarStrings.cs @@ -22,12 +22,12 @@ namespace osu.Game.Localisation /// /// "home" /// - public static LocalisableString HomeHeaderTitle => new TranslatableString(getKey(@"header_title"), @"home"); + public static LocalisableString HomeHeaderTitle => new TranslatableString(getKey(@"home_header_title"), @"home"); /// /// "return to the main menu" /// - public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"header_description"), @"return to the main menu"); + public static LocalisableString HomeHeaderDescription => new TranslatableString(getKey(@"home_header_description"), @"return to the main menu"); /// /// "play some {0}" From 26f3b1dbfee45ed20d9bc62f003832f8bfca92c8 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 19:37:47 +0300 Subject: [PATCH 54/83] Localise "revert to default" tooltip --- osu.Game/Localisation/CommonStrings.cs | 5 +++++ osu.Game/Overlays/RestoreDefaultValueButton.cs | 4 +++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 10178915a2..fed7b6cab7 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -154,6 +154,11 @@ namespace osu.Game.Localisation /// public static LocalisableString Exit => new TranslatableString(getKey(@"exit"), @"Exit"); + /// + /// "Revert to default" + /// + public static LocalisableString RevertToDefault => new TranslatableString(getKey(@"revert_to_default"), @"Revert to default"); + private static string getKey(string key) => $@"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/RestoreDefaultValueButton.cs b/osu.Game/Overlays/RestoreDefaultValueButton.cs index 9d5e5db6e6..97c66fdf02 100644 --- a/osu.Game/Overlays/RestoreDefaultValueButton.cs +++ b/osu.Game/Overlays/RestoreDefaultValueButton.cs @@ -6,6 +6,7 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; @@ -17,6 +18,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osuTK; +using osu.Game.Localisation; namespace osu.Game.Overlays { @@ -96,7 +98,7 @@ namespace osu.Game.Overlays FinishTransforms(true); } - public override LocalisableString TooltipText => "revert to default"; + public override LocalisableString TooltipText => CommonStrings.RevertToDefault.ToLower(); protected override bool OnHover(HoverEvent e) { From 6eb5508404c5841fc0dc007bc9224efc8df0c55b Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 19:39:50 +0300 Subject: [PATCH 55/83] Localise menu bar --- osu.Game/Skinning/Editor/SkinEditor.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 0ed4e5afd2..5fe92b33aa 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -122,14 +122,14 @@ namespace osu.Game.Skinning.Editor RelativeSizeAxes = Axes.Both, Items = new[] { - new MenuItem("File") + new MenuItem(CommonStrings.MenuBarFile) { Items = new[] { - new EditorMenuItem("Save", MenuItemType.Standard, Save), - new EditorMenuItem("Revert to default", MenuItemType.Destructive, revert), + new EditorMenuItem(Resources.Localisation.Web.CommonStrings.ButtonsSave, MenuItemType.Standard, Save), + new EditorMenuItem(CommonStrings.RevertToDefault, MenuItemType.Destructive, revert), new EditorMenuItemSpacer(), - new EditorMenuItem("Exit", MenuItemType.Standard, () => skinEditorOverlay?.Hide()), + new EditorMenuItem(CommonStrings.Exit, MenuItemType.Standard, () => skinEditorOverlay?.Hide()), }, }, } From 17aeb0ec192b13e158233d2f299fabe759d61794 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 19:55:28 +0300 Subject: [PATCH 56/83] Localise editor's UI --- osu.Game/Localisation/SkinEditorStrings.cs | 49 +++++++++++++++++++ .../Skinning/Editor/SkinComponentToolbox.cs | 3 +- osu.Game/Skinning/Editor/SkinEditor.cs | 9 ++-- .../Skinning/Editor/SkinEditorSceneLibrary.cs | 9 ++-- .../Skinning/Editor/SkinSettingsToolbox.cs | 5 +- 5 files changed, 62 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Localisation/SkinEditorStrings.cs diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs new file mode 100644 index 0000000000..605b7d6a9d --- /dev/null +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -0,0 +1,49 @@ +// 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.Localisation; + +namespace osu.Game.Localisation +{ + public static class SkinEditorStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.SkinEditor"; + + /// + /// "Skin editor" + /// + public static LocalisableString SkinEditor => new TranslatableString(getKey(@"skin_editor"), @"Skin editor"); + + /// + /// "Currently editing" + /// + public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); + + /// + /// "Components" + /// + public static LocalisableString Components => new TranslatableString(getKey(@"components"), @"Components"); + + /// + /// "Scene library" + /// + public static LocalisableString SceneLibrary => new TranslatableString(getKey(@"scene_library"), @"Scene library"); + + /// + /// "Song Select" + /// + public static LocalisableString SongSelect => new TranslatableString(getKey(@"song_select"), @"Song Select"); + + /// + /// "Gameplay" + /// + public static LocalisableString Gameplay => new TranslatableString(getKey(@"gameplay"), @"Gameplay"); + + /// + /// "Settings ({0})" + /// + public static LocalisableString Settings(string arg0) => new TranslatableString(getKey(@"settings"), @"Settings ({0})", arg0); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs index 053119557f..9985b81059 100644 --- a/osu.Game/Skinning/Editor/SkinComponentToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinComponentToolbox.cs @@ -10,6 +10,7 @@ using osu.Framework.Logging; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Screens.Edit.Components; using osu.Game.Screens.Play.HUD; @@ -26,7 +27,7 @@ namespace osu.Game.Skinning.Editor private FillFlowContainer fill = null!; public SkinComponentToolbox(CompositeDrawable? target = null) - : base("Components") + : base(SkinEditorStrings.Components) { this.target = target; } diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 5fe92b33aa..74391e5269 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -109,7 +109,7 @@ namespace osu.Game.Skinning.Editor { new Container { - Name = "Menu container", + Name = @"Menu container", RelativeSizeAxes = Axes.X, Depth = float.MinValue, Height = MENU_HEIGHT, @@ -234,7 +234,6 @@ namespace osu.Game.Skinning.Editor // Immediately clear the previous blueprint container to ensure it doesn't try to interact with the old target. content?.Clear(); - Scheduler.AddOnce(loadBlueprintContainer); Scheduler.AddOnce(populateSettings); @@ -253,15 +252,15 @@ namespace osu.Game.Skinning.Editor { headerText.Clear(); - headerText.AddParagraph("Skin editor", cp => cp.Font = OsuFont.Default.With(size: 16)); + headerText.AddParagraph(SkinEditorStrings.SkinEditor, cp => cp.Font = OsuFont.Default.With(size: 16)); headerText.NewParagraph(); - headerText.AddText("Currently editing ", cp => + headerText.AddText(SkinEditorStrings.CurrentlyEditing, cp => { cp.Font = OsuFont.Default.With(size: 12); cp.Colour = colours.Yellow; }); - headerText.AddText($"{currentSkin.Value.SkinInfo}", cp => + headerText.AddText($" {currentSkin.Value.SkinInfo}", cp => { cp.Font = OsuFont.Default.With(size: 12, weight: FontWeight.Bold); cp.Colour = colours.Yellow; diff --git a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs index c3907ea60d..44045e8916 100644 --- a/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs +++ b/osu.Game/Skinning/Editor/SkinEditorSceneLibrary.cs @@ -16,6 +16,7 @@ using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Rulesets; using osu.Game.Rulesets.Mods; @@ -66,7 +67,7 @@ namespace osu.Game.Skinning.Editor { new FillFlowContainer { - Name = "Scene library", + Name = @"Scene library", AutoSizeAxes = Axes.X, RelativeSizeAxes = Axes.Y, Spacing = new Vector2(padding), @@ -76,14 +77,14 @@ namespace osu.Game.Skinning.Editor { new OsuSpriteText { - Text = "Scene library", + Text = SkinEditorStrings.SceneLibrary, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Margin = new MarginPadding(10), }, new SceneButton { - Text = "Song Select", + Text = SkinEditorStrings.SongSelect, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Action = () => performer?.PerformFromScreen(screen => @@ -96,7 +97,7 @@ namespace osu.Game.Skinning.Editor }, new SceneButton { - Text = "Gameplay", + Text = SkinEditorStrings.Gameplay, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, Action = () => performer?.PerformFromScreen(screen => diff --git a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs b/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs index 8c08f40b70..6afe92c6b2 100644 --- a/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs +++ b/osu.Game/Skinning/Editor/SkinSettingsToolbox.cs @@ -1,12 +1,11 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.Linq; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Screens.Edit.Components; using osuTK; @@ -17,7 +16,7 @@ namespace osu.Game.Skinning.Editor protected override Container Content { get; } public SkinSettingsToolbox(Drawable component) - : base($"Settings ({component.GetType().Name})") + : base(SkinEditorStrings.Settings(component.GetType().Name)) { base.Content.Add(Content = new FillFlowContainer { From 1a776eb546119761f1f1283956c65a5b4fae1347 Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Thu, 12 Jan 2023 14:36:56 +0300 Subject: [PATCH 57/83] Mark item-mutating queue mode tests with `FlakyTest` attribute --- .../TestSceneAllPlayersQueueMode.cs | 33 ++++++--- .../Multiplayer/TestSceneHostOnlyQueueMode.cs | 71 +++++++++++-------- 2 files changed, 64 insertions(+), 40 deletions(-) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs index 7b1abd104f..6da9d37648 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneAllPlayersQueueMode.cs @@ -34,6 +34,24 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + public void TestSingleItemExpiredAfterGameplay() + { + RunGameplay(); + + AddUntilStep("playlist has only one item", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 1); + AddUntilStep("playlist item is expired", () => MultiplayerClient.ClientAPIRoom?.Playlist[0].Expired == true); + AddUntilStep("last item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + + [Test] + [FlakyTest] + /* + * TearDown : System.TimeoutException : "wait for ongoing operation to complete" timed out + * --TearDown + * at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() + * at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) + * at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) + */ public void TestItemAddedToTheEndOfQueue() { addItem(() => OtherBeatmap); @@ -46,16 +64,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] - public void TestSingleItemExpiredAfterGameplay() - { - RunGameplay(); - - AddUntilStep("playlist has only one item", () => MultiplayerClient.ClientAPIRoom?.Playlist.Count == 1); - AddUntilStep("playlist item is expired", () => MultiplayerClient.ClientAPIRoom?.Playlist[0].Expired == true); - AddUntilStep("last item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - - [Test] + [FlakyTest] // See above public void TestNextItemSelectedAfterGameplayFinish() { addItem(() => OtherBeatmap); @@ -73,6 +82,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestItemsNotClearedWhenSwitchToHostOnlyMode() { addItem(() => OtherBeatmap); @@ -88,6 +98,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestCorrectItemSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap); @@ -95,6 +106,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestCorrectRulesetSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap, new CatchRuleset().RulesetInfo); @@ -112,6 +124,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestCorrectModsSelectedAfterNewItemAdded() { addItem(() => OtherBeatmap, mods: new Mod[] { new OsuModDoubleTime() }); diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs index 145c655c0a..dc36f539e3 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneHostOnlyQueueMode.cs @@ -27,22 +27,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("first item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); } - [Test] - public void TestItemStillSelectedAfterChangeToSameBeatmap() - { - selectNewItem(() => InitialBeatmap); - - AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - - [Test] - public void TestItemStillSelectedAfterChangeToOtherBeatmap() - { - selectNewItem(() => OtherBeatmap); - - AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); - } - [Test] public void TestNewItemCreatedAfterGameplayFinished() { @@ -54,20 +38,6 @@ namespace osu.Game.Tests.Visual.Multiplayer AddUntilStep("second playlist item selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[1].ID); } - [Test] - public void TestOnlyLastItemChangedAfterGameplayFinished() - { - RunGameplay(); - - IBeatmapInfo firstBeatmap = null; - AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap); - - selectNewItem(() => OtherBeatmap); - - AddUntilStep("first playlist item hasn't changed", () => MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap == firstBeatmap); - AddUntilStep("second playlist item changed", () => MultiplayerClient.ClientAPIRoom?.Playlist[1].Beatmap != firstBeatmap); - } - [Test] public void TestSettingsUpdatedWhenChangingQueueMode() { @@ -80,6 +50,47 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] + /* + * TearDown : System.TimeoutException : "wait for ongoing operation to complete" timed out + * --TearDown + * at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() + * at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) + * at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) + */ + public void TestItemStillSelectedAfterChangeToSameBeatmap() + { + selectNewItem(() => InitialBeatmap); + + AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + + [Test] + [FlakyTest] // See above + public void TestItemStillSelectedAfterChangeToOtherBeatmap() + { + selectNewItem(() => OtherBeatmap); + + AddUntilStep("playlist item still selected", () => MultiplayerClient.ClientRoom?.Settings.PlaylistItemId == MultiplayerClient.ClientAPIRoom?.Playlist[0].ID); + } + + [Test] + [FlakyTest] // See above + public void TestOnlyLastItemChangedAfterGameplayFinished() + { + RunGameplay(); + + IBeatmapInfo firstBeatmap = null; + AddStep("get first playlist item beatmap", () => firstBeatmap = MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap); + + selectNewItem(() => OtherBeatmap); + + AddUntilStep("first playlist item hasn't changed", () => MultiplayerClient.ServerAPIRoom?.Playlist[0].Beatmap == firstBeatmap); + AddUntilStep("second playlist item changed", () => MultiplayerClient.ClientAPIRoom?.Playlist[1].Beatmap != firstBeatmap); + } + + [Test] + [FlakyTest] // See above public void TestAddItemsAsHost() { addItem(() => OtherBeatmap); From f63de55a20a92f2669d6faae73cc5716c273a72d Mon Sep 17 00:00:00 2001 From: Salman Ahmed Date: Mon, 16 Jan 2023 22:34:29 +0300 Subject: [PATCH 58/83] Mark ready-button-pressing multiplayer tests with `FlakyTest` attribute --- .../Multiplayer/TestSceneMultiplayer.cs | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs index 5033347b15..d747d23229 100644 --- a/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs +++ b/osu.Game.Tests/Visual/Multiplayer/TestSceneMultiplayer.cs @@ -377,6 +377,17 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] + /* + * On a slight investigation, this is occurring due to the ready button + * not receiving the click input generated by the manual input manager. + * + * TearDown : System.TimeoutException : "wait for ready button to be enabled" timed out + * --TearDown + * at osu.Framework.Testing.Drawables.Steps.UntilStepButton.<>c__DisplayClass11_0.<.ctor>b__0() + * at osu.Framework.Testing.Drawables.Steps.StepButton.PerformStep(Boolean userTriggered) + * at osu.Framework.Testing.TestScene.runNextStep(Action onCompletion, Action`1 onError, Func`2 stopCondition) + */ public void TestUserSetToIdleWhenBeatmapDeleted() { createRoom(() => new Room @@ -398,6 +409,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestPlayStartsWithCorrectBeatmapWhileAtSongSelect() { PlaylistItem? item = null; @@ -438,6 +450,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestPlayStartsWithCorrectRulesetWhileAtSongSelect() { PlaylistItem? item = null; @@ -478,6 +491,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestPlayStartsWithCorrectModsWhileAtSongSelect() { PlaylistItem? item = null; @@ -651,6 +665,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestGameplayFlow() { createRoom(() => new Room @@ -678,6 +693,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestGameplayExitFlow() { Bindable? holdDelay = null; @@ -715,6 +731,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestGameplayDoesntStartWithNonLoadedUser() { createRoom(() => new Room @@ -796,6 +813,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestSpectatingStateResetOnBackButtonDuringGameplay() { createRoom(() => new Room @@ -831,6 +849,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestSpectatingStateNotResetOnBackButtonOutsideOfGameplay() { createRoom(() => new Room @@ -869,6 +888,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestItemAddedByOtherUserDuringGameplay() { createRoom(() => new Room @@ -899,6 +919,7 @@ namespace osu.Game.Tests.Visual.Multiplayer } [Test] + [FlakyTest] // See above public void TestItemAddedAndDeletedByOtherUserDuringGameplay() { createRoom(() => new Room From 0ec608ec5d67dc341ea768ac7e3460cacbd96937 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 22:46:57 +0300 Subject: [PATCH 59/83] Select button using its index in test --- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index e0b61794e4..3b49161dd6 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Click gameplay scene button", () => { - InputManager.MoveMouseTo(skinEditor.ChildrenOfType().First(b => b.Text == "Gameplay")); + InputManager.MoveMouseTo(skinEditor.ChildrenOfType().Skip(1).First()); InputManager.Click(MouseButton.Left); }); From 133b9b79d768c41711429ff8c329729577c05dcf Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Mon, 16 Jan 2023 22:52:17 +0300 Subject: [PATCH 60/83] Do not touch "currently editing" line --- osu.Game/Localisation/SkinEditorStrings.cs | 5 ----- osu.Game/Skinning/Editor/SkinEditor.cs | 4 ++-- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/osu.Game/Localisation/SkinEditorStrings.cs b/osu.Game/Localisation/SkinEditorStrings.cs index 605b7d6a9d..b2e5f3aeb6 100644 --- a/osu.Game/Localisation/SkinEditorStrings.cs +++ b/osu.Game/Localisation/SkinEditorStrings.cs @@ -14,11 +14,6 @@ namespace osu.Game.Localisation /// public static LocalisableString SkinEditor => new TranslatableString(getKey(@"skin_editor"), @"Skin editor"); - /// - /// "Currently editing" - /// - public static LocalisableString CurrentlyEditing => new TranslatableString(getKey(@"currently_editing"), @"Currently editing"); - /// /// "Components" /// diff --git a/osu.Game/Skinning/Editor/SkinEditor.cs b/osu.Game/Skinning/Editor/SkinEditor.cs index 74391e5269..98b4e960dd 100644 --- a/osu.Game/Skinning/Editor/SkinEditor.cs +++ b/osu.Game/Skinning/Editor/SkinEditor.cs @@ -254,13 +254,13 @@ namespace osu.Game.Skinning.Editor headerText.AddParagraph(SkinEditorStrings.SkinEditor, cp => cp.Font = OsuFont.Default.With(size: 16)); headerText.NewParagraph(); - headerText.AddText(SkinEditorStrings.CurrentlyEditing, cp => + headerText.AddText("Currently editing ", cp => { cp.Font = OsuFont.Default.With(size: 12); cp.Colour = colours.Yellow; }); - headerText.AddText($" {currentSkin.Value.SkinInfo}", cp => + headerText.AddText($"{currentSkin.Value.SkinInfo}", cp => { cp.Font = OsuFont.Default.With(size: 12, weight: FontWeight.Bold); cp.Colour = colours.Yellow; From 6207a96a29f93733fbd1569d26f0ce02b78ae8f5 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 16 Jan 2023 23:24:09 +0300 Subject: [PATCH 61/83] Refactor `LevelBadge` to use `LevelInfo` --- .../Profile/Header/CentreHeaderContainer.cs | 15 ++++++++++++--- .../Profile/Header/Components/LevelBadge.cs | 10 +++++----- 2 files changed, 17 insertions(+), 8 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index 7721342ba8..fbd8f1e0c6 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -6,6 +6,7 @@ using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Online.API.Requests.Responses; using osu.Game.Overlays.Profile.Header.Components; using osuTK; @@ -15,6 +16,8 @@ namespace osu.Game.Overlays.Profile.Header { public readonly Bindable User = new Bindable(); + private LevelBadge levelBadge = null!; + public CentreHeaderContainer() { Height = 60; @@ -62,12 +65,11 @@ namespace osu.Game.Overlays.Profile.Header Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN }, Children = new Drawable[] { - new LevelBadge + levelBadge = new LevelBadge { Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, - Size = new Vector2(40), - User = { BindTarget = User } + Size = new Vector2(40) }, new Container { @@ -85,6 +87,13 @@ namespace osu.Game.Overlays.Profile.Header } } }; + + User.BindValueChanged(user => updateDisplay(user.NewValue?.User)); + } + + private void updateDisplay(APIUser? user) + { + levelBadge.LevelInfo.Value = user?.Statistics?.Level; } } } diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index 78c5231736..a0c17ccf93 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -11,14 +11,14 @@ using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; -using osu.Game.Online.API.Requests.Responses; using osu.Game.Resources.Localisation.Web; +using osu.Game.Users; namespace osu.Game.Overlays.Profile.Header.Components { public partial class LevelBadge : CompositeDrawable, IHasTooltip { - public readonly Bindable User = new Bindable(); + public readonly Bindable LevelInfo = new Bindable(); public LocalisableString TooltipText { get; private set; } @@ -48,12 +48,12 @@ namespace osu.Game.Overlays.Profile.Header.Components } }; - User.BindValueChanged(user => updateLevel(user.NewValue?.User)); + LevelInfo.BindValueChanged(user => updateLevel(user.NewValue)); } - private void updateLevel(APIUser? user) + private void updateLevel(UserStatistics.LevelInfo? levelInfo) { - string level = user?.Statistics?.Level.Current.ToString() ?? "0"; + string level = levelInfo?.Current.ToString() ?? "0"; levelText.Text = level; TooltipText = UsersStrings.ShowStatsLevel(level); } From c5d09c0e2c82ff4ae5c7259d6459994972ff3ca2 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 16 Jan 2023 23:36:50 +0300 Subject: [PATCH 62/83] Rename variable MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index a0c17ccf93..251cd1bae5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -48,7 +48,7 @@ namespace osu.Game.Overlays.Profile.Header.Components } }; - LevelInfo.BindValueChanged(user => updateLevel(user.NewValue)); + LevelInfo.BindValueChanged(level => updateLevel(level.NewValue)); } private void updateLevel(UserStatistics.LevelInfo? levelInfo) From 3f75506552e9285534cfa47b69aa81cb41633df0 Mon Sep 17 00:00:00 2001 From: StanR Date: Mon, 16 Jan 2023 23:42:07 +0300 Subject: [PATCH 63/83] Move binding to `LoadComplete` --- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index 251cd1bae5..b75ffcaf98 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -47,8 +47,11 @@ namespace osu.Game.Overlays.Profile.Header.Components Font = OsuFont.GetFont(size: 20) } }; + } - LevelInfo.BindValueChanged(level => updateLevel(level.NewValue)); + protected override void LoadComplete() + { + LevelInfo.BindValueChanged(level => updateLevel(level.NewValue), true); } private void updateLevel(UserStatistics.LevelInfo? levelInfo) From f79037cefb206f9e57a3dd450d51ec6f7af0c343 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Mon, 16 Jan 2023 21:47:31 +0100 Subject: [PATCH 64/83] Move to `LoadComplete()` better --- osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs | 7 ++++++- osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs | 2 ++ 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs index fbd8f1e0c6..0dab4d582d 100644 --- a/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/CentreHeaderContainer.cs @@ -87,8 +87,13 @@ namespace osu.Game.Overlays.Profile.Header } } }; + } - User.BindValueChanged(user => updateDisplay(user.NewValue?.User)); + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(user => updateDisplay(user.NewValue?.User), true); } private void updateDisplay(APIUser? user) diff --git a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs index b75ffcaf98..00bb8cbc75 100644 --- a/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs +++ b/osu.Game/Overlays/Profile/Header/Components/LevelBadge.cs @@ -51,6 +51,8 @@ namespace osu.Game.Overlays.Profile.Header.Components protected override void LoadComplete() { + base.LoadComplete(); + LevelInfo.BindValueChanged(level => updateLevel(level.NewValue), true); } From 4cf448ec11898985fc56ea2f1178ef765aa412eb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 11:51:17 +0900 Subject: [PATCH 65/83] Use `ToString()` for test instead of linq skip --- .../Visual/Navigation/TestSceneSkinEditorNavigation.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs index 3b49161dd6..845cfdd6df 100644 --- a/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs +++ b/osu.Game.Tests/Visual/Navigation/TestSceneSkinEditorNavigation.cs @@ -219,7 +219,7 @@ namespace osu.Game.Tests.Visual.Navigation AddStep("Click gameplay scene button", () => { - InputManager.MoveMouseTo(skinEditor.ChildrenOfType().Skip(1).First()); + InputManager.MoveMouseTo(skinEditor.ChildrenOfType().First(b => b.Text.ToString() == "Gameplay")); InputManager.Click(MouseButton.Left); }); From a02556d2fa93e7ca6242ba614af42ab37cc05a53 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 14:43:22 +0900 Subject: [PATCH 66/83] Move hover logic to `SettingsToolboxGroup` to avoid expanded state clash --- osu.Game/Overlays/SettingsToolboxGroup.cs | 4 +++- .../Play/PlayerSettings/PlayerSettingsGroup.cs | 18 ------------------ 2 files changed, 3 insertions(+), 19 deletions(-) diff --git a/osu.Game/Overlays/SettingsToolboxGroup.cs b/osu.Game/Overlays/SettingsToolboxGroup.cs index 86964e7ed4..c0948c1eab 100644 --- a/osu.Game/Overlays/SettingsToolboxGroup.cs +++ b/osu.Game/Overlays/SettingsToolboxGroup.cs @@ -135,12 +135,14 @@ namespace osu.Game.Overlays protected override bool OnHover(HoverEvent e) { updateFadeState(); + updateExpandedState(true); return false; } protected override void OnHoverLost(HoverLostEvent e) { updateFadeState(); + updateExpandedState(true); base.OnHoverLost(e); } @@ -168,7 +170,7 @@ namespace osu.Game.Overlays // potentially continuing to get processed while content has changed to autosize. content.ClearTransforms(); - if (Expanded.Value) + if (Expanded.Value || IsHovered) { content.AutoSizeAxes = Axes.Y; content.AutoSizeDuration = animate ? transition_duration : 0; diff --git a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs index ea4d983343..838106e198 100644 --- a/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs +++ b/osu.Game/Screens/Play/PlayerSettings/PlayerSettingsGroup.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Input.Events; using osu.Game.Overlays; @@ -15,28 +13,12 @@ namespace osu.Game.Screens.Play.PlayerSettings { } - private bool expandedByDefault = true; - protected override bool OnHover(HoverEvent e) { - if (IsHovered && !Expanded.Value) - { - Expanded.Value = true; - expandedByDefault = false; - } - base.OnHover(e); // Importantly, return true to correctly take focus away from PlayerLoader. return true; } - - protected override void OnHoverLost(HoverLostEvent e) - { - if (!expandedByDefault) - Expanded.Value = false; - - base.OnHoverLost(e); - } } } From ef354938646837725471a384172021f95a8ed51b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 15:27:19 +0900 Subject: [PATCH 67/83] Avoid need for weird null check by reordering initialisation process --- osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index d4d75d0ad6..64deb59026 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -127,9 +127,6 @@ namespace osu.Game.Screens.Select [BackgroundDependencyLoader(true)] private void load(AudioManager audio, OsuColour colours, ManageCollectionsDialog? manageCollectionsDialog, DifficultyRecommender? recommender) { - // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). - transferRulesetValue(); - LoadComponentAsync(Carousel = new BeatmapCarousel { AllowSelection = false, // delay any selection until our bindables are ready to make a good choice. @@ -143,6 +140,9 @@ namespace osu.Game.Screens.Select GetRecommendedBeatmap = s => recommender?.GetRecommendedBeatmap(s), }, c => carouselContainer.Child = c); + // initial value transfer is required for FilterControl (it uses our re-cached bindables in its async load for the initial filter). + transferRulesetValue(); + AddRangeInternal(new Drawable[] { new ResetScrollContainer(() => Carousel.ScrollToSelected()) @@ -860,9 +860,6 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // We want to check for null since this method gets called before the loading of the carousel. - if (Carousel.IsNull()) return true; - // if we have a pending filter operation, we want to run it now. // it could change selection (ie. if the ruleset has been changed). Carousel.FlushPendingFilterOperations(); From 08c570849f15c77e2f8fc7ab6800c5db742f5155 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 16 Jan 2023 23:24:47 -0800 Subject: [PATCH 68/83] Simplify container logic --- osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs index 8e0ee896a5..a5e0bddc6b 100644 --- a/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs +++ b/osu.Game/Tests/Visual/OsuManualInputManagerTestScene.cs @@ -46,8 +46,6 @@ namespace osu.Game.Tests.Visual { var mainContent = content = new Container { RelativeSizeAxes = Axes.Both }; - var inputContainer = new Container { RelativeSizeAxes = Axes.Both }; - if (DisplayCursorForManualInput) { var cursorDisplay = new GlobalCursorDisplay { RelativeSizeAxes = Axes.Both }; @@ -57,12 +55,11 @@ namespace osu.Game.Tests.Visual RelativeSizeAxes = Axes.Both, }); - inputContainer.Add(cursorDisplay); - mainContent = inputContainer; + mainContent.Add(cursorDisplay); } if (CreateNestedActionContainer) - inputContainer.Add(new GlobalActionContainer(null)); + mainContent.Add(new GlobalActionContainer(null)); base.Content.AddRange(new Drawable[] { From 8f7cb18217187084ccdecebe9328cbbcc98f3324 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Mon, 16 Jan 2023 23:36:28 -0800 Subject: [PATCH 69/83] Use `TriggerClick()` instead of calling `BackButton` action for pause gameplay --- osu.Game/Screens/Play/PauseOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index db2b87dae6..dc4c4fdc5a 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play switch (e.Action) { case GlobalAction.PauseGameplay: - BackAction.Invoke(); + InternalButtons.Children.First().TriggerClick(); return true; } From da0eb9b0cbe7ef101063085d244102fe7db389b4 Mon Sep 17 00:00:00 2001 From: Joseph Madamba Date: Tue, 17 Jan 2023 00:34:52 -0800 Subject: [PATCH 70/83] Simplify `TriggerClick`s in gameplay menu overlays --- osu.Game/Screens/Play/GameplayMenuOverlay.cs | 2 +- osu.Game/Screens/Play/PauseOverlay.cs | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Play/GameplayMenuOverlay.cs b/osu.Game/Screens/Play/GameplayMenuOverlay.cs index 13f32d3b6a..81146a4ea6 100644 --- a/osu.Game/Screens/Play/GameplayMenuOverlay.cs +++ b/osu.Game/Screens/Play/GameplayMenuOverlay.cs @@ -44,7 +44,7 @@ namespace osu.Game.Screens.Play /// /// Action that is invoked when is triggered. /// - protected virtual Action BackAction => () => InternalButtons.Children.LastOrDefault()?.TriggerClick(); + protected virtual Action BackAction => () => InternalButtons.LastOrDefault()?.TriggerClick(); /// /// Action that is invoked when is triggered. diff --git a/osu.Game/Screens/Play/PauseOverlay.cs b/osu.Game/Screens/Play/PauseOverlay.cs index dc4c4fdc5a..d9c60519ad 100644 --- a/osu.Game/Screens/Play/PauseOverlay.cs +++ b/osu.Game/Screens/Play/PauseOverlay.cs @@ -28,7 +28,7 @@ namespace osu.Game.Screens.Play private SkinnableSound pauseLoop; - protected override Action BackAction => () => InternalButtons.Children.First().TriggerClick(); + protected override Action BackAction => () => InternalButtons.First().TriggerClick(); [BackgroundDependencyLoader] private void load(OsuColour colours) @@ -64,7 +64,7 @@ namespace osu.Game.Screens.Play switch (e.Action) { case GlobalAction.PauseGameplay: - InternalButtons.Children.First().TriggerClick(); + InternalButtons.First().TriggerClick(); return true; } From 26cd70f2bfde476c3fe08df4ef363b6bfc10512b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:44:42 +0900 Subject: [PATCH 71/83] Always use production (non-experimental) endpoints for tournament client --- osu.Game.Tournament/TournamentGameBase.cs | 9 +++++++++ .../ExperimentalEndpointConfiguration.cs | 19 +++++++++++++++++++ .../Online/ProductionEndpointConfiguration.cs | 5 +---- osu.Game/OsuGameBase.cs | 4 ++-- 4 files changed, 31 insertions(+), 6 deletions(-) create mode 100644 osu.Game/Online/ExperimentalEndpointConfiguration.cs diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..c61ee0d3e8 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -16,6 +16,7 @@ using osu.Framework.IO.Stores; using osu.Framework.Logging; using osu.Framework.Platform; using osu.Game.Graphics; +using osu.Game.Online; using osu.Game.Online.API.Requests; using osu.Game.Online.API.Requests.Responses; using osu.Game.Tournament.IO; @@ -44,6 +45,14 @@ namespace osu.Game.Tournament return dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); } + public override EndpointConfiguration CreateEndpoints() + { + if (UseDevelopmentServer) + return base.CreateEndpoints(); + + return new ProductionEndpointConfiguration(); + } + private TournamentSpriteText initialisationText; [BackgroundDependencyLoader] diff --git a/osu.Game/Online/ExperimentalEndpointConfiguration.cs b/osu.Game/Online/ExperimentalEndpointConfiguration.cs new file mode 100644 index 0000000000..c3d0014c8b --- /dev/null +++ b/osu.Game/Online/ExperimentalEndpointConfiguration.cs @@ -0,0 +1,19 @@ +// 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.Online +{ + public class ExperimentalEndpointConfiguration : EndpointConfiguration + { + public ExperimentalEndpointConfiguration() + { + WebsiteRootUrl = @"https://osu.ppy.sh"; + APIEndpointUrl = @"https://lazer.ppy.sh"; + APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; + APIClientID = "5"; + SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; + MultiplayerEndpointUrl = "https://spectator.ppy.sh/multiplayer"; + MetadataEndpointUrl = "https://spectator.ppy.sh/metadata"; + } + } +} diff --git a/osu.Game/Online/ProductionEndpointConfiguration.cs b/osu.Game/Online/ProductionEndpointConfiguration.cs index 003ec50afd..0244761b65 100644 --- a/osu.Game/Online/ProductionEndpointConfiguration.cs +++ b/osu.Game/Online/ProductionEndpointConfiguration.cs @@ -1,16 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - namespace osu.Game.Online { public class ProductionEndpointConfiguration : EndpointConfiguration { public ProductionEndpointConfiguration() { - WebsiteRootUrl = @"https://osu.ppy.sh"; - APIEndpointUrl = @"https://lazer.ppy.sh"; + WebsiteRootUrl = APIEndpointUrl = @"https://osu.ppy.sh"; APIClientSecret = @"FGc9GAtyHzeQDshWP5Ah7dega8hJACAJpQtw6OXk"; APIClientID = "5"; SpectatorEndpointUrl = "https://spectator.ppy.sh/spectator"; diff --git a/osu.Game/OsuGameBase.cs b/osu.Game/OsuGameBase.cs index b27be37591..1c50349941 100644 --- a/osu.Game/OsuGameBase.cs +++ b/osu.Game/OsuGameBase.cs @@ -98,8 +98,8 @@ namespace osu.Game public virtual bool UseDevelopmentServer => DebugUtils.IsDebugBuild; - internal EndpointConfiguration CreateEndpoints() => - UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ProductionEndpointConfiguration(); + public virtual EndpointConfiguration CreateEndpoints() => + UseDevelopmentServer ? new DevelopmentEndpointConfiguration() : new ExperimentalEndpointConfiguration(); public virtual Version AssemblyVersion => Assembly.GetEntryAssembly()?.GetName().Version ?? new Version(); From 68636aeaaa339d9a2dc82402d46d68bbb6004b90 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:56:15 +0900 Subject: [PATCH 72/83] Fix tournament client not saving changes after populating new data --- osu.Game.Tournament/TournamentGameBase.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..e4fe922a51 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -156,7 +156,7 @@ namespace osu.Game.Tournament addedInfo |= addSeedingBeatmaps(); if (addedInfo) - SaveChanges(); + saveChanges(); ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value); } @@ -306,6 +306,11 @@ namespace osu.Game.Tournament return; } + saveChanges(); + } + + private void saveChanges() + { foreach (var r in ladder.Rounds) r.Matches = ladder.Matches.Where(p => p.Round.Value == r).Select(p => p.ID).ToList(); From 74bb44e05d668b70a53d08d1d1289e9ae9084cdd Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 17 Jan 2023 18:59:43 +0900 Subject: [PATCH 73/83] Fix player rank data not being re-fetched after a tournament's ruleset is changed --- osu.Game.Tournament/Screens/Setup/SetupScreen.cs | 2 +- osu.Game.Tournament/TournamentGameBase.cs | 12 ++++++++++++ 2 files changed, 13 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs index b86513eb49..ceddd4d1a1 100644 --- a/osu.Game.Tournament/Screens/Setup/SetupScreen.cs +++ b/osu.Game.Tournament/Screens/Setup/SetupScreen.cs @@ -113,7 +113,7 @@ namespace osu.Game.Tournament.Screens.Setup new LabelledDropdown { Label = "Ruleset", - Description = "Decides what stats are displayed and which ranks are retrieved for players.", + Description = "Decides what stats are displayed and which ranks are retrieved for players. This requires a restart to reload data for an existing bracket.", Items = rulesets.AvailableRulesets, Current = LadderInfo.Ruleset, }, diff --git a/osu.Game.Tournament/TournamentGameBase.cs b/osu.Game.Tournament/TournamentGameBase.cs index 08f21cb556..ed766c69df 100644 --- a/osu.Game.Tournament/TournamentGameBase.cs +++ b/osu.Game.Tournament/TournamentGameBase.cs @@ -159,6 +159,18 @@ namespace osu.Game.Tournament SaveChanges(); ladder.CurrentMatch.Value = ladder.Matches.FirstOrDefault(p => p.Current.Value); + + ladder.Ruleset.BindValueChanged(r => + { + // Refetch player rank data on next startup as the ruleset has changed. + foreach (var team in ladder.Teams) + { + foreach (var player in team.Players) + player.Rank = null; + } + + SaveChanges(); + }); } catch (Exception e) { From e65108533ab3f42a0d6a6fdfc0926d2cf02f96a0 Mon Sep 17 00:00:00 2001 From: ekrctb Date: Tue, 17 Jan 2023 22:12:06 +0900 Subject: [PATCH 74/83] Reduce number of tested value combination 121 combinations took 2min+ --- .../TestSceneSliderFollowCircleInput.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 0af0ff5604..369c3d6168 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -31,9 +31,9 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestMaximumDistanceTrackingWithoutMovement( - [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + [Values(0, 5, 10)] float circleSize, - [Values(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10)] + [Values(0, 5, 10)] double velocity) { const double time_slider_start = 1000; From 8e1002b7448e1045f12cea690ed50c2e3361c6ed Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 01:56:12 +0900 Subject: [PATCH 75/83] Fix song select potentially operating on `Carousel` before it is fully loaded Should fix test failures like https://github.com/ppy/osu/actions/runs/3939620830/jobs/6739690253. --- osu.Game/Screens/Select/SongSelect.cs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 64deb59026..db4d326991 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -860,9 +860,13 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - Carousel.FlushPendingFilterOperations(); + if (Carousel.IsLoaded) + { + // if we have a pending filter operation, we want to run it now. + // it could change selection (ie. if the ruleset has been changed). + Carousel.FlushPendingFilterOperations(); + } + return true; } From 452bf9255023fe6a7ac9c62e6856af7d721b4b3e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Jan 2023 18:02:06 +0100 Subject: [PATCH 76/83] Fix code quality inspection --- .../TestSceneSliderFollowCircleInput.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs index 369c3d6168..a32f0a13b8 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneSliderFollowCircleInput.cs @@ -31,10 +31,8 @@ namespace osu.Game.Rulesets.Osu.Tests [Test] public void TestMaximumDistanceTrackingWithoutMovement( - [Values(0, 5, 10)] - float circleSize, - [Values(0, 5, 10)] - double velocity) + [Values(0, 5, 10)] float circleSize, + [Values(0, 5, 10)] double velocity) { const double time_slider_start = 1000; From 364034280563cfd683136e9c005e91801fc3a678 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Tue, 17 Jan 2023 21:30:46 +0100 Subject: [PATCH 77/83] Add logging on comment post failure --- osu.Game/Overlays/Comments/CommentsContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/Comments/CommentsContainer.cs b/osu.Game/Overlays/Comments/CommentsContainer.cs index 3639fe1835..a334fac215 100644 --- a/osu.Game/Overlays/Comments/CommentsContainer.cs +++ b/osu.Game/Overlays/Comments/CommentsContainer.cs @@ -19,6 +19,7 @@ using osu.Framework.Threading; using System.Collections.Generic; using JetBrains.Annotations; using osu.Framework.Localisation; +using osu.Framework.Logging; using osu.Game.Graphics.Sprites; using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; @@ -420,9 +421,10 @@ namespace osu.Game.Overlays.Comments { ShowLoadingSpinner = true; CommentPostRequest req = new CommentPostRequest(commentsContainer.Type.Value, commentsContainer.Id.Value, text); - req.Failure += _ => Schedule(() => + req.Failure += e => Schedule(() => { ShowLoadingSpinner = false; + Logger.Error(e, "Posting comment failed."); }); req.Success += cb => Schedule(() => { From 350cce1315d050b8d466edd3549ad309517fe8d8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 18:39:36 +0100 Subject: [PATCH 78/83] Move contents of detail header to separate component --- .../Profile/Header/Components/MainDetails.cs | 187 ++++++++++++++++++ .../Profile/Header/DetailHeaderContainer.cs | 161 +-------------- 2 files changed, 190 insertions(+), 158 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/MainDetails.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs new file mode 100644 index 0000000000..930ba29c7f --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -0,0 +1,187 @@ +// 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 osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Online.Leaderboards; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Scoring; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class MainDetails : CompositeDrawable + { + private readonly Dictionary scoreRankInfos = new Dictionary(); + private ProfileValueDisplay medalInfo = null!; + private ProfileValueDisplay ppInfo = null!; + private ProfileValueDisplay detailGlobalRank = null!; + private ProfileValueDisplay detailCountryRank = null!; + private RankGraph rankGraph = null!; + + public readonly Bindable User = new Bindable(); + + [BackgroundDependencyLoader] + private void load() + { + AutoSizeAxes = Axes.Y; + + InternalChild = new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + AutoSizeDuration = 200, + AutoSizeEasing = Easing.OutQuint, + Masking = true, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, 15), + Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20), + Children = new Drawable[] + { + detailGlobalRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankGlobalSimple, + }, + detailCountryRank = new ProfileValueDisplay(true) + { + Title = UsersStrings.ShowRankCountrySimple, + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + Height = 60, + Children = new Drawable[] + { + rankGraph = new RankGraph + { + RelativeSizeAxes = Axes.Both, + }, + } + }, + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(10, 0), + Children = new Drawable[] + { + medalInfo = new ProfileValueDisplay + { + Title = UsersStrings.ShowStatsMedals, + }, + ppInfo = new ProfileValueDisplay + { + Title = "pp", + }, + new TotalPlayTime + { + User = { BindTarget = User } + }, + } + }, + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Anchor = Anchor.CentreRight, + Origin = Anchor.CentreRight, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(5), + Children = new[] + { + scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH), + scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X), + scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH), + scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S), + scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A), + } + } + } + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + User.BindValueChanged(e => updateDisplay(e.NewValue), true); + } + + private void updateDisplay(UserProfileData? data) + { + var user = data?.User; + + medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; + ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; + + foreach (var scoreRankInfo in scoreRankInfos) + scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; + + detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; + + rankGraph.Statistics.Value = user?.Statistics; + } + + private partial class ScoreRankInfo : CompositeDrawable + { + private readonly OsuSpriteText rankCount; + + public int RankCount + { + set => rankCount.Text = value.ToLocalisableString("#,##0"); + } + + public ScoreRankInfo(ScoreRank rank) + { + AutoSizeAxes = Axes.Both; + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Y, + Width = 44, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new DrawableRank(rank) + { + RelativeSizeAxes = Axes.X, + Height = 22, + }, + rankCount = new OsuSpriteText + { + Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre + } + } + }; + } + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 890e6c4e04..17de8b8ba0 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -1,33 +1,17 @@ // 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 osu.Framework.Allocation; using osu.Framework.Bindables; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; -using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; -using osu.Game.Online.Leaderboards; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Resources.Localisation.Web; -using osu.Game.Scoring; -using osuTK; namespace osu.Game.Overlays.Profile.Header { public partial class DetailHeaderContainer : CompositeDrawable { - private readonly Dictionary scoreRankInfos = new Dictionary(); - private ProfileValueDisplay medalInfo = null!; - private ProfileValueDisplay ppInfo = null!; - private ProfileValueDisplay detailGlobalRank = null!; - private ProfileValueDisplay detailCountryRank = null!; - private RankGraph rankGraph = null!; - public readonly Bindable User = new Bindable(); [BackgroundDependencyLoader] @@ -35,8 +19,6 @@ namespace osu.Game.Overlays.Profile.Header { AutoSizeAxes = Axes.Y; - User.ValueChanged += e => updateDisplay(e.NewValue); - InternalChildren = new Drawable[] { new Box @@ -44,149 +26,12 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new FillFlowContainer + new MainDetails { RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - AutoSizeDuration = 200, - AutoSizeEasing = Easing.OutQuint, - Masking = true, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, - Direction = FillDirection.Vertical, - Spacing = new Vector2(0, 15), - Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(20), - Children = new Drawable[] - { - detailGlobalRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankGlobalSimple, - }, - detailCountryRank = new ProfileValueDisplay(true) - { - Title = UsersStrings.ShowRankCountrySimple, - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - Height = 60, - Children = new Drawable[] - { - rankGraph = new RankGraph - { - RelativeSizeAxes = Axes.Both, - }, - } - }, - new Container - { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreLeft, - Origin = Anchor.CentreLeft, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(10, 0), - Children = new Drawable[] - { - medalInfo = new ProfileValueDisplay - { - Title = UsersStrings.ShowStatsMedals, - }, - ppInfo = new ProfileValueDisplay - { - Title = "pp", - }, - new TotalPlayTime - { - User = { BindTarget = User } - }, - } - }, - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Anchor = Anchor.CentreRight, - Origin = Anchor.CentreRight, - Direction = FillDirection.Horizontal, - Spacing = new Vector2(5), - Children = new[] - { - scoreRankInfos[ScoreRank.XH] = new ScoreRankInfo(ScoreRank.XH), - scoreRankInfos[ScoreRank.X] = new ScoreRankInfo(ScoreRank.X), - scoreRankInfos[ScoreRank.SH] = new ScoreRankInfo(ScoreRank.SH), - scoreRankInfos[ScoreRank.S] = new ScoreRankInfo(ScoreRank.S), - scoreRankInfos[ScoreRank.A] = new ScoreRankInfo(ScoreRank.A), - } - } - } - }, - } - }, + User = { BindTarget = User } + } }; } - - private void updateDisplay(UserProfileData? data) - { - var user = data?.User; - - medalInfo.Content = user?.Achievements?.Length.ToString() ?? "0"; - ppInfo.Content = user?.Statistics?.PP?.ToLocalisableString("#,##0") ?? (LocalisableString)"0"; - - foreach (var scoreRankInfo in scoreRankInfos) - scoreRankInfo.Value.RankCount = user?.Statistics?.GradesCount[scoreRankInfo.Key] ?? 0; - - detailGlobalRank.Content = user?.Statistics?.GlobalRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - detailCountryRank.Content = user?.Statistics?.CountryRank?.ToLocalisableString("\\##,##0") ?? (LocalisableString)"-"; - - rankGraph.Statistics.Value = user?.Statistics; - } - - private partial class ScoreRankInfo : CompositeDrawable - { - private readonly OsuSpriteText rankCount; - - public int RankCount - { - set => rankCount.Text = value.ToLocalisableString("#,##0"); - } - - public ScoreRankInfo(ScoreRank rank) - { - AutoSizeAxes = Axes.Both; - InternalChild = new FillFlowContainer - { - AutoSizeAxes = Axes.Y, - Width = 44, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new DrawableRank(rank) - { - RelativeSizeAxes = Axes.X, - Height = 22, - }, - rankCount = new OsuSpriteText - { - Font = OsuFont.GetFont(size: 12, weight: FontWeight.Bold), - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre - } - } - }; - } - } } } From 7a475d9cf8b160ad9ce77ba283c8b4696298c2aa Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 18:55:27 +0100 Subject: [PATCH 79/83] Move out stats from top header container --- .../Header/Components/ExtendedDetails.cs | 108 ++++++++++++++++++ .../Profile/Header/TopHeaderContainer.cs | 51 --------- 2 files changed, 108 insertions(+), 51 deletions(-) create mode 100644 osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs diff --git a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs new file mode 100644 index 0000000000..b50b0041d0 --- /dev/null +++ b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs @@ -0,0 +1,108 @@ +// 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.Bindables; +using osu.Framework.Extensions.LocalisationExtensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Resources.Localisation.Web; +using osu.Game.Users; +using osuTK; + +namespace osu.Game.Overlays.Profile.Header.Components +{ + public partial class ExtendedDetails : CompositeDrawable + { + public Bindable UserProfile { get; } = new Bindable(); + + private SpriteText rankedScore = null!; + private SpriteText hitAccuracy = null!; + private SpriteText playCount = null!; + private SpriteText totalScore = null!; + private SpriteText totalHits = null!; + private SpriteText maximumCombo = null!; + private SpriteText replaysWatched = null!; + + [BackgroundDependencyLoader] + private void load() + { + var font = OsuFont.Default.With(size: 12); + const float vertical_spacing = 4; + + AutoSizeAxes = Axes.Both; + + // this should really be a grid, but trying to avoid one to avoid the performance hit. + InternalChild = new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Spacing = new Vector2(20, 0), + Children = new[] + { + new FillFlowContainer + { + Name = @"Labels", + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, vertical_spacing), + Children = new Drawable[] + { + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsRankedScore }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsHitAccuracy }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsPlayCount }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalScore }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsTotalHits }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsMaximumCombo }, + new OsuSpriteText { Font = font, Text = UsersStrings.ShowStatsReplaysWatchedByOthers }, + } + }, + new FillFlowContainer + { + Name = @"Values", + Direction = FillDirection.Vertical, + Spacing = new Vector2(0, vertical_spacing), + Children = new Drawable[] + { + rankedScore = new OsuSpriteText { Font = font }, + hitAccuracy = new OsuSpriteText { Font = font }, + playCount = new OsuSpriteText { Font = font }, + totalScore = new OsuSpriteText { Font = font }, + totalHits = new OsuSpriteText { Font = font }, + maximumCombo = new OsuSpriteText { Font = font }, + replaysWatched = new OsuSpriteText { Font = font }, + } + }, + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + UserProfile.BindValueChanged(userProfile => updateStatistics(userProfile.NewValue?.User.Statistics), true); + } + + private void updateStatistics(UserStatistics? statistics) + { + if (statistics == null) + { + Alpha = 0; + return; + } + + Alpha = 1; + + rankedScore.Text = statistics.RankedScore.ToLocalisableString(@"N0"); + hitAccuracy.Text = statistics.DisplayAccuracy; + playCount.Text = statistics.PlayCount.ToLocalisableString(@"N0"); + totalScore.Text = statistics.TotalScore.ToLocalisableString(@"N0"); + totalHits.Text = statistics.TotalHits.ToLocalisableString(@"N0"); + maximumCombo.Text = statistics.MaxCombo.ToLocalisableString(@"N0"); + replaysWatched.Text = statistics.ReplaysWatched.ToLocalisableString(@"N0"); + } + } +} diff --git a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs index e04a8ad9ad..1fe39cb570 100644 --- a/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/TopHeaderContainer.cs @@ -5,18 +5,15 @@ using osu.Framework.Allocation; using osu.Framework.Bindables; using osu.Framework.Extensions; using osu.Framework.Extensions.Color4Extensions; -using osu.Framework.Extensions.LocalisationExtensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; -using osu.Framework.Localisation; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.Cursor; using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Profile.Header.Components; -using osu.Game.Resources.Localisation.Web; using osu.Game.Users.Drawables; using osuTK; @@ -38,7 +35,6 @@ namespace osu.Game.Overlays.Profile.Header private OsuSpriteText titleText = null!; private UpdateableFlag userFlag = null!; private OsuSpriteText userCountryText = null!; - private FillFlowContainer userStats = null!; private GroupBadgeFlow groupBadgeFlow = null!; [BackgroundDependencyLoader] @@ -164,16 +160,6 @@ namespace osu.Game.Overlays.Profile.Header } } }, - userStats = new FillFlowContainer - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - AutoSizeAxes = Axes.Y, - Width = 300, - Margin = new MarginPadding { Right = UserProfileOverlay.CONTENT_X_MARGIN }, - Padding = new MarginPadding { Vertical = 15 }, - Spacing = new Vector2(0, 2) - } }; User.BindValueChanged(user => updateUser(user.NewValue)); @@ -192,43 +178,6 @@ namespace osu.Game.Overlays.Profile.Header titleText.Text = user?.Title ?? string.Empty; titleText.Colour = Color4Extensions.FromHex(user?.Colour ?? "fff"); groupBadgeFlow.User.Value = user; - - userStats.Clear(); - - if (user?.Statistics != null) - { - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsRankedScore, user.Statistics.RankedScore.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsHitAccuracy, user.Statistics.DisplayAccuracy)); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsPlayCount, user.Statistics.PlayCount.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalScore, user.Statistics.TotalScore.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsTotalHits, user.Statistics.TotalHits.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsMaximumCombo, user.Statistics.MaxCombo.ToLocalisableString("#,##0"))); - userStats.Add(new UserStatsLine(UsersStrings.ShowStatsReplaysWatchedByOthers, user.Statistics.ReplaysWatched.ToLocalisableString("#,##0"))); - } - } - - private partial class UserStatsLine : Container - { - public UserStatsLine(LocalisableString left, LocalisableString right) - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Children = new Drawable[] - { - new OsuSpriteText - { - Font = OsuFont.GetFont(size: 15), - Text = left, - }, - new OsuSpriteText - { - Anchor = Anchor.TopRight, - Origin = Anchor.TopRight, - Font = OsuFont.GetFont(size: 15, weight: FontWeight.Bold), - Text = right, - }, - }; - } } } } From f7c942ac10b22d365f9f9b98228959d8c5d8350e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Sat, 31 Dec 2022 19:00:40 +0100 Subject: [PATCH 80/83] Move user stats into detail header container --- .../Header/Components/ExtendedDetails.cs | 6 ++- .../Profile/Header/Components/MainDetails.cs | 1 - .../Profile/Header/DetailHeaderContainer.cs | 44 ++++++++++++++++++- 3 files changed, 46 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs index b50b0041d0..50fc52600c 100644 --- a/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/ExtendedDetails.cs @@ -17,7 +17,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { public partial class ExtendedDetails : CompositeDrawable { - public Bindable UserProfile { get; } = new Bindable(); + public Bindable User { get; } = new Bindable(); private SpriteText rankedScore = null!; private SpriteText hitAccuracy = null!; @@ -46,6 +46,7 @@ namespace osu.Game.Overlays.Profile.Header.Components new FillFlowContainer { Name = @"Labels", + AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, vertical_spacing), Children = new Drawable[] @@ -62,6 +63,7 @@ namespace osu.Game.Overlays.Profile.Header.Components new FillFlowContainer { Name = @"Values", + AutoSizeAxes = Axes.Both, Direction = FillDirection.Vertical, Spacing = new Vector2(0, vertical_spacing), Children = new Drawable[] @@ -83,7 +85,7 @@ namespace osu.Game.Overlays.Profile.Header.Components { base.LoadComplete(); - UserProfile.BindValueChanged(userProfile => updateStatistics(userProfile.NewValue?.User.Statistics), true); + User.BindValueChanged(user => updateStatistics(user.NewValue?.User.Statistics), true); } private void updateStatistics(UserStatistics? statistics) diff --git a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs index 930ba29c7f..b89973c5e5 100644 --- a/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs +++ b/osu.Game/Overlays/Profile/Header/Components/MainDetails.cs @@ -40,7 +40,6 @@ namespace osu.Game.Overlays.Profile.Header.Components AutoSizeDuration = 200, AutoSizeEasing = Easing.OutQuint, Masking = true, - Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, Direction = FillDirection.Vertical, Spacing = new Vector2(0, 15), Children = new Drawable[] diff --git a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs index 17de8b8ba0..1cc3aae735 100644 --- a/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs +++ b/osu.Game/Overlays/Profile/Header/DetailHeaderContainer.cs @@ -26,10 +26,50 @@ namespace osu.Game.Overlays.Profile.Header RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, - new MainDetails + new Container { RelativeSizeAxes = Axes.X, - User = { BindTarget = User } + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding { Horizontal = UserProfileOverlay.CONTENT_X_MARGIN, Vertical = 10 }, + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + ColumnDimensions = new[] + { + new Dimension(), + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new Drawable[] + { + new MainDetails + { + RelativeSizeAxes = Axes.X, + User = { BindTarget = User } + }, + new Box + { + RelativeSizeAxes = Axes.Y, + Width = 2, + Colour = colourProvider.Background6, + Margin = new MarginPadding { Horizontal = 15 } + }, + new ExtendedDetails + { + Anchor = Anchor.CentreLeft, + Origin = Anchor.CentreLeft, + User = { BindTarget = User } + } + } + } + } } }; } From 12544c16eab2510ce4c8d90ba415103ba632b364 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 02:10:02 +0300 Subject: [PATCH 81/83] Remove canBeNull --- osu.Game/Overlays/Comments/DrawableComment.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 834abd5e9f..70ffbd8baf 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -70,7 +70,7 @@ namespace osu.Game.Overlays.Comments private GridContainer content = null!; private VotePill votePill = null!; - [Resolved(canBeNull: true)] + [Resolved] private IDialogOverlay? dialogOverlay { get; set; } [Resolved] @@ -79,7 +79,7 @@ namespace osu.Game.Overlays.Comments [Resolved] private GameHost host { get; set; } = null!; - [Resolved(canBeNull: true)] + [Resolved] private OnScreenDisplay? onScreenDisplay { get; set; } public DrawableComment(Comment comment) From ca3be7138149e9ed8f6af73986cef0b559fa60f6 Mon Sep 17 00:00:00 2001 From: ansel <79257300125@ya.ru> Date: Wed, 18 Jan 2023 02:11:07 +0300 Subject: [PATCH 82/83] Track comment's nesting and reduce padding for too nested --- osu.Game/Overlays/Comments/DrawableComment.cs | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/Comments/DrawableComment.cs b/osu.Game/Overlays/Comments/DrawableComment.cs index 70ffbd8baf..1df65ab4b1 100644 --- a/osu.Game/Overlays/Comments/DrawableComment.cs +++ b/osu.Game/Overlays/Comments/DrawableComment.cs @@ -57,6 +57,11 @@ namespace osu.Game.Overlays.Comments /// public bool WasDeleted { get; protected set; } + /// + /// Tracks this comment's level of nesting. 0 means that this comment has no parents. + /// + public int Level { get; private set; } + private FillFlowContainer childCommentsVisibilityContainer = null!; private FillFlowContainer childCommentsContainer = null!; private LoadRepliesButton loadRepliesButton = null!; @@ -88,12 +93,16 @@ namespace osu.Game.Overlays.Comments } [BackgroundDependencyLoader] - private void load(OverlayColourProvider colourProvider) + private void load(OverlayColourProvider colourProvider, DrawableComment? parentComment) { LinkFlowContainer username; FillFlowContainer info; CommentMarkdownContainer message; + Level = parentComment?.Level + 1 ?? 0; + + float childrenPadding = Level < 6 ? 20 : 5; + RelativeSizeAxes = Axes.X; AutoSizeAxes = Axes.Y; InternalChildren = new Drawable[] @@ -248,7 +257,7 @@ namespace osu.Game.Overlays.Comments RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, Direction = FillDirection.Vertical, - Padding = new MarginPadding { Left = 20 }, + Padding = new MarginPadding { Left = childrenPadding }, Children = new Drawable[] { childCommentsContainer = new FillFlowContainer From 4ad79a8a0ac721be0e409a9fd729a45d5c6c1bd0 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 18 Jan 2023 12:00:47 +0900 Subject: [PATCH 83/83] Move `IsLoaded` check inside `BeatmapCarousel` --- osu.Game/Screens/Select/BeatmapCarousel.cs | 3 +++ osu.Game/Screens/Select/SongSelect.cs | 9 +++------ 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapCarousel.cs b/osu.Game/Screens/Select/BeatmapCarousel.cs index 19eced08d9..774ecc2c9c 100644 --- a/osu.Game/Screens/Select/BeatmapCarousel.cs +++ b/osu.Game/Screens/Select/BeatmapCarousel.cs @@ -596,6 +596,9 @@ namespace osu.Game.Screens.Select public void FlushPendingFilterOperations() { + if (!IsLoaded) + return; + if (PendingFilter?.Completed == false) { applyActiveCriteria(false); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index db4d326991..4b3222c14a 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -860,12 +860,9 @@ namespace osu.Game.Screens.Select Logger.Log($"decoupled ruleset transferred (\"{decoupledRuleset.Value}\" -> \"{Ruleset.Value}\")"); rulesetNoDebounce = decoupledRuleset.Value = Ruleset.Value; - if (Carousel.IsLoaded) - { - // if we have a pending filter operation, we want to run it now. - // it could change selection (ie. if the ruleset has been changed). - Carousel.FlushPendingFilterOperations(); - } + // if we have a pending filter operation, we want to run it now. + // it could change selection (ie. if the ruleset has been changed). + Carousel.FlushPendingFilterOperations(); return true; }