1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-21 18:47:27 +08:00

Merge pull request #12860 from peppy/editor-exit-stability

This commit is contained in:
Bartłomiej Dach 2021-05-31 00:09:41 +02:00 committed by GitHub
commit be0605450b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 106 additions and 38 deletions

View File

@ -358,7 +358,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("has selection", () => songSelect.Carousel.SelectedBeatmap.Equals(target));
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo == target);
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target));
}
[Test]
@ -390,7 +390,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("has correct ruleset", () => Ruleset.Value.ID == 0);
// this is an important check, to make sure updateComponentFromBeatmap() was actually run
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo == target);
AddUntilStep("selection shown on wedge", () => songSelect.CurrentBeatmapDetailsBeatmap.BeatmapInfo.Equals(target));
}
[Test]
@ -781,7 +781,7 @@ namespace osu.Game.Tests.Visual.SongSelect
AddUntilStep("Check ruleset changed to mania", () => Ruleset.Value.ID == 3);
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo == groupIcon.Items.First().Beatmap);
AddAssert("Check first item in group selected", () => Beatmap.Value.BeatmapInfo.Equals(groupIcon.Items.First().Beatmap));
}
[Test]

View File

@ -2,7 +2,9 @@
// See the LICENCE file in the repository root for full licence text.
using NUnit.Framework;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Testing;
using osu.Game.Overlays;
using osu.Game.Overlays.Dialog;
@ -11,13 +13,20 @@ namespace osu.Game.Tests.Visual.UserInterface
[TestFixture]
public class TestSceneDialogOverlay : OsuTestScene
{
public TestSceneDialogOverlay()
private DialogOverlay overlay;
[SetUpSteps]
public void SetUpSteps()
{
DialogOverlay overlay;
AddStep("create dialog overlay", () => Child = overlay = new DialogOverlay());
}
Add(overlay = new DialogOverlay());
[Test]
public void TestBasic()
{
TestPopupDialog dialog = null;
AddStep("dialog #1", () => overlay.Push(new TestPopupDialog
AddStep("dialog #1", () => overlay.Push(dialog = new TestPopupDialog
{
Icon = FontAwesome.Regular.TrashAlt,
HeaderText = @"Confirm deletion of",
@ -37,7 +46,9 @@ namespace osu.Game.Tests.Visual.UserInterface
},
}));
AddStep("dialog #2", () => overlay.Push(new TestPopupDialog
AddAssert("first dialog displayed", () => overlay.CurrentDialog == dialog);
AddStep("dialog #2", () => overlay.Push(dialog = new TestPopupDialog
{
Icon = FontAwesome.Solid.Cog,
HeaderText = @"What do you want to do with",
@ -70,6 +81,42 @@ namespace osu.Game.Tests.Visual.UserInterface
},
},
}));
AddAssert("second dialog displayed", () => overlay.CurrentDialog == dialog);
}
[Test]
public void TestDismissBeforePush()
{
AddStep("dismissed dialog push", () =>
{
overlay.Push(new TestPopupDialog
{
State = { Value = Visibility.Hidden }
});
});
AddAssert("no dialog pushed", () => overlay.CurrentDialog == null);
}
[Test]
public void TestDismissBeforePushViaButtonPress()
{
AddStep("dismissed dialog push", () =>
{
TestPopupDialog dialog;
overlay.Push(dialog = new TestPopupDialog
{
Buttons = new PopupDialogButton[]
{
new PopupDialogOkButton { Text = @"OK" },
},
});
dialog.PerformOkAction();
});
AddAssert("no dialog pushed", () => overlay.CurrentDialog == null);
}
private class TestPopupDialog : PopupDialog

View File

@ -3,6 +3,7 @@
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Linq.Expressions;
@ -244,6 +245,8 @@ namespace osu.Game.Beatmaps
{
var setInfo = info.BeatmapSet;
Debug.Assert(setInfo.Files != null);
using (var stream = new MemoryStream())
{
using (var sw = new StreamWriter(stream, Encoding.UTF8, 1024, true))
@ -290,7 +293,9 @@ namespace osu.Game.Beatmaps
if (beatmapInfo?.BeatmapSet == null || beatmapInfo == DefaultBeatmap?.BeatmapInfo)
return DefaultBeatmap;
if (beatmapInfo.BeatmapSet.Files == null)
// force a re-query if files are not in a state which looks like the model has
// full database information present.
if (beatmapInfo.BeatmapSet.Files == null || beatmapInfo.BeatmapSet.Files.Count == 0)
{
var info = beatmapInfo;
beatmapInfo = QueryBeatmap(b => b.ID == info.ID);

View File

@ -95,6 +95,10 @@ namespace osu.Game.Overlays.Dialog
}
}
// We always want dialogs to show their appear animation, so we request they start hidden.
// Normally this would not be required, but is here due to the manual Show() call that occurs before LoadComplete().
protected override bool StartHidden => true;
protected PopupDialog()
{
RelativeSizeAxes = Axes.Both;
@ -205,8 +209,17 @@ namespace osu.Game.Overlays.Dialog
},
},
};
// It's important we start in a visible state so our state fires on hide, even before load.
// This is used by the DialogOverlay to know when the dialog was dismissed.
Show();
}
/// <summary>
/// Programmatically clicks the first <see cref="PopupDialogOkButton"/>.
/// </summary>
public void PerformOkAction() => Buttons.OfType<PopupDialogOkButton>().First().Click();
protected override bool OnKeyDown(KeyDownEvent e)
{
if (e.Repeat) return false;

View File

@ -35,15 +35,16 @@ namespace osu.Game.Overlays
public void Push(PopupDialog dialog)
{
if (dialog == CurrentDialog) return;
if (dialog == CurrentDialog || dialog.State.Value != Visibility.Visible) return;
// if any existing dialog is being displayed, dismiss it before showing a new one.
CurrentDialog?.Hide();
CurrentDialog = dialog;
CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue);
dialogContainer.Add(CurrentDialog);
CurrentDialog.Show();
CurrentDialog.State.ValueChanged += state => onDialogOnStateChanged(dialog, state.NewValue);
Show();
}

View File

@ -473,25 +473,23 @@ namespace osu.Game.Screens.Edit
{
if (!exitConfirmed)
{
// if the confirm dialog is already showing (or we can't show it, ie. in tests) exit without save.
if (dialogOverlay == null || dialogOverlay.CurrentDialog is PromptForSaveDialog)
// dialog overlay may not be available in visual tests.
if (dialogOverlay == null)
{
confirmExit();
return base.OnExiting(next);
return true;
}
// if the dialog is already displayed, confirm exit with no save.
if (dialogOverlay.CurrentDialog is PromptForSaveDialog saveDialog)
{
saveDialog.PerformOkAction();
return true;
}
if (isNewBeatmap || HasUnsavedChanges)
{
dialogOverlay?.Push(new PromptForSaveDialog(() =>
{
confirmExit();
this.Exit();
}, () =>
{
confirmExitWithSave();
this.Exit();
}));
dialogOverlay?.Push(new PromptForSaveDialog(confirmExit, confirmExitWithSave));
return true;
}
}
@ -499,15 +497,23 @@ namespace osu.Game.Screens.Edit
ApplyToBackground(b => b.FadeColour(Color4.White, 500));
resetTrack();
Beatmap.Value = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo);
// To update the game-wide beatmap with any changes, perform a re-fetch on exit.
// This is required as the editor makes its local changes via EditorBeatmap
// (which are not propagated outwards to a potentially cached WorkingBeatmap).
var refetchedBeatmap = beatmapManager.GetWorkingBeatmap(Beatmap.Value.BeatmapInfo);
if (!(refetchedBeatmap is DummyWorkingBeatmap))
Beatmap.Value = refetchedBeatmap;
return base.OnExiting(next);
}
private void confirmExitWithSave()
{
exitConfirmed = true;
Save();
exitConfirmed = true;
this.Exit();
}
private void confirmExit()
@ -529,6 +535,7 @@ namespace osu.Game.Screens.Edit
}
exitConfirmed = true;
this.Exit();
}
private readonly Bindable<string> clipboard = new Bindable<string>();

View File

@ -1,9 +1,6 @@
// 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.Linq;
using osuTK;
using osuTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
@ -22,6 +19,8 @@ using osu.Game.Screens.Edit;
using osu.Game.Screens.OnlinePlay.Multiplayer;
using osu.Game.Screens.OnlinePlay.Playlists;
using osu.Game.Screens.Select;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Screens.Menu
{
@ -120,7 +119,7 @@ namespace osu.Game.Screens.Menu
Origin = Anchor.TopRight,
Margin = new MarginPadding { Right = 15, Top = 5 }
},
exitConfirmOverlay?.CreateProxy() ?? Drawable.Empty()
exitConfirmOverlay?.CreateProxy() ?? Empty()
});
buttons.StateChanged += state =>
@ -270,15 +269,11 @@ namespace osu.Game.Screens.Menu
if (!exitConfirmed && dialogOverlay != null)
{
if (dialogOverlay.CurrentDialog is ConfirmExitDialog exitDialog)
{
exitConfirmed = true;
exitDialog.Buttons.First().Click();
}
exitDialog.PerformOkAction();
else
{
dialogOverlay.Push(new ConfirmExitDialog(confirmAndExit, () => exitConfirmOverlay.Abort()));
return true;
}
return true;
}
buttons.State = ButtonSystemState.Exit;