1
0
mirror of https://github.com/ppy/osu.git synced 2024-11-19 03:52:55 +08:00
osu-lazer/osu.Game/Overlays/FirstRunSetup/ScreenImportFromStable.cs

Ignoring revisions in .git-blame-ignore-revs. Click here to bypass and see the normal blame view.

300 lines
12 KiB
C#
Raw Normal View History

2022-05-16 18:21:26 +08:00
// 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;
2022-05-16 19:53:04 +08:00
using System.Collections.Generic;
2022-05-16 20:07:42 +08:00
using System.IO;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework;
2022-05-16 18:21:26 +08:00
using osu.Framework.Allocation;
using osu.Framework.Bindables;
2022-05-16 19:13:34 +08:00
using osu.Framework.Extensions;
2022-05-16 18:21:26 +08:00
using osu.Framework.Graphics;
2022-05-16 20:07:42 +08:00
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.UserInterface;
2022-05-16 18:21:26 +08:00
using osu.Framework.Localisation;
using osu.Framework.Logging;
using osu.Framework.Screens;
2022-05-16 18:21:26 +08:00
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.UserInterfaceV2;
2022-05-16 18:21:26 +08:00
using osu.Game.Localisation;
using osu.Game.Overlays.Settings;
using osu.Game.Overlays.Settings.Sections.Maintenance;
using osu.Game.Screens.Edit.Setup;
2022-05-16 18:21:26 +08:00
using osuTK;
namespace osu.Game.Overlays.FirstRunSetup
{
[LocalisableDescription(typeof(FirstRunOverlayImportFromStableScreenStrings), nameof(FirstRunOverlayImportFromStableScreenStrings.Header))]
2022-05-16 18:21:26 +08:00
public partial class ScreenImportFromStable : FirstRunSetupScreen
{
2022-05-16 20:33:15 +08:00
private static readonly Vector2 button_size = new Vector2(400, 50);
2022-05-16 18:21:26 +08:00
private ProgressRoundedButton importButton = null!;
private OsuTextFlowContainer progressText = null!;
2022-05-16 19:13:34 +08:00
[Resolved]
private LegacyImportManager legacyImportManager { get; set; } = null!;
2022-05-16 18:21:26 +08:00
private StableLocatorLabelledTextBox stableLocatorTextBox = null!;
private LinkFlowContainer copyInformation = null!;
2022-05-16 19:53:04 +08:00
private IEnumerable<ImportCheckbox> contentCheckboxes => Content.Children.OfType<ImportCheckbox>();
2022-05-16 18:21:26 +08:00
[BackgroundDependencyLoader(permitNulls: true)]
private void load()
{
Content.Children = new Drawable[]
{
new LinkFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE))
2022-05-16 18:21:26 +08:00
{
Colour = OverlayColourProvider.Content1,
Text = FirstRunOverlayImportFromStableScreenStrings.Description,
2022-05-16 18:21:26 +08:00
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
},
stableLocatorTextBox = new StableLocatorLabelledTextBox
{
Label = FirstRunOverlayImportFromStableScreenStrings.LocateDirectoryLabel,
PlaceholderText = FirstRunOverlayImportFromStableScreenStrings.LocateDirectoryPlaceholder
},
new ImportCheckbox(CommonStrings.Beatmaps, StableContent.Beatmaps),
new ImportCheckbox(CommonStrings.Scores, StableContent.Scores),
new ImportCheckbox(CommonStrings.Skins, StableContent.Skins),
new ImportCheckbox(CommonStrings.Collections, StableContent.Collections),
copyInformation = new LinkFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE))
{
Colour = OverlayColourProvider.Content1,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y
},
2022-05-16 18:21:26 +08:00
importButton = new ProgressRoundedButton
{
2022-05-16 20:33:15 +08:00
Size = button_size,
2022-05-16 18:21:26 +08:00
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,
Text = FirstRunOverlayImportFromStableScreenStrings.ImportButton,
2022-05-16 18:21:26 +08:00
Action = runImport
},
progressText = new OsuTextFlowContainer(cp => cp.Font = OsuFont.Default.With(size: CONTENT_FONT_SIZE))
{
Colour = OverlayColourProvider.Content1,
Text = FirstRunOverlayImportFromStableScreenStrings.ImportInProgress,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Alpha = 0,
},
2022-05-16 18:21:26 +08:00
};
2022-05-16 19:13:34 +08:00
stableLocatorTextBox.Current.BindValueChanged(_ => updateStablePath(), true);
}
[Resolved(canBeNull: true)]
private OsuGame? game { get; set; }
private void updateStablePath()
{
var storage = legacyImportManager.GetCurrentStableStorage();
if (storage == null)
{
2022-05-18 20:22:17 +08:00
toggleInteraction(false);
2022-05-16 20:33:15 +08:00
stableLocatorTextBox.Current.Disabled = false;
stableLocatorTextBox.Current.Value = string.Empty;
return;
}
2022-05-16 19:53:04 +08:00
foreach (var c in contentCheckboxes)
{
c.Current.Disabled = false;
2022-05-16 19:53:04 +08:00
c.UpdateCount();
}
2022-05-18 20:22:17 +08:00
toggleInteraction(true);
stableLocatorTextBox.Current.Value = storage.GetFullPath(string.Empty);
2022-05-16 20:33:15 +08:00
importButton.Enabled.Value = true;
bool available = legacyImportManager.CheckHardLinkAvailability();
Logger.Log($"Hard link support is {available}");
if (available)
{
copyInformation.Text = "Data migration will use \"hard links\". No extra disk space will be used, and you can delete either data folder at any point without affecting the other installation.";
}
else if (RuntimeInfo.OS != RuntimeInfo.Platform.Windows)
copyInformation.Text = "Lightweight linking of files is not supported on your operating system yet, so a copy of all files will be made during import.";
else
{
copyInformation.Text =
"A second copy of all files will be made during import. To avoid this, please make sure the lazer data folder is on the same drive as your previous osu! install (and the file system is NTFS). ";
copyInformation.AddLink(GeneralSettingsStrings.ChangeFolderLocation, () =>
{
game?.PerformFromScreen(menu => menu.Push(new MigrationSelectScreen()));
});
}
2022-05-16 19:53:04 +08:00
}
2022-05-16 19:53:04 +08:00
private void runImport()
{
2022-05-18 20:22:17 +08:00
toggleInteraction(false);
progressText.FadeIn(1000, Easing.OutQuint);
2022-05-16 19:53:04 +08:00
StableContent importableContent = 0;
2022-05-16 19:53:04 +08:00
foreach (var c in contentCheckboxes.Where(c => c.Current.Value))
importableContent |= c.StableContent;
2022-05-16 19:53:04 +08:00
legacyImportManager.ImportFromStableAsync(importableContent, false).ContinueWith(t => Schedule(() =>
{
progressText.FadeOut(500, Easing.OutQuint);
2022-05-16 19:53:04 +08:00
if (t.IsCompletedSuccessfully)
importButton.Complete();
else
{
2022-05-18 20:22:17 +08:00
toggleInteraction(true);
2022-05-16 19:53:04 +08:00
importButton.Abort();
}
}));
2022-05-16 18:21:26 +08:00
}
2022-05-18 20:22:17 +08:00
private void toggleInteraction(bool allow)
{
importButton.Enabled.Value = allow;
stableLocatorTextBox.Current.Disabled = !allow;
foreach (var c in contentCheckboxes)
c.Current.Disabled = !allow;
}
2022-05-16 19:53:04 +08:00
private partial class ImportCheckbox : SettingsCheckbox
2022-05-16 18:21:26 +08:00
{
2022-05-16 19:53:04 +08:00
public readonly StableContent StableContent;
2022-05-16 18:21:26 +08:00
2022-05-16 19:53:04 +08:00
private readonly LocalisableString title;
[Resolved]
private LegacyImportManager legacyImportManager { get; set; } = null!;
private CancellationTokenSource? countUpdateCancellation;
public ImportCheckbox(LocalisableString title, StableContent stableContent)
{
this.title = title;
2022-05-16 18:21:26 +08:00
2022-05-16 19:53:04 +08:00
StableContent = stableContent;
Current.Default = true;
2022-05-16 19:53:04 +08:00
Current.Value = true;
LabelText = title;
}
public void UpdateCount()
{
LabelText = LocalisableString.Interpolate($"{title} ({FirstRunOverlayImportFromStableScreenStrings.Calculating})");
2022-05-16 19:53:04 +08:00
countUpdateCancellation?.Cancel();
countUpdateCancellation = new CancellationTokenSource();
legacyImportManager.GetImportCount(StableContent, countUpdateCancellation.Token).ContinueWith(task => Schedule(() =>
{
if (task.IsCanceled)
return;
int count = task.GetResultSafely();
LabelText = LocalisableString.Interpolate($"{title} ({FirstRunOverlayImportFromStableScreenStrings.Items(count)})");
2022-05-16 19:53:04 +08:00
}));
}
2022-05-16 18:21:26 +08:00
}
2022-05-16 20:07:42 +08:00
internal partial class StableLocatorLabelledTextBox : LabelledTextBoxWithPopover, ICanAcceptFiles
2022-05-16 20:07:42 +08:00
{
[Resolved]
private LegacyImportManager legacyImportManager { get; set; } = null!;
2022-05-16 20:07:42 +08:00
public IEnumerable<string> HandledExtensions { get; } = new[] { string.Empty };
2022-05-16 20:07:42 +08:00
private readonly Bindable<DirectoryInfo?> currentDirectory = new Bindable<DirectoryInfo?>();
2022-05-16 20:07:42 +08:00
[Resolved(canBeNull: true)] // Can't really be null but required to handle potential of disposal before DI completes.
private OsuGameBase? game { get; set; }
2022-05-16 20:07:42 +08:00
protected override void LoadComplete()
2022-05-16 20:07:42 +08:00
{
base.LoadComplete();
2022-05-16 20:07:42 +08:00
game?.RegisterImportHandler(this);
2022-05-16 20:07:42 +08:00
currentDirectory.BindValueChanged(onDirectorySelected);
string? fullPath = legacyImportManager.GetCurrentStableStorage()?.GetFullPath(string.Empty);
if (fullPath != null)
currentDirectory.Value = new DirectoryInfo(fullPath);
}
private void onDirectorySelected(ValueChangedEvent<DirectoryInfo?> directory)
2022-05-16 20:07:42 +08:00
{
if (directory.NewValue == null)
{
Current.Value = string.Empty;
return;
}
2022-05-16 20:07:42 +08:00
// DirectorySelectors can trigger a noop value changed, but `DirectoryInfo` equality doesn't catch this.
if (directory.OldValue?.FullName == directory.NewValue.FullName)
return;
if (directory.NewValue?.GetFiles(@"osu!.*.cfg").Any() ?? false)
{
this.HidePopover();
string path = directory.NewValue.FullName;
legacyImportManager.UpdateStorage(path);
Current.Value = path;
}
2022-05-16 20:07:42 +08:00
}
Task ICanAcceptFiles.Import(params string[] paths)
2022-05-16 20:07:42 +08:00
{
Schedule(() => currentDirectory.Value = new DirectoryInfo(paths.First()));
return Task.CompletedTask;
}
Task ICanAcceptFiles.Import(ImportTask[] tasks, ImportParameters parameters) => throw new NotImplementedException();
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);
game?.UnregisterImportHandler(this);
}
public override Popover GetPopover() => new DirectoryChooserPopover(currentDirectory);
2022-05-16 20:07:42 +08:00
private partial class DirectoryChooserPopover : OsuPopover
{
public DirectoryChooserPopover(Bindable<DirectoryInfo?> currentDirectory)
{
Child = new Container
{
Size = new Vector2(600, 400),
Child = new OsuDirectorySelector(currentDirectory.Value?.FullName)
{
RelativeSizeAxes = Axes.Both,
CurrentPath = { BindTarget = currentDirectory }
},
};
}
2022-05-16 20:07:42 +08:00
}
}
2022-05-16 18:21:26 +08:00
}
}