From ae07b2b512b61ff86bd36632d67c6f01664c8d3c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Apr 2022 17:42:10 +0900 Subject: [PATCH 01/41] Initial setup --- .../Visual/Navigation/TestFirstRunSetup.cs | 15 ++ osu.Game/OsuGame.cs | 3 + .../FirstRunSetup/FirstRunSetupScreen.cs | 51 +++++++ .../Overlays/FirstRunSetup/ScreenWelcome.cs | 58 ++++++++ osu.Game/Overlays/FirstRunSetupOverlay.cs | 134 ++++++++++++++++++ 5 files changed, 261 insertions(+) create mode 100644 osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs create mode 100644 osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs create mode 100644 osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs create mode 100644 osu.Game/Overlays/FirstRunSetupOverlay.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs b/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs new file mode 100644 index 000000000000..ab49334af124 --- /dev/null +++ b/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs @@ -0,0 +1,15 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; + +namespace osu.Game.Tests.Visual.Navigation +{ + public class TestFirstRunSetup : OsuGameTestScene + { + [Test] + public void TestOverlay() + { + } + } +} diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 5a150b0c4921..52aa6b8f07c4 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -149,6 +149,8 @@ public class OsuGame : OsuGameBase, IKeyBindingHandler, ILocalUser protected SettingsOverlay Settings; + private FirstRunSetupOverlay firstRunOverlay; + private VolumeOverlay volume; private OsuLogo osuLogo; @@ -791,6 +793,7 @@ protected override void LoadComplete() loadComponentSingleFile(CreateUpdateManager(), Add, true); // overlay elements + loadComponentSingleFile(firstRunOverlay = new FirstRunSetupOverlay(), overlayContent.Add, true); loadComponentSingleFile(new ManageCollectionsDialog(), overlayContent.Add, true); loadComponentSingleFile(beatmapListing = new BeatmapListingOverlay(), overlayContent.Add, true); loadComponentSingleFile(dashboard = new DashboardOverlay(), overlayContent.Add, true); diff --git a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs new file mode 100644 index 000000000000..d00d21d34701 --- /dev/null +++ b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs @@ -0,0 +1,51 @@ +// 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.Framework.Input.Events; +using osu.Framework.Screens; + +namespace osu.Game.Overlays.FirstRunSetup +{ + public abstract class FirstRunSetupScreen : Screen + { + [Resolved] + protected FirstRunSetupOverlay Overlay { get; private set; } + + protected Container Content { get; private set; } + + protected FirstRunSetupScreen() + { + InternalChildren = new Drawable[] + { + Content = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + }, + }; + } + + protected override bool OnClick(ClickEvent e) => true; + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + this.FadeOut().Delay(200).FadeIn(200); + } + + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + this.FadeIn(200); + } + + public override void OnSuspending(IScreen next) + { + base.OnSuspending(next); + this.FadeOut(200); + } + } +} diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs new file mode 100644 index 000000000000..be21712c95c4 --- /dev/null +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -0,0 +1,58 @@ +// 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.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Screens; +using osu.Framework.Utils; +using osu.Game.Graphics.Containers; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osuTK; + +namespace osu.Game.Overlays.FirstRunSetup +{ + public class ScreenWelcome : FirstRunSetupScreen + { + public ScreenWelcome() + { + Content.Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuTextFlowContainer + { + Text = "Welcome to the first-run setup guide!\n\nThis will help you get osu! setup in a way that suits you.", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + } + }, + new PurpleTriangleButton + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Margin = new MarginPadding(10), + Text = "Get started", + Action = () => this.Push(new ScreenWelcome()), + } + }; + } + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + Overlay.MoveDisplayTo(new Vector2(RNG.NextSingle(), RNG.NextSingle())); + } + + public override void OnResuming(IScreen last) + { + base.OnResuming(last); + Overlay.MoveDisplayTo(new Vector2(RNG.NextSingle(), RNG.NextSingle())); + } + } +} diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs new file mode 100644 index 000000000000..218e6018e214 --- /dev/null +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -0,0 +1,134 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Allocation; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Effects; +using osu.Framework.Graphics.Shapes; +using osu.Framework.Input.Events; +using osu.Framework.Screens; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Online.API; +using osu.Game.Overlays.Dialog; +using osu.Game.Overlays.FirstRunSetup; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Menu; +using osuTK; +using osuTK.Graphics; + +namespace osu.Game.Overlays +{ + [Cached] + public class FirstRunSetupOverlay : OsuFocusedOverlayContainer + { + protected override bool StartHidden => true; + + [Resolved] + private DialogOverlay dialogOverlay { get; set; } + + [Resolved] + private OsuGame osuGame { get; set; } + + private ScreenWelcome welcomeScreen; + + private Container currentDisplayContainer; + + private PlayfieldBorder border; + + public FirstRunSetupOverlay() + { + RelativeSizeAxes = Axes.Both; + } + + [BackgroundDependencyLoader] + private void load(IAPIProvider api, OsuColour colours) + { + Children = new Drawable[] + { + border = new PlayfieldBorder + { + PlayfieldBorderStyle = { Value = PlayfieldBorderStyle.Full }, + Colour = colours.Blue, + }, + currentDisplayContainer = new Container + { + Origin = Anchor.Centre, + RelativePositionAxes = Axes.Both, + Size = new Vector2(400, 300), + Position = new Vector2(0.5f), + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 5, + Colour = Color4.Black.Opacity(0.2f), + }, + Masking = true, + CornerRadius = 10, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black, + Alpha = 0.8f, + }, + new ScreenStack(welcomeScreen = new ScreenWelcome()) + { + RelativeSizeAxes = Axes.Both, + }, + } + } + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + // if we are valid for display, only do so after reaching the main menu. + osuGame.PerformFromScreen(_ => + { + Show(); + }, new[] { typeof(MainMenu) }); + + border + .FadeInFromZero(500) + .Delay(1000) + .FadeOut(500) + .Loop(); + } + + protected override bool OnClick(ClickEvent e) + { + if (dialogOverlay.CurrentDialog == null) + { + dialogOverlay.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", + Hide, + () => { })); + } + + return base.OnClick(e); + } + + protected override void PopIn() + { + base.PopIn(); + this.FadeIn(400, Easing.OutQuint); + + if (welcomeScreen.GetChildScreen() != null) + welcomeScreen.MakeCurrent(); + } + + protected override void PopOut() + { + base.PopOut(); + this.FadeOut(100); + } + + public void MoveDisplayTo(Vector2 position) => + currentDisplayContainer.MoveTo(position, 1000, Easing.OutElasticQuarter); + } +} From c2df3465b281fe8523e51379785780005cb98041 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 6 Apr 2022 18:11:32 +0900 Subject: [PATCH 02/41] Add ui scaling setup screen, kind of --- .../FirstRunSetup/ScreenSetupUIScale.cs | 87 +++++++++++++++++++ .../Overlays/FirstRunSetup/ScreenWelcome.cs | 11 +-- osu.Game/Overlays/FirstRunSetupOverlay.cs | 6 +- 3 files changed, 94 insertions(+), 10 deletions(-) create mode 100644 osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs new file mode 100644 index 000000000000..7c703f65bdc4 --- /dev/null +++ b/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs @@ -0,0 +1,87 @@ +// 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.Framework.Localisation; +using osu.Framework.Screens; +using osu.Game.Configuration; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Overlays.Settings; +using osu.Game.Screens; +using osu.Game.Screens.OnlinePlay.Match.Components; +using osu.Game.Screens.Select; +using osuTK; + +namespace osu.Game.Overlays.FirstRunSetup +{ + public class ScreenSetupUIScale : FirstRunSetupScreen + { + [Resolved] + private OsuConfigManager osuConfig { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + OsuScreenStack stack; + Content.Children = new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.Both, + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + Children = new Drawable[] + { + new OsuTextFlowContainer + { + Text = "The osu! user interface size can be adjusted to your liking.", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new SettingsSlider + { + LabelText = GraphicsSettingsStrings.UIScaling, + TransferValueOnCommit = true, + Current = osuConfig.GetBindable(OsuSetting.UIScale), + KeyboardStep = 0.01f, + }, + new DrawSizePreservingFillContainer + { + Masking = true, + RelativeSizeAxes = Axes.X, + Height = 300, + Child = stack = new OsuScreenStack() + } + } + }, + new PurpleTriangleButton + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Margin = new MarginPadding(10), + Text = "Finish", + Action = () => Overlay.Hide() + } + }; + + stack.Push(new PlaySongSelect()); + } + + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + Overlay.MoveDisplayTo(new Vector2(0.5f)); + Overlay.ResizeDisplayTo(new Vector2(0.8f)); + } + + private class UIScaleSlider : OsuSliderBar + { + public override LocalisableString TooltipText => base.TooltipText + "x"; + } + } +} diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index be21712c95c4..b436db24312e 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -4,7 +4,6 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; -using osu.Framework.Utils; using osu.Game.Graphics.Containers; using osu.Game.Screens.OnlinePlay.Match.Components; using osuTK; @@ -38,7 +37,7 @@ public ScreenWelcome() RelativeSizeAxes = Axes.X, Margin = new MarginPadding(10), Text = "Get started", - Action = () => this.Push(new ScreenWelcome()), + Action = () => this.Push(new ScreenSetupUIScale()), } }; } @@ -46,13 +45,7 @@ public ScreenWelcome() public override void OnEntering(IScreen last) { base.OnEntering(last); - Overlay.MoveDisplayTo(new Vector2(RNG.NextSingle(), RNG.NextSingle())); - } - - public override void OnResuming(IScreen last) - { - base.OnResuming(last); - Overlay.MoveDisplayTo(new Vector2(RNG.NextSingle(), RNG.NextSingle())); + Overlay.MoveDisplayTo(new Vector2(0.5f)); } } } diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 218e6018e214..1578ef8cbfd8 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -57,7 +57,8 @@ private void load(IAPIProvider api, OsuColour colours) { Origin = Anchor.Centre, RelativePositionAxes = Axes.Both, - Size = new Vector2(400, 300), + RelativeSizeAxes = Axes.Both, + Size = new Vector2(0.5f), Position = new Vector2(0.5f), EdgeEffect = new EdgeEffectParameters { @@ -130,5 +131,8 @@ protected override void PopOut() public void MoveDisplayTo(Vector2 position) => currentDisplayContainer.MoveTo(position, 1000, Easing.OutElasticQuarter); + + public void ResizeDisplayTo(Vector2 scale) => + currentDisplayContainer.ScaleTo(scale, 1000, Easing.OutElasticQuarter); } } From e064f2f23efac42cca67225d59854852edb61092 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 15:20:54 +0900 Subject: [PATCH 03/41] Improve general layout and allow overlay to be displayed without dependencies for now --- .../Visual/Navigation/TestFirstRunSetup.cs | 7 +- .../Overlays/FirstRunSetup/ScreenWelcome.cs | 13 +- osu.Game/Overlays/FirstRunSetupOverlay.cs | 118 ++++++++++++------ 3 files changed, 91 insertions(+), 47 deletions(-) diff --git a/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs b/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs index ab49334af124..98558652844d 100644 --- a/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs +++ b/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs @@ -2,14 +2,19 @@ // See the LICENCE file in the repository root for full licence text. using NUnit.Framework; +using osu.Game.Overlays; namespace osu.Game.Tests.Visual.Navigation { - public class TestFirstRunSetup : OsuGameTestScene + public class TestFirstRunSetup : OsuTestScene { [Test] public void TestOverlay() { + AddStep("add overlay", () => + { + Child = new FirstRunSetupOverlay(); + }); } } } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index b436db24312e..f67ab1cd7f55 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -4,9 +4,9 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Screens; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Screens.OnlinePlay.Match.Components; -using osuTK; namespace osu.Game.Overlays.FirstRunSetup { @@ -22,9 +22,10 @@ public ScreenWelcome() Direction = FillDirection.Vertical, Children = new Drawable[] { - new OsuTextFlowContainer + new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 20)) { - Text = "Welcome to the first-run setup guide!\n\nThis will help you get osu! setup in a way that suits you.", + Text = + "Welcome to the first-run setup guide!\n\nosu! is a very configurable game, and diving straight into the settings can sometimes be overwhelming. This guide will help you get the important choices out of the way to ensure a great first experience!", RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y }, @@ -41,11 +42,5 @@ public ScreenWelcome() } }; } - - public override void OnEntering(IScreen last) - { - base.OnEntering(last); - Overlay.MoveDisplayTo(new Vector2(0.5f)); - } } } diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 1578ef8cbfd8..d213f87fe50a 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -11,10 +11,10 @@ using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Graphics.Sprites; using osu.Game.Online.API; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.FirstRunSetup; -using osu.Game.Rulesets.UI; using osu.Game.Screens.Menu; using osuTK; using osuTK.Graphics; @@ -26,17 +26,16 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer { protected override bool StartHidden => true; - [Resolved] + [Resolved(canBeNull: true)] private DialogOverlay dialogOverlay { get; set; } - [Resolved] + [Resolved(canBeNull: true)] private OsuGame osuGame { get; set; } - private ScreenWelcome welcomeScreen; - - private Container currentDisplayContainer; + [Cached] + private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - private PlayfieldBorder border; + private ScreenWelcome welcomeScreen; public FirstRunSetupOverlay() { @@ -48,18 +47,12 @@ private void load(IAPIProvider api, OsuColour colours) { Children = new Drawable[] { - border = new PlayfieldBorder - { - PlayfieldBorderStyle = { Value = PlayfieldBorderStyle.Full }, - Colour = colours.Blue, - }, - currentDisplayContainer = new Container + new Container { - Origin = Anchor.Centre, - RelativePositionAxes = Axes.Both, RelativeSizeAxes = Axes.Both, - Size = new Vector2(0.5f), - Position = new Vector2(0.5f), + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(0.95f), EdgeEffect = new EdgeEffectParameters { Type = EdgeEffectType.Shadow, @@ -73,12 +66,68 @@ private void load(IAPIProvider api, OsuColour colours) new Box { RelativeSizeAxes = Axes.Both, - Colour = Color4.Black, - Alpha = 0.8f, + Colour = colourProvider.Background5, }, - new ScreenStack(welcomeScreen = new ScreenWelcome()) + new GridContainer { RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + }, + Content = new[] + { + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] + { + new Box + { + Colour = colourProvider.Background6, + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + Margin = new MarginPadding(10), + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new Drawable[] + { + new OsuSpriteText + { + Text = "First run setup", + Font = OsuFont.Default.With(size: 32), + Colour = colourProvider.Content2, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + }, + new OsuTextFlowContainer + { + Text = "Setup osu! to suit you", + Colour = colourProvider.Content1, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + }, + } + }, + } + }, + }, + new Drawable[] + { + new ScreenStack(welcomeScreen = new ScreenWelcome()) + { + RelativeSizeAxes = Axes.Both, + }, + } + } }, } } @@ -89,24 +138,25 @@ protected override void LoadComplete() { base.LoadComplete(); - // if we are valid for display, only do so after reaching the main menu. - osuGame.PerformFromScreen(_ => + if (osuGame != null) + { + // if we are valid for display, only do so after reaching the main menu. + osuGame.PerformFromScreen(_ => + { + Show(); + }, new[] { typeof(MainMenu) }); + } + else { Show(); - }, new[] { typeof(MainMenu) }); - - border - .FadeInFromZero(500) - .Delay(1000) - .FadeOut(500) - .Loop(); + } } protected override bool OnClick(ClickEvent e) { - if (dialogOverlay.CurrentDialog == null) + if (dialogOverlay?.CurrentDialog == null) { - dialogOverlay.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", + dialogOverlay?.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", Hide, () => { })); } @@ -128,11 +178,5 @@ protected override void PopOut() base.PopOut(); this.FadeOut(100); } - - public void MoveDisplayTo(Vector2 position) => - currentDisplayContainer.MoveTo(position, 1000, Easing.OutElasticQuarter); - - public void ResizeDisplayTo(Vector2 scale) => - currentDisplayContainer.ScaleTo(scale, 1000, Easing.OutElasticQuarter); } } From 3b94e01fe64ad1094e895f6822444c36b45cf042 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 15:21:09 +0900 Subject: [PATCH 04/41] Improve layout of ui scale step --- .../FirstRunSetup/ScreenSetupUIScale.cs | 55 ++++++++++++++----- 1 file changed, 41 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs index 7c703f65bdc4..1a8ef0338c7e 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs @@ -5,13 +5,14 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Framework.Localisation; -using osu.Framework.Screens; using osu.Game.Configuration; +using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays.Settings; using osu.Game.Screens; +using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Match.Components; using osu.Game.Screens.Select; using osuTK; @@ -23,6 +24,9 @@ public class ScreenSetupUIScale : FirstRunSetupScreen [Resolved] private OsuConfigManager osuConfig { get; set; } + [Cached] + private OsuLogo osuLogo = new OsuLogo(); + [BackgroundDependencyLoader] private void load() { @@ -36,7 +40,7 @@ private void load() Spacing = new Vector2(20), Children = new Drawable[] { - new OsuTextFlowContainer + new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 32)) { Text = "The osu! user interface size can be adjusted to your liking.", RelativeSizeAxes = Axes.X, @@ -49,12 +53,42 @@ private void load() Current = osuConfig.GetBindable(OsuSetting.UIScale), KeyboardStep = 0.01f, }, - new DrawSizePreservingFillContainer + new GridContainer { - Masking = true, - RelativeSizeAxes = Axes.X, - Height = 300, - Child = stack = new OsuScreenStack() + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new ScalingContainer(ScalingMode.Off) + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Child = stack = new OsuScreenStack() + }, + new ScalingContainer(ScalingMode.Off) + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Child = stack = new OsuScreenStack() + } + }, + new Drawable[] + { + new ScalingContainer(ScalingMode.Off) + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Child = stack = new OsuScreenStack() + }, + new ScalingContainer(ScalingMode.Off) + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Child = stack = new OsuScreenStack() + } + } + } } } }, @@ -72,13 +106,6 @@ private void load() stack.Push(new PlaySongSelect()); } - public override void OnEntering(IScreen last) - { - base.OnEntering(last); - Overlay.MoveDisplayTo(new Vector2(0.5f)); - Overlay.ResizeDisplayTo(new Vector2(0.8f)); - } - private class UIScaleSlider : OsuSliderBar { public override LocalisableString TooltipText => base.TooltipText + "x"; From 07da1cd731b7acf89337a066fd3ed677216c5e67 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 16:07:30 +0900 Subject: [PATCH 05/41] Move buttons to top level and add backwards navigation --- .../FirstRunSetup/FirstRunSetupScreen.cs | 28 ++-- .../Overlays/FirstRunSetup/ScreenWelcome.cs | 13 +- osu.Game/Overlays/FirstRunSetupOverlay.cs | 128 +++++++++++++++++- 3 files changed, 133 insertions(+), 36 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs index d00d21d34701..5cf3d562a98a 100644 --- a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs +++ b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Input.Events; using osu.Framework.Screens; @@ -14,38 +13,31 @@ public abstract class FirstRunSetupScreen : Screen [Resolved] protected FirstRunSetupOverlay Overlay { get; private set; } - protected Container Content { get; private set; } - - protected FirstRunSetupScreen() - { - InternalChildren = new Drawable[] - { - Content = new Container - { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(20), - }, - }; - } - protected override bool OnClick(ClickEvent e) => true; public override void OnEntering(IScreen last) { base.OnEntering(last); - this.FadeOut().Delay(200).FadeIn(200); + this + .FadeInFromZero(500) + .MoveToX(100) + .MoveToX(0, 500, Easing.OutQuint); } public override void OnResuming(IScreen last) { base.OnResuming(last); - this.FadeIn(200); + this + .FadeInFromZero(500) + .MoveToX(0, 500, Easing.OutQuint); } public override void OnSuspending(IScreen next) { base.OnSuspending(next); - this.FadeOut(200); + this + .FadeOut(100) + .MoveToX(-100, 500, Easing.OutQuint); } } } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index f67ab1cd7f55..879ffdf19836 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -3,10 +3,8 @@ using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; -using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; -using osu.Game.Screens.OnlinePlay.Match.Components; namespace osu.Game.Overlays.FirstRunSetup { @@ -14,7 +12,7 @@ public class ScreenWelcome : FirstRunSetupScreen { public ScreenWelcome() { - Content.Children = new Drawable[] + InternalChildren = new Drawable[] { new FillFlowContainer { @@ -31,15 +29,6 @@ public ScreenWelcome() }, } }, - new PurpleTriangleButton - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding(10), - Text = "Get started", - Action = () => this.Push(new ScreenSetupUIScale()), - } }; } } diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index d213f87fe50a..4eb46c38f39d 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -1,6 +1,10 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +#nullable enable + +using System; +using System.Diagnostics; using osu.Framework.Allocation; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; @@ -8,14 +12,17 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Input.Events; +using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; +using osu.Game.Graphics.UserInterface; using osu.Game.Online.API; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Screens.Menu; +using osu.Game.Screens.OnlinePlay.Match.Components; using osuTK; using osuTK.Graphics; @@ -27,15 +34,26 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer protected override bool StartHidden => true; [Resolved(canBeNull: true)] - private DialogOverlay dialogOverlay { get; set; } + private DialogOverlay? dialogOverlay { get; set; } [Resolved(canBeNull: true)] - private OsuGame osuGame { get; set; } + private OsuGame? osuGame { get; set; } + + private ScreenStack stack = null!; + + private PurpleTriangleButton nextButton = null!; + private DangerousTriangleButton backButton = null!; [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); - private ScreenWelcome welcomeScreen; + private int? currentStepIndex; + + private readonly FirstRunStep[] steps = + { + new FirstRunStep(typeof(ScreenWelcome), "Welcome"), + new FirstRunStep(typeof(ScreenSetupUIScale), "UI Scale"), + }; public FirstRunSetupOverlay() { @@ -75,6 +93,7 @@ private void load(IAPIProvider api, OsuColour colours) { new Dimension(GridSizeMode.AutoSize), new Dimension(), + new Dimension(GridSizeMode.AutoSize), }, Content = new[] { @@ -122,10 +141,60 @@ private void load(IAPIProvider api, OsuColour colours) }, new Drawable[] { - new ScreenStack(welcomeScreen = new ScreenWelcome()) + new Container { RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + Child = stack = new ScreenStack + { + RelativeSizeAxes = Axes.Both, + }, }, + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(20), + Child = new GridContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 10), + new Dimension(), + }, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new[] + { + backButton = new DangerousTriangleButton + { + Width = 200, + Text = "Back", + Action = showLastStep, + Enabled = { Value = false }, + }, + Empty(), + nextButton = new PurpleTriangleButton + { + RelativeSizeAxes = Axes.X, + Width = 1, + Text = "Get started", + Action = showNextStep + } + }, + } + }, + } } } }, @@ -169,8 +238,43 @@ protected override void PopIn() base.PopIn(); this.FadeIn(400, Easing.OutQuint); - if (welcomeScreen.GetChildScreen() != null) - welcomeScreen.MakeCurrent(); + if (currentStepIndex == null) + showNextStep(); + } + + private void showLastStep() + { + Debug.Assert(currentStepIndex > 0); + + stack.CurrentScreen.Exit(); + currentStepIndex--; + + backButton.Enabled.Value = currentStepIndex != 0; + } + + private void showNextStep() + { + if (currentStepIndex == null) + currentStepIndex = 0; + else + currentStepIndex++; + + Debug.Assert(currentStepIndex != null); + backButton.Enabled.Value = currentStepIndex > 0; + + if (currentStepIndex < steps.Length) + { + var nextStep = steps[currentStepIndex.Value]; + stack.Push((Screen)Activator.CreateInstance(nextStep.ScreenType)); + } + else + { + Hide(); + } + + nextButton.Text = currentStepIndex + 1 < steps.Length + ? $"Next ({steps[currentStepIndex.Value + 1].Description})" + : "Finish"; } protected override void PopOut() @@ -178,5 +282,17 @@ protected override void PopOut() base.PopOut(); this.FadeOut(100); } + + private class FirstRunStep + { + public readonly Type ScreenType; + public readonly LocalisableString Description; + + public FirstRunStep(Type screenType, LocalisableString description) + { + ScreenType = screenType; + Description = description; + } + } } } From 288f759bb4bd8480e4157faf6e1e3d4681028299 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 16:34:13 +0900 Subject: [PATCH 06/41] Add test coverage of navigation --- .../Visual/Navigation/TestFirstRunSetup.cs | 20 ------ .../TestSceneFirstRunSetupOverlay.cs | 63 +++++++++++++++++++ osu.Game/Overlays/FirstRunSetupOverlay.cs | 19 +++--- 3 files changed, 75 insertions(+), 27 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs create mode 100644 osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs b/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs deleted file mode 100644 index 98558652844d..000000000000 --- a/osu.Game.Tests/Visual/Navigation/TestFirstRunSetup.cs +++ /dev/null @@ -1,20 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Game.Overlays; - -namespace osu.Game.Tests.Visual.Navigation -{ - public class TestFirstRunSetup : OsuTestScene - { - [Test] - public void TestOverlay() - { - AddStep("add overlay", () => - { - Child = new FirstRunSetupOverlay(); - }); - } - } -} diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs new file mode 100644 index 000000000000..c9aba315ebb3 --- /dev/null +++ b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs @@ -0,0 +1,63 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using NUnit.Framework; +using osu.Framework.Graphics.Containers; +using osu.Framework.Testing; +using osu.Game.Overlays; +using osu.Game.Overlays.FirstRunSetup; + +namespace osu.Game.Tests.Visual.Navigation +{ + public class TestSceneFirstRunSetupOverlay : OsuTestScene + { + private FirstRunSetupOverlay overlay; + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("add overlay", () => + { + Child = overlay = new FirstRunSetupOverlay(); + }); + } + + [Test] + public void TestOverlayRunsToFinish() + { + AddUntilStep("step through", () => + { + if (overlay.CurrentScreen?.IsLoaded != false) + overlay.NextButton.TriggerClick(); + + return overlay.State.Value == Visibility.Hidden; + }); + } + + [Test] + public void TestBackButton() + { + AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); + + AddUntilStep("step to last", () => + { + var nextButton = overlay.NextButton; + + if (overlay.CurrentScreen?.IsLoaded != false) + nextButton.TriggerClick(); + + return nextButton.Text.ToString() == "Finish"; + }); + + AddUntilStep("step back to start", () => + { + if (overlay.CurrentScreen?.IsLoaded != false) + overlay.BackButton.TriggerClick(); + + return overlay.CurrentScreen is ScreenWelcome; + }); + + AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); + } + } +} diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 4eb46c38f39d..bd6cb0b4d787 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -41,14 +41,19 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer private ScreenStack stack = null!; - private PurpleTriangleButton nextButton = null!; - private DangerousTriangleButton backButton = null!; + public PurpleTriangleButton NextButton = null!; + public DangerousTriangleButton BackButton = null!; [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); private int? currentStepIndex; + /// + /// The currently displayed screen, if any. + /// + public FirstRunSetupScreen? CurrentScreen => (FirstRunSetupScreen?)stack.CurrentScreen; + private readonly FirstRunStep[] steps = { new FirstRunStep(typeof(ScreenWelcome), "Welcome"), @@ -176,7 +181,7 @@ private void load(IAPIProvider api, OsuColour colours) { new[] { - backButton = new DangerousTriangleButton + BackButton = new DangerousTriangleButton { Width = 200, Text = "Back", @@ -184,7 +189,7 @@ private void load(IAPIProvider api, OsuColour colours) Enabled = { Value = false }, }, Empty(), - nextButton = new PurpleTriangleButton + NextButton = new PurpleTriangleButton { RelativeSizeAxes = Axes.X, Width = 1, @@ -249,7 +254,7 @@ private void showLastStep() stack.CurrentScreen.Exit(); currentStepIndex--; - backButton.Enabled.Value = currentStepIndex != 0; + BackButton.Enabled.Value = currentStepIndex != 0; } private void showNextStep() @@ -260,7 +265,7 @@ private void showNextStep() currentStepIndex++; Debug.Assert(currentStepIndex != null); - backButton.Enabled.Value = currentStepIndex > 0; + BackButton.Enabled.Value = currentStepIndex > 0; if (currentStepIndex < steps.Length) { @@ -272,7 +277,7 @@ private void showNextStep() Hide(); } - nextButton.Text = currentStepIndex + 1 < steps.Length + NextButton.Text = currentStepIndex + 1 < steps.Length ? $"Next ({steps[currentStepIndex.Value + 1].Description})" : "Finish"; } From 56c4283764752f6a1eb2282df17e2db40196c794 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 17:10:08 +0900 Subject: [PATCH 07/41] Only exit dialog from click if outside the dialog content --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index bd6cb0b4d787..0efeded06273 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -60,6 +60,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer new FirstRunStep(typeof(ScreenSetupUIScale), "UI Scale"), }; + private Container mainContent; + public FirstRunSetupOverlay() { RelativeSizeAxes = Axes.Both; @@ -70,7 +72,7 @@ private void load(IAPIProvider api, OsuColour colours) { Children = new Drawable[] { - new Container + mainContent = new Container { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -228,7 +230,7 @@ protected override void LoadComplete() protected override bool OnClick(ClickEvent e) { - if (dialogOverlay?.CurrentDialog == null) + if (!mainContent.IsHovered && dialogOverlay?.CurrentDialog == null) { dialogOverlay?.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", Hide, From ea52fab5b1202268f43fadeb9f47cb7c516e3717 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 18:58:14 +0900 Subject: [PATCH 08/41] Tidy up dependencies and test naming --- .../TestSceneFirstRunSetupOverlay.cs | 63 -------- .../TestSceneFirstRunScreenUIScale.cs | 19 +++ .../TestSceneFirstRunSetupOverlay.cs | 111 +++++++++++++ .../FirstRunSetup/FirstRunSetupScreen.cs | 23 +-- .../FirstRunSetup/ScreenSetupUIScale.cs | 114 -------------- .../Overlays/FirstRunSetup/ScreenUIScale.cs | 146 ++++++++++++++++++ osu.Game/Overlays/FirstRunSetupOverlay.cs | 38 ++--- 7 files changed, 303 insertions(+), 211 deletions(-) delete mode 100644 osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs create mode 100644 osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs delete mode 100644 osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs create mode 100644 osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs diff --git a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs deleted file mode 100644 index c9aba315ebb3..000000000000 --- a/osu.Game.Tests/Visual/Navigation/TestSceneFirstRunSetupOverlay.cs +++ /dev/null @@ -1,63 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using NUnit.Framework; -using osu.Framework.Graphics.Containers; -using osu.Framework.Testing; -using osu.Game.Overlays; -using osu.Game.Overlays.FirstRunSetup; - -namespace osu.Game.Tests.Visual.Navigation -{ - public class TestSceneFirstRunSetupOverlay : OsuTestScene - { - private FirstRunSetupOverlay overlay; - - [SetUpSteps] - public void SetUpSteps() - { - AddStep("add overlay", () => - { - Child = overlay = new FirstRunSetupOverlay(); - }); - } - - [Test] - public void TestOverlayRunsToFinish() - { - AddUntilStep("step through", () => - { - if (overlay.CurrentScreen?.IsLoaded != false) - overlay.NextButton.TriggerClick(); - - return overlay.State.Value == Visibility.Hidden; - }); - } - - [Test] - public void TestBackButton() - { - AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); - - AddUntilStep("step to last", () => - { - var nextButton = overlay.NextButton; - - if (overlay.CurrentScreen?.IsLoaded != false) - nextButton.TriggerClick(); - - return nextButton.Text.ToString() == "Finish"; - }); - - AddUntilStep("step back to start", () => - { - if (overlay.CurrentScreen?.IsLoaded != false) - overlay.BackButton.TriggerClick(); - - return overlay.CurrentScreen is ScreenWelcome; - }); - - AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); - } - } -} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs new file mode 100644 index 000000000000..5ca09b34aae1 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunScreenUIScale.cs @@ -0,0 +1,19 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Screens; +using osu.Game.Overlays.FirstRunSetup; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneFirstRunScreenUIScale : OsuManualInputManagerTestScene + { + public TestSceneFirstRunScreenUIScale() + { + AddStep("load screen", () => + { + Child = new ScreenStack(new ScreenUIScale()); + }); + } + } +} diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs new file mode 100644 index 000000000000..d892301a81a5 --- /dev/null +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -0,0 +1,111 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using System.Collections.Generic; +using Moq; +using NUnit.Framework; +using osu.Framework.Allocation; +using osu.Framework.Graphics.Containers; +using osu.Framework.Screens; +using osu.Framework.Testing; +using osu.Game.Overlays; +using osu.Game.Overlays.Dialog; +using osu.Game.Overlays.FirstRunSetup; +using osu.Game.Screens; +using osuTK; +using osuTK.Input; + +namespace osu.Game.Tests.Visual.UserInterface +{ + public class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene + { + private FirstRunSetupOverlay overlay; + + private readonly Mock perfomer = new Mock(); + private readonly Mock dialogOverlay = new Mock(); + + [BackgroundDependencyLoader] + private void load() + { + Dependencies.CacheAs(perfomer.Object); + Dependencies.CacheAs(dialogOverlay.Object); + + perfomer.Setup(g => g.PerformFromScreen(It.IsAny>(), It.IsAny>())) + .Callback((Action action, IEnumerable types) => action(null)); + + dialogOverlay.Setup(d => d.Push(It.IsAny())) + .Callback((PopupDialog dialog) => dialog.PerformOkAction()); + } + + [SetUpSteps] + public void SetUpSteps() + { + AddStep("add overlay", () => + { + Child = overlay = new FirstRunSetupOverlay + { + State = { Value = Visibility.Visible } + }; + }); + } + + [Test] + public void TestOverlayRunsToFinish() + { + AddUntilStep("step through", () => + { + if (overlay.CurrentScreen?.IsLoaded != false) + overlay.NextButton.TriggerClick(); + + return overlay.State.Value == Visibility.Hidden; + }); + } + + [Test] + public void TestBackButton() + { + AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); + + AddUntilStep("step to last", () => + { + var nextButton = overlay.NextButton; + + if (overlay.CurrentScreen?.IsLoaded != false) + nextButton.TriggerClick(); + + return nextButton.Text.ToString() == "Finish"; + }); + + AddUntilStep("step back to start", () => + { + if (overlay.CurrentScreen?.IsLoaded != false) + overlay.BackButton.TriggerClick(); + + return overlay.CurrentScreen is ScreenWelcome; + }); + + AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); + } + + [Test] + public void TestClickAwayToExit() + { + AddStep("click inside content", () => + { + InputManager.MoveMouseTo(overlay.ScreenSpaceDrawQuad.Centre); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("overlay not dismissed", () => overlay.State.Value == Visibility.Visible); + + AddStep("click outside content", () => + { + InputManager.MoveMouseTo(overlay.ScreenSpaceDrawQuad.TopLeft - new Vector2(1)); + InputManager.Click(MouseButton.Left); + }); + + AddAssert("overlay dismissed", () => overlay.State.Value == Visibility.Hidden); + } + } +} diff --git a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs index 5cf3d562a98a..2d025d46ef1e 100644 --- a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs +++ b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs @@ -1,26 +1,21 @@ // 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.Input.Events; using osu.Framework.Screens; namespace osu.Game.Overlays.FirstRunSetup { public abstract class FirstRunSetupScreen : Screen { - [Resolved] - protected FirstRunSetupOverlay Overlay { get; private set; } - - protected override bool OnClick(ClickEvent e) => true; + private const float offset = 100; public override void OnEntering(IScreen last) { base.OnEntering(last); this .FadeInFromZero(500) - .MoveToX(100) + .MoveToX(offset) .MoveToX(0, 500, Easing.OutQuint); } @@ -32,12 +27,22 @@ public override void OnResuming(IScreen last) .MoveToX(0, 500, Easing.OutQuint); } + public override bool OnExiting(IScreen next) + { + this + .FadeOut(100) + .MoveToX(offset, 500, Easing.OutQuint); + + return base.OnExiting(next); + } + public override void OnSuspending(IScreen next) { - base.OnSuspending(next); this .FadeOut(100) - .MoveToX(-100, 500, Easing.OutQuint); + .MoveToX(-offset, 500, Easing.OutQuint); + + base.OnSuspending(next); } } } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs deleted file mode 100644 index 1a8ef0338c7e..000000000000 --- a/osu.Game/Overlays/FirstRunSetup/ScreenSetupUIScale.cs +++ /dev/null @@ -1,114 +0,0 @@ -// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. -// See the LICENCE file in the repository root for full licence text. - -using osu.Framework.Allocation; -using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; -using osu.Framework.Localisation; -using osu.Game.Configuration; -using osu.Game.Graphics; -using osu.Game.Graphics.Containers; -using osu.Game.Graphics.UserInterface; -using osu.Game.Localisation; -using osu.Game.Overlays.Settings; -using osu.Game.Screens; -using osu.Game.Screens.Menu; -using osu.Game.Screens.OnlinePlay.Match.Components; -using osu.Game.Screens.Select; -using osuTK; - -namespace osu.Game.Overlays.FirstRunSetup -{ - public class ScreenSetupUIScale : FirstRunSetupScreen - { - [Resolved] - private OsuConfigManager osuConfig { get; set; } - - [Cached] - private OsuLogo osuLogo = new OsuLogo(); - - [BackgroundDependencyLoader] - private void load() - { - OsuScreenStack stack; - Content.Children = new Drawable[] - { - new FillFlowContainer - { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Spacing = new Vector2(20), - Children = new Drawable[] - { - new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 32)) - { - Text = "The osu! user interface size can be adjusted to your liking.", - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - new SettingsSlider - { - LabelText = GraphicsSettingsStrings.UIScaling, - TransferValueOnCommit = true, - Current = osuConfig.GetBindable(OsuSetting.UIScale), - KeyboardStep = 0.01f, - }, - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new ScalingContainer(ScalingMode.Off) - { - Masking = true, - RelativeSizeAxes = Axes.Both, - Child = stack = new OsuScreenStack() - }, - new ScalingContainer(ScalingMode.Off) - { - Masking = true, - RelativeSizeAxes = Axes.Both, - Child = stack = new OsuScreenStack() - } - }, - new Drawable[] - { - new ScalingContainer(ScalingMode.Off) - { - Masking = true, - RelativeSizeAxes = Axes.Both, - Child = stack = new OsuScreenStack() - }, - new ScalingContainer(ScalingMode.Off) - { - Masking = true, - RelativeSizeAxes = Axes.Both, - Child = stack = new OsuScreenStack() - } - } - } - } - } - }, - new PurpleTriangleButton - { - Anchor = Anchor.BottomCentre, - Origin = Anchor.BottomCentre, - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding(10), - Text = "Finish", - Action = () => Overlay.Hide() - } - }; - - stack.Push(new PlaySongSelect()); - } - - private class UIScaleSlider : OsuSliderBar - { - public override LocalisableString TooltipText => base.TooltipText + "x"; - } - } -} diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs new file mode 100644 index 000000000000..5070856087a8 --- /dev/null +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -0,0 +1,146 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using System; +using osu.Framework.Allocation; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Localisation; +using osu.Framework.Screens; +using osu.Game.Configuration; +using osu.Game.Graphics; +using osu.Game.Graphics.Containers; +using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; +using osu.Game.Overlays.Settings; +using osu.Game.Screens; +using osu.Game.Screens.Menu; +using osu.Game.Screens.Select; +using osu.Game.Tests.Visual; +using osuTK; + +namespace osu.Game.Overlays.FirstRunSetup +{ + public class ScreenUIScale : FirstRunSetupScreen + { + [Resolved] + private OsuConfigManager osuConfig { get; set; } + + [BackgroundDependencyLoader] + private void load() + { + InternalChildren = new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] + { + new Dimension(GridSizeMode.AutoSize), + new Dimension() + }, + Content = new[] + { + new Drawable[] + { + new FillFlowContainer + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Spacing = new Vector2(20), + Children = new Drawable[] + { + new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 24)) + { + Text = "The osu! user interface size can be adjusted to your liking.", + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new SettingsSlider + { + LabelText = GraphicsSettingsStrings.UIScaling, + Current = osuConfig.GetBindable(OsuSetting.UIScale), + KeyboardStep = 0.01f, + }, + } + } + }, + new Drawable[] + { + new GridContainer + { + RelativeSizeAxes = Axes.Both, + Content = new[] + { + new Drawable[] + { + new SampleScreenContainer(new MainMenu()), + new SampleScreenContainer(new PlaySongSelect()), + }, + new Drawable[] + { + new SampleScreenContainer(new MainMenu()), + new SampleScreenContainer(new MainMenu()), + } + } + } + }, + } + } + }; + } + + private class SampleScreenContainer : CompositeDrawable + { + public override bool HandlePositionalInput => false; + public override bool HandleNonPositionalInput => false; + public override bool PropagatePositionalInputSubTree => false; + public override bool PropagateNonPositionalInputSubTree => false; + + public SampleScreenContainer(Screen screen) + { + OsuScreenStack stack; + RelativeSizeAxes = Axes.Both; + + OsuLogo logo; + + InternalChildren = new Drawable[] + { + new DependencyProvidingContainer + { + CachedDependencies = new (Type, object)[] + { + (typeof(OsuLogo), logo = new OsuLogo + { + RelativePositionAxes = Axes.Both, + Position = new Vector2(0.5f), + }) + }, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + new ScalingContainer(ScalingMode.Off) + { + Masking = true, + RelativeSizeAxes = Axes.Both, + Children = new Drawable[] + { + stack = new OsuScreenStack(), + logo + }, + }, + } + }, + }; + + stack.Push(screen); + } + } + + private class UIScaleSlider : OsuSliderBar + { + public override LocalisableString TooltipText => base.TooltipText + "x"; + } + } +} diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 0efeded06273..b391f714377a 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -21,6 +21,7 @@ using osu.Game.Online.API; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.FirstRunSetup; +using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Match.Components; using osuTK; @@ -33,16 +34,17 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer { protected override bool StartHidden => true; - [Resolved(canBeNull: true)] - private DialogOverlay? dialogOverlay { get; set; } + [Resolved] + private IDialogOverlay dialogOverlay { get; set; } = null!; - [Resolved(canBeNull: true)] - private OsuGame? osuGame { get; set; } + [Resolved] + private IPerformFromScreenRunner performer { get; set; } = null!; private ScreenStack stack = null!; public PurpleTriangleButton NextButton = null!; public DangerousTriangleButton BackButton = null!; + private Container mainContent = null!; [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); @@ -57,11 +59,9 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer private readonly FirstRunStep[] steps = { new FirstRunStep(typeof(ScreenWelcome), "Welcome"), - new FirstRunStep(typeof(ScreenSetupUIScale), "UI Scale"), + new FirstRunStep(typeof(ScreenUIScale), "UI Scale"), }; - private Container mainContent; - public FirstRunSetupOverlay() { RelativeSizeAxes = Axes.Both; @@ -91,7 +91,7 @@ private void load(IAPIProvider api, OsuColour colours) new Box { RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background5, + Colour = colourProvider.Background6, }, new GridContainer { @@ -114,7 +114,7 @@ private void load(IAPIProvider api, OsuColour colours) { new Box { - Colour = colourProvider.Background6, + Colour = colourProvider.Background5, RelativeSizeAxes = Axes.Both, }, new FillFlowContainer @@ -214,27 +214,15 @@ protected override void LoadComplete() { base.LoadComplete(); - if (osuGame != null) - { - // if we are valid for display, only do so after reaching the main menu. - osuGame.PerformFromScreen(_ => - { - Show(); - }, new[] { typeof(MainMenu) }); - } - else - { - Show(); - } + // if we are valid for display, only do so after reaching the main menu. + performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); } protected override bool OnClick(ClickEvent e) { - if (!mainContent.IsHovered && dialogOverlay?.CurrentDialog == null) + if (!mainContent.IsHovered && dialogOverlay.CurrentDialog == null) { - dialogOverlay?.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", - Hide, - () => { })); + dialogOverlay.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", Hide, () => { })); } return base.OnClick(e); From 11395c40b7e4586c7c3c1030bc7e36d9e51ac5d3 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 18:58:24 +0900 Subject: [PATCH 09/41] Add button to access first run setup on demand --- osu.Game/Overlays/Settings/Sections/GeneralSection.cs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 87e9f3483375..786db85bbf98 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -1,6 +1,7 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; @@ -11,6 +12,9 @@ namespace osu.Game.Overlays.Settings.Sections { public class GeneralSection : SettingsSection { + [Resolved(CanBeNull = true)] + private FirstRunSetupOverlay firstRunSetupOverlay { get; set; } + public override LocalisableString Header => GeneralSettingsStrings.GeneralSectionHeader; public override Drawable CreateIcon() => new SpriteIcon @@ -22,6 +26,11 @@ public GeneralSection() { Children = new Drawable[] { + new SettingsButton + { + Text = "Run setup wizard", + Action = () => firstRunSetupOverlay?.Show(), + }, new LanguageSettings(), new UpdateSettings(), }; From 671662144443d40ef313773a6674c7c5dc741f73 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:06:13 +0900 Subject: [PATCH 10/41] Re-fix clicking inside display also dismissing --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index b391f714377a..d7fd7ed10444 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -18,7 +18,6 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Online.API; using osu.Game.Overlays.Dialog; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Screens; @@ -68,11 +67,11 @@ public FirstRunSetupOverlay() } [BackgroundDependencyLoader] - private void load(IAPIProvider api, OsuColour colours) + private void load() { Children = new Drawable[] { - mainContent = new Container + mainContent = new BlockingContainer { RelativeSizeAxes = Axes.Both, Anchor = Anchor.Centre, @@ -210,6 +209,11 @@ private void load(IAPIProvider api, OsuColour colours) }; } + private class BlockingContainer : Container + { + protected override bool OnMouseDown(MouseDownEvent e) => true; + } + protected override void LoadComplete() { base.LoadComplete(); @@ -220,10 +224,7 @@ protected override void LoadComplete() protected override bool OnClick(ClickEvent e) { - if (!mainContent.IsHovered && dialogOverlay.CurrentDialog == null) - { - dialogOverlay.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", Hide, () => { })); - } + dialogOverlay.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", Hide, () => { })); return base.OnClick(e); } From fb7dc895036aae174fa77f10189b253eebb6f8a9 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:08:34 +0900 Subject: [PATCH 11/41] Ensure wizard returns to initial screen after completion --- .../UserInterface/TestSceneFirstRunSetupOverlay.cs | 4 ++++ osu.Game/Overlays/FirstRunSetupOverlay.cs | 9 +++++---- 2 files changed, 9 insertions(+), 4 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index d892301a81a5..d22dd260ebb2 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -60,6 +60,10 @@ public void TestOverlayRunsToFinish() return overlay.State.Value == Visibility.Hidden; }); + + AddStep("display again on demand", () => overlay.Show()); + + AddUntilStep("back at start", () => overlay.CurrentScreen is ScreenWelcome); } [Test] diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index d7fd7ed10444..0c800888ee96 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -262,15 +262,16 @@ private void showNextStep() { var nextStep = steps[currentStepIndex.Value]; stack.Push((Screen)Activator.CreateInstance(nextStep.ScreenType)); + + NextButton.Text = currentStepIndex + 1 < steps.Length + ? $"Next ({steps[currentStepIndex.Value + 1].Description})" + : "Finish"; } else { Hide(); + currentStepIndex = null; } - - NextButton.Text = currentStepIndex + 1 < steps.Length - ? $"Next ({steps[currentStepIndex.Value + 1].Description})" - : "Finish"; } protected override void PopOut() From 3ea4eabdb6aba9f384ae376b062a452dcbea3c46 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:18:13 +0900 Subject: [PATCH 12/41] Ensure button text is updated on going backwards --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 0c800888ee96..abde9636baa2 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -246,6 +246,8 @@ private void showLastStep() currentStepIndex--; BackButton.Enabled.Value = currentStepIndex != 0; + + updateButtonText(); } private void showNextStep() @@ -260,12 +262,8 @@ private void showNextStep() if (currentStepIndex < steps.Length) { - var nextStep = steps[currentStepIndex.Value]; - stack.Push((Screen)Activator.CreateInstance(nextStep.ScreenType)); - - NextButton.Text = currentStepIndex + 1 < steps.Length - ? $"Next ({steps[currentStepIndex.Value + 1].Description})" - : "Finish"; + stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value].ScreenType)); + updateButtonText(); } else { @@ -274,6 +272,15 @@ private void showNextStep() } } + private void updateButtonText() + { + Debug.Assert(currentStepIndex != null); + + NextButton.Text = currentStepIndex + 1 < steps.Length + ? $"Next ({steps[currentStepIndex.Value + 1].Description})" + : "Finish"; + } + protected override void PopOut() { base.PopOut(); From 8bfa59d12f6165f7f30cca862264b9d84c73bd41 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:35:09 +0900 Subject: [PATCH 13/41] Ensure all other dialogs and overlays are dismissed when the first run wizard is shown --- osu.Game/OsuGame.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/OsuGame.cs b/osu.Game/OsuGame.cs index 52aa6b8f07c4..7aa488d7a899 100644 --- a/osu.Game/OsuGame.cs +++ b/osu.Game/OsuGame.cs @@ -844,7 +844,7 @@ void updateChatPollRate() Add(new MusicKeyBindingHandler()); // side overlays which cancel each other. - var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications }; + var singleDisplaySideOverlays = new OverlayContainer[] { Settings, Notifications, firstRunOverlay }; foreach (var overlay in singleDisplaySideOverlays) { @@ -869,7 +869,7 @@ void updateChatPollRate() } // ensure only one of these overlays are open at once. - var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, news, dashboard, beatmapListing, changelogOverlay, rankingsOverlay, wikiOverlay }; + var singleDisplayOverlays = new OverlayContainer[] { firstRunOverlay, chatOverlay, news, dashboard, beatmapListing, changelogOverlay, rankingsOverlay, wikiOverlay }; foreach (var overlay in singleDisplayOverlays) { From 9074eb283dd43e2f0f593c26e3cfddd7b81ec22f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:35:51 +0900 Subject: [PATCH 14/41] Show a notification instead of blocking exit of wizard --- .../TestSceneFirstRunSetupOverlay.cs | 6 ------ osu.Game/Overlays/FirstRunSetupOverlay.cs | 21 ++++++++++++------- 2 files changed, 14 insertions(+), 13 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index d22dd260ebb2..3a4dc09e26be 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -10,7 +10,6 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Overlays; -using osu.Game.Overlays.Dialog; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Screens; using osuTK; @@ -23,19 +22,14 @@ public class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene private FirstRunSetupOverlay overlay; private readonly Mock perfomer = new Mock(); - private readonly Mock dialogOverlay = new Mock(); [BackgroundDependencyLoader] private void load() { Dependencies.CacheAs(perfomer.Object); - Dependencies.CacheAs(dialogOverlay.Object); perfomer.Setup(g => g.PerformFromScreen(It.IsAny>(), It.IsAny>())) .Callback((Action action, IEnumerable types) => action(null)); - - dialogOverlay.Setup(d => d.Push(It.IsAny())) - .Callback((PopupDialog dialog) => dialog.PerformOkAction()); } [SetUpSteps] diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index abde9636baa2..b7d7a21493e7 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -222,13 +222,6 @@ protected override void LoadComplete() performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); } - protected override bool OnClick(ClickEvent e) - { - dialogOverlay.Push(new ConfirmDialog("Are you sure you want to exit the setup process?", Hide, () => { })); - - return base.OnClick(e); - } - protected override void PopIn() { base.PopIn(); @@ -283,6 +276,20 @@ private void updateButtonText() protected override void PopOut() { + if (currentStepIndex != null) + { + notificationOverlay?.Post(new SimpleNotification + { + Text = "Click here to resume initial setup at any point", + Icon = FontAwesome.Solid.Horse, + Activated = () => + { + Show(); + return true; + }, + }); + } + base.PopOut(); this.FadeOut(100); } From 2682373bf25102647c142cdecdaf442be1428725 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:36:12 +0900 Subject: [PATCH 15/41] Use existing blocking / exit logic provided by `OsuFocusedOverlayContainer` --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 230 +++++++++++----------- 1 file changed, 115 insertions(+), 115 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index b7d7a21493e7..4a9e8d0efd7c 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -11,15 +11,15 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; -using osu.Framework.Input.Events; +using osu.Framework.Graphics.Sprites; using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; -using osu.Game.Overlays.Dialog; using osu.Game.Overlays.FirstRunSetup; +using osu.Game.Overlays.Notifications; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.OnlinePlay.Match.Components; @@ -33,17 +33,16 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer { protected override bool StartHidden => true; - [Resolved] - private IDialogOverlay dialogOverlay { get; set; } = null!; - [Resolved] private IPerformFromScreenRunner performer { get; set; } = null!; + [Resolved(canBeNull: true)] + private NotificationOverlay notificationOverlay { get; set; } = null!; + private ScreenStack stack = null!; public PurpleTriangleButton NextButton = null!; public DangerousTriangleButton BackButton = null!; - private Container mainContent = null!; [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); @@ -61,6 +60,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer new FirstRunStep(typeof(ScreenUIScale), "UI Scale"), }; + private Container stackContainer = null!; + public FirstRunSetupOverlay() { RelativeSizeAxes = Axes.Both; @@ -69,151 +70,140 @@ public FirstRunSetupOverlay() [BackgroundDependencyLoader] private void load() { + Anchor = Anchor.Centre; + Origin = Anchor.Centre; + + RelativeSizeAxes = Axes.Both; + Size = new Vector2(0.95f); + + EdgeEffect = new EdgeEffectParameters + { + Type = EdgeEffectType.Shadow, + Radius = 5, + Colour = Color4.Black.Opacity(0.2f), + }; + + Masking = true; + CornerRadius = 10; + Children = new Drawable[] { - mainContent = new BlockingContainer + new Box { RelativeSizeAxes = Axes.Both, - Anchor = Anchor.Centre, - Origin = Anchor.Centre, - Size = new Vector2(0.95f), - EdgeEffect = new EdgeEffectParameters + Colour = colourProvider.Background6, + }, + new GridContainer + { + RelativeSizeAxes = Axes.Both, + RowDimensions = new[] { - Type = EdgeEffectType.Shadow, - Radius = 5, - Colour = Color4.Black.Opacity(0.2f), + new Dimension(GridSizeMode.AutoSize), + new Dimension(), + new Dimension(GridSizeMode.AutoSize), }, - Masking = true, - CornerRadius = 10, - Children = new Drawable[] + Content = new[] { - new Box - { - RelativeSizeAxes = Axes.Both, - Colour = colourProvider.Background6, - }, - new GridContainer + new Drawable[] { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] + new Container { - new Dimension(GridSizeMode.AutoSize), - new Dimension(), - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new Drawable[] + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Children = new Drawable[] { - new Container + new Box + { + Colour = colourProvider.Background5, + RelativeSizeAxes = Axes.Both, + }, + new FillFlowContainer { RelativeSizeAxes = Axes.X, + Margin = new MarginPadding(10), AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, Children = new Drawable[] { - new Box + new OsuSpriteText { - Colour = colourProvider.Background5, - RelativeSizeAxes = Axes.Both, + Text = "First run setup", + Font = OsuFont.Default.With(size: 32), + Colour = colourProvider.Content2, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, }, - new FillFlowContainer + new OsuTextFlowContainer { - RelativeSizeAxes = Axes.X, - Margin = new MarginPadding(10), - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new OsuSpriteText - { - Text = "First run setup", - Font = OsuFont.Default.With(size: 32), - Colour = colourProvider.Content2, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - }, - new OsuTextFlowContainer - { - Text = "Setup osu! to suit you", - Colour = colourProvider.Content1, - Anchor = Anchor.TopCentre, - Origin = Anchor.TopCentre, - AutoSizeAxes = Axes.Both, - }, - } + Text = "Setup osu! to suit you", + Colour = colourProvider.Content1, + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, }, } }, - }, - new Drawable[] + } + }, + }, + new Drawable[] + { + stackContainer = new Container + { + RelativeSizeAxes = Axes.Both, + Padding = new MarginPadding(20), + }, + }, + new Drawable[] + { + new Container + { + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Padding = new MarginPadding(20), + Child = new GridContainer { - new Container + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + ColumnDimensions = new[] { - RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding(20), - Child = stack = new ScreenStack - { - RelativeSizeAxes = Axes.Both, - }, + new Dimension(GridSizeMode.AutoSize), + new Dimension(GridSizeMode.Absolute, 10), + new Dimension(), }, - }, - new Drawable[] - { - new Container + RowDimensions = new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(20), - Child = new GridContainer + new Dimension(GridSizeMode.AutoSize), + }, + Content = new[] + { + new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - ColumnDimensions = new[] + BackButton = new DangerousTriangleButton { - new Dimension(GridSizeMode.AutoSize), - new Dimension(GridSizeMode.Absolute, 10), - new Dimension(), + Width = 200, + Text = "Back", + Action = showLastStep, + Enabled = { Value = false }, }, - RowDimensions = new[] + Empty(), + NextButton = new PurpleTriangleButton { - new Dimension(GridSizeMode.AutoSize), - }, - Content = new[] - { - new[] - { - BackButton = new DangerousTriangleButton - { - Width = 200, - Text = "Back", - Action = showLastStep, - Enabled = { Value = false }, - }, - Empty(), - NextButton = new PurpleTriangleButton - { - RelativeSizeAxes = Axes.X, - Width = 1, - Text = "Get started", - Action = showNextStep - } - }, + RelativeSizeAxes = Axes.X, + Width = 1, + Text = "Get started", + Action = showNextStep } }, } - } + }, } - }, + } } - } + }, }; } - private class BlockingContainer : Container - { - protected override bool OnMouseDown(MouseDownEvent e) => true; - } - protected override void LoadComplete() { base.LoadComplete(); @@ -246,7 +236,14 @@ private void showLastStep() private void showNextStep() { if (currentStepIndex == null) + { + stackContainer.Child = stack = new ScreenStack + { + RelativeSizeAxes = Axes.Both, + }; + currentStepIndex = 0; + } else currentStepIndex++; @@ -260,8 +257,11 @@ private void showNextStep() } else { - Hide(); + stack.FadeOut(500); + stack.Expire(); + currentStepIndex = null; + Hide(); } } From 5fd64a4c782cb67e9d88ac9751c4955165553d5f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:41:07 +0900 Subject: [PATCH 16/41] Add test coverage to ensure we don't leave any screens in the first run overlay --- .../Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs | 3 +++ 1 file changed, 3 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index 3a4dc09e26be..dfe7ba025253 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -3,6 +3,7 @@ using System; using System.Collections.Generic; +using System.Linq; using Moq; using NUnit.Framework; using osu.Framework.Allocation; @@ -55,6 +56,8 @@ public void TestOverlayRunsToFinish() return overlay.State.Value == Visibility.Hidden; }); + AddUntilStep("wait for screens removed", () => !overlay.ChildrenOfType().Any()); + AddStep("display again on demand", () => overlay.Show()); AddUntilStep("back at start", () => overlay.CurrentScreen is ScreenWelcome); From 02f8367d66abbd278751092cb06b2f17ca97aabb Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 19:47:47 +0900 Subject: [PATCH 17/41] Improve animation when showing/hiding first run overlay --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 43 ++++++++++++++--------- 1 file changed, 27 insertions(+), 16 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 4a9e8d0efd7c..ee7886561878 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -36,8 +36,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer [Resolved] private IPerformFromScreenRunner performer { get; set; } = null!; - [Resolved(canBeNull: true)] - private NotificationOverlay notificationOverlay { get; set; } = null!; + [Resolved] + private INotificationOverlay notificationOverlay { get; set; } = null!; private ScreenStack stack = null!; @@ -49,6 +49,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer private int? currentStepIndex; + private const float scale_when_hidden = 0.9f; + /// /// The currently displayed screen, if any. /// @@ -212,15 +214,6 @@ protected override void LoadComplete() performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); } - protected override void PopIn() - { - base.PopIn(); - this.FadeIn(400, Easing.OutQuint); - - if (currentStepIndex == null) - showNextStep(); - } - private void showLastStep() { Debug.Assert(currentStepIndex > 0); @@ -257,9 +250,6 @@ private void showNextStep() } else { - stack.FadeOut(500); - stack.Expire(); - currentStepIndex = null; Hide(); } @@ -274,11 +264,24 @@ private void updateButtonText() : "Finish"; } + protected override void PopIn() + { + base.PopIn(); + + this.ScaleTo(scale_when_hidden) + .ScaleTo(1, 400, Easing.OutElasticHalf); + + this.FadeIn(400, Easing.OutQuint); + + if (currentStepIndex == null) + showNextStep(); + } + protected override void PopOut() { if (currentStepIndex != null) { - notificationOverlay?.Post(new SimpleNotification + notificationOverlay.Post(new SimpleNotification { Text = "Click here to resume initial setup at any point", Icon = FontAwesome.Solid.Horse, @@ -289,9 +292,17 @@ protected override void PopOut() }, }); } + else + { + stack? + .FadeOut(100) + .Expire(); + } base.PopOut(); - this.FadeOut(100); + + this.ScaleTo(0.96f, 400, Easing.OutQuint); + this.FadeOut(200, Easing.OutQuint); } private class FirstRunStep From a8d32a20611650c6bf3af729e0cb4c9bcfb79f19 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Mon, 18 Apr 2022 23:37:08 +0900 Subject: [PATCH 18/41] Add test coverage of notification resume flow --- .../TestSceneFirstRunSetupOverlay.cs | 45 ++++++++++++++++--- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index dfe7ba025253..77a37e7420bd 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -12,6 +12,7 @@ using osu.Framework.Testing; using osu.Game.Overlays; using osu.Game.Overlays.FirstRunSetup; +using osu.Game.Overlays.Notifications; using osu.Game.Screens; using osuTK; using osuTK.Input; @@ -22,20 +23,34 @@ public class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene { private FirstRunSetupOverlay overlay; - private readonly Mock perfomer = new Mock(); + private readonly Mock performer = new Mock(); + + private readonly Mock notificationOverlay = new Mock(); + + private Notification lastNotification; [BackgroundDependencyLoader] private void load() { - Dependencies.CacheAs(perfomer.Object); - - perfomer.Setup(g => g.PerformFromScreen(It.IsAny>(), It.IsAny>())) - .Callback((Action action, IEnumerable types) => action(null)); + Dependencies.CacheAs(performer.Object); + Dependencies.CacheAs(notificationOverlay.Object); } [SetUpSteps] public void SetUpSteps() { + AddStep("setup dependencies", () => + { + performer.Reset(); + notificationOverlay.Reset(); + + performer.Setup(g => g.PerformFromScreen(It.IsAny>(), It.IsAny>())) + .Callback((Action action, IEnumerable types) => action(null)); + + notificationOverlay.Setup(n => n.Post(It.IsAny())) + .Callback((Notification n) => lastNotification = n); + }); + AddStep("add overlay", () => { Child = overlay = new FirstRunSetupOverlay @@ -58,6 +73,8 @@ public void TestOverlayRunsToFinish() AddUntilStep("wait for screens removed", () => !overlay.ChildrenOfType().Any()); + AddStep("no notifications", () => notificationOverlay.VerifyNoOtherCalls()); + AddStep("display again on demand", () => overlay.Show()); AddUntilStep("back at start", () => overlay.CurrentScreen is ScreenWelcome); @@ -108,5 +125,23 @@ public void TestClickAwayToExit() AddAssert("overlay dismissed", () => overlay.State.Value == Visibility.Hidden); } + + [Test] + public void TestResumeViaNotification() + { + AddStep("step to next", () => overlay.NextButton.TriggerClick()); + + AddAssert("is at known screen", () => overlay.CurrentScreen is ScreenUIScale); + + AddStep("hide", () => overlay.Hide()); + AddAssert("overlay hidden", () => overlay.State.Value == Visibility.Hidden); + + AddStep("notification arrived", () => notificationOverlay.Verify(n => n.Post(It.IsAny()), Times.Once)); + + AddStep("run notification action", () => lastNotification.Activated()); + + AddAssert("overlay shown", () => overlay.State.Value == Visibility.Visible); + AddAssert("is resumed", () => overlay.CurrentScreen is ScreenUIScale); + } } } From 5dc38050056e4bb524e48af24bb385c65c5c276b Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 13:48:43 +0900 Subject: [PATCH 19/41] Fix `stack` nullability --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index ee7886561878..27ff4aaabfdc 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -39,7 +39,7 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer [Resolved] private INotificationOverlay notificationOverlay { get; set; } = null!; - private ScreenStack stack = null!; + private ScreenStack? stack; public PurpleTriangleButton NextButton = null!; public DangerousTriangleButton BackButton = null!; @@ -54,7 +54,7 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer /// /// The currently displayed screen, if any. /// - public FirstRunSetupScreen? CurrentScreen => (FirstRunSetupScreen?)stack.CurrentScreen; + public FirstRunSetupScreen? CurrentScreen => (FirstRunSetupScreen?)stack?.CurrentScreen; private readonly FirstRunStep[] steps = { @@ -217,6 +217,7 @@ protected override void LoadComplete() private void showLastStep() { Debug.Assert(currentStepIndex > 0); + Debug.Assert(stack != null); stack.CurrentScreen.Exit(); currentStepIndex--; @@ -241,6 +242,8 @@ private void showNextStep() currentStepIndex++; Debug.Assert(currentStepIndex != null); + Debug.Assert(stack != null); + BackButton.Enabled.Value = currentStepIndex > 0; if (currentStepIndex < steps.Length) @@ -294,9 +297,8 @@ protected override void PopOut() } else { - stack? - .FadeOut(100) - .Expire(); + stack?.FadeOut(100) + .Expire(); } base.PopOut(); From e67cc293b8215e57d412165989754071d748f254 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 13:52:55 +0900 Subject: [PATCH 20/41] Add localisation support for all new strings --- osu.Game/Localisation/CommonStrings.cs | 10 ++++ .../FirstRunSetupOverlayStrings.cs | 58 +++++++++++++++++++ .../Localisation/GeneralSettingsStrings.cs | 5 ++ .../Overlays/FirstRunSetup/ScreenUIScale.cs | 2 +- .../Overlays/FirstRunSetup/ScreenWelcome.cs | 4 +- osu.Game/Overlays/FirstRunSetupOverlay.cs | 19 +++--- .../Settings/Sections/GeneralSection.cs | 2 +- 7 files changed, 87 insertions(+), 13 deletions(-) create mode 100644 osu.Game/Localisation/FirstRunSetupOverlayStrings.cs diff --git a/osu.Game/Localisation/CommonStrings.cs b/osu.Game/Localisation/CommonStrings.cs index 3ea337c279b6..05c4d97cccb7 100644 --- a/osu.Game/Localisation/CommonStrings.cs +++ b/osu.Game/Localisation/CommonStrings.cs @@ -19,6 +19,16 @@ public static class CommonStrings /// public static LocalisableString Clear => new TranslatableString(getKey(@"clear"), @"Clear"); + /// + /// "Back" + /// + public static LocalisableString Back => new TranslatableString(getKey(@"back"), @"Back"); + + /// + /// "Finish" + /// + public static LocalisableString Finish => new TranslatableString(getKey(@"finish"), @"Finish"); + /// /// "Enabled" /// diff --git a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs new file mode 100644 index 000000000000..ec2e97d82a9f --- /dev/null +++ b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs @@ -0,0 +1,58 @@ +// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. +// See the LICENCE file in the repository root for full licence text. + +using osu.Framework.Localisation; + +namespace osu.Game.Localisation +{ + public static class FirstRunSetupOverlayStrings + { + private const string prefix = @"osu.Game.Resources.Localisation.FirstRunSetupOverlay"; + + /// + /// "Get started" + /// + public static LocalisableString GetStarted => new TranslatableString(getKey(@"get_started"), @"Get started"); + + /// + /// "Click to resume first-run setup at any point" + /// + public static LocalisableString ClickToResumeFirstRunSetupAtAnyPoint => new TranslatableString(getKey(@"click_to_resume_first_run_setup_at_any_point"), @"Click to resume first-run setup at any point"); + + /// + /// "First-run setup" + /// + public static LocalisableString FirstRunSetup => new TranslatableString(getKey(@"first_run_setup"), @"First-run setup"); + + /// + /// "Setup osu! to suit you" + /// + public static LocalisableString SetupOsuToSuitYou => new TranslatableString(getKey(@"setup_osu_to_suit_you"), @"Setup osu! to suit you"); + + /// + /// "Welcome" + /// + public static LocalisableString Welcome => new TranslatableString(getKey(@"welcome"), @"Welcome"); + + /// + /// "Welcome to the first-run setup guide! + /// + /// osu! is a very configurable game, and diving straight into the settings can sometimes be overwhelming. This guide will help you get the important choices out of the way to ensure a great first experience!" + /// + public static LocalisableString WelcomeDescription => new TranslatableString(getKey(@"welcome_description"), @"Welcome to the first-run setup guide! + +osu! is a very configurable game, and diving straight into the settings can sometimes be overwhelming. This guide will help you get the important choices out of the way to ensure a great first experience!"); + + /// + /// "The size of the osu! user interface size can be adjusted to your liking." + /// + public static LocalisableString UIScaleDescription => new TranslatableString(getKey(@"ui_scale_description"), @"The size of the osu! user interface size can be adjusted to your liking."); + + /// + /// "Next ({0})" + /// + public static LocalisableString Next(LocalisableString nextStepDescription) => new TranslatableString(getKey(@"next"), @"Next ({0})", nextStepDescription); + + private static string getKey(string key) => $@"{prefix}:{key}"; + } +} diff --git a/osu.Game/Localisation/GeneralSettingsStrings.cs b/osu.Game/Localisation/GeneralSettingsStrings.cs index c65e6c77f4e0..2aa91f5245f4 100644 --- a/osu.Game/Localisation/GeneralSettingsStrings.cs +++ b/osu.Game/Localisation/GeneralSettingsStrings.cs @@ -59,6 +59,11 @@ public static class GeneralSettingsStrings /// public static LocalisableString ChangeFolderLocation => new TranslatableString(getKey(@"change_folder_location"), @"Change folder location..."); + /// + /// "Run setup wizard" + /// + public static LocalisableString RunSetupWizard => new TranslatableString(getKey(@"run_setup_wizard"), @"Run setup wizard"); + private static string getKey(string key) => $"{prefix}:{key}"; } } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 5070856087a8..80ff7bdf2544 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -53,7 +53,7 @@ private void load() { new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 24)) { - Text = "The osu! user interface size can be adjusted to your liking.", + Text = FirstRunSetupOverlayStrings.UIScaleDescription, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y }, diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index 879ffdf19836..9f80c80a02d0 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -5,6 +5,7 @@ using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; +using osu.Game.Localisation; namespace osu.Game.Overlays.FirstRunSetup { @@ -22,8 +23,7 @@ public ScreenWelcome() { new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 20)) { - Text = - "Welcome to the first-run setup guide!\n\nosu! is a very configurable game, and diving straight into the settings can sometimes be overwhelming. This guide will help you get the important choices out of the way to ensure a great first experience!", + Text = FirstRunSetupOverlayStrings.WelcomeDescription, RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y }, diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 27ff4aaabfdc..e8829136f034 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -18,6 +18,7 @@ using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Localisation; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Overlays.Notifications; using osu.Game.Screens; @@ -58,8 +59,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer private readonly FirstRunStep[] steps = { - new FirstRunStep(typeof(ScreenWelcome), "Welcome"), - new FirstRunStep(typeof(ScreenUIScale), "UI Scale"), + new FirstRunStep(typeof(ScreenWelcome), FirstRunSetupOverlayStrings.Welcome), + new FirstRunStep(typeof(ScreenUIScale), GraphicsSettingsStrings.UIScaling), }; private Container stackContainer = null!; @@ -129,7 +130,7 @@ private void load() { new OsuSpriteText { - Text = "First run setup", + Text = FirstRunSetupOverlayStrings.FirstRunSetup, Font = OsuFont.Default.With(size: 32), Colour = colourProvider.Content2, Anchor = Anchor.TopCentre, @@ -137,7 +138,7 @@ private void load() }, new OsuTextFlowContainer { - Text = "Setup osu! to suit you", + Text = FirstRunSetupOverlayStrings.SetupOsuToSuitYou, Colour = colourProvider.Content1, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, @@ -184,7 +185,7 @@ private void load() BackButton = new DangerousTriangleButton { Width = 200, - Text = "Back", + Text = CommonStrings.Back, Action = showLastStep, Enabled = { Value = false }, }, @@ -193,7 +194,7 @@ private void load() { RelativeSizeAxes = Axes.X, Width = 1, - Text = "Get started", + Text = FirstRunSetupOverlayStrings.GetStarted, Action = showNextStep } }, @@ -263,8 +264,8 @@ private void updateButtonText() Debug.Assert(currentStepIndex != null); NextButton.Text = currentStepIndex + 1 < steps.Length - ? $"Next ({steps[currentStepIndex.Value + 1].Description})" - : "Finish"; + ? FirstRunSetupOverlayStrings.Next(steps[currentStepIndex.Value + 1].Description) + : CommonStrings.Finish; } protected override void PopIn() @@ -286,7 +287,7 @@ protected override void PopOut() { notificationOverlay.Post(new SimpleNotification { - Text = "Click here to resume initial setup at any point", + Text = FirstRunSetupOverlayStrings.ClickToResumeFirstRunSetupAtAnyPoint, Icon = FontAwesome.Solid.Horse, Activated = () => { diff --git a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs index 786db85bbf98..ced31167287d 100644 --- a/osu.Game/Overlays/Settings/Sections/GeneralSection.cs +++ b/osu.Game/Overlays/Settings/Sections/GeneralSection.cs @@ -28,7 +28,7 @@ public GeneralSection() { new SettingsButton { - Text = "Run setup wizard", + Text = GeneralSettingsStrings.RunSetupWizard, Action = () => firstRunSetupOverlay?.Show(), }, new LanguageSettings(), From 6d534046ff2cedc67315f4d6e10f8f810afab33a Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 14:46:01 +0900 Subject: [PATCH 21/41] Add keyboard traversal support for first run dialog (and tidy up step traversal logic) --- .../TestSceneFirstRunSetupOverlay.cs | 30 ++++- osu.Game/Overlays/FirstRunSetupOverlay.cs | 123 +++++++++++------- 2 files changed, 102 insertions(+), 51 deletions(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index 77a37e7420bd..ff54e34ca0cc 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -60,13 +60,19 @@ public void SetUpSteps() }); } - [Test] - public void TestOverlayRunsToFinish() + [TestCase(false)] + [TestCase(true)] + public void TestOverlayRunsToFinish(bool keyboard) { AddUntilStep("step through", () => { if (overlay.CurrentScreen?.IsLoaded != false) - overlay.NextButton.TriggerClick(); + { + if (keyboard) + InputManager.Key(Key.Enter); + else + overlay.NextButton.TriggerClick(); + } return overlay.State.Value == Visibility.Hidden; }); @@ -80,8 +86,9 @@ public void TestOverlayRunsToFinish() AddUntilStep("back at start", () => overlay.CurrentScreen is ScreenWelcome); } - [Test] - public void TestBackButton() + [TestCase(false)] + [TestCase(true)] + public void TestBackButton(bool keyboard) { AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); @@ -98,12 +105,23 @@ public void TestBackButton() AddUntilStep("step back to start", () => { if (overlay.CurrentScreen?.IsLoaded != false) - overlay.BackButton.TriggerClick(); + { + if (keyboard) + InputManager.Key(Key.Escape); + else + overlay.BackButton.TriggerClick(); + } return overlay.CurrentScreen is ScreenWelcome; }); AddAssert("back button disabled", () => !overlay.BackButton.Enabled.Value); + + if (keyboard) + { + AddStep("exit via keyboard", () => InputManager.Key(Key.Escape)); + AddAssert("overlay dismissed", () => overlay.State.Value == Visibility.Hidden); + } } [Test] diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index e8829136f034..00396e6d851e 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -12,12 +12,14 @@ using osu.Framework.Graphics.Effects; using osu.Framework.Graphics.Shapes; using osu.Framework.Graphics.Sprites; +using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Screens; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; +using osu.Game.Input.Bindings; using osu.Game.Localisation; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Overlays.Notifications; @@ -215,57 +217,30 @@ protected override void LoadComplete() performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); } - private void showLastStep() + public override bool OnPressed(KeyBindingPressEvent e) { - Debug.Assert(currentStepIndex > 0); - Debug.Assert(stack != null); - - stack.CurrentScreen.Exit(); - currentStepIndex--; - - BackButton.Enabled.Value = currentStepIndex != 0; - - updateButtonText(); - } - - private void showNextStep() - { - if (currentStepIndex == null) + if (!e.Repeat) { - stackContainer.Child = stack = new ScreenStack + switch (e.Action) { - RelativeSizeAxes = Axes.Both, - }; - - currentStepIndex = 0; - } - else - currentStepIndex++; - - Debug.Assert(currentStepIndex != null); - Debug.Assert(stack != null); + case GlobalAction.Select: + NextButton.TriggerClick(); + return true; - BackButton.Enabled.Value = currentStepIndex > 0; + case GlobalAction.Back: + if (BackButton.Enabled.Value) + { + BackButton.TriggerClick(); + return true; + } - if (currentStepIndex < steps.Length) - { - stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value].ScreenType)); - updateButtonText(); + // If back button is disabled, we are at the first step. + // The base call will handle dismissal of the overlay. + break; + } } - else - { - currentStepIndex = null; - Hide(); - } - } - private void updateButtonText() - { - Debug.Assert(currentStepIndex != null); - - NextButton.Text = currentStepIndex + 1 < steps.Length - ? FirstRunSetupOverlayStrings.Next(steps[currentStepIndex.Value + 1].Description) - : CommonStrings.Finish; + return base.OnPressed(e); } protected override void PopIn() @@ -278,7 +253,7 @@ protected override void PopIn() this.FadeIn(400, Easing.OutQuint); if (currentStepIndex == null) - showNextStep(); + showFirstStep(); } protected override void PopOut() @@ -308,6 +283,64 @@ protected override void PopOut() this.FadeOut(200, Easing.OutQuint); } + private void showFirstStep() + { + Debug.Assert(currentStepIndex == null); + + stackContainer.Child = stack = new ScreenStack + { + RelativeSizeAxes = Axes.Both, + }; + + currentStepIndex = -1; + showNextStep(); + } + + private void showLastStep() + { + if (currentStepIndex == 0) + return; + + Debug.Assert(stack != null); + + stack.CurrentScreen.Exit(); + currentStepIndex--; + + BackButton.Enabled.Value = currentStepIndex != 0; + + updateButtonText(); + } + + private void showNextStep() + { + Debug.Assert(currentStepIndex != null); + Debug.Assert(stack != null); + + currentStepIndex++; + + BackButton.Enabled.Value = currentStepIndex > 0; + + if (currentStepIndex < steps.Length) + { + stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value].ScreenType)); + updateButtonText(); + } + else + { + currentStepIndex = null; + Hide(); + } + } + + private void updateButtonText() + { + Debug.Assert(currentStepIndex != null); + + NextButton.Text = currentStepIndex + 1 < steps.Length + ? FirstRunSetupOverlayStrings.Next(steps[currentStepIndex.Value + 1].Description) + : CommonStrings.Finish; + } + private class FirstRunStep { public readonly Type ScreenType; From c4bade099574fa36af497f4d8fe8d97493041ee2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 15:46:03 +0900 Subject: [PATCH 22/41] Expose `MainMenu` buttons --- osu.Game/Screens/Menu/ButtonSystem.cs | 14 +++++++++++--- osu.Game/Screens/Menu/MainMenu.cs | 26 +++++++++++++------------- 2 files changed, 24 insertions(+), 16 deletions(-) diff --git a/osu.Game/Screens/Menu/ButtonSystem.cs b/osu.Game/Screens/Menu/ButtonSystem.cs index 598c4410424e..a153eda0c4d4 100644 --- a/osu.Game/Screens/Menu/ButtonSystem.cs +++ b/osu.Game/Screens/Menu/ButtonSystem.cs @@ -88,6 +88,8 @@ public void SetOsuLogo(OsuLogo logo) private readonly LogoTrackingContainer logoTrackingContainer; + public bool ReturnToTopOnIdle { get; set; } = true; + public ButtonSystem() { RelativeSizeAxes = Axes.Both; @@ -101,7 +103,8 @@ public ButtonSystem() buttonArea.AddRange(new Drawable[] { new MainMenuButton(ButtonSystemStrings.Settings, string.Empty, FontAwesome.Solid.Cog, new Color4(85, 85, 85, 255), () => OnSettings?.Invoke(), -WEDGE_WIDTH, Key.O), - backButton = new MainMenuButton(ButtonSystemStrings.Back, @"button-back-select", OsuIcon.LeftCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, -WEDGE_WIDTH) + backButton = new MainMenuButton(ButtonSystemStrings.Back, @"button-back-select", OsuIcon.LeftCircle, new Color4(51, 58, 94, 255), () => State = ButtonSystemState.TopLevel, + -WEDGE_WIDTH) { VisibleState = ButtonSystemState.Play, }, @@ -131,9 +134,11 @@ private void load(AudioManager audio, IdleTracker idleTracker, GameHost host) buttonsPlay.Add(new MainMenuButton(ButtonSystemStrings.Playlists, @"button-generic-select", OsuIcon.Charts, new Color4(94, 63, 186, 255), onPlaylists, 0, Key.L)); buttonsPlay.ForEach(b => b.VisibleState = ButtonSystemState.Play); - buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Play, @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, Key.P)); + buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Play, @"button-play-select", OsuIcon.Logo, new Color4(102, 68, 204, 255), () => State = ButtonSystemState.Play, WEDGE_WIDTH, + Key.P)); buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Edit, @"button-edit-select", OsuIcon.EditCircle, new Color4(238, 170, 0, 255), () => OnEdit?.Invoke(), 0, Key.E)); - buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Browse, @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, Key.D)); + buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Browse, @"button-direct-select", OsuIcon.ChevronDownCircle, new Color4(165, 204, 0, 255), () => OnBeatmapListing?.Invoke(), 0, + Key.D)); if (host.CanExit) buttonsTopLevel.Add(new MainMenuButton(ButtonSystemStrings.Exit, string.Empty, OsuIcon.CrossCircle, new Color4(238, 51, 153, 255), () => OnExit?.Invoke(), 0, Key.Q)); @@ -201,6 +206,9 @@ private void onPlaylists() private void updateIdleState(bool isIdle) { + if (!ReturnToTopOnIdle) + return; + if (isIdle && State != ButtonSystemState.Exit && State != ButtonSystemState.EnteringMode) State = ButtonSystemState.Initial; } diff --git a/osu.Game/Screens/Menu/MainMenu.cs b/osu.Game/Screens/Menu/MainMenu.cs index 08df06816b9c..422508b60e37 100644 --- a/osu.Game/Screens/Menu/MainMenu.cs +++ b/osu.Game/Screens/Menu/MainMenu.cs @@ -35,7 +35,7 @@ public class MainMenu : OsuScreen, IHandlePresentBeatmap, IKeyBindingHandler buttons == null || buttons.State == ButtonSystemState.Initial; + public override bool HideOverlaysOnEnter => Buttons == null || Buttons.State == ButtonSystemState.Initial; public override bool AllowBackButton => false; @@ -45,7 +45,7 @@ public class MainMenu : OsuScreen, IHandlePresentBeatmap, IKeyBindingHandler + Buttons.StateChanged += state => { switch (state) { @@ -140,8 +140,8 @@ private void load(BeatmapListingOverlay beatmapListing, SettingsOverlay settings } }; - buttons.OnSettings = () => settings?.ToggleVisibility(); - buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility(); + Buttons.OnSettings = () => settings?.ToggleVisibility(); + Buttons.OnBeatmapListing = () => beatmapListing?.ToggleVisibility(); LoadComponentAsync(background = new BackgroundScreenDefault()); preloadSongSelect(); @@ -179,7 +179,7 @@ private Screen consumeSongSelect() public override void OnEntering(IScreen last) { base.OnEntering(last); - buttons.FadeInFromZero(500); + Buttons.FadeInFromZero(500); if (last is IntroScreen && musicController.TrackLoaded) { @@ -203,14 +203,14 @@ protected override void LogoArriving(OsuLogo logo, bool resuming) { base.LogoArriving(logo, resuming); - buttons.SetOsuLogo(logo); + Buttons.SetOsuLogo(logo); logo.FadeColour(Color4.White, 100, Easing.OutQuint); logo.FadeIn(100, Easing.OutQuint); if (resuming) { - buttons.State = ButtonSystemState.TopLevel; + Buttons.State = ButtonSystemState.TopLevel; this.FadeIn(FADE_IN_DURATION, Easing.OutQuint); buttonsContainer.MoveTo(new Vector2(0, 0), FADE_IN_DURATION, Easing.OutQuint); @@ -245,15 +245,15 @@ protected override void LogoSuspending(OsuLogo logo) var seq = logo.FadeOut(300, Easing.InSine) .ScaleTo(0.2f, 300, Easing.InSine); - seq.OnComplete(_ => buttons.SetOsuLogo(null)); - seq.OnAbort(_ => buttons.SetOsuLogo(null)); + seq.OnComplete(_ => Buttons.SetOsuLogo(null)); + seq.OnAbort(_ => Buttons.SetOsuLogo(null)); } public override void OnSuspending(IScreen next) { base.OnSuspending(next); - buttons.State = ButtonSystemState.EnteringMode; + Buttons.State = ButtonSystemState.EnteringMode; this.FadeOut(FADE_OUT_DURATION, Easing.InSine); buttonsContainer.MoveTo(new Vector2(-800, 0), FADE_OUT_DURATION, Easing.InSine); @@ -285,7 +285,7 @@ public override bool OnExiting(IScreen next) return true; } - buttons.State = ButtonSystemState.Exit; + Buttons.State = ButtonSystemState.Exit; OverlayActivationMode.Value = OverlayActivation.Disabled; songTicker.Hide(); From c27831145ccd47975d0ba862d0b11408fe9c5368 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 16:37:29 +0900 Subject: [PATCH 23/41] Add scroll and flow at the `FirstRunSetupScreen` level --- .../FirstRunSetup/FirstRunSetupScreen.cs | 23 +++++++++++++++++++ .../Overlays/FirstRunSetup/ScreenWelcome.cs | 19 ++++----------- 2 files changed, 28 insertions(+), 14 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs index 2d025d46ef1e..b2284a999d4e 100644 --- a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs +++ b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs @@ -2,7 +2,10 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; using osu.Framework.Screens; +using osu.Game.Graphics.Containers; +using osuTK; namespace osu.Game.Overlays.FirstRunSetup { @@ -10,6 +13,26 @@ public abstract class FirstRunSetupScreen : Screen { private const float offset = 100; + protected FillFlowContainer Content { get; private set; } + + protected FirstRunSetupScreen() + { + InternalChildren = new Drawable[] + { + new OsuScrollContainer(Direction.Vertical) + { + RelativeSizeAxes = Axes.Both, + Child = Content = new FillFlowContainer + { + Spacing = new Vector2(20), + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + }, + } + }; + } + public override void OnEntering(IScreen last) { base.OnEntering(last); diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs index 9f80c80a02d0..39da180f4057 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenWelcome.cs @@ -2,7 +2,6 @@ // See the LICENCE file in the repository root for full licence text. using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Localisation; @@ -13,21 +12,13 @@ public class ScreenWelcome : FirstRunSetupScreen { public ScreenWelcome() { - InternalChildren = new Drawable[] + Content.Children = new Drawable[] { - new FillFlowContainer + new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 20)) { - RelativeSizeAxes = Axes.Both, - Direction = FillDirection.Vertical, - Children = new Drawable[] - { - new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 20)) - { - Text = FirstRunSetupOverlayStrings.WelcomeDescription, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - } + Text = FirstRunSetupOverlayStrings.WelcomeDescription, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y }, }; } From 1490502d4ccc84472f34e23e04e91e04b001f7b4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 16:37:38 +0900 Subject: [PATCH 24/41] Improve overall usability of scale adjust screen --- .../Graphics/Containers/ScalingContainer.cs | 10 +- .../Overlays/FirstRunSetup/ScreenUIScale.cs | 153 +++++++++++------- 2 files changed, 101 insertions(+), 62 deletions(-) diff --git a/osu.Game/Graphics/Containers/ScalingContainer.cs b/osu.Game/Graphics/Containers/ScalingContainer.cs index ca8b6f388f0a..6589de40b7b3 100644 --- a/osu.Game/Graphics/Containers/ScalingContainer.cs +++ b/osu.Game/Graphics/Containers/ScalingContainer.cs @@ -79,12 +79,12 @@ public ScalingContainer(ScalingMode? targetMode = null) }; } - private class ScalingDrawSizePreservingFillContainer : DrawSizePreservingFillContainer + public class ScalingDrawSizePreservingFillContainer : DrawSizePreservingFillContainer { private readonly bool applyUIScale; private Bindable uiScale; - private float currentScale = 1; + protected float CurrentScale { get; private set; } = 1; public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => true; @@ -99,14 +99,14 @@ private void load(OsuConfigManager osuConfig) if (applyUIScale) { uiScale = osuConfig.GetBindable(OsuSetting.UIScale); - uiScale.BindValueChanged(args => this.TransformTo(nameof(currentScale), args.NewValue, duration, Easing.OutQuart), true); + uiScale.BindValueChanged(args => this.TransformTo(nameof(CurrentScale), args.NewValue, duration, Easing.OutQuart), true); } } protected override void Update() { - Scale = new Vector2(currentScale); - Size = new Vector2(1 / currentScale); + Scale = new Vector2(CurrentScale); + Size = new Vector2(1 / CurrentScale); base.Update(); } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 80ff7bdf2544..52aeb8082e1e 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -2,17 +2,23 @@ // See the LICENCE file in the repository root for full licence text. using System; +using System.Linq; using osu.Framework.Allocation; +using osu.Framework.Audio; +using osu.Framework.Bindables; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Textures; using osu.Framework.Localisation; using osu.Framework.Screens; +using osu.Game.Beatmaps; using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.UserInterface; using osu.Game.Localisation; using osu.Game.Overlays.Settings; +using osu.Game.Rulesets; using osu.Game.Screens; using osu.Game.Screens.Menu; using osu.Game.Screens.Select; @@ -27,77 +33,113 @@ public class ScreenUIScale : FirstRunSetupScreen private OsuConfigManager osuConfig { get; set; } [BackgroundDependencyLoader] - private void load() + private void load(RulesetStore rulesets, BeatmapManager beatmaps) { - InternalChildren = new Drawable[] + Content.Children = new Drawable[] { - new GridContainer + new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 24)) { - RelativeSizeAxes = Axes.Both, - RowDimensions = new[] - { - new Dimension(GridSizeMode.AutoSize), - new Dimension() - }, - Content = new[] + Text = FirstRunSetupOverlayStrings.UIScaleDescription, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y + }, + new SettingsSlider + { + LabelText = GraphicsSettingsStrings.UIScaling, + Current = osuConfig.GetBindable(OsuSetting.UIScale), + KeyboardStep = 0.01f, + }, + new InverseScalingDrawSizePreservingFillContainer + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + RelativeSizeAxes = Axes.None, + Size = new Vector2(960, 960 / 16f * 9 / 2), + Children = new Drawable[] { - new Drawable[] + new GridContainer { - new FillFlowContainer + RelativeSizeAxes = Axes.Both, + Content = new[] { - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y, - Direction = FillDirection.Vertical, - Spacing = new Vector2(20), - Children = new Drawable[] + new Drawable[] { - new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: 24)) - { - Text = FirstRunSetupOverlayStrings.UIScaleDescription, - RelativeSizeAxes = Axes.X, - AutoSizeAxes = Axes.Y - }, - new SettingsSlider - { - LabelText = GraphicsSettingsStrings.UIScaling, - Current = osuConfig.GetBindable(OsuSetting.UIScale), - KeyboardStep = 0.01f, - }, - } - } - }, - new Drawable[] - { - new GridContainer - { - RelativeSizeAxes = Axes.Both, - Content = new[] - { - new Drawable[] - { - new SampleScreenContainer(new MainMenu()), - new SampleScreenContainer(new PlaySongSelect()), - }, - new Drawable[] - { - new SampleScreenContainer(new MainMenu()), - new SampleScreenContainer(new MainMenu()), - } - } + new SampleScreenContainer(new PinnedMainMenu()), + new SampleScreenContainer(new PlaySongSelect()), + }, + // TODO: add more screens here in the future (gameplay / results) + // requires a bit more consideration to isolate their behaviour from the "parent" game. } - }, + } } } }; } + private class InverseScalingDrawSizePreservingFillContainer : ScalingContainer.ScalingDrawSizePreservingFillContainer + { + private Vector2 initialSize; + + public InverseScalingDrawSizePreservingFillContainer() + : base(true) + { + } + + protected override void LoadComplete() + { + base.LoadComplete(); + + initialSize = Size; + } + + protected override void Update() + { + Size = initialSize / CurrentScale; + } + } + + private class PinnedMainMenu : MainMenu + { + public override void OnEntering(IScreen last) + { + base.OnEntering(last); + + Buttons.ReturnToTopOnIdle = false; + Buttons.State = ButtonSystemState.TopLevel; + } + } + + private class UIScaleSlider : OsuSliderBar + { + public override LocalisableString TooltipText => base.TooltipText + "x"; + } + private class SampleScreenContainer : CompositeDrawable { + // Minimal isolation from main game. + + [Cached] + [Cached(typeof(IBindable))] + protected readonly Bindable Ruleset = new Bindable(); + + [Cached] + [Cached(typeof(IBindable))] + protected Bindable Beatmap { get; private set; } = new Bindable(); + public override bool HandlePositionalInput => false; public override bool HandleNonPositionalInput => false; public override bool PropagatePositionalInputSubTree => false; public override bool PropagateNonPositionalInputSubTree => false; + [BackgroundDependencyLoader] + private void load(AudioManager audio, TextureStore textures, RulesetStore rulesets) + { + Beatmap.Value = new DummyWorkingBeatmap(audio, textures); + Beatmap.Value.LoadTrack(); + + Ruleset.Value = rulesets.AvailableRulesets.First(); + } + public SampleScreenContainer(Screen screen) { OsuScreenStack stack; @@ -105,6 +147,8 @@ public SampleScreenContainer(Screen screen) OsuLogo logo; + Padding = new MarginPadding(5); + InternalChildren = new Drawable[] { new DependencyProvidingContainer @@ -120,7 +164,7 @@ public SampleScreenContainer(Screen screen) RelativeSizeAxes = Axes.Both, Children = new Drawable[] { - new ScalingContainer(ScalingMode.Off) + new ScalingContainer.ScalingDrawSizePreservingFillContainer(true) { Masking = true, RelativeSizeAxes = Axes.Both, @@ -137,10 +181,5 @@ public SampleScreenContainer(Screen screen) stack.Push(screen); } } - - private class UIScaleSlider : OsuSliderBar - { - public override LocalisableString TooltipText => base.TooltipText + "x"; - } } } From 3378c919013f67690a168fddd79d07d9baf2078c Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 16:53:41 +0900 Subject: [PATCH 25/41] Fix double applied padding --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 00396e6d851e..1411539b374d 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -165,7 +165,10 @@ private void load() { RelativeSizeAxes = Axes.X, AutoSizeAxes = Axes.Y, - Padding = new MarginPadding(20), + Padding = new MarginPadding(20) + { + Top = 0 // provided by the stack container above. + }, Child = new GridContainer { RelativeSizeAxes = Axes.X, From e2da1d76ca34999f4e3d45531b65ea8795838299 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 16:59:25 +0900 Subject: [PATCH 26/41] Only show first run setup once per install --- osu.Game/Configuration/OsuConfigManager.cs | 3 +++ osu.Game/Overlays/FirstRunSetupOverlay.cs | 17 +++++++++++++++-- 2 files changed, 18 insertions(+), 2 deletions(-) diff --git a/osu.Game/Configuration/OsuConfigManager.cs b/osu.Game/Configuration/OsuConfigManager.cs index 9aacb5068430..2c04b0364628 100644 --- a/osu.Game/Configuration/OsuConfigManager.cs +++ b/osu.Game/Configuration/OsuConfigManager.cs @@ -134,6 +134,8 @@ protected override void InitialiseDefaults() SetDefault(OsuSetting.Version, string.Empty); + SetDefault(OsuSetting.ShowFirstRunSetup, true); + SetDefault(OsuSetting.ScreenshotFormat, ScreenshotFormat.Jpg); SetDefault(OsuSetting.ScreenshotCaptureMenuCursor, false); @@ -308,6 +310,7 @@ public enum OsuSetting BeatmapListingCardSize, ToolbarClockDisplayMode, Version, + ShowFirstRunSetup, ShowConvertedBeatmaps, Skin, ScreenshotFormat, diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 1411539b374d..207eeb0f6e0b 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -6,6 +6,7 @@ using System; using System.Diagnostics; using osu.Framework.Allocation; +using osu.Framework.Bindables; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -15,6 +16,7 @@ using osu.Framework.Input.Events; using osu.Framework.Localisation; using osu.Framework.Screens; +using osu.Game.Configuration; using osu.Game.Graphics; using osu.Game.Graphics.Containers; using osu.Game.Graphics.Sprites; @@ -42,6 +44,9 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer [Resolved] private INotificationOverlay notificationOverlay { get; set; } = null!; + [Resolved] + private OsuConfigManager config { get; set; } = null!; + private ScreenStack? stack; public PurpleTriangleButton NextButton = null!; @@ -50,6 +55,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer [Cached] private OverlayColourProvider colourProvider = new OverlayColourProvider(OverlayColourScheme.Purple); + private readonly Bindable showFirstRunSetup = new Bindable(); + private int? currentStepIndex; private const float scale_when_hidden = 0.9f; @@ -216,8 +223,13 @@ protected override void LoadComplete() { base.LoadComplete(); - // if we are valid for display, only do so after reaching the main menu. - performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); + config.BindWith(OsuSetting.ShowFirstRunSetup, showFirstRunSetup); + + if (showFirstRunSetup.Value) + { + // if we are valid for display, only do so after reaching the main menu. + performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); + } } public override bool OnPressed(KeyBindingPressEvent e) @@ -330,6 +342,7 @@ private void showNextStep() } else { + showFirstRunSetup.Value = false; currentStepIndex = null; Hide(); } From c562004fe9784065fddc14fe56950148ed50eca2 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 17:08:38 +0900 Subject: [PATCH 27/41] Add test coverage of only showing on first run --- .../TestSceneFirstRunSetupOverlay.cs | 27 +++++++++++++++++++ 1 file changed, 27 insertions(+) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index ff54e34ca0cc..00f1d4ac4e70 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers; using osu.Framework.Screens; using osu.Framework.Testing; +using osu.Game.Configuration; using osu.Game.Overlays; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Overlays.Notifications; @@ -29,9 +30,12 @@ public class TestSceneFirstRunSetupOverlay : OsuManualInputManagerTestScene private Notification lastNotification; + protected OsuConfigManager LocalConfig; + [BackgroundDependencyLoader] private void load() { + Dependencies.Cache(LocalConfig = new OsuConfigManager(LocalStorage)); Dependencies.CacheAs(performer.Object); Dependencies.CacheAs(notificationOverlay.Object); } @@ -60,6 +64,29 @@ public void SetUpSteps() }); } + [Test] + public void TestDoesntOpenOnSecondRun() + { + AddStep("set first run", () => LocalConfig.SetValue(OsuSetting.ShowFirstRunSetup, true)); + + AddUntilStep("step through", () => + { + if (overlay.CurrentScreen?.IsLoaded != false) overlay.NextButton.TriggerClick(); + return overlay.State.Value == Visibility.Hidden; + }); + + AddAssert("first run false", () => !LocalConfig.Get(OsuSetting.ShowFirstRunSetup)); + + AddStep("add overlay", () => + { + Child = overlay = new FirstRunSetupOverlay(); + }); + + AddWaitStep("wait some", 5); + + AddAssert("overlay didn't show", () => overlay.State.Value == Visibility.Hidden); + } + [TestCase(false)] [TestCase(true)] public void TestOverlayRunsToFinish(bool keyboard) From 17eaa44af1c773d581a8a54455ef505fbf000b4f Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 17:40:35 +0900 Subject: [PATCH 28/41] Ensure notifications don't interrupt the first run setup process --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 35 +++++++++++++++++++---- osu.Game/Screens/OsuScreen.cs | 2 +- 2 files changed, 31 insertions(+), 6 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 207eeb0f6e0b..b118e61fba5f 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -74,6 +74,8 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer private Container stackContainer = null!; + private Bindable? overlayActivationMode; + public FirstRunSetupOverlay() { RelativeSizeAxes = Axes.Both; @@ -225,11 +227,7 @@ protected override void LoadComplete() config.BindWith(OsuSetting.ShowFirstRunSetup, showFirstRunSetup); - if (showFirstRunSetup.Value) - { - // if we are valid for display, only do so after reaching the main menu. - performer.PerformFromScreen(_ => { Show(); }, new[] { typeof(MainMenu) }); - } + if (showFirstRunSetup.Value) Show(); } public override bool OnPressed(KeyBindingPressEvent e) @@ -258,6 +256,26 @@ public override bool OnPressed(KeyBindingPressEvent e) return base.OnPressed(e); } + public override void Show() + { + // if we are valid for display, only do so after reaching the main menu. + performer.PerformFromScreen(screen => + { + MainMenu menu = (MainMenu)screen; + + // Eventually I'd like to replace this with a better method that doesn't access the screen. + // Either this dialog would be converted to its own screen, or at very least be "hosted" by a screen pushed to the main menu. + // Alternatively, another method of disabling notifications could be added to `INotificationOverlay`. + if (menu != null) + { + overlayActivationMode = menu.OverlayActivationMode.GetBoundCopy(); + overlayActivationMode.Value = OverlayActivation.UserTriggered; + } + + base.Show(); + }, new[] { typeof(MainMenu) }); + } + protected override void PopIn() { base.PopIn(); @@ -273,6 +291,13 @@ protected override void PopIn() protected override void PopOut() { + if (overlayActivationMode != null) + { + // If this is non-null we are guaranteed to have come from the main menu. + overlayActivationMode.Value = OverlayActivation.All; + overlayActivationMode = null; + } + if (currentStepIndex != null) { notificationOverlay.Post(new SimpleNotification diff --git a/osu.Game/Screens/OsuScreen.cs b/osu.Game/Screens/OsuScreen.cs index ed4901e1fa9b..d87a86cedf99 100644 --- a/osu.Game/Screens/OsuScreen.cs +++ b/osu.Game/Screens/OsuScreen.cs @@ -48,7 +48,7 @@ public abstract class OsuScreen : Screen, IOsuScreen, IHasDescription /// protected virtual OverlayActivation InitialOverlayActivationMode => OverlayActivation.All; - protected readonly Bindable OverlayActivationMode; + public readonly Bindable OverlayActivationMode; IBindable IOsuScreen.OverlayActivationMode => OverlayActivationMode; From ce70c10afae4bc91f6cb751f8b59fd46c0488689 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 18:00:39 +0900 Subject: [PATCH 29/41] Tidy up unused dependencies --- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 7 ++----- 1 file changed, 2 insertions(+), 5 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index 52aeb8082e1e..e63217097568 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -29,11 +29,8 @@ namespace osu.Game.Overlays.FirstRunSetup { public class ScreenUIScale : FirstRunSetupScreen { - [Resolved] - private OsuConfigManager osuConfig { get; set; } - [BackgroundDependencyLoader] - private void load(RulesetStore rulesets, BeatmapManager beatmaps) + private void load(OsuConfigManager config) { Content.Children = new Drawable[] { @@ -46,7 +43,7 @@ private void load(RulesetStore rulesets, BeatmapManager beatmaps) new SettingsSlider { LabelText = GraphicsSettingsStrings.UIScaling, - Current = osuConfig.GetBindable(OsuSetting.UIScale), + Current = config.GetBindable(OsuSetting.UIScale), KeyboardStep = 0.01f, }, new InverseScalingDrawSizePreservingFillContainer From e8adbb319bd1a4d6eb6c16218cda13870a8dcdd4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Tue, 19 Apr 2022 22:57:04 +0900 Subject: [PATCH 30/41] Skip first run setup in `OsuGameTestScene`s --- osu.Game/Tests/Visual/OsuGameTestScene.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/osu.Game/Tests/Visual/OsuGameTestScene.cs b/osu.Game/Tests/Visual/OsuGameTestScene.cs index 34d7723fa356..7a6f8c8cfb55 100644 --- a/osu.Game/Tests/Visual/OsuGameTestScene.cs +++ b/osu.Game/Tests/Visual/OsuGameTestScene.cs @@ -156,6 +156,7 @@ protected override void LoadComplete() base.LoadComplete(); LocalConfig.SetValue(OsuSetting.IntroSequence, IntroSequence.Circles); + LocalConfig.SetValue(OsuSetting.ShowFirstRunSetup, false); API.Login("Rhythm Champion", "osu!"); From 488fc9db67b82baebdc59f71477569960580c439 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 14:48:51 +0900 Subject: [PATCH 31/41] Reverse content colours to match design spec --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index b118e61fba5f..7ad7e6f77059 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -143,14 +143,14 @@ private void load() { Text = FirstRunSetupOverlayStrings.FirstRunSetup, Font = OsuFont.Default.With(size: 32), - Colour = colourProvider.Content2, + Colour = colourProvider.Content1, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, }, new OsuTextFlowContainer { Text = FirstRunSetupOverlayStrings.SetupOsuToSuitYou, - Colour = colourProvider.Content1, + Colour = colourProvider.Content2, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, AutoSizeAxes = Axes.Both, From 9797e2d8871682f9a036a625e5230f324788ec52 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 14:49:17 +0900 Subject: [PATCH 32/41] Rename `showLastStep` method to avoid ambiguity --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 7ad7e6f77059..0e8919fd822b 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -200,7 +200,7 @@ private void load() { Width = 200, Text = CommonStrings.Back, - Action = showLastStep, + Action = showPreviousStep, Enabled = { Value = false }, }, Empty(), @@ -336,7 +336,7 @@ private void showFirstStep() showNextStep(); } - private void showLastStep() + private void showPreviousStep() { if (currentStepIndex == 0) return; From 66373bf038f01e1ff5b26bdc134530db504ff6c4 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 14:50:41 +0900 Subject: [PATCH 33/41] Move back button enable handling to shared method --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index 0e8919fd822b..c74adbabaeb3 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -346,8 +346,6 @@ private void showPreviousStep() stack.CurrentScreen.Exit(); currentStepIndex--; - BackButton.Enabled.Value = currentStepIndex != 0; - updateButtonText(); } @@ -358,8 +356,6 @@ private void showNextStep() currentStepIndex++; - BackButton.Enabled.Value = currentStepIndex > 0; - if (currentStepIndex < steps.Length) { stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value].ScreenType)); @@ -377,6 +373,8 @@ private void updateButtonText() { Debug.Assert(currentStepIndex != null); + BackButton.Enabled.Value = currentStepIndex != 0; + NextButton.Text = currentStepIndex + 1 < steps.Length ? FirstRunSetupOverlayStrings.Next(steps[currentStepIndex.Value + 1].Description) : CommonStrings.Finish; From 7e7fa633f0b2fdde41d9a22c4ce052cb46762201 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 14:51:16 +0900 Subject: [PATCH 34/41] Use direct localised string reference in test --- .../Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index 00f1d4ac4e70..8a9ed50725b8 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -11,6 +11,7 @@ using osu.Framework.Screens; using osu.Framework.Testing; using osu.Game.Configuration; +using osu.Game.Localisation; using osu.Game.Overlays; using osu.Game.Overlays.FirstRunSetup; using osu.Game.Overlays.Notifications; @@ -126,7 +127,7 @@ public void TestBackButton(bool keyboard) if (overlay.CurrentScreen?.IsLoaded != false) nextButton.TriggerClick(); - return nextButton.Text.ToString() == "Finish"; + return nextButton.Text.ToString() == CommonStrings.Finish; }); AddUntilStep("step back to start", () => From 8c2d70e93fb01036538638dc50f399cc0bffa023 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 17:50:31 +0900 Subject: [PATCH 35/41] Disable forward button when already at end --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 21 ++++++++++++--------- 1 file changed, 12 insertions(+), 9 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index c74adbabaeb3..d5aa1178e075 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -346,7 +346,7 @@ private void showPreviousStep() stack.CurrentScreen.Exit(); currentStepIndex--; - updateButtonText(); + updateButtons(); } private void showNextStep() @@ -359,7 +359,6 @@ private void showNextStep() if (currentStepIndex < steps.Length) { stack.Push((Screen)Activator.CreateInstance(steps[currentStepIndex.Value].ScreenType)); - updateButtonText(); } else { @@ -367,17 +366,21 @@ private void showNextStep() currentStepIndex = null; Hide(); } + + updateButtons(); } - private void updateButtonText() + private void updateButtons() { - Debug.Assert(currentStepIndex != null); - - BackButton.Enabled.Value = currentStepIndex != 0; + BackButton.Enabled.Value = currentStepIndex > 0; + NextButton.Enabled.Value = currentStepIndex != null; - NextButton.Text = currentStepIndex + 1 < steps.Length - ? FirstRunSetupOverlayStrings.Next(steps[currentStepIndex.Value + 1].Description) - : CommonStrings.Finish; + if (currentStepIndex != null) + { + NextButton.Text = currentStepIndex + 1 < steps.Length + ? FirstRunSetupOverlayStrings.Next(steps[currentStepIndex.Value + 1].Description) + : CommonStrings.Finish; + } } private class FirstRunStep From 2906af323af33c835473b28bdc67ff88cb168cb1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Wed, 20 Apr 2022 17:51:08 +0900 Subject: [PATCH 36/41] Fix incorrectly written string equality logic --- .../Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs index 8a9ed50725b8..efce4f350b96 100644 --- a/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs +++ b/osu.Game.Tests/Visual/UserInterface/TestSceneFirstRunSetupOverlay.cs @@ -127,7 +127,7 @@ public void TestBackButton(bool keyboard) if (overlay.CurrentScreen?.IsLoaded != false) nextButton.TriggerClick(); - return nextButton.Text.ToString() == CommonStrings.Finish; + return nextButton.Text == CommonStrings.Finish; }); AddUntilStep("step back to start", () => From 56d8de23e2b649f305c87111fd31dd3a0abbaec1 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 12:18:54 +0900 Subject: [PATCH 37/41] Replace horse with "more suitable" icon MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bartłomiej Dach --- osu.Game/Overlays/FirstRunSetupOverlay.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index d5aa1178e075..f73d82b7934d 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -303,7 +303,7 @@ protected override void PopOut() notificationOverlay.Post(new SimpleNotification { Text = FirstRunSetupOverlayStrings.ClickToResumeFirstRunSetupAtAnyPoint, - Icon = FontAwesome.Solid.Horse, + Icon = FontAwesome.Solid.Redo, Activated = () => { Show(); From 5ae3d0eb274785ac3bb55cf26e8860ca7e35456e Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 19:36:19 +0900 Subject: [PATCH 38/41] Fix wording of ui scale screen description Co-authored-by: Walavouchey <36758269+Walavouchey@users.noreply.github.com> --- osu.Game/Localisation/FirstRunSetupOverlayStrings.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs index ec2e97d82a9f..b55102db202a 100644 --- a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs +++ b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs @@ -44,9 +44,9 @@ public static class FirstRunSetupOverlayStrings osu! is a very configurable game, and diving straight into the settings can sometimes be overwhelming. This guide will help you get the important choices out of the way to ensure a great first experience!"); /// - /// "The size of the osu! user interface size can be adjusted to your liking." + /// "The size of the osu! user interface can be adjusted to your liking." /// - public static LocalisableString UIScaleDescription => new TranslatableString(getKey(@"ui_scale_description"), @"The size of the osu! user interface size can be adjusted to your liking."); + public static LocalisableString UIScaleDescription => new TranslatableString(getKey(@"ui_scale_description"), @"The size of the osu! user interface can be adjusted to your liking."); /// /// "Next ({0})" From 1f967ecba3f4b30821640091d94ee55d238e44cf Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 19:52:28 +0900 Subject: [PATCH 39/41] Update string keys and change "setup" to "set up" to fix grammar --- osu.Game/Localisation/FirstRunSetupOverlayStrings.cs | 6 +++--- osu.Game/Overlays/FirstRunSetupOverlay.cs | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs index b55102db202a..d2fb0e746707 100644 --- a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs +++ b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs @@ -22,12 +22,12 @@ public static class FirstRunSetupOverlayStrings /// /// "First-run setup" /// - public static LocalisableString FirstRunSetup => new TranslatableString(getKey(@"first_run_setup"), @"First-run setup"); + public static LocalisableString FirstRunSetupTitle => new TranslatableString(getKey(@"first_run_setup_title"), @"First-run setup"); /// - /// "Setup osu! to suit you" + /// "Set up osu! to suit you" /// - public static LocalisableString SetupOsuToSuitYou => new TranslatableString(getKey(@"setup_osu_to_suit_you"), @"Setup osu! to suit you"); + public static LocalisableString FirstRunSetupDescription => new TranslatableString(getKey(@"first_run_setup_description"), @"Set up osu! to suit you"); /// /// "Welcome" diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index f73d82b7934d..dd36475a231c 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -141,7 +141,7 @@ private void load() { new OsuSpriteText { - Text = FirstRunSetupOverlayStrings.FirstRunSetup, + Text = FirstRunSetupOverlayStrings.FirstRunSetupTitle, Font = OsuFont.Default.With(size: 32), Colour = colourProvider.Content1, Anchor = Anchor.TopCentre, @@ -149,7 +149,7 @@ private void load() }, new OsuTextFlowContainer { - Text = FirstRunSetupOverlayStrings.SetupOsuToSuitYou, + Text = FirstRunSetupOverlayStrings.FirstRunSetupDescription, Colour = colourProvider.Content2, Anchor = Anchor.TopCentre, Origin = Anchor.TopCentre, From ed6481f7084277a063d26c63515d6631f560d9d6 Mon Sep 17 00:00:00 2001 From: Dean Herbert Date: Thu, 21 Apr 2022 19:55:15 +0900 Subject: [PATCH 40/41] Also rename `Welcome` to `WelcomeTitle` to match other usages --- osu.Game/Localisation/FirstRunSetupOverlayStrings.cs | 2 +- osu.Game/Overlays/FirstRunSetupOverlay.cs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs index d2fb0e746707..001de93c1679 100644 --- a/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs +++ b/osu.Game/Localisation/FirstRunSetupOverlayStrings.cs @@ -32,7 +32,7 @@ public static class FirstRunSetupOverlayStrings /// /// "Welcome" /// - public static LocalisableString Welcome => new TranslatableString(getKey(@"welcome"), @"Welcome"); + public static LocalisableString WelcomeTitle => new TranslatableString(getKey(@"welcome_title"), @"Welcome"); /// /// "Welcome to the first-run setup guide! diff --git a/osu.Game/Overlays/FirstRunSetupOverlay.cs b/osu.Game/Overlays/FirstRunSetupOverlay.cs index dd36475a231c..a12fec450758 100644 --- a/osu.Game/Overlays/FirstRunSetupOverlay.cs +++ b/osu.Game/Overlays/FirstRunSetupOverlay.cs @@ -68,7 +68,7 @@ public class FirstRunSetupOverlay : OsuFocusedOverlayContainer private readonly FirstRunStep[] steps = { - new FirstRunStep(typeof(ScreenWelcome), FirstRunSetupOverlayStrings.Welcome), + new FirstRunStep(typeof(ScreenWelcome), FirstRunSetupOverlayStrings.WelcomeTitle), new FirstRunStep(typeof(ScreenUIScale), GraphicsSettingsStrings.UIScaling), }; From 8fe4443029420bf4d1df46eda7c3a73b4018279a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bart=C5=82omiej=20Dach?= Date: Thu, 21 Apr 2022 22:29:23 +0200 Subject: [PATCH 41/41] Update screen method signatures to match framework API changes --- .../FirstRunSetup/FirstRunSetupScreen.cs | 16 ++++++++-------- osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs | 4 ++-- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs index b2284a999d4e..eb4b97069cb0 100644 --- a/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs +++ b/osu.Game/Overlays/FirstRunSetup/FirstRunSetupScreen.cs @@ -33,39 +33,39 @@ protected FirstRunSetupScreen() }; } - public override void OnEntering(IScreen last) + public override void OnEntering(ScreenTransitionEvent e) { - base.OnEntering(last); + base.OnEntering(e); this .FadeInFromZero(500) .MoveToX(offset) .MoveToX(0, 500, Easing.OutQuint); } - public override void OnResuming(IScreen last) + public override void OnResuming(ScreenTransitionEvent e) { - base.OnResuming(last); + base.OnResuming(e); this .FadeInFromZero(500) .MoveToX(0, 500, Easing.OutQuint); } - public override bool OnExiting(IScreen next) + public override bool OnExiting(ScreenExitEvent e) { this .FadeOut(100) .MoveToX(offset, 500, Easing.OutQuint); - return base.OnExiting(next); + return base.OnExiting(e); } - public override void OnSuspending(IScreen next) + public override void OnSuspending(ScreenTransitionEvent e) { this .FadeOut(100) .MoveToX(-offset, 500, Easing.OutQuint); - base.OnSuspending(next); + base.OnSuspending(e); } } } diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs index e63217097568..d9a612ea26b6 100644 --- a/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs +++ b/osu.Game/Overlays/FirstRunSetup/ScreenUIScale.cs @@ -97,9 +97,9 @@ protected override void Update() private class PinnedMainMenu : MainMenu { - public override void OnEntering(IScreen last) + public override void OnEntering(ScreenTransitionEvent e) { - base.OnEntering(last); + base.OnEntering(e); Buttons.ReturnToTopOnIdle = false; Buttons.State = ButtonSystemState.TopLevel;