mirror of
https://github.com/ppy/osu.git
synced 2025-02-19 09:52:53 +08:00
Merge pull request #7678 from peppy/perform-from-screen
Refactor performFromMenu to work with multiple screen targets
This commit is contained in:
commit
1d1a5b26ab
@ -1,6 +1,8 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Configuration;
|
||||
@ -76,6 +78,13 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
ConfirmAtMainMenu();
|
||||
}
|
||||
|
||||
protected void PushAndConfirm(Func<Screen> newScreen)
|
||||
{
|
||||
Screen screen = null;
|
||||
AddStep("Push new screen", () => Game.ScreenStack.Push(screen = newScreen()));
|
||||
AddUntilStep("Wait for new screen", () => Game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
|
||||
}
|
||||
|
||||
protected void ConfirmAtMainMenu() => AddUntilStep("Wait for main menu", () => Game.ScreenStack.CurrentScreen is MainMenu menu && menu.IsLoaded);
|
||||
|
||||
public class TestOsuGame : OsuGame
|
||||
@ -96,6 +105,8 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
protected override Loader CreateLoader() => new TestLoader();
|
||||
|
||||
public new void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null) => base.PerformFromScreen(action, validScreens);
|
||||
|
||||
public TestOsuGame(Storage storage, IAPIProvider api)
|
||||
{
|
||||
Storage = storage;
|
||||
|
@ -0,0 +1,72 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Game.Screens.Menu;
|
||||
using osu.Game.Screens.Play;
|
||||
using osu.Game.Screens.Select;
|
||||
|
||||
namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
public class TestScenePerformFromScreen : OsuGameTestScene
|
||||
{
|
||||
[Test]
|
||||
public void TestPerformAtMenu()
|
||||
{
|
||||
AddAssert("could perform immediately", () =>
|
||||
{
|
||||
bool actionPerformed = false;
|
||||
Game.PerformFromScreen(_ => actionPerformed = true);
|
||||
return actionPerformed;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtSongSelect()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
|
||||
AddAssert("could perform immediately", () =>
|
||||
{
|
||||
bool actionPerformed = false;
|
||||
Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) });
|
||||
return actionPerformed;
|
||||
});
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtMenuFromSongSelect()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
|
||||
bool actionPerformed = false;
|
||||
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
|
||||
AddUntilStep("returned to menu", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||
AddAssert("did perform", () => actionPerformed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtSongSelectFromPlayerLoader()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
PushAndConfirm(() => new PlayerLoader(() => new Player()));
|
||||
|
||||
bool actionPerformed = false;
|
||||
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true, new[] { typeof(PlaySongSelect) }));
|
||||
AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is PlaySongSelect);
|
||||
AddAssert("did perform", () => actionPerformed);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestPerformAtMenuFromPlayerLoader()
|
||||
{
|
||||
PushAndConfirm(() => new PlaySongSelect());
|
||||
PushAndConfirm(() => new PlayerLoader(() => new Player()));
|
||||
|
||||
bool actionPerformed = false;
|
||||
AddStep("try to perform", () => Game.PerformFromScreen(_ => actionPerformed = true));
|
||||
AddUntilStep("returned to song select", () => Game.ScreenStack.CurrentScreen is MainMenu);
|
||||
AddAssert("did perform", () => actionPerformed);
|
||||
}
|
||||
}
|
||||
}
|
@ -1,13 +1,11 @@
|
||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Screens;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Overlays;
|
||||
using osu.Game.Overlays.Mods;
|
||||
@ -32,7 +30,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
|
||||
pushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
PushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||
pushEscape();
|
||||
@ -49,7 +47,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
WorkingBeatmap beatmap() => Game.Beatmap.Value;
|
||||
Track track() => beatmap().Track;
|
||||
|
||||
pushAndConfirm(() => new TestSongSelect());
|
||||
PushAndConfirm(() => new TestSongSelect());
|
||||
|
||||
AddStep("import beatmap", () => ImportBeatmapTest.LoadOszIntoOsu(Game, virtualTrack: true).Wait());
|
||||
|
||||
@ -77,7 +75,7 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
{
|
||||
TestSongSelect songSelect = null;
|
||||
|
||||
pushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
PushAndConfirm(() => songSelect = new TestSongSelect());
|
||||
AddStep("Show mods overlay", () => songSelect.ModSelectOverlay.Show());
|
||||
AddAssert("Overlay was shown", () => songSelect.ModSelectOverlay.State.Value == Visibility.Visible);
|
||||
AddStep("Move mouse to backButton", () => InputManager.MoveMouseTo(backButtonPosition));
|
||||
@ -93,14 +91,14 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
[Test]
|
||||
public void TestExitMultiWithEscape()
|
||||
{
|
||||
pushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
PushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
exitViaEscapeAndConfirm();
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestExitMultiWithBackButton()
|
||||
{
|
||||
pushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
PushAndConfirm(() => new Screens.Multi.Multiplayer());
|
||||
exitViaBackButtonAndConfirm();
|
||||
}
|
||||
|
||||
@ -116,13 +114,6 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
AddAssert("Options overlay was closed", () => Game.Settings.State.Value == Visibility.Hidden);
|
||||
}
|
||||
|
||||
private void pushAndConfirm(Func<Screen> newScreen)
|
||||
{
|
||||
Screen screen = null;
|
||||
AddStep("Push new screen", () => Game.ScreenStack.Push(screen = newScreen()));
|
||||
AddUntilStep("Wait for new screen", () => Game.ScreenStack.CurrentScreen == screen && screen.IsLoaded);
|
||||
}
|
||||
|
||||
private void pushEscape() =>
|
||||
AddStep("Press escape", () => pressAndRelease(Key.Escape));
|
||||
|
||||
|
@ -327,10 +327,10 @@ namespace osu.Game
|
||||
return;
|
||||
}
|
||||
|
||||
performFromMainMenu(() =>
|
||||
PerformFromScreen(screen =>
|
||||
{
|
||||
// we might already be at song select, so a check is required before performing the load to solo.
|
||||
if (menuScreen.IsCurrentScreen())
|
||||
if (screen is MainMenu)
|
||||
menuScreen.LoadToSolo();
|
||||
|
||||
// we might even already be at the song
|
||||
@ -344,7 +344,7 @@ namespace osu.Game
|
||||
|
||||
Ruleset.Value = first.Ruleset;
|
||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(first);
|
||||
}, $"load {beatmap}", bypassScreenAllowChecks: true, targetScreen: typeof(PlaySongSelect));
|
||||
}, validScreens: new[] { typeof(PlaySongSelect) });
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@ -381,12 +381,12 @@ namespace osu.Game
|
||||
return;
|
||||
}
|
||||
|
||||
performFromMainMenu(() =>
|
||||
PerformFromScreen(screen =>
|
||||
{
|
||||
Beatmap.Value = BeatmapManager.GetWorkingBeatmap(databasedBeatmap);
|
||||
|
||||
menuScreen.Push(new ReplayPlayerLoader(databasedScore));
|
||||
}, $"watch {databasedScoreInfo}", bypassScreenAllowChecks: true);
|
||||
screen.Push(new ReplayPlayerLoader(databasedScore));
|
||||
});
|
||||
}
|
||||
|
||||
protected virtual Loader CreateLoader() => new Loader();
|
||||
@ -441,53 +441,42 @@ namespace osu.Game
|
||||
private ScheduledDelegate performFromMainMenuTask;
|
||||
|
||||
/// <summary>
|
||||
/// Perform an action only after returning to the main menu.
|
||||
/// Perform an action only after returning to a specific screen as indicated by <paramref name="validScreens"/>.
|
||||
/// Eagerly tries to exit the current screen until it succeeds.
|
||||
/// </summary>
|
||||
/// <param name="action">The action to perform once we are in the correct state.</param>
|
||||
/// <param name="taskName">The task name to display in a notification (if we can't immediately reach the main menu state).</param>
|
||||
/// <param name="targetScreen">An optional target screen type. If this screen is already current we can immediately perform the action without returning to the menu.</param>
|
||||
/// <param name="bypassScreenAllowChecks">Whether checking <see cref="IOsuScreen.AllowExternalScreenChange"/> should be bypassed.</param>
|
||||
private void performFromMainMenu(Action action, string taskName, Type targetScreen = null, bool bypassScreenAllowChecks = false)
|
||||
/// <param name="validScreens">An optional collection of valid screen types. If any of these screens are already current we can perform the action immediately, else the first valid parent will be made current before performing the action. <see cref="MainMenu"/> is used if not specified.</param>
|
||||
protected void PerformFromScreen(Action<IScreen> action, IEnumerable<Type> validScreens = null)
|
||||
{
|
||||
performFromMainMenuTask?.Cancel();
|
||||
|
||||
// if the current screen does not allow screen changing, give the user an option to try again later.
|
||||
if (!bypassScreenAllowChecks && (ScreenStack.CurrentScreen as IOsuScreen)?.AllowExternalScreenChange == false)
|
||||
{
|
||||
notifications.Post(new SimpleNotification
|
||||
{
|
||||
Text = $"Click here to {taskName}",
|
||||
Activated = () =>
|
||||
{
|
||||
performFromMainMenu(action, taskName, targetScreen, true);
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
return;
|
||||
}
|
||||
validScreens ??= Enumerable.Empty<Type>();
|
||||
validScreens = validScreens.Append(typeof(MainMenu));
|
||||
|
||||
CloseAllOverlays(false);
|
||||
|
||||
// we may already be at the target screen type.
|
||||
if (targetScreen != null && ScreenStack.CurrentScreen?.GetType() == targetScreen)
|
||||
if (validScreens.Contains(ScreenStack.CurrentScreen?.GetType()) && !Beatmap.Disabled)
|
||||
{
|
||||
action();
|
||||
action(ScreenStack.CurrentScreen);
|
||||
return;
|
||||
}
|
||||
|
||||
// all conditions have been met to continue with the action.
|
||||
if (menuScreen?.IsCurrentScreen() == true && !Beatmap.Disabled)
|
||||
// find closest valid target
|
||||
IScreen screen = ScreenStack.CurrentScreen;
|
||||
|
||||
while (screen != null)
|
||||
{
|
||||
action();
|
||||
return;
|
||||
if (validScreens.Contains(screen.GetType()))
|
||||
{
|
||||
screen.MakeCurrent();
|
||||
break;
|
||||
}
|
||||
|
||||
screen = screen.GetParentScreen();
|
||||
}
|
||||
|
||||
// menuScreen may not be initialised yet (null check required).
|
||||
menuScreen?.MakeCurrent();
|
||||
|
||||
performFromMainMenuTask = Schedule(() => performFromMainMenu(action, taskName));
|
||||
performFromMainMenuTask = Schedule(() => PerformFromScreen(action, validScreens));
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
Loading…
Reference in New Issue
Block a user