From e1eda89ea69234164ae055d1f129626d8fc970f7 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 8 Jan 2020 17:41:44 +0100 Subject: [PATCH 01/39] Implement OnlineContainer --- osu.Game/Online/OnlineContainer.cs | 76 ++++++++++++++++++++++++++++++ 1 file changed, 76 insertions(+) create mode 100644 osu.Game/Online/OnlineContainer.cs diff --git a/osu.Game/Online/OnlineContainer.cs b/osu.Game/Online/OnlineContainer.cs new file mode 100644 index 0000000000..6ab5203fe6 --- /dev/null +++ b/osu.Game/Online/OnlineContainer.cs @@ -0,0 +1,76 @@ +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Online.Placeholders; + +namespace osu.Game.Online +{ + /// + /// A for dislaying online content who require a local user to be logged in. + /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. + /// + public class OnlineViewContainer : Container, IOnlineComponent + { + private readonly Container content; + private readonly Container placeholderContainer; + private readonly Placeholder placeholder; + + private const int transform_time = 300; + + protected override Container Content => content; + + public OnlineViewContainer(string placeholder_message) + { + InternalChildren = new Drawable[] + { + content = new Container + { + RelativeSizeAxes = Axes.Both, + }, + placeholderContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + Child = placeholder = new LoginPlaceholder() + }, + }; + } + + public void APIStateChanged(IAPIProvider api, APIState state) + { + switch (state) + { + case APIState.Offline: + case APIState.Connecting: + Schedule(() =>updatePlaceholderVisibility(true)); + break; + + default: + Schedule(() => updatePlaceholderVisibility(false)); + break; + } + } + + private void updatePlaceholderVisibility(bool show_placeholder) + { + if (show_placeholder) + { + content.FadeOut(transform_time / 2, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); + placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + } + else + { + placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); + content.FadeIn(transform_time, Easing.OutQuint); + } + } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api) + { + api.Register(this); + } + } +} From e9a52984845e9a39cab5a5dd09081aa7045d6436 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 12 Jan 2020 15:50:35 +0100 Subject: [PATCH 02/39] Allow setting the displayed text on LoginPlaceholder --- osu.Game/Online/Leaderboards/Leaderboard.cs | 2 +- osu.Game/Online/OnlineContainer.cs | 2 +- osu.Game/Online/Placeholders/LoginPlaceholder.cs | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game/Online/Leaderboards/Leaderboard.cs b/osu.Game/Online/Leaderboards/Leaderboard.cs index 55233bef6e..095e552ddd 100644 --- a/osu.Game/Online/Leaderboards/Leaderboard.cs +++ b/osu.Game/Online/Leaderboards/Leaderboard.cs @@ -151,7 +151,7 @@ namespace osu.Game.Online.Leaderboards break; case PlaceholderState.NotLoggedIn: - replacePlaceholder(new LoginPlaceholder()); + replacePlaceholder(new LoginPlaceholder(@"Please sign in to view online leaderboards!")); break; case PlaceholderState.NotSupporter: diff --git a/osu.Game/Online/OnlineContainer.cs b/osu.Game/Online/OnlineContainer.cs index 6ab5203fe6..6a8963599f 100644 --- a/osu.Game/Online/OnlineContainer.cs +++ b/osu.Game/Online/OnlineContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder() + Child = placeholder = new LoginPlaceholder(placeholder_message) }, }; } diff --git a/osu.Game/Online/Placeholders/LoginPlaceholder.cs b/osu.Game/Online/Placeholders/LoginPlaceholder.cs index ffc6623229..f3b5a86785 100644 --- a/osu.Game/Online/Placeholders/LoginPlaceholder.cs +++ b/osu.Game/Online/Placeholders/LoginPlaceholder.cs @@ -14,7 +14,7 @@ namespace osu.Game.Online.Placeholders [Resolved(CanBeNull = true)] private LoginOverlay login { get; set; } - public LoginPlaceholder() + public LoginPlaceholder(string actionMessage) { AddIcon(FontAwesome.Solid.UserLock, cp => { @@ -22,7 +22,7 @@ namespace osu.Game.Online.Placeholders cp.Padding = new MarginPadding { Right = 10 }; }); - AddText(@"Please sign in to view online leaderboards!"); + AddText(actionMessage); } protected override bool OnMouseDown(MouseDownEvent e) From 8f6c6ad77a6198c8954195e656099b6fc4450732 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 12 Jan 2020 17:43:44 +0100 Subject: [PATCH 03/39] Fix class name not corresponding to filename --- osu.Game/Online/{OnlineContainer.cs => OnlineViewContainer.cs} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename osu.Game/Online/{OnlineContainer.cs => OnlineViewContainer.cs} (100%) diff --git a/osu.Game/Online/OnlineContainer.cs b/osu.Game/Online/OnlineViewContainer.cs similarity index 100% rename from osu.Game/Online/OnlineContainer.cs rename to osu.Game/Online/OnlineViewContainer.cs From 0422b326ad3faa719ba34852a4d80e3b22ce273d Mon Sep 17 00:00:00 2001 From: Lucas A Date: Mon, 13 Jan 2020 21:12:19 +0100 Subject: [PATCH 04/39] Add visual tests --- .../Online/TestSceneOnlineViewContainer.cs | 75 +++++++++++++++++++ osu.Game/Online/API/DummyAPIAccess.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 25 ++++--- 3 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs new file mode 100644 index 0000000000..a8c50a37e7 --- /dev/null +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -0,0 +1,75 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System.Linq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics.Sprites; +using osu.Game.Online; +using osu.Game.Online.API; +using osuTK.Graphics; + +namespace osu.Game.Tests.Visual.Online +{ + [TestFixture] + public class TestSceneOnlineViewContainer : OsuTestScene + { + private OnlineViewContainer onlineView; + private Box box; + + public TestSceneOnlineViewContainer() + { + Child = new Container + { + RelativeSizeAxes = Axes.Both, + Child = onlineView = new OnlineViewContainer(@"Please login to view dummy test content") + { + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + box = new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue.Opacity(0.8f), + }, + new OsuSpriteText + { + Text = "dummy online content", + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + } + } + }; + } + + [BackgroundDependencyLoader] + private void load() + { + AddStep("set status to offline", () => + { + (API as DummyAPIAccess).State = APIState.Offline; + }); + + AddAssert("children are hidden", () => + { + return !onlineView.Children.First().Parent.IsPresent; + }); + + AddStep("set status to online", () => + { + (API as DummyAPIAccess).State = APIState.Online; + }); + + AddAssert("children are visible", () => + { + return onlineView.Children.First().Parent.IsPresent; + }); + } + } +} diff --git a/osu.Game/Online/API/DummyAPIAccess.cs b/osu.Game/Online/API/DummyAPIAccess.cs index 7f23f9b5d5..a1c3475fd9 100644 --- a/osu.Game/Online/API/DummyAPIAccess.cs +++ b/osu.Game/Online/API/DummyAPIAccess.cs @@ -33,7 +33,7 @@ namespace osu.Game.Online.API public APIState State { get => state; - private set + set { if (state == value) return; diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 6a8963599f..a7f81b4776 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -1,4 +1,7 @@ -using osu.Framework.Allocation; +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Online.API; @@ -20,7 +23,7 @@ namespace osu.Game.Online protected override Container Content => content; - public OnlineViewContainer(string placeholder_message) + public OnlineViewContainer(string placeholderMessage) { InternalChildren = new Drawable[] { @@ -32,7 +35,7 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder(placeholder_message) + Child = placeholder = new LoginPlaceholder(placeholderMessage) }, }; } @@ -43,7 +46,7 @@ namespace osu.Game.Online { case APIState.Offline: case APIState.Connecting: - Schedule(() =>updatePlaceholderVisibility(true)); + Schedule(() => updatePlaceholderVisibility(true)); break; default: @@ -52,18 +55,18 @@ namespace osu.Game.Online } } - private void updatePlaceholderVisibility(bool show_placeholder) + private void updatePlaceholderVisibility(bool showPlaceholder) { - if (show_placeholder) + if (showPlaceholder) { - content.FadeOut(transform_time / 2, Easing.OutQuint); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); - placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + content.FadeOut(transform_time / 2, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); + placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); } else { - placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); - content.FadeIn(transform_time, Easing.OutQuint); + placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); + content.FadeIn(transform_time, Easing.OutQuint); } } From f00938971eda2ba95c451792a6ce56234f073532 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 17 Jan 2020 18:53:17 +0100 Subject: [PATCH 05/39] Apply review suggestions --- .../Online/TestSceneOnlineViewContainer.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 19 ++++++++++++++----- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index a8c50a37e7..9b7de2b7f4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -26,7 +26,7 @@ namespace osu.Game.Tests.Visual.Online Child = new Container { RelativeSizeAxes = Axes.Both, - Child = onlineView = new OnlineViewContainer(@"Please login to view dummy test content") + Child = onlineView = new OnlineViewContainer(@"view dummy test content") { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index a7f81b4776..ac3a3edd67 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -23,6 +23,9 @@ namespace osu.Game.Online protected override Container Content => content; + [Resolved] + protected IAPIProvider API { get; private set; } + public OnlineViewContainer(string placeholderMessage) { InternalChildren = new Drawable[] @@ -35,12 +38,12 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder(placeholderMessage) + Child = placeholder = new LoginPlaceholder($@"Please sign in to {placeholderMessage}") }, }; } - public void APIStateChanged(IAPIProvider api, APIState state) + public virtual void APIStateChanged(IAPIProvider api, APIState state) { switch (state) { @@ -70,10 +73,16 @@ namespace osu.Game.Online } } - [BackgroundDependencyLoader] - private void load(IAPIProvider api) + protected override void LoadComplete() { - api.Register(this); + API?.Register(this); + base.LoadComplete(); + } + + protected override void Dispose(bool isDisposing) + { + API?.Unregister(this); + base.Dispose(isDisposing); } } } From e1f172e3f820c88b481f546b49752a71a1b754bc Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 17 Jan 2020 19:29:42 +0100 Subject: [PATCH 06/39] Fix CI issues --- .../Online/TestSceneOnlineViewContainer.cs | 25 +++++-------------- osu.Game/Online/OnlineViewContainer.cs | 4 +-- 2 files changed, 8 insertions(+), 21 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 9b7de2b7f4..4579e4f428 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -18,8 +18,7 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public class TestSceneOnlineViewContainer : OsuTestScene { - private OnlineViewContainer onlineView; - private Box box; + private readonly OnlineViewContainer onlineView; public TestSceneOnlineViewContainer() { @@ -31,7 +30,7 @@ namespace osu.Game.Tests.Visual.Online RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - box = new Box + new Box { RelativeSizeAxes = Axes.Both, Colour = Color4.Blue.Opacity(0.8f), @@ -51,25 +50,13 @@ namespace osu.Game.Tests.Visual.Online [BackgroundDependencyLoader] private void load() { - AddStep("set status to offline", () => - { - (API as DummyAPIAccess).State = APIState.Offline; - }); + AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => - { - return !onlineView.Children.First().Parent.IsPresent; - }); + AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); - AddStep("set status to online", () => - { - (API as DummyAPIAccess).State = APIState.Online; - }); + AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => - { - return onlineView.Children.First().Parent.IsPresent; - }); + AddAssert("children are visible", () => onlineView.Children.First().Parent.IsPresent); } } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index ac3a3edd67..0a8432ee12 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -62,13 +62,13 @@ namespace osu.Game.Online { if (showPlaceholder) { - content.FadeOut(transform_time / 2, Easing.OutQuint); + content.FadeOut(150, Easing.OutQuint); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); } else { - placeholderContainer.FadeOut(transform_time / 2, Easing.OutQuint); + placeholderContainer.FadeOut(150, Easing.OutQuint); content.FadeIn(transform_time, Easing.OutQuint); } } From 6d51b344abfc6929f5029044dc01b10f8e9dc28d Mon Sep 17 00:00:00 2001 From: Lucas A Date: Sun, 19 Jan 2020 20:24:46 +0100 Subject: [PATCH 07/39] Display a loading animation when the user is connecting --- .../Online/TestSceneOnlineViewContainer.cs | 4 ++ osu.Game/Online/OnlineViewContainer.cs | 57 ++++++++++++++----- 2 files changed, 46 insertions(+), 15 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 4579e4f428..ddb672dbf4 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -57,6 +57,10 @@ namespace osu.Game.Tests.Visual.Online AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); AddAssert("children are visible", () => onlineView.Children.First().Parent.IsPresent); + + AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); + + AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); } } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 0a8432ee12..35296409e5 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -4,6 +4,7 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Online.Placeholders; @@ -15,12 +16,13 @@ namespace osu.Game.Online /// public class OnlineViewContainer : Container, IOnlineComponent { - private readonly Container content; private readonly Container placeholderContainer; private readonly Placeholder placeholder; + private readonly LoadingAnimation loading; private const int transform_time = 300; + private readonly Container content; protected override Container Content => content; [Resolved] @@ -40,6 +42,10 @@ namespace osu.Game.Online Alpha = 0, Child = placeholder = new LoginPlaceholder($@"Please sign in to {placeholderMessage}") }, + loading = new LoadingAnimation + { + Alpha = 0, + } }; } @@ -47,29 +53,43 @@ namespace osu.Game.Online { switch (state) { - case APIState.Offline: + case APIState.Failing: case APIState.Connecting: - Schedule(() => updatePlaceholderVisibility(true)); + Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Connecting)); break; - default: - Schedule(() => updatePlaceholderVisibility(false)); + case APIState.Offline: + Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Offline)); + break; + + case APIState.Online: + Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Online)); break; } } - private void updatePlaceholderVisibility(bool showPlaceholder) + protected void UpdatePlaceholderVisibility(PlaceholderStatus status) { - if (showPlaceholder) + switch (status) { - content.FadeOut(150, Easing.OutQuint); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); - placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); - } - else - { - placeholderContainer.FadeOut(150, Easing.OutQuint); - content.FadeIn(transform_time, Easing.OutQuint); + case PlaceholderStatus.Offline: + Content.FadeOut(150, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); + placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + loading.Hide(); + break; + + case PlaceholderStatus.Online: + placeholderContainer.FadeOut(150, Easing.OutQuint); + Content.FadeIn(transform_time, Easing.OutQuint); + loading.Hide(); + break; + + case PlaceholderStatus.Connecting: + loading.Show(); + placeholderContainer.FadeOut(150, Easing.OutQuint); + Content.FadeOut(150, Easing.OutQuint); + break; } } @@ -84,5 +104,12 @@ namespace osu.Game.Online API?.Unregister(this); base.Dispose(isDisposing); } + + protected enum PlaceholderStatus + { + Offline, + Online, + Connecting, + } } } From d3dc0b63ff9cc9715b5e46909e39ef76435d5007 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 23 Jan 2020 19:09:34 +0100 Subject: [PATCH 08/39] Remove string concatenation from ctor --- osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index ddb672dbf4..fddb82d400 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -25,7 +25,7 @@ namespace osu.Game.Tests.Visual.Online Child = new Container { RelativeSizeAxes = Axes.Both, - Child = onlineView = new OnlineViewContainer(@"view dummy test content") + Child = onlineView = new OnlineViewContainer(@"Please sign in to view dummy test content") { RelativeSizeAxes = Axes.Both, Children = new Drawable[] diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 35296409e5..49174320d3 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -40,7 +40,7 @@ namespace osu.Game.Online { RelativeSizeAxes = Axes.Both, Alpha = 0, - Child = placeholder = new LoginPlaceholder($@"Please sign in to {placeholderMessage}") + Child = placeholder = new LoginPlaceholder(placeholderMessage) }, loading = new LoadingAnimation { From 7ca9f4dc2091c56bd66b11365cbc2dfaa403e4df Mon Sep 17 00:00:00 2001 From: Lucas A Date: Fri, 24 Jan 2020 21:10:31 +0100 Subject: [PATCH 09/39] Apply review suggestions --- .../Online/TestSceneOnlineViewContainer.cs | 85 ++++++++++++------- osu.Game/Online/OnlineViewContainer.cs | 48 +++-------- 2 files changed, 66 insertions(+), 67 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index fddb82d400..277146e4be 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -1,14 +1,13 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -using System.Linq; using NUnit.Framework; -using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online; using osu.Game.Online.API; using osuTK.Graphics; @@ -18,49 +17,75 @@ namespace osu.Game.Tests.Visual.Online [TestFixture] public class TestSceneOnlineViewContainer : OsuTestScene { - private readonly OnlineViewContainer onlineView; + private readonly TestOnlineViewContainer onlineView; public TestSceneOnlineViewContainer() { Child = new Container { RelativeSizeAxes = Axes.Both, - Child = onlineView = new OnlineViewContainer(@"Please sign in to view dummy test content") - { - RelativeSizeAxes = Axes.Both, - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Blue.Opacity(0.8f), - }, - new OsuSpriteText - { - Text = "dummy online content", - RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - } - } + Child = onlineView = new TestOnlineViewContainer() }; } - [BackgroundDependencyLoader] - private void load() + private class TestOnlineViewContainer : OnlineViewContainer + { + public new Container Content => base.Content; + + public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; + + public TestOnlineViewContainer() + : base(@"Please sign in to view dummy test content") + { + RelativeSizeAxes = Axes.Both; + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue.Opacity(0.8f), + }, + new OsuSpriteText + { + Text = "dummy online content", + RelativeSizeAxes = Axes.Both, + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + } + + [Test] + public void TestOnlineStateVisibility() + { + AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); + + AddAssert("children are visible", () => onlineView.Content.IsPresent); + AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + } + + [Test] + public void TestOfflineStateVisibility() { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); - - AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - - AddAssert("children are visible", () => onlineView.Children.First().Parent.IsPresent); + AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + } + [Test] + public void TestConnectingStateVisibility() + { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.Children.First().Parent.IsPresent); + AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + + AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); + + AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 49174320d3..7874a9fcaf 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -14,16 +14,15 @@ namespace osu.Game.Online /// A for dislaying online content who require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// - public class OnlineViewContainer : Container, IOnlineComponent + public abstract class OnlineViewContainer : Container, IOnlineComponent { private readonly Container placeholderContainer; private readonly Placeholder placeholder; - private readonly LoadingAnimation loading; + protected readonly LoadingAnimation LoadingAnimation; private const int transform_time = 300; - private readonly Container content; - protected override Container Content => content; + protected override Container Content { get; } [Resolved] protected IAPIProvider API { get; private set; } @@ -32,7 +31,7 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - content = new Container + Content = new Container { RelativeSizeAxes = Axes.Both, }, @@ -42,7 +41,7 @@ namespace osu.Game.Online Alpha = 0, Child = placeholder = new LoginPlaceholder(placeholderMessage) }, - loading = new LoadingAnimation + LoadingAnimation = new LoadingAnimation { Alpha = 0, } @@ -53,40 +52,22 @@ namespace osu.Game.Online { switch (state) { - case APIState.Failing: - case APIState.Connecting: - Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Connecting)); - break; - case APIState.Offline: - Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Offline)); - break; - - case APIState.Online: - Schedule(() => UpdatePlaceholderVisibility(PlaceholderStatus.Online)); - break; - } - } - - protected void UpdatePlaceholderVisibility(PlaceholderStatus status) - { - switch (status) - { - case PlaceholderStatus.Offline: Content.FadeOut(150, Easing.OutQuint); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); - loading.Hide(); + LoadingAnimation.Hide(); break; - case PlaceholderStatus.Online: + case APIState.Online: placeholderContainer.FadeOut(150, Easing.OutQuint); Content.FadeIn(transform_time, Easing.OutQuint); - loading.Hide(); + LoadingAnimation.Hide(); break; - case PlaceholderStatus.Connecting: - loading.Show(); + case APIState.Failing: + case APIState.Connecting: + LoadingAnimation.Show(); placeholderContainer.FadeOut(150, Easing.OutQuint); Content.FadeOut(150, Easing.OutQuint); break; @@ -104,12 +85,5 @@ namespace osu.Game.Online API?.Unregister(this); base.Dispose(isDisposing); } - - protected enum PlaceholderStatus - { - Offline, - Online, - Connecting, - } } } From 30e0a34e50d083af8726aaaff54fde5c3133f4b0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Wed, 5 Feb 2020 15:04:10 +0100 Subject: [PATCH 10/39] Wrap Content into a container for animating visibility. --- .../Online/TestSceneOnlineViewContainer.cs | 14 ++++--- osu.Game/Online/OnlineViewContainer.cs | 39 ++++++++++--------- 2 files changed, 29 insertions(+), 24 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 277146e4be..5427db5af3 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -30,8 +30,6 @@ namespace osu.Game.Tests.Visual.Online private class TestOnlineViewContainer : OnlineViewContainer { - public new Container Content => base.Content; - public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; public TestOnlineViewContainer() @@ -54,6 +52,10 @@ namespace osu.Game.Tests.Visual.Online } }; } + + protected override void FadeContentOut(Drawable content) => content.Hide(); + + protected override void FadeContentIn(Drawable content) => content.Show(); } [Test] @@ -61,7 +63,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => onlineView.Content.IsPresent); + AddAssert("children are visible", () => onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -70,7 +72,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -79,12 +81,12 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); - AddAssert("children are hidden", () => !onlineView.Content.IsPresent); + AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 7874a9fcaf..ac5a7941ea 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -11,36 +11,35 @@ using osu.Game.Online.Placeholders; namespace osu.Game.Online { /// - /// A for dislaying online content who require a local user to be logged in. + /// A for dislaying online content which require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// public abstract class OnlineViewContainer : Container, IOnlineComponent { - private readonly Container placeholderContainer; private readonly Placeholder placeholder; protected readonly LoadingAnimation LoadingAnimation; - private const int transform_time = 300; + protected const double TRANSFORM_TIME = 300.0; + internal readonly Container TransformationTarget; protected override Container Content { get; } [Resolved] protected IAPIProvider API { get; private set; } - public OnlineViewContainer(string placeholderMessage) + protected OnlineViewContainer(string placeholderMessage) { InternalChildren = new Drawable[] { - Content = new Container + TransformationTarget = new Container { RelativeSizeAxes = Axes.Both, + Child = Content = new Container + { + RelativeSizeAxes = Axes.Both, + } }, - placeholderContainer = new Container - { - RelativeSizeAxes = Axes.Both, - Alpha = 0, - Child = placeholder = new LoginPlaceholder(placeholderMessage) - }, + placeholder = new LoginPlaceholder(placeholderMessage), LoadingAnimation = new LoadingAnimation { Alpha = 0, @@ -53,27 +52,31 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - Content.FadeOut(150, Easing.OutQuint); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_time, Easing.OutQuint); - placeholderContainer.FadeInFromZero(2 * transform_time, Easing.OutQuint); + FadeContentOut(TransformationTarget); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); + placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - placeholderContainer.FadeOut(150, Easing.OutQuint); - Content.FadeIn(transform_time, Easing.OutQuint); + FadeContentIn(TransformationTarget); + placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: + FadeContentOut(TransformationTarget); LoadingAnimation.Show(); - placeholderContainer.FadeOut(150, Easing.OutQuint); - Content.FadeOut(150, Easing.OutQuint); + placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; } } + protected abstract void FadeContentOut(Drawable content); + + protected abstract void FadeContentIn(Drawable content); + protected override void LoadComplete() { API?.Register(this); From b9e10cb49872c4eb0253a6498050e5cca49a96e0 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Tue, 11 Feb 2020 18:10:46 +0100 Subject: [PATCH 11/39] Privatize ViewTarget --- .../Online/TestSceneOnlineViewContainer.cs | 18 ++++++++++++------ osu.Game/Online/OnlineViewContainer.cs | 16 ++++++++-------- 2 files changed, 20 insertions(+), 14 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 5427db5af3..2b9609f6e0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -32,6 +32,8 @@ namespace osu.Game.Tests.Visual.Online { public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; + public CompositeDrawable ViewTarget => base.Content.Parent; + public TestOnlineViewContainer() : base(@"Please sign in to view dummy test content") { @@ -53,9 +55,9 @@ namespace osu.Game.Tests.Visual.Online }; } - protected override void FadeContentOut(Drawable content) => content.Hide(); + protected override void PopContentOut(Drawable content) => content.Hide(); - protected override void FadeContentIn(Drawable content) => content.Show(); + protected override void PopContentIn(Drawable content) => content.Show(); } [Test] @@ -63,7 +65,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => onlineView.TransformationTarget.IsPresent); + AddAssert("children are visible", () => onlineView.ViewTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -72,7 +74,7 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); + AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } @@ -81,12 +83,16 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); + AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + } + [Test] + public void TestFailingStateVisibility() + { AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); - AddAssert("children are hidden", () => !onlineView.TransformationTarget.IsPresent); + AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index ac5a7941ea..c512ca531a 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -11,7 +11,7 @@ using osu.Game.Online.Placeholders; namespace osu.Game.Online { /// - /// A for dislaying online content which require a local user to be logged in. + /// A for displaying online content which require a local user to be logged in. /// Shows its children only when the local user is logged in and supports displaying a placeholder if not. /// public abstract class OnlineViewContainer : Container, IOnlineComponent @@ -21,7 +21,7 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - internal readonly Container TransformationTarget; + private readonly Container viewTarget; protected override Container Content { get; } [Resolved] @@ -31,7 +31,7 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - TransformationTarget = new Container + viewTarget = new Container { RelativeSizeAxes = Axes.Both, Child = Content = new Container @@ -52,30 +52,30 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - FadeContentOut(TransformationTarget); + PopContentOut(viewTarget); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - FadeContentIn(TransformationTarget); + PopContentIn(viewTarget); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: - FadeContentOut(TransformationTarget); + PopContentOut(viewTarget); LoadingAnimation.Show(); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; } } - protected abstract void FadeContentOut(Drawable content); + protected abstract void PopContentOut(Drawable content); - protected abstract void FadeContentIn(Drawable content); + protected abstract void PopContentIn(Drawable content); protected override void LoadComplete() { From c386589cc09682ccf21db710775aa4bc6420e64e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Feb 2020 19:02:25 +0900 Subject: [PATCH 12/39] Reapply current state, not idle --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index e391157b5b..f4ce71b803 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -116,7 +116,7 @@ namespace osu.Game.Rulesets.Objects.Drawables HitObject.DefaultsApplied += onDefaultsApplied; startTimeBindable = HitObject.StartTimeBindable.GetBoundCopy(); - startTimeBindable.BindValueChanged(_ => updateState(ArmedState.Idle, true)); + startTimeBindable.BindValueChanged(_ => updateState(State.Value, true)); if (HitObject is IHasComboInformation combo) { From f7ee675102c4dc76f6b69711046f4678515988b2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Feb 2020 19:02:54 +0900 Subject: [PATCH 13/39] Clear and revert to negative infinity, avoiding transforms getting left behind on StartTime change --- osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs index f4ce71b803..d3a0b3450f 100644 --- a/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs +++ b/osu.Game/Rulesets/Objects/Drawables/DrawableHitObject.cs @@ -250,8 +250,8 @@ namespace osu.Game.Rulesets.Objects.Drawables double transformTime = HitObject.StartTime - InitialLifetimeOffset; - base.ApplyTransformsAt(transformTime, true); - base.ClearTransformsAfter(transformTime, true); + base.ApplyTransformsAt(double.MinValue, true); + base.ClearTransformsAfter(double.MinValue, true); using (BeginAbsoluteSequence(transformTime, true)) { From 85a443783755a52cc2d46581644180a264339a2d Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 12 Feb 2020 19:03:22 +0900 Subject: [PATCH 14/39] Fix editor custom FadeOut causing overlapping issues by removing existing FadeOut --- osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs index 22b4c3e82e..a8719e0aa8 100644 --- a/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs +++ b/osu.Game.Rulesets.Osu/Edit/DrawableOsuEditRuleset.cs @@ -40,6 +40,8 @@ namespace osu.Game.Rulesets.Osu.Edit if (existing == null) return; + hitObject.RemoveTransform(existing); + using (hitObject.BeginAbsoluteSequence(existing.StartTime)) hitObject.FadeOut(editor_hit_object_fade_out_extension).Expire(); break; From e34a24a063dc7e67a48dc16abe1463012e4133ae Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 10:45:16 +0900 Subject: [PATCH 15/39] Update placement blueprint more often for better display --- .../Components/ComposeBlueprintContainer.cs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 8b47ea2c6c..7087eac6b6 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -76,17 +76,6 @@ namespace osu.Game.Screens.Edit.Compose.Components #endregion - protected override bool OnMouseMove(MouseMoveEvent e) - { - if (currentPlacement != null) - { - updatePlacementPosition(e.ScreenSpaceMousePosition); - return true; - } - - return base.OnMouseMove(e); - } - protected override void Update() { base.Update(); @@ -95,6 +84,9 @@ namespace osu.Game.Screens.Edit.Compose.Components createPlacement(); else if (currentPlacement?.PlacementActive == false) removePlacement(); + + if (currentPlacement != null) + updatePlacementPosition(inputManager.CurrentState.Mouse.Position); } protected sealed override SelectionBlueprint CreateBlueprintFor(HitObject hitObject) From 03bf10f9a24a7a5b259e13435a9979c4e32adfea Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 11:15:00 +0900 Subject: [PATCH 16/39] Remove unused using statement --- .../Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs | 1 - 1 file changed, 1 deletion(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs index 7087eac6b6..0eb77a8561 100644 --- a/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/ComposeBlueprintContainer.cs @@ -7,7 +7,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Input; -using osu.Framework.Input.Events; using osu.Game.Rulesets.Edit; using osu.Game.Rulesets.Edit.Tools; using osu.Game.Rulesets.Objects; From 118f862342dd5903cfdea4661c15302ca6b361f1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 13 Feb 2020 12:02:10 +0900 Subject: [PATCH 17/39] Fix not being able to seek using scroll wheel in timeline while playing track --- .../Components/Timeline/ZoomableScrollContainer.cs | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index 7ce8a751e0..baaad63e57 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -2,10 +2,12 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Transforms; using osu.Framework.Input.Events; +using osu.Framework.Timing; using osu.Framework.Utils; using osu.Game.Graphics.Containers; using osuTK; @@ -30,6 +32,9 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private float currentZoom = 1; + [Resolved] + private IFrameBasedClock editorClock { get; set; } + public ZoomableScrollContainer() : base(Direction.Horizontal) { @@ -104,8 +109,15 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline protected override bool OnScroll(ScrollEvent e) { if (e.IsPrecise) + { + // can't handle scroll correctly while playing. + // the editor will handle this case for us. + if (editorClock.IsRunning) + return false; + // for now, we don't support zoom when using a precision scroll device. this needs gesture support. return base.OnScroll(e); + } setZoomTarget(zoomTarget + e.ScrollDelta.Y, zoomedContent.ToLocalSpace(e.ScreenSpaceMousePosition).X); return true; From 6f7196b0b81c4063c43006f655090e434df259a9 Mon Sep 17 00:00:00 2001 From: smoogipoo Date: Wed, 12 Feb 2020 19:52:47 +0900 Subject: [PATCH 18/39] Make beatmap detail area abstractable --- osu.Game/Configuration/OsuConfigManager.cs | 2 +- osu.Game/Screens/Select/BeatmapDetailArea.cs | 106 +++++++------ .../Select/BeatmapDetailAreaDetailTabItem.cs | 10 ++ .../BeatmapDetailAreaLeaderboardTabItem.cs | 22 +++ .../Select/BeatmapDetailAreaTabControl.cs | 51 ++++--- .../Select/BeatmapDetailAreaTabItem.cs | 35 +++++ osu.Game/Screens/Select/MatchSongSelect.cs | 2 + .../Screens/Select/PlayBeatmapDetailArea.cs | 143 ++++++++++++++++++ osu.Game/Screens/Select/PlaySongSelect.cs | 4 + osu.Game/Screens/Select/SongSelect.cs | 20 +-- 10 files changed, 318 insertions(+), 77 deletions(-) create mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs create mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs create mode 100644 osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs create mode 100644 osu.Game/Screens/Select/PlayBeatmapDetailArea.cs diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 6ae3c7ac64..ce959e9057 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -20,7 +20,7 @@ namespace osu.Game.Configuration Set(OsuSetting.Ruleset, 0, 0, int.MaxValue); Set(OsuSetting.Skin, 0, -1, int.MaxValue); - Set(OsuSetting.BeatmapDetailTab, BeatmapDetailTab.Details); + Set(OsuSetting.BeatmapDetailTab, PlayBeatmapDetailArea.TabType.Details); Set(OsuSetting.ShowConvertedBeatmaps, true); Set(OsuSetting.DisplayStarsMinimum, 0.0, 0, 10, 0.1); diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 71733c9f06..1aae0cc243 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -2,37 +2,44 @@ // See the LICENCE file in the repository root for full licence text. using System; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Beatmaps; -using osu.Game.Screens.Select.Leaderboards; namespace osu.Game.Screens.Select { - public class BeatmapDetailArea : Container + public abstract class BeatmapDetailArea : Container { private const float details_padding = 10; - private readonly Container content; - protected override Container Content => content; - - public readonly BeatmapDetails Details; - public readonly BeatmapLeaderboard Leaderboard; - private WorkingBeatmap beatmap; - public WorkingBeatmap Beatmap + public virtual WorkingBeatmap Beatmap { get => beatmap; set { beatmap = value; - Details.Beatmap = beatmap?.BeatmapInfo; - Leaderboard.Beatmap = beatmap is DummyWorkingBeatmap ? null : beatmap?.BeatmapInfo; + + Details.Beatmap = value?.BeatmapInfo; } } - public BeatmapDetailArea() + public readonly BeatmapDetails Details; + + protected Bindable CurrentTab + { + get => tabControl.Current; + set => tabControl.Current = value; + } + + private readonly Container content; + protected override Container Content => content; + + private readonly BeatmapDetailAreaTabControl tabControl; + + protected BeatmapDetailArea() { AddRangeInternal(new Drawable[] { @@ -40,51 +47,62 @@ namespace osu.Game.Screens.Select { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Top = BeatmapDetailAreaTabControl.HEIGHT }, - }, - new BeatmapDetailAreaTabControl - { - RelativeSizeAxes = Axes.X, - OnFilter = (tab, mods) => + Child = Details = new BeatmapDetails { - Leaderboard.FilterMods = mods; - - switch (tab) - { - case BeatmapDetailTab.Details: - Details.Show(); - Leaderboard.Hide(); - break; - - default: - Details.Hide(); - Leaderboard.Scope = (BeatmapLeaderboardScope)tab - 1; - Leaderboard.Show(); - break; - } - }, + RelativeSizeAxes = Axes.X, + Alpha = 0, + Margin = new MarginPadding { Top = details_padding }, + } }, - }); - - AddRange(new Drawable[] - { - Details = new BeatmapDetails + tabControl = new BeatmapDetailAreaTabControl { RelativeSizeAxes = Axes.X, - Alpha = 0, - Margin = new MarginPadding { Top = details_padding }, + TabItems = CreateTabItems(), + OnFilter = OnTabChanged, }, - Leaderboard = new BeatmapLeaderboard - { - RelativeSizeAxes = Axes.Both, - } }); } + /// + /// Refreshes the currently-displayed details. + /// + public virtual void Refresh() + { + } + protected override void UpdateAfterChildren() { base.UpdateAfterChildren(); Details.Height = Math.Min(DrawHeight - details_padding * 3 - BeatmapDetailAreaTabControl.HEIGHT, 450); } + + /// + /// Invoked when a new tab is selected. + /// + /// The tab that was selected. + /// Whether the currently-selected mods should be considered. + protected virtual void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) + { + switch (tab) + { + case BeatmapDetailAreaDetailTabItem _: + Details.Show(); + break; + + default: + Details.Hide(); + break; + } + } + + /// + /// Creates the tabs to be displayed. + /// + /// The tabs. + protected virtual BeatmapDetailAreaTabItem[] CreateTabItems() => new BeatmapDetailAreaTabItem[] + { + new BeatmapDetailAreaDetailTabItem(), + }; } } diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs new file mode 100644 index 0000000000..7376cb4708 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapDetailAreaDetailTabItem.cs @@ -0,0 +1,10 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +namespace osu.Game.Screens.Select +{ + public class BeatmapDetailAreaDetailTabItem : BeatmapDetailAreaTabItem + { + public override string Name => "Details"; + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs new file mode 100644 index 0000000000..066944e9d2 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapDetailAreaLeaderboardTabItem.cs @@ -0,0 +1,22 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Screens.Select +{ + public class BeatmapDetailAreaLeaderboardTabItem : BeatmapDetailAreaTabItem + where TScope : Enum + { + public override string Name => Scope.ToString(); + + public override bool FilterableByMods => true; + + public readonly TScope Scope; + + public BeatmapDetailAreaLeaderboardTabItem(TScope scope) + { + Scope = scope; + } + } +} diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs index 19ecdb6dbf..f4bf1ab059 100644 --- a/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabControl.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Collections.Generic; using osuTK.Graphics; using osu.Framework.Allocation; using osu.Framework.Bindables; @@ -18,14 +19,25 @@ namespace osu.Game.Screens.Select public class BeatmapDetailAreaTabControl : Container { public const float HEIGHT = 24; + + public Bindable Current + { + get => tabs.Current; + set => tabs.Current = value; + } + + public Action OnFilter; //passed the selected tab and if mods is checked + + public IReadOnlyList TabItems + { + get => tabs.Items; + set => tabs.Items = value; + } + private readonly OsuTabControlCheckbox modsCheckbox; - private readonly OsuTabControl tabs; + private readonly OsuTabControl tabs; private readonly Container tabsContainer; - public Action OnFilter; //passed the selected tab and if mods is checked - - private Bindable selectedTab; - public BeatmapDetailAreaTabControl() { Height = HEIGHT; @@ -43,7 +55,7 @@ namespace osu.Game.Screens.Select tabsContainer = new Container { RelativeSizeAxes = Axes.Both, - Child = tabs = new OsuTabControl + Child = tabs = new OsuTabControl { Anchor = Anchor.BottomLeft, Origin = Anchor.BottomLeft, @@ -68,29 +80,22 @@ namespace osu.Game.Screens.Select private void load(OsuColour colour, OsuConfigManager config) { modsCheckbox.AccentColour = tabs.AccentColour = colour.YellowLight; - - selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab); - - tabs.Current.BindTo(selectedTab); - tabs.Current.TriggerChange(); } private void invokeOnFilter() { OnFilter?.Invoke(tabs.Current.Value, modsCheckbox.Current.Value); - modsCheckbox.FadeTo(tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 1, 200, Easing.OutQuint); - - tabsContainer.Padding = new MarginPadding { Right = tabs.Current.Value == BeatmapDetailTab.Details ? 0 : 100 }; + if (tabs.Current.Value.FilterableByMods) + { + modsCheckbox.FadeTo(1, 200, Easing.OutQuint); + tabsContainer.Padding = new MarginPadding { Right = 100 }; + } + else + { + modsCheckbox.FadeTo(0, 200, Easing.OutQuint); + tabsContainer.Padding = new MarginPadding(); + } } } - - public enum BeatmapDetailTab - { - Details, - Local, - Country, - Global, - Friends - } } diff --git a/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs b/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs new file mode 100644 index 0000000000..f28e5a7c22 --- /dev/null +++ b/osu.Game/Screens/Select/BeatmapDetailAreaTabItem.cs @@ -0,0 +1,35 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; + +namespace osu.Game.Screens.Select +{ + public abstract class BeatmapDetailAreaTabItem : IEquatable + { + /// + /// The name of this tab, to be displayed in the tab control. + /// + public abstract string Name { get; } + + /// + /// Whether the contents of this tab can be filtered by the user's currently-selected mods. + /// + public virtual bool FilterableByMods => false; + + public override string ToString() => Name; + + public bool Equals(BeatmapDetailAreaTabItem other) + { + if (ReferenceEquals(null, other)) return false; + if (ReferenceEquals(this, other)) return true; + + return Name == other.Name; + } + + public override int GetHashCode() + { + return Name != null ? Name.GetHashCode() : 0; + } + } +} diff --git a/osu.Game/Screens/Select/MatchSongSelect.cs b/osu.Game/Screens/Select/MatchSongSelect.cs index 6ba4157797..fd7a8a539c 100644 --- a/osu.Game/Screens/Select/MatchSongSelect.cs +++ b/osu.Game/Screens/Select/MatchSongSelect.cs @@ -34,6 +34,8 @@ namespace osu.Game.Screens.Select Padding = new MarginPadding { Horizontal = HORIZONTAL_OVERFLOW_PADDING }; } + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); // Todo: Temporary + protected override bool OnStart() { var item = new PlaylistItem diff --git a/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs new file mode 100644 index 0000000000..d719502a4f --- /dev/null +++ b/osu.Game/Screens/Select/PlayBeatmapDetailArea.cs @@ -0,0 +1,143 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Linq; +using osu.Framework.Allocation; +using osu.Framework.Bindables; +using osu.Framework.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Configuration; +using osu.Game.Screens.Select.Leaderboards; + +namespace osu.Game.Screens.Select +{ + public class PlayBeatmapDetailArea : BeatmapDetailArea + { + public readonly BeatmapLeaderboard Leaderboard; + + public override WorkingBeatmap Beatmap + { + get => base.Beatmap; + set + { + base.Beatmap = value; + + Leaderboard.Beatmap = value is DummyWorkingBeatmap ? null : value?.BeatmapInfo; + } + } + + private Bindable selectedTab; + + public PlayBeatmapDetailArea() + { + Add(Leaderboard = new BeatmapLeaderboard { RelativeSizeAxes = Axes.Both }); + } + + [BackgroundDependencyLoader] + private void load(OsuConfigManager config) + { + selectedTab = config.GetBindable(OsuSetting.BeatmapDetailTab); + selectedTab.BindValueChanged(tab => CurrentTab.Value = getTabItemFromTabType(tab.NewValue), true); + CurrentTab.BindValueChanged(tab => selectedTab.Value = getTabTypeFromTabItem(tab.NewValue)); + } + + public override void Refresh() + { + base.Refresh(); + + Leaderboard.RefreshScores(); + } + + protected override void OnTabChanged(BeatmapDetailAreaTabItem tab, bool selectedMods) + { + base.OnTabChanged(tab, selectedMods); + + Leaderboard.FilterMods = selectedMods; + + switch (tab) + { + case BeatmapDetailAreaLeaderboardTabItem leaderboard: + Leaderboard.Scope = leaderboard.Scope; + Leaderboard.Show(); + break; + + default: + Leaderboard.Hide(); + break; + } + } + + protected override BeatmapDetailAreaTabItem[] CreateTabItems() => base.CreateTabItems().Concat(new BeatmapDetailAreaTabItem[] + { + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global), + new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend), + }).ToArray(); + + private BeatmapDetailAreaTabItem getTabItemFromTabType(TabType type) + { + switch (type) + { + case TabType.Details: + return new BeatmapDetailAreaDetailTabItem(); + + case TabType.Local: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Local); + + case TabType.Country: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Country); + + case TabType.Global: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Global); + + case TabType.Friends: + return new BeatmapDetailAreaLeaderboardTabItem(BeatmapLeaderboardScope.Friend); + + default: + throw new ArgumentOutOfRangeException(nameof(type)); + } + } + + private TabType getTabTypeFromTabItem(BeatmapDetailAreaTabItem item) + { + switch (item) + { + case BeatmapDetailAreaDetailTabItem _: + return TabType.Details; + + case BeatmapDetailAreaLeaderboardTabItem leaderboardTab: + switch (leaderboardTab.Scope) + { + case BeatmapLeaderboardScope.Local: + return TabType.Local; + + case BeatmapLeaderboardScope.Country: + return TabType.Country; + + case BeatmapLeaderboardScope.Global: + return TabType.Global; + + case BeatmapLeaderboardScope.Friend: + return TabType.Friends; + + default: + throw new ArgumentOutOfRangeException(nameof(item)); + } + + default: + throw new ArgumentOutOfRangeException(nameof(item)); + } + } + + public enum TabType + { + Details, + Local, + Country, + Global, + Friends + } + } +} diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index f1dd125362..e744fd6a7b 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -29,8 +29,12 @@ namespace osu.Game.Screens.Select ValidForResume = false; Edit(); }, Key.Number4); + + ((PlayBeatmapDetailArea)BeatmapDetails).Leaderboard.ScoreSelected += score => this.Push(new SoloResults(score)); } + protected override BeatmapDetailArea CreateBeatmapDetailArea() => new PlayBeatmapDetailArea(); + public override void OnResuming(IScreen last) { base.OnResuming(last); diff --git a/osu.Game/Screens/Select/SongSelect.cs b/osu.Game/Screens/Select/SongSelect.cs index 0da260d752..67626d1e4f 100644 --- a/osu.Game/Screens/Select/SongSelect.cs +++ b/osu.Game/Screens/Select/SongSelect.cs @@ -23,7 +23,6 @@ using osu.Game.Rulesets.Mods; using osu.Game.Screens.Backgrounds; using osu.Game.Screens.Edit; using osu.Game.Screens.Menu; -using osu.Game.Screens.Play; using osu.Game.Screens.Select.Options; using osu.Game.Skinning; using osuTK; @@ -207,11 +206,11 @@ namespace osu.Game.Screens.Select Left = left_area_padding, Right = left_area_padding * 2, }, - Child = BeatmapDetails = new BeatmapDetailArea + Child = BeatmapDetails = CreateBeatmapDetailArea().With(d => { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Top = 10, Right = 5 }, - }, + d.RelativeSizeAxes = Axes.Both; + d.Padding = new MarginPadding { Top = 10, Right = 5 }; + }) }, } }, @@ -262,8 +261,6 @@ namespace osu.Game.Screens.Select }); } - BeatmapDetails.Leaderboard.ScoreSelected += score => this.Push(new SoloResults(score)); - if (Footer != null) { Footer.AddButton(new FooterButtonMods { Current = Mods }, ModSelect); @@ -319,6 +316,11 @@ namespace osu.Game.Screens.Select return dependencies; } + /// + /// Creates the beatmap details to be displayed underneath the wedge. + /// + protected abstract BeatmapDetailArea CreateBeatmapDetailArea(); + public void Edit(BeatmapInfo beatmap = null) { if (!AllowEditing) @@ -533,7 +535,7 @@ namespace osu.Game.Screens.Select Carousel.AllowSelection = true; - BeatmapDetails.Leaderboard.RefreshScores(); + BeatmapDetails.Refresh(); Beatmap.Value.Track.Looping = true; music?.ResetTrackAdjustments(); @@ -716,7 +718,7 @@ namespace osu.Game.Screens.Select dialogOverlay?.Push(new BeatmapClearScoresDialog(beatmap, () => // schedule done here rather than inside the dialog as the dialog may fade out and never callback. - Schedule(() => BeatmapDetails.Leaderboard.RefreshScores()))); + Schedule(() => BeatmapDetails.Refresh()))); } public virtual bool OnPressed(GlobalAction action) From dac0148c94076026b579a8bc31fbba93bdd134c3 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 13 Feb 2020 20:08:14 +0100 Subject: [PATCH 19/39] Apply review suggestions. --- .../Online/TestSceneOnlineViewContainer.cs | 2 +- osu.Game/Online/OnlineViewContainer.cs | 16 ++++++---------- 2 files changed, 7 insertions(+), 11 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 2b9609f6e0..9dac28d347 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Tests.Visual.Online { public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; - public CompositeDrawable ViewTarget => base.Content.Parent; + public CompositeDrawable ViewTarget => base.Content; public TestOnlineViewContainer() : base(@"Please sign in to view dummy test content") diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index c512ca531a..4b59f6ae80 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -21,8 +21,8 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - private readonly Container viewTarget; - protected override Container Content { get; } + private Container viewContent; + protected override Container Content => viewContent; [Resolved] protected IAPIProvider API { get; private set; } @@ -31,13 +31,9 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - viewTarget = new Container + viewContent = new Container { RelativeSizeAxes = Axes.Both, - Child = Content = new Container - { - RelativeSizeAxes = Axes.Both, - } }, placeholder = new LoginPlaceholder(placeholderMessage), LoadingAnimation = new LoadingAnimation @@ -52,21 +48,21 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - PopContentOut(viewTarget); + PopContentOut(viewContent); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - PopContentIn(viewTarget); + PopContentIn(viewContent); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: - PopContentOut(viewTarget); + PopContentOut(viewContent); LoadingAnimation.Show(); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; From 049b0d93d13530c090612a20a27124ee79fcaf38 Mon Sep 17 00:00:00 2001 From: Lucas A Date: Thu, 13 Feb 2020 21:40:08 +0100 Subject: [PATCH 20/39] Add back default content fade transitions --- .../Visual/Online/TestSceneOnlineViewContainer.cs | 4 ---- osu.Game/Online/OnlineViewContainer.cs | 6 +++--- 2 files changed, 3 insertions(+), 7 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 9dac28d347..39b9fd71d0 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -54,10 +54,6 @@ namespace osu.Game.Tests.Visual.Online } }; } - - protected override void PopContentOut(Drawable content) => content.Hide(); - - protected override void PopContentIn(Drawable content) => content.Show(); } [Test] diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 4b59f6ae80..2a9aa60e2d 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -21,7 +21,7 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - private Container viewContent; + private readonly Container viewContent; protected override Container Content => viewContent; [Resolved] @@ -69,9 +69,9 @@ namespace osu.Game.Online } } - protected abstract void PopContentOut(Drawable content); + protected virtual void PopContentOut(Drawable content) => content.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); - protected abstract void PopContentIn(Drawable content); + protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); protected override void LoadComplete() { From 50899ddccba2e8dfc89d0282ee5a547728c53f3e Mon Sep 17 00:00:00 2001 From: Berkan Diler Date: Fri, 14 Feb 2020 03:19:25 +0100 Subject: [PATCH 21/39] Use Span for OsuColour.FromHex --- osu.Game/Graphics/OsuColour.cs | 34 +++++++++++++++++----------------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/osu.Game/Graphics/OsuColour.cs b/osu.Game/Graphics/OsuColour.cs index c8298543a1..59dd823266 100644 --- a/osu.Game/Graphics/OsuColour.cs +++ b/osu.Game/Graphics/OsuColour.cs @@ -2,6 +2,7 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Globalization; using osu.Game.Beatmaps; using osuTK.Graphics; @@ -14,41 +15,40 @@ namespace osu.Game.Graphics public static Color4 FromHex(string hex) { - if (hex[0] == '#') - hex = hex.Substring(1); + var hexSpan = hex[0] == '#' ? hex.AsSpan().Slice(1) : hex.AsSpan(); - switch (hex.Length) + switch (hexSpan.Length) { default: throw new ArgumentException(@"Invalid hex string length!"); case 3: return new Color4( - (byte)(Convert.ToByte(hex.Substring(0, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(1, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(2, 1), 16) * 17), + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(2, 1), NumberStyles.HexNumber) * 17), 255); case 6: return new Color4( - Convert.ToByte(hex.Substring(0, 2), 16), - Convert.ToByte(hex.Substring(2, 2), 16), - Convert.ToByte(hex.Substring(4, 2), 16), + byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber), 255); case 4: return new Color4( - (byte)(Convert.ToByte(hex.Substring(0, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(1, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(2, 1), 16) * 17), - (byte)(Convert.ToByte(hex.Substring(3, 1), 16) * 17)); + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(1, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17), + (byte)(byte.Parse(hexSpan.Slice(0, 1), NumberStyles.HexNumber) * 17)); case 8: return new Color4( - Convert.ToByte(hex.Substring(0, 2), 16), - Convert.ToByte(hex.Substring(2, 2), 16), - Convert.ToByte(hex.Substring(4, 2), 16), - Convert.ToByte(hex.Substring(6, 2), 16)); + byte.Parse(hexSpan.Slice(0, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(2, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(4, 2), NumberStyles.HexNumber), + byte.Parse(hexSpan.Slice(6, 2), NumberStyles.HexNumber)); } } From 884a5fbad44f1eb58731de2176d7cf67428dd521 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 12:30:11 +0900 Subject: [PATCH 22/39] Fix osu! gameplay cursor not adjusting to mod/convert circle size changes --- .../TestSceneGameplayCursor.cs | 46 +++++++++++++++++-- .../UI/Cursor/OsuCursorContainer.cs | 44 +++++++++++++----- osu.Game/Screens/Play/GameplayBeatmap.cs | 42 +++++++++++++++++ osu.Game/Screens/Play/Player.cs | 11 +++++ 4 files changed, 128 insertions(+), 15 deletions(-) create mode 100644 osu.Game/Screens/Play/GameplayBeatmap.cs diff --git a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs index aa170eae1e..90f1cdb2ea 100644 --- a/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs +++ b/osu.Game.Rulesets.Osu.Tests/TestSceneGameplayCursor.cs @@ -7,7 +7,9 @@ using NUnit.Framework; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Testing.Input; +using osu.Game.Configuration; using osu.Game.Rulesets.Osu.UI.Cursor; +using osu.Game.Screens.Play; using osuTK; namespace osu.Game.Rulesets.Osu.Tests @@ -21,12 +23,50 @@ namespace osu.Game.Rulesets.Osu.Tests typeof(CursorTrail) }; - [BackgroundDependencyLoader] - private void load() + [Cached] + private GameplayBeatmap gameplayBeatmap; + + private ClickingCursorContainer lastContainer; + + [Resolved] + private OsuConfigManager config { get; set; } + + public TestSceneGameplayCursor() + { + gameplayBeatmap = new GameplayBeatmap(CreateBeatmap(new OsuRuleset().RulesetInfo)); + } + + [TestCase(1, 1)] + [TestCase(5, 1)] + [TestCase(10, 1)] + [TestCase(1, 1.5f)] + [TestCase(5, 1.5f)] + [TestCase(10, 1.5f)] + public void TestSizing(int circleSize, float userScale) + { + AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale)); + AddStep($"adjust cs to {circleSize}", () => gameplayBeatmap.BeatmapInfo.BaseDifficulty.CircleSize = circleSize); + AddStep("turn on autosizing", () => config.Set(OsuSetting.AutoCursorSize, true)); + + AddStep("load content", loadContent); + + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize) * userScale); + + AddStep("set user scale to 1", () => config.Set(OsuSetting.GameplayCursorSize, 1f)); + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == OsuCursorContainer.GetScaleForCircleSize(circleSize)); + + AddStep("turn off autosizing", () => config.Set(OsuSetting.AutoCursorSize, false)); + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == 1); + + AddStep($"set user scale to {userScale}", () => config.Set(OsuSetting.GameplayCursorSize, userScale)); + AddUntilStep("cursor size correct", () => lastContainer.ActiveCursor.Scale.X == userScale); + } + + private void loadContent() { SetContents(() => new MovingCursorInputManager { - Child = new ClickingCursorContainer + Child = lastContainer = new ClickingCursorContainer { RelativeSizeAxes = Axes.Both, Masking = true, diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 79b5d1b7f8..7ebc26ebfb 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -12,6 +12,7 @@ using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Rulesets.Osu.Configuration; using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play; using osu.Game.Skinning; using osuTK; @@ -32,7 +33,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor public Bindable CursorScale; private Bindable userCursorScale; private Bindable autoCursorScale; - private readonly IBindable beatmap = new Bindable(); public OsuCursorContainer() { @@ -43,13 +43,21 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; } + [Resolved(canBeNull: true)] + private GameplayBeatmap beatmap { get; set; } + + [Resolved] + private OsuConfigManager config { get; set; } + [BackgroundDependencyLoader(true)] - private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig, IBindable beatmap) + private void load(OsuConfigManager config, OsuRulesetConfigManager rulesetConfig) { rulesetConfig?.BindWith(OsuRulesetSetting.ShowCursorTrail, showTrail); + } - this.beatmap.BindTo(beatmap); - this.beatmap.ValueChanged += _ => calculateScale(); + protected override void LoadComplete() + { + showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); userCursorScale.ValueChanged += _ => calculateScale(); @@ -58,29 +66,41 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor autoCursorScale.ValueChanged += _ => calculateScale(); CursorScale = new BindableFloat(); - CursorScale.ValueChanged += e => ActiveCursor.Scale = cursorTrail.Scale = new Vector2(e.NewValue); + CursorScale.ValueChanged += e => + { + var newScale = new Vector2(e.NewValue); + + ActiveCursor.Scale = newScale; + cursorTrail.Scale = newScale; + }; calculateScale(); + + base.LoadComplete(); } + /// + /// Get the scale applicable to the ActiveCursor based on a beatmap's circle size. + /// + public static float GetScaleForCircleSize(float circleSize) => + 1f - 0.7f * (1f + circleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; + private void calculateScale() { float scale = userCursorScale.Value; - if (autoCursorScale.Value && beatmap.Value != null) + if (autoCursorScale.Value && beatmap != null) { // if we have a beatmap available, let's get its circle size to figure out an automatic cursor scale modifier. - scale *= 1f - 0.7f * (1f + beatmap.Value.BeatmapInfo.BaseDifficulty.CircleSize - BeatmapDifficulty.DEFAULT_DIFFICULTY) / BeatmapDifficulty.DEFAULT_DIFFICULTY; + scale *= GetScaleForCircleSize(beatmap.BeatmapInfo.BaseDifficulty.CircleSize); } CursorScale.Value = scale; - } - protected override void LoadComplete() - { - base.LoadComplete(); + var newScale = new Vector2(scale); - showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); + ActiveCursor.ScaleTo(newScale, 400, Easing.OutQuint); + cursorTrail.Scale = newScale; } private int downCount; diff --git a/osu.Game/Screens/Play/GameplayBeatmap.cs b/osu.Game/Screens/Play/GameplayBeatmap.cs new file mode 100644 index 0000000000..d7f939a883 --- /dev/null +++ b/osu.Game/Screens/Play/GameplayBeatmap.cs @@ -0,0 +1,42 @@ +// 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.Graphics; +using osu.Game.Beatmaps; +using osu.Game.Beatmaps.ControlPoints; +using osu.Game.Beatmaps.Timing; +using osu.Game.Rulesets.Objects; + +namespace osu.Game.Screens.Play +{ + public class GameplayBeatmap : Component, IBeatmap + { + public readonly IBeatmap PlayableBeatmap; + + public GameplayBeatmap(IBeatmap playableBeatmap) + { + PlayableBeatmap = playableBeatmap; + } + + public BeatmapInfo BeatmapInfo + { + get => PlayableBeatmap.BeatmapInfo; + set => PlayableBeatmap.BeatmapInfo = value; + } + + public BeatmapMetadata Metadata => PlayableBeatmap.Metadata; + + public ControlPointInfo ControlPointInfo => PlayableBeatmap.ControlPointInfo; + + public List Breaks => PlayableBeatmap.Breaks; + + public double TotalBreakTime => PlayableBeatmap.TotalBreakTime; + + public IReadOnlyList HitObjects => PlayableBeatmap.HitObjects; + + public IEnumerable GetStatistics() => PlayableBeatmap.GetStatistics(); + + public IBeatmap Clone() => PlayableBeatmap.Clone(); + } +} diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index aecd35f7dc..9bfdcd79fe 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -110,6 +110,13 @@ namespace osu.Game.Screens.Play this.showResults = showResults; } + private GameplayBeatmap gameplayBeatmap; + + private DependencyContainer dependencies; + + protected override IReadOnlyDependencyContainer CreateChildDependencies(IReadOnlyDependencyContainer parent) + => dependencies = new DependencyContainer(base.CreateChildDependencies(parent)); + [BackgroundDependencyLoader] private void load(AudioManager audio, IAPIProvider api, OsuConfigManager config) { @@ -143,6 +150,10 @@ namespace osu.Game.Screens.Play InternalChild = GameplayClockContainer = new GameplayClockContainer(Beatmap.Value, Mods.Value, DrawableRuleset.GameplayStartTime); + AddInternal(gameplayBeatmap = new GameplayBeatmap(playableBeatmap)); + + dependencies.CacheAs(gameplayBeatmap); + addUnderlayComponents(GameplayClockContainer); addGameplayComponents(GameplayClockContainer, Beatmap.Value); addOverlayComponents(GameplayClockContainer, Beatmap.Value); From 0e439e3a7025a2cfded813fda28f90c8d9a79a88 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 14:41:55 +0900 Subject: [PATCH 23/39] Fix missing dependency in ZoomableScrollContainer test --- .../Compose/Components/Timeline/ZoomableScrollContainer.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs index baaad63e57..227eecf9c7 100644 --- a/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs +++ b/osu.Game/Screens/Edit/Compose/Components/Timeline/ZoomableScrollContainer.cs @@ -32,7 +32,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline private float currentZoom = 1; - [Resolved] + [Resolved(canBeNull: true)] private IFrameBasedClock editorClock { get; set; } public ZoomableScrollContainer() @@ -112,7 +112,7 @@ namespace osu.Game.Screens.Edit.Compose.Components.Timeline { // can't handle scroll correctly while playing. // the editor will handle this case for us. - if (editorClock.IsRunning) + if (editorClock?.IsRunning == true) return false; // for now, we don't support zoom when using a precision scroll device. this needs gesture support. From aa7efe6141e0ca80c3a908e3902b1dba5c95d4e9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:26:55 +0900 Subject: [PATCH 24/39] Fix tests potentially failing due to timing issues --- .../Online/TestSceneOnlineViewContainer.cs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 39b9fd71d0..d656600a18 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -61,8 +61,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to online", () => ((DummyAPIAccess)API).State = APIState.Online); - AddAssert("children are visible", () => onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are visible", () => onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } [Test] @@ -70,8 +70,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to offline", () => ((DummyAPIAccess)API).State = APIState.Offline); - AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is not visible", () => !onlineView.LoadingAnimation.IsPresent); } [Test] @@ -79,8 +79,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to connecting", () => ((DummyAPIAccess)API).State = APIState.Connecting); - AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } [Test] @@ -88,8 +88,8 @@ namespace osu.Game.Tests.Visual.Online { AddStep("set status to failing", () => ((DummyAPIAccess)API).State = APIState.Failing); - AddAssert("children are hidden", () => !onlineView.ViewTarget.IsPresent); - AddAssert("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); + AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); + AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } } } From c34f1f40eafd8e06f6a7009fc4661105e40664cc Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:27:09 +0900 Subject: [PATCH 25/39] Fix test text not being centered --- osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index d656600a18..2bd0d59632 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -6,6 +6,7 @@ using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Shapes; +using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; using osu.Game.Online; @@ -38,6 +39,7 @@ namespace osu.Game.Tests.Visual.Online : base(@"Please sign in to view dummy test content") { RelativeSizeAxes = Axes.Both; + Children = new Drawable[] { new Box @@ -48,7 +50,7 @@ namespace osu.Game.Tests.Visual.Online new OsuSpriteText { Text = "dummy online content", - RelativeSizeAxes = Axes.Both, + Font = OsuFont.Default.With(size: 40), Anchor = Anchor.Centre, Origin = Anchor.Centre, } From b86b5e9adb3369f675346d0ef2b22429d87c7a61 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:27:39 +0900 Subject: [PATCH 26/39] Move nested class to bottom of file --- .../Online/TestSceneOnlineViewContainer.cs | 58 +++++++++---------- 1 file changed, 29 insertions(+), 29 deletions(-) diff --git a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs index 2bd0d59632..3c2735ca56 100644 --- a/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs +++ b/osu.Game.Tests/Visual/Online/TestSceneOnlineViewContainer.cs @@ -29,35 +29,6 @@ namespace osu.Game.Tests.Visual.Online }; } - private class TestOnlineViewContainer : OnlineViewContainer - { - public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; - - public CompositeDrawable ViewTarget => base.Content; - - public TestOnlineViewContainer() - : base(@"Please sign in to view dummy test content") - { - RelativeSizeAxes = Axes.Both; - - Children = new Drawable[] - { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = Color4.Blue.Opacity(0.8f), - }, - new OsuSpriteText - { - Text = "dummy online content", - Font = OsuFont.Default.With(size: 40), - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - } - }; - } - } - [Test] public void TestOnlineStateVisibility() { @@ -93,5 +64,34 @@ namespace osu.Game.Tests.Visual.Online AddUntilStep("children are not visible", () => !onlineView.ViewTarget.IsPresent); AddUntilStep("loading animation is visible", () => onlineView.LoadingAnimation.IsPresent); } + + private class TestOnlineViewContainer : OnlineViewContainer + { + public new LoadingAnimation LoadingAnimation => base.LoadingAnimation; + + public CompositeDrawable ViewTarget => base.Content; + + public TestOnlineViewContainer() + : base(@"Please sign in to view dummy test content") + { + RelativeSizeAxes = Axes.Both; + + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Blue.Opacity(0.8f), + }, + new OsuSpriteText + { + Text = "dummy online content", + Font = OsuFont.Default.With(size: 40), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + } + }; + } + } } } From 4d5abab2ee0b39704f0e5b91bf41e01e7b50f83b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:29:50 +0900 Subject: [PATCH 27/39] Remove unnecessary content private storage --- osu.Game/Online/OnlineViewContainer.cs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 2a9aa60e2d..0ffb342bfc 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -21,8 +21,7 @@ namespace osu.Game.Online protected const double TRANSFORM_TIME = 300.0; - private readonly Container viewContent; - protected override Container Content => viewContent; + protected override Container Content { get; } [Resolved] protected IAPIProvider API { get; private set; } @@ -31,7 +30,7 @@ namespace osu.Game.Online { InternalChildren = new Drawable[] { - viewContent = new Container + Content = new Container { RelativeSizeAxes = Axes.Both, }, @@ -48,21 +47,21 @@ namespace osu.Game.Online switch (state) { case APIState.Offline: - PopContentOut(viewContent); + PopContentOut(Content); placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: - PopContentIn(viewContent); + PopContentIn(Content); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Failing: case APIState.Connecting: - PopContentOut(viewContent); + PopContentOut(Content); LoadingAnimation.Show(); placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); break; From 7e6c194d4a9c9f04712db293bc39f5f6baf201f5 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:34:46 +0900 Subject: [PATCH 28/39] Add missing xmldoc --- osu.Game/Online/OnlineViewContainer.cs | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 0ffb342bfc..50b4820d15 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -68,8 +68,14 @@ namespace osu.Game.Online } } + /// + /// Applies a transform to the online content to make it hidden. + /// protected virtual void PopContentOut(Drawable content) => content.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + /// + /// Applies a transform to the online content to make it visible. + /// protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); protected override void LoadComplete() From 6f1cecd86f7fc4efa6e00c0da8e44972f332f880 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:35:39 +0900 Subject: [PATCH 29/39] Move LoadComplete up in method --- osu.Game/Online/OnlineViewContainer.cs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 50b4820d15..3b2243c97a 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -42,6 +42,12 @@ namespace osu.Game.Online }; } + protected override void LoadComplete() + { + API?.Register(this); + base.LoadComplete(); + } + public virtual void APIStateChanged(IAPIProvider api, APIState state) { switch (state) @@ -78,12 +84,6 @@ namespace osu.Game.Online /// protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); - protected override void LoadComplete() - { - API?.Register(this); - base.LoadComplete(); - } - protected override void Dispose(bool isDisposing) { API?.Unregister(this); From edf9cfc8635580d7e40c188828a2533ec5b824ab Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:36:06 +0900 Subject: [PATCH 30/39] API can't be null on load --- osu.Game/Online/OnlineViewContainer.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 3b2243c97a..b16fbb7aed 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -44,7 +44,7 @@ namespace osu.Game.Online protected override void LoadComplete() { - API?.Register(this); + API.Register(this); base.LoadComplete(); } From 720ceca78a3cdd5c90acf75684c8a0d65af2f67b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:38:47 +0900 Subject: [PATCH 31/39] Final tidy-up pass --- osu.Game/Online/OnlineViewContainer.cs | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index b16fbb7aed..83fbff733f 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -19,7 +19,7 @@ namespace osu.Game.Online private readonly Placeholder placeholder; protected readonly LoadingAnimation LoadingAnimation; - protected const double TRANSFORM_TIME = 300.0; + private const double transform_duration = 300; protected override Container Content { get; } @@ -44,8 +44,9 @@ namespace osu.Game.Online protected override void LoadComplete() { - API.Register(this); base.LoadComplete(); + + API.Register(this); } public virtual void APIStateChanged(IAPIProvider api, APIState state) @@ -54,14 +55,14 @@ namespace osu.Game.Online { case APIState.Offline: PopContentOut(Content); - placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * TRANSFORM_TIME, Easing.OutQuint); - placeholder.FadeInFromZero(2 * TRANSFORM_TIME, Easing.OutQuint); + placeholder.ScaleTo(0.8f).Then().ScaleTo(1, 3 * transform_duration, Easing.OutQuint); + placeholder.FadeInFromZero(2 * transform_duration, Easing.OutQuint); LoadingAnimation.Hide(); break; case APIState.Online: PopContentIn(Content); - placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + placeholder.FadeOut(transform_duration / 2, Easing.OutQuint); LoadingAnimation.Hide(); break; @@ -69,7 +70,7 @@ namespace osu.Game.Online case APIState.Connecting: PopContentOut(Content); LoadingAnimation.Show(); - placeholder.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + placeholder.FadeOut(transform_duration / 2, Easing.OutQuint); break; } } @@ -77,12 +78,12 @@ namespace osu.Game.Online /// /// Applies a transform to the online content to make it hidden. /// - protected virtual void PopContentOut(Drawable content) => content.FadeOut(TRANSFORM_TIME / 2, Easing.OutQuint); + protected virtual void PopContentOut(Drawable content) => content.FadeOut(transform_duration / 2, Easing.OutQuint); /// /// Applies a transform to the online content to make it visible. /// - protected virtual void PopContentIn(Drawable content) => content.FadeIn(TRANSFORM_TIME, Easing.OutQuint); + protected virtual void PopContentIn(Drawable content) => content.FadeIn(transform_duration, Easing.OutQuint); protected override void Dispose(bool isDisposing) { From a75715607b3882c14ccab7984cc9ee4a97534522 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:41:46 +0900 Subject: [PATCH 32/39] Move drawable load to asynchronous context --- osu.Game/Online/OnlineViewContainer.cs | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/osu.Game/Online/OnlineViewContainer.cs b/osu.Game/Online/OnlineViewContainer.cs index 83fbff733f..689c1c0afb 100644 --- a/osu.Game/Online/OnlineViewContainer.cs +++ b/osu.Game/Online/OnlineViewContainer.cs @@ -16,24 +16,30 @@ namespace osu.Game.Online /// public abstract class OnlineViewContainer : Container, IOnlineComponent { - private readonly Placeholder placeholder; - protected readonly LoadingAnimation LoadingAnimation; + protected LoadingAnimation LoadingAnimation { get; private set; } + + protected override Container Content { get; } = new Container { RelativeSizeAxes = Axes.Both }; + + private readonly string placeholderMessage; + + private Placeholder placeholder; private const double transform_duration = 300; - protected override Container Content { get; } - [Resolved] protected IAPIProvider API { get; private set; } protected OnlineViewContainer(string placeholderMessage) + { + this.placeholderMessage = placeholderMessage; + } + + [BackgroundDependencyLoader] + private void load() { InternalChildren = new Drawable[] { - Content = new Container - { - RelativeSizeAxes = Axes.Both, - }, + Content, placeholder = new LoginPlaceholder(placeholderMessage), LoadingAnimation = new LoadingAnimation { From 9cbb37b682fe35508c1aa030b4a97dad3ece41f4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 15:59:59 +0900 Subject: [PATCH 33/39] Fix bindable being created far too late in construction --- osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs index 7ebc26ebfb..28600ef55b 100644 --- a/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs +++ b/osu.Game.Rulesets.Osu/UI/Cursor/OsuCursorContainer.cs @@ -30,7 +30,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor private readonly Drawable cursorTrail; - public Bindable CursorScale; + public Bindable CursorScale = new BindableFloat(1); + private Bindable userCursorScale; private Bindable autoCursorScale; @@ -57,6 +58,8 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor protected override void LoadComplete() { + base.LoadComplete(); + showTrail.BindValueChanged(v => cursorTrail.FadeTo(v.NewValue ? 1 : 0, 200), true); userCursorScale = config.GetBindable(OsuSetting.GameplayCursorSize); @@ -65,7 +68,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor autoCursorScale = config.GetBindable(OsuSetting.AutoCursorSize); autoCursorScale.ValueChanged += _ => calculateScale(); - CursorScale = new BindableFloat(); CursorScale.ValueChanged += e => { var newScale = new Vector2(e.NewValue); @@ -75,8 +77,6 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor }; calculateScale(); - - base.LoadComplete(); } /// From 9ea6912520954aa28e6a5b1eb23d16da90716f95 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 16:58:56 +0900 Subject: [PATCH 34/39] Improve overall readability of OsuModeRelax --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 45 +++++++++++++++-------- 1 file changed, 29 insertions(+), 16 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 649b01c132..7ebb6fd76d 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -19,33 +19,46 @@ namespace osu.Game.Rulesets.Osu.Mods public override string Description => @"You don't need to click. Give your clicking/tapping fingers a break from the heat of things."; public override Type[] IncompatibleMods => base.IncompatibleMods.Append(typeof(OsuModAutopilot)).ToArray(); + /// + /// How early before a hitobject's start time to trigger a hit. + /// + private const float relax_leniency = 3; + public void Update(Playfield playfield) { bool requiresHold = false; bool requiresHit = false; - const float relax_leniency = 3; + double time = playfield.Clock.CurrentTime; - foreach (var drawable in playfield.HitObjectContainer.AliveObjects) + foreach (var h in playfield.HitObjectContainer.AliveObjects.OfType()) { - if (!(drawable is DrawableOsuHitObject osuHit)) + // we are not yet close enough to the object. + if (time < h.HitObject.StartTime - relax_leniency) + break; + + // already hit or beyond the hittable end time. + if (h.IsHit || (h.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime)) continue; - double time = osuHit.Clock.CurrentTime; - double relativetime = time - osuHit.HitObject.StartTime; - - if (time < osuHit.HitObject.StartTime - relax_leniency) continue; - - if ((osuHit.HitObject is IHasEndTime hasEnd && time > hasEnd.EndTime) || osuHit.IsHit) - continue; - - if (osuHit is DrawableHitCircle && osuHit.IsHovered) + switch (h) { - Debug.Assert(osuHit.HitObject.HitWindows != null); - requiresHit |= osuHit.HitObject.HitWindows.CanBeHit(relativetime); - } + case DrawableHitCircle _: + if (!h.IsHovered) + break; - requiresHold |= (osuHit is DrawableSlider slider && (slider.Ball.IsHovered || osuHit.IsHovered)) || osuHit is DrawableSpinner; + Debug.Assert(h.HitObject.HitWindows != null); + requiresHit |= h.HitObject.HitWindows.CanBeHit(time - h.HitObject.StartTime); + break; + + case DrawableSlider slider: + requiresHold |= slider.Ball.IsHovered || h.IsHovered; + break; + + case DrawableSpinner _: + requiresHold = true; + break; + } } if (requiresHit) From cd2d1b06697d5b49fda11240425b8982d2af66b1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 17:00:55 +0900 Subject: [PATCH 35/39] Fix 2B maps not playing correctly with relax mod enabled --- osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs | 21 +++++++++++++++------ 1 file changed, 15 insertions(+), 6 deletions(-) diff --git a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs index 7ebb6fd76d..d971e777ec 100644 --- a/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs +++ b/osu.Game.Rulesets.Osu/Mods/OsuModRelax.cs @@ -43,15 +43,15 @@ namespace osu.Game.Rulesets.Osu.Mods switch (h) { - case DrawableHitCircle _: - if (!h.IsHovered) - break; - - Debug.Assert(h.HitObject.HitWindows != null); - requiresHit |= h.HitObject.HitWindows.CanBeHit(time - h.HitObject.StartTime); + case DrawableHitCircle circle: + handleHitCircle(circle); break; case DrawableSlider slider: + // Handles cases like "2B" beatmaps, where sliders may be overlapping and simply holding is not enough. + if (!slider.HeadCircle.IsHit) + handleHitCircle(slider.HeadCircle); + requiresHold |= slider.Ball.IsHovered || h.IsHovered; break; @@ -68,6 +68,15 @@ namespace osu.Game.Rulesets.Osu.Mods } addAction(requiresHold); + + void handleHitCircle(DrawableHitCircle circle) + { + if (!circle.IsHovered) + return; + + Debug.Assert(circle.HitObject.HitWindows != null); + requiresHit |= circle.HitObject.HitWindows.CanBeHit(time - circle.HitObject.StartTime); + } } private bool wasHit; From 66910f1ee3489ed83890b772599e6ce02475a30e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 17:50:53 +0900 Subject: [PATCH 36/39] Remove unnecessary bindable setter --- osu.Game/Screens/Select/BeatmapDetailArea.cs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/osu.Game/Screens/Select/BeatmapDetailArea.cs b/osu.Game/Screens/Select/BeatmapDetailArea.cs index 1aae0cc243..2e78b1aed2 100644 --- a/osu.Game/Screens/Select/BeatmapDetailArea.cs +++ b/osu.Game/Screens/Select/BeatmapDetailArea.cs @@ -28,11 +28,7 @@ namespace osu.Game.Screens.Select public readonly BeatmapDetails Details; - protected Bindable CurrentTab - { - get => tabControl.Current; - set => tabControl.Current = value; - } + protected Bindable CurrentTab => tabControl.Current; private readonly Container content; protected override Container Content => content; From be30ef3cca69c1b00beebdf1a579edc5f47f84f9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 18:13:52 +0900 Subject: [PATCH 37/39] Move BeatmapMetadataDisplay to its own class --- .../Screens/Play/BeatmapMetadataDisplay.cs | 180 ++++++++++++++++++ osu.Game/Screens/Play/PlayerLoader.cs | 163 ---------------- 2 files changed, 180 insertions(+), 163 deletions(-) create mode 100644 osu.Game/Screens/Play/BeatmapMetadataDisplay.cs diff --git a/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs new file mode 100644 index 0000000000..074341226e --- /dev/null +++ b/osu.Game/Screens/Play/BeatmapMetadataDisplay.cs @@ -0,0 +1,180 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Localisation; +using osu.Game.Beatmaps; +using osu.Game.Graphics; +using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; +using osu.Game.Rulesets.Mods; +using osu.Game.Screens.Play.HUD; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Screens.Play +{ + /// + /// Displays beatmap metadata inside + /// + public class BeatmapMetadataDisplay : Container + { + private class MetadataLine : Container + { + public MetadataLine(string left, string right) + { + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopRight, + Margin = new MarginPadding { Right = 5 }, + Colour = OsuColour.Gray(0.8f), + Text = left, + }, + new OsuSpriteText + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopLeft, + Margin = new MarginPadding { Left = 5 }, + Text = string.IsNullOrEmpty(right) ? @"-" : right, + } + }; + } + } + + private readonly WorkingBeatmap beatmap; + private readonly Bindable> mods; + private readonly Drawable facade; + private LoadingAnimation loading; + private Sprite backgroundSprite; + + public IBindable> Mods => mods; + + public bool Loading + { + set + { + if (value) + { + loading.Show(); + backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint); + } + else + { + loading.Hide(); + backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint); + } + } + } + + public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade) + { + this.beatmap = beatmap; + this.facade = facade; + + this.mods = new Bindable>(); + this.mods.BindTo(mods); + } + + [BackgroundDependencyLoader] + private void load() + { + var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); + + AutoSizeAxes = Axes.Both; + Children = new Drawable[] + { + new FillFlowContainer + { + AutoSizeAxes = Axes.Both, + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Direction = FillDirection.Vertical, + Children = new[] + { + facade.With(d => + { + d.Anchor = Anchor.TopCentre; + d.Origin = Anchor.TopCentre; + }), + new OsuSpriteText + { + Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), + Font = OsuFont.GetFont(size: 36, italics: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Margin = new MarginPadding { Top = 15 }, + }, + new OsuSpriteText + { + Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)), + Font = OsuFont.GetFont(size: 26, italics: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + new Container + { + Size = new Vector2(300, 60), + Margin = new MarginPadding(10), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + CornerRadius = 10, + Masking = true, + Children = new Drawable[] + { + backgroundSprite = new Sprite + { + RelativeSizeAxes = Axes.Both, + Texture = beatmap?.Background, + Origin = Anchor.Centre, + Anchor = Anchor.Centre, + FillMode = FillMode.Fill, + }, + loading = new LoadingAnimation { Scale = new Vector2(1.3f) } + } + }, + new OsuSpriteText + { + Text = beatmap?.BeatmapInfo?.Version, + Font = OsuFont.GetFont(size: 26, italics: true), + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + Margin = new MarginPadding + { + Bottom = 40 + }, + }, + new MetadataLine("Source", metadata.Source) + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + new MetadataLine("Mapper", metadata.AuthorString) + { + Origin = Anchor.TopCentre, + Anchor = Anchor.TopCentre, + }, + new ModDisplay + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Top = 20 }, + Current = mods + } + }, + } + }; + + Loading = true; + } + } +} diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index f37faac988..ebc2422dc5 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using System; -using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using osu.Framework.Allocation; @@ -12,21 +11,15 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Sprites; using osu.Framework.Input; -using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Framework.Threading; -using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Graphics.Sprites; -using osu.Game.Graphics.UserInterface; using osu.Game.Input; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; -using osu.Game.Rulesets.Mods; using osu.Game.Screens.Menu; -using osu.Game.Screens.Play.HUD; using osu.Game.Screens.Play.PlayerSettings; using osu.Game.Users; using osuTK; @@ -350,162 +343,6 @@ namespace osu.Game.Screens.Play } } - protected class BeatmapMetadataDisplay : Container - { - private class MetadataLine : Container - { - public MetadataLine(string left, string right) - { - AutoSizeAxes = Axes.Both; - Children = new Drawable[] - { - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopRight, - Margin = new MarginPadding { Right = 5 }, - Colour = OsuColour.Gray(0.8f), - Text = left, - }, - new OsuSpriteText - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopLeft, - Margin = new MarginPadding { Left = 5 }, - Text = string.IsNullOrEmpty(right) ? @"-" : right, - } - }; - } - } - - private readonly WorkingBeatmap beatmap; - private readonly Bindable> mods; - private readonly Drawable facade; - private LoadingAnimation loading; - private Sprite backgroundSprite; - - public IBindable> Mods => mods; - - public bool Loading - { - set - { - if (value) - { - loading.Show(); - backgroundSprite.FadeColour(OsuColour.Gray(0.5f), 400, Easing.OutQuint); - } - else - { - loading.Hide(); - backgroundSprite.FadeColour(Color4.White, 400, Easing.OutQuint); - } - } - } - - public BeatmapMetadataDisplay(WorkingBeatmap beatmap, Bindable> mods, Drawable facade) - { - this.beatmap = beatmap; - this.facade = facade; - - this.mods = new Bindable>(); - this.mods.BindTo(mods); - } - - [BackgroundDependencyLoader] - private void load() - { - var metadata = beatmap.BeatmapInfo?.Metadata ?? new BeatmapMetadata(); - - AutoSizeAxes = Axes.Both; - Children = new Drawable[] - { - new FillFlowContainer - { - AutoSizeAxes = Axes.Both, - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Direction = FillDirection.Vertical, - Children = new[] - { - facade.With(d => - { - d.Anchor = Anchor.TopCentre; - d.Origin = Anchor.TopCentre; - }), - new OsuSpriteText - { - Text = new LocalisedString((metadata.TitleUnicode, metadata.Title)), - Font = OsuFont.GetFont(size: 36, italics: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Margin = new MarginPadding { Top = 15 }, - }, - new OsuSpriteText - { - Text = new LocalisedString((metadata.ArtistUnicode, metadata.Artist)), - Font = OsuFont.GetFont(size: 26, italics: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - new Container - { - Size = new Vector2(300, 60), - Margin = new MarginPadding(10), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - CornerRadius = 10, - Masking = true, - Children = new Drawable[] - { - backgroundSprite = new Sprite - { - RelativeSizeAxes = Axes.Both, - Texture = beatmap?.Background, - Origin = Anchor.Centre, - Anchor = Anchor.Centre, - FillMode = FillMode.Fill, - }, - loading = new LoadingAnimation { Scale = new Vector2(1.3f) } - } - }, - new OsuSpriteText - { - Text = beatmap?.BeatmapInfo?.Version, - Font = OsuFont.GetFont(size: 26, italics: true), - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - Margin = new MarginPadding - { - Bottom = 40 - }, - }, - new MetadataLine("Source", metadata.Source) - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - new MetadataLine("Mapper", metadata.AuthorString) - { - Origin = Anchor.TopCentre, - Anchor = Anchor.TopCentre, - }, - new ModDisplay - { - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - Margin = new MarginPadding { Top = 20 }, - Current = mods - } - }, - } - }; - - Loading = true; - } - } - private class MutedNotification : SimpleNotification { public MutedNotification() From b69d1ad678b9052091777aad6669ac4e643d3513 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 18:22:57 +0900 Subject: [PATCH 38/39] Reorder and clean up PlayerLoader --- osu.Game/Screens/Play/PlayerLoader.cs | 308 +++++++++++++------------- 1 file changed, 158 insertions(+), 150 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index ebc2422dc5..6e968de397 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -31,30 +31,60 @@ namespace osu.Game.Screens.Play { protected const float BACKGROUND_BLUR = 15; + public override bool HideOverlaysOnEnter => hideOverlays; + + public override bool DisallowExternalBeatmapRulesetChanges => true; + + // Here because IsHovered will not update unless we do so. + public override bool HandlePositionalInput => true; + + // We show the previous screen status + protected override UserActivity InitialActivity => null; + + protected override bool PlayResumeSound => false; + + protected BeatmapMetadataDisplay MetadataInfo; + + protected VisualSettings VisualSettings; + + protected Task LoadTask { get; private set; } + + protected Task DisposalTask { get; private set; } + + private bool backgroundBrightnessReduction; + + protected bool BackgroundBrightnessReduction + { + set + { + if (value == backgroundBrightnessReduction) + return; + + backgroundBrightnessReduction = value; + + Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200); + } + } + + private bool readyForPush => + player.LoadState == LoadState.Ready && (IsHovered || idleTracker.IsIdle.Value) && inputManager?.DraggedDrawable == null; + private readonly Func createPlayer; private Player player; private LogoTrackingContainer content; - protected BeatmapMetadataDisplay MetadataInfo; - private bool hideOverlays; - public override bool HideOverlaysOnEnter => hideOverlays; - - protected override UserActivity InitialActivity => null; //shows the previous screen status - - public override bool DisallowExternalBeatmapRulesetChanges => true; - - protected override bool PlayResumeSound => false; - - protected Task LoadTask { get; private set; } - - protected Task DisposalTask { get; private set; } private InputManager inputManager; + private IdleTracker idleTracker; + private Bindable muteWarningShownOnce; + + private ScheduledDelegate scheduledPushPlayer; + [Resolved(CanBeNull = true)] private NotificationOverlay notificationOverlay { get; set; } @@ -64,19 +94,11 @@ namespace osu.Game.Screens.Play [Resolved] private AudioManager audioManager { get; set; } - private Bindable muteWarningShownOnce; - public PlayerLoader(Func createPlayer) { this.createPlayer = createPlayer; } - private void restartRequested() - { - hideOverlays = true; - ValidForResume = true; - } - [BackgroundDependencyLoader] private void load(SessionStatics sessionStatics) { @@ -124,7 +146,7 @@ namespace osu.Game.Screens.Play { base.OnEntering(last); - loadNewPlayer(); + prepareNewPlayer(); content.ScaleTo(0.7f); Background?.FadeColour(Color4.White, 800, Easing.OutQuint); @@ -153,36 +175,32 @@ namespace osu.Game.Screens.Play MetadataInfo.Loading = true; - //we will only be resumed if the player has requested a re-run (see ValidForResume setting above) - loadNewPlayer(); + // we will only be resumed if the player has requested a re-run (see restartRequested). + prepareNewPlayer(); this.Delay(400).Schedule(pushWhenLoaded); } - private void loadNewPlayer() + public override void OnSuspending(IScreen next) { - var restartCount = player?.RestartCount + 1 ?? 0; + base.OnSuspending(next); - player = createPlayer(); - player.RestartCount = restartCount; - player.RestartRequested = restartRequested; + cancelLoad(); - LoadTask = LoadComponentAsync(player, _ => MetadataInfo.Loading = false); + BackgroundBrightnessReduction = false; } - private void contentIn() + public override bool OnExiting(IScreen next) { - content.ScaleTo(1, 650, Easing.OutQuint); - content.FadeInFromZero(400); - } + cancelLoad(); - private void contentOut() - { - // Ensure the logo is no longer tracking before we scale the content - content.StopTracking(); + content.ScaleTo(0.7f, 150, Easing.InQuint); + this.FadeOut(150); - content.ScaleTo(0.7f, 300, Easing.InQuint); - content.FadeOut(250); + Background.EnableUserDim.Value = false; + BackgroundBrightnessReduction = false; + + return base.OnExiting(next); } protected override void LogoArriving(OsuLogo logo, bool resuming) @@ -191,10 +209,7 @@ namespace osu.Game.Screens.Play const double duration = 300; - if (!resuming) - { - logo.MoveTo(new Vector2(0.5f), duration, Easing.In); - } + if (!resuming) logo.MoveTo(new Vector2(0.5f), duration, Easing.In); logo.ScaleTo(new Vector2(0.15f), duration, Easing.In); logo.FadeIn(350); @@ -212,110 +227,6 @@ namespace osu.Game.Screens.Play content.StopTracking(); } - private ScheduledDelegate pushDebounce; - protected VisualSettings VisualSettings; - - // Here because IsHovered will not update unless we do so. - public override bool HandlePositionalInput => true; - - private bool readyForPush => player.LoadState == LoadState.Ready && (IsHovered || idleTracker.IsIdle.Value) && inputManager?.DraggedDrawable == null; - - private void pushWhenLoaded() - { - if (!this.IsCurrentScreen()) return; - - try - { - if (!readyForPush) - { - // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce - // if we become unready for push during the delay. - cancelLoad(); - return; - } - - if (pushDebounce != null) - return; - - pushDebounce = Scheduler.AddDelayed(() => - { - contentOut(); - - this.Delay(250).Schedule(() => - { - if (!this.IsCurrentScreen()) return; - - LoadTask = null; - - //By default, we want to load the player and never be returned to. - //Note that this may change if the player we load requested a re-run. - ValidForResume = false; - - if (player.LoadedBeatmapSuccessfully) - this.Push(player); - else - this.Exit(); - }); - }, 500); - } - finally - { - Schedule(pushWhenLoaded); - } - } - - private void cancelLoad() - { - pushDebounce?.Cancel(); - pushDebounce = null; - } - - public override void OnSuspending(IScreen next) - { - BackgroundBrightnessReduction = false; - base.OnSuspending(next); - cancelLoad(); - } - - public override bool OnExiting(IScreen next) - { - content.ScaleTo(0.7f, 150, Easing.InQuint); - this.FadeOut(150); - cancelLoad(); - - Background.EnableUserDim.Value = false; - BackgroundBrightnessReduction = false; - - return base.OnExiting(next); - } - - protected override void Dispose(bool isDisposing) - { - base.Dispose(isDisposing); - - if (isDisposing) - { - // if the player never got pushed, we should explicitly dispose it. - DisposalTask = LoadTask?.ContinueWith(_ => player.Dispose()); - } - } - - private bool backgroundBrightnessReduction; - - protected bool BackgroundBrightnessReduction - { - get => backgroundBrightnessReduction; - set - { - if (value == backgroundBrightnessReduction) - return; - - backgroundBrightnessReduction = value; - - Background.FadeColour(OsuColour.Gray(backgroundBrightnessReduction ? 0.8f : 1), 200); - } - } - protected override void Update() { base.Update(); @@ -343,15 +254,112 @@ namespace osu.Game.Screens.Play } } + private void prepareNewPlayer() + { + var restartCount = player?.RestartCount + 1 ?? 0; + + player = createPlayer(); + player.RestartCount = restartCount; + player.RestartRequested = restartRequested; + + LoadTask = LoadComponentAsync(player, _ => MetadataInfo.Loading = false); + } + + private void restartRequested() + { + hideOverlays = true; + ValidForResume = true; + } + + private void contentIn() + { + content.ScaleTo(1, 650, Easing.OutQuint); + content.FadeInFromZero(400); + } + + private void contentOut() + { + // Ensure the logo is no longer tracking before we scale the content + content.StopTracking(); + + content.ScaleTo(0.7f, 300, Easing.InQuint); + content.FadeOut(250); + } + + private void pushWhenLoaded() + { + if (!this.IsCurrentScreen()) return; + + try + { + if (!readyForPush) + { + // as the pushDebounce below has a delay, we need to keep checking and cancel a future debounce + // if we become unready for push during the delay. + cancelLoad(); + return; + } + + if (scheduledPushPlayer != null) + return; + + scheduledPushPlayer = Scheduler.AddDelayed(() => + { + contentOut(); + + this.Delay(250).Schedule(() => + { + if (!this.IsCurrentScreen()) return; + + LoadTask = null; + + //By default, we want to load the player and never be returned to. + //Note that this may change if the player we load requested a re-run. + ValidForResume = false; + + if (player.LoadedBeatmapSuccessfully) + this.Push(player); + else + this.Exit(); + }); + }, 500); + } + finally + { + Schedule(pushWhenLoaded); + } + } + + private void cancelLoad() + { + scheduledPushPlayer?.Cancel(); + scheduledPushPlayer = null; + } + + #region Disposal + + protected override void Dispose(bool isDisposing) + { + base.Dispose(isDisposing); + + if (isDisposing) + { + // if the player never got pushed, we should explicitly dispose it. + DisposalTask = LoadTask?.ContinueWith(_ => player.Dispose()); + } + } + + #endregion + private class MutedNotification : SimpleNotification { + public override bool IsImportant => true; + public MutedNotification() { Text = "Your music volume is set to 0%! Click here to restore it."; } - public override bool IsImportant => true; - [BackgroundDependencyLoader] private void load(OsuColour colours, AudioManager audioManager, NotificationOverlay notificationOverlay, VolumeOverlay volumeOverlay) { From 2808f8167dd40866481315156fd3b1954614f6ef Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Fri, 14 Feb 2020 18:28:58 +0900 Subject: [PATCH 39/39] Use more regions --- osu.Game/Screens/Play/PlayerLoader.cs | 35 ++++++++++++++++++--------- 1 file changed, 24 insertions(+), 11 deletions(-) diff --git a/osu.Game/Screens/Play/PlayerLoader.cs b/osu.Game/Screens/Play/PlayerLoader.cs index 6e968de397..01873f7114 100644 --- a/osu.Game/Screens/Play/PlayerLoader.cs +++ b/osu.Game/Screens/Play/PlayerLoader.cs @@ -81,8 +81,6 @@ namespace osu.Game.Screens.Play private IdleTracker idleTracker; - private Bindable muteWarningShownOnce; - private ScheduledDelegate scheduledPushPlayer; [Resolved(CanBeNull = true)] @@ -142,6 +140,8 @@ namespace osu.Game.Screens.Play inputManager = GetContainingInputManager(); } + #region Screen handling + public override void OnEntering(IScreen last) { base.OnEntering(last); @@ -156,15 +156,7 @@ namespace osu.Game.Screens.Play MetadataInfo.Delay(750).FadeIn(500); this.Delay(1800).Schedule(pushWhenLoaded); - if (!muteWarningShownOnce.Value) - { - //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. - if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) - { - notificationOverlay?.Post(new MutedNotification()); - muteWarningShownOnce.Value = true; - } - } + showMuteWarningIfNeeded(); } public override void OnResuming(IScreen last) @@ -227,6 +219,8 @@ namespace osu.Game.Screens.Play content.StopTracking(); } + #endregion + protected override void Update() { base.Update(); @@ -351,6 +345,23 @@ namespace osu.Game.Screens.Play #endregion + #region Mute warning + + private Bindable muteWarningShownOnce; + + private void showMuteWarningIfNeeded() + { + if (!muteWarningShownOnce.Value) + { + //Checks if the notification has not been shown yet and also if master volume is muted, track/music volume is muted or if the whole game is muted. + if (volumeOverlay?.IsMuted.Value == true || audioManager.Volume.Value <= audioManager.Volume.MinValue || audioManager.VolumeTrack.Value <= audioManager.VolumeTrack.MinValue) + { + notificationOverlay?.Post(new MutedNotification()); + muteWarningShownOnce.Value = true; + } + } + } + private class MutedNotification : SimpleNotification { public override bool IsImportant => true; @@ -378,5 +389,7 @@ namespace osu.Game.Screens.Play }; } } + + #endregion } }