diff --git a/osu.Game/Database/LegacyImportManager.cs b/osu.Game/Database/LegacyImportManager.cs
index 20738f859e..7e1641d16f 100644
--- a/osu.Game/Database/LegacyImportManager.cs
+++ b/osu.Game/Database/LegacyImportManager.cs
@@ -3,6 +3,9 @@
using System;
using System.Collections.Generic;
+using System.Diagnostics.CodeAnalysis;
+using System.IO;
+using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework;
@@ -54,6 +57,49 @@ namespace osu.Game.Database
public void UpdateStorage(string stablePath) => cachedStorage = new StableStorage(stablePath, gameHost as DesktopGameHost);
+ ///
+ /// Checks whether a valid location to run a stable import from can be determined starting from the supplied .
+ ///
+ /// The directory to check for stable import eligibility.
+ ///
+ /// If the return value is ,
+ /// this parameter will contain the to use as the root directory for importing.
+ ///
+ public bool IsUsableForStableImport(DirectoryInfo? directory, [NotNullWhen(true)] out DirectoryInfo? stableRoot)
+ {
+ if (directory == null)
+ {
+ stableRoot = null;
+ return false;
+ }
+
+ // A full stable installation will have a configuration file present.
+ // This is the best case scenario, as it may contain a custom beatmap directory we need to traverse to.
+ if (directory.GetFiles(@"osu!.*.cfg").Any())
+ {
+ stableRoot = directory;
+ return true;
+ }
+
+ // The user may only have their songs or skins folders left.
+ // We still want to allow them to import based on this.
+ if (directory.GetDirectories(@"Songs").Any() || directory.GetDirectories(@"Skins").Any())
+ {
+ stableRoot = directory;
+ return true;
+ }
+
+ // The user may have traversed *inside* their songs or skins folders.
+ if (directory.Parent != null && (directory.Name == @"Songs" || directory.Name == @"Skins"))
+ {
+ stableRoot = directory.Parent;
+ return true;
+ }
+
+ stableRoot = null;
+ return false;
+ }
+
public bool CheckSongsFolderHardLinkAvailability()
{
var stableStorage = GetCurrentStableStorage();
diff --git a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs
index 23f3b3e1af..185a47c371 100644
--- a/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs
+++ b/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs
@@ -269,11 +269,11 @@ namespace osu.Game.Overlays.FirstRunSetup
if (directory.OldValue?.FullName == directory.NewValue.FullName)
return;
- if (directory.NewValue?.GetFiles(@"osu!.*.cfg").Any() ?? false)
+ if (legacyImportManager.IsUsableForStableImport(directory.NewValue, out var stableRoot))
{
this.HidePopover();
- string path = directory.NewValue.FullName;
+ string path = stableRoot.FullName;
legacyImportManager.UpdateStorage(path);
Current.Value = path;
diff --git a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs
index 17f09ade4e..3f12b9c0df 100644
--- a/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs
+++ b/osu.Game/Overlays/Settings/Sections/Maintenance/StableDirectorySelectScreen.cs
@@ -1,11 +1,13 @@
// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
+using System;
using System.IO;
-using System.Linq;
using System.Threading.Tasks;
+using osu.Framework.Allocation;
using osu.Framework.Localisation;
using osu.Framework.Screens;
+using osu.Game.Database;
namespace osu.Game.Overlays.Settings.Sections.Maintenance
{
@@ -13,18 +15,12 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
{
private readonly TaskCompletionSource taskCompletionSource;
+ [Resolved]
+ private LegacyImportManager legacyImportManager { get; set; } = null!;
+
protected override OverlayActivation InitialOverlayActivationMode => OverlayActivation.Disabled;
- protected override bool IsValidDirectory(DirectoryInfo? info) =>
- // A full stable installation will have a configuration file present.
- // This is the best case scenario, as it may contain a custom beatmap directory we need to traverse to.
- info?.GetFiles("osu!.*.cfg").Any() == true ||
- // The user may only have their songs or skins folders left.
- // We still want to allow them to import based on this.
- info?.GetDirectories("Songs").Any() == true ||
- info?.GetDirectories("Skins").Any() == true ||
- // The user may have traverse *inside* their songs or skins folders.
- shouldUseParentDirectory(info);
+ protected override bool IsValidDirectory(DirectoryInfo? info) => legacyImportManager.IsUsableForStableImport(info, out _);
public override LocalisableString HeaderText => "Please select your osu!stable install location";
@@ -35,7 +31,10 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
protected override void OnSelection(DirectoryInfo directory)
{
- taskCompletionSource.TrySetResult(shouldUseParentDirectory(directory) ? directory.Parent!.FullName : directory.FullName);
+ if (!legacyImportManager.IsUsableForStableImport(directory, out var stableRoot))
+ throw new InvalidOperationException($@"{nameof(OnSelection)} was called on an invalid directory. This should never happen.");
+
+ taskCompletionSource.TrySetResult(stableRoot.FullName);
this.Exit();
}
@@ -44,8 +43,5 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
taskCompletionSource.TrySetCanceled();
return base.OnExiting(e);
}
-
- private bool shouldUseParentDirectory(DirectoryInfo? info)
- => info?.Parent != null && (info.Name == "Songs" || info.Name == "Skins");
}
}