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.
#nullable enable
2022-05-16 19:53:04 +08:00
using System.Collections.Generic ;
2022-05-16 20:07:42 +08:00
using System.IO ;
2022-05-16 19:37:38 +08:00
using System.Linq ;
using System.Threading ;
2022-05-16 18:21:26 +08:00
using osu.Framework.Allocation ;
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 ;
2022-05-16 18:21:26 +08:00
using osu.Framework.Localisation ;
2022-05-16 20:07:42 +08:00
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 ;
2022-05-16 19:37:38 +08:00
using osu.Game.Graphics.UserInterfaceV2 ;
2022-05-16 20:07:42 +08:00
using osu.Game.IO ;
2022-05-16 18:21:26 +08:00
using osu.Game.Localisation ;
using osu.Game.Overlays.Settings ;
using osuTK ;
2022-05-16 20:07:42 +08:00
using CommonStrings = osu . Game . Resources . Localisation . Web . CommonStrings ;
2022-05-16 18:21:26 +08:00
namespace osu.Game.Overlays.FirstRunSetup
{
[LocalisableDescription(typeof(FirstRunSetupOverlayStrings), nameof(FirstRunSetupOverlayStrings.ImportTitle))]
public 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 ! ;
2022-05-16 20:07:42 +08:00
private RoundedButton locateStableButton = null ! ;
2022-05-16 18:21:26 +08:00
2022-05-16 19:37:38 +08:00
private OsuTextFlowContainer currentStablePath = null ! ;
2022-05-16 18:21:26 +08:00
[Resolved]
private OsuColour colours { get ; set ; } = null ! ;
2022-05-16 19:13:34 +08:00
[Resolved]
private LegacyImportManager legacyImportManager { get ; set ; } = null ! ;
2022-05-16 18:21:26 +08:00
2022-05-16 19:37:38 +08:00
private CancellationTokenSource ? stablePathUpdateCancellation ;
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 OsuTextFlowContainer ( cp = > cp . Font = OsuFont . Default . With ( size : CONTENT_FONT_SIZE ) )
{
Colour = OverlayColourProvider . Content1 ,
Text =
"If you have an installation of a previous osu! version, you can choose to migrate your existing content. Note that this will create a copy, and not affect your existing installation." ,
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y
} ,
2022-05-16 19:37:38 +08:00
currentStablePath = new OsuTextFlowContainer ( cp = > cp . Font = OsuFont . Default . With ( size : HEADER_FONT_SIZE , weight : FontWeight . SemiBold ) )
{
Colour = OverlayColourProvider . Content2 ,
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
2022-05-16 20:33:15 +08:00
TextAnchor = Anchor . Centre ,
2022-05-16 19:37:38 +08:00
} ,
2022-05-16 20:07:42 +08:00
locateStableButton = new RoundedButton
2022-05-16 19:37:38 +08:00
{
2022-05-16 20:33:15 +08:00
Size = button_size ,
2022-05-16 19:37:38 +08:00
Anchor = Anchor . TopCentre ,
Origin = Anchor . TopCentre ,
2022-05-16 20:33:15 +08:00
Text = "Change location" ,
2022-05-16 19:37:38 +08:00
Action = locateStable ,
} ,
2022-05-16 19:53:04 +08:00
new ImportCheckbox ( "Beatmaps" , StableContent . Beatmaps ) ,
new ImportCheckbox ( "Scores" , StableContent . Scores ) ,
new ImportCheckbox ( "Skins" , StableContent . Skins ) ,
new ImportCheckbox ( "Collections" , StableContent . Collections ) ,
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 = FirstRunSetupOverlayStrings . ImportContentFromStable ,
Action = runImport
} ,
} ;
2022-05-16 19:13:34 +08:00
2022-05-16 19:37:38 +08:00
updateStablePath ( ) ;
}
2022-05-16 20:07:42 +08:00
private void locateStable ( ) = > this . Push ( new LocateStableScreen ( ) ) ;
public override void OnResuming ( ScreenTransitionEvent e )
2022-05-16 19:37:38 +08:00
{
2022-05-16 20:07:42 +08:00
base . OnResuming ( e ) ;
if ( e . Last is LocateStableScreen )
// stable storage may have changed.
2022-05-16 19:37:38 +08:00
Schedule ( updateStablePath ) ;
}
private void updateStablePath ( )
{
stablePathUpdateCancellation ? . Cancel ( ) ;
var storage = legacyImportManager . GetCurrentStableStorage ( ) ;
if ( storage = = null )
{
2022-05-16 19:53:04 +08:00
foreach ( var c in contentCheckboxes )
2022-05-16 19:37:38 +08:00
c . Current . Disabled = true ;
2022-05-16 20:33:15 +08:00
currentStablePath . FadeColour ( colours . Red1 , 500 , Easing . OutQuint ) ;
2022-05-16 19:37:38 +08:00
currentStablePath . Text = "No installation found" ;
2022-05-16 20:33:15 +08:00
importButton . Enabled . Value = false ;
2022-05-16 19:37:38 +08:00
return ;
}
2022-05-16 19:53:04 +08:00
foreach ( var c in contentCheckboxes )
{
2022-05-16 19:37:38 +08:00
c . Current . Disabled = false ;
2022-05-16 19:53:04 +08:00
c . UpdateCount ( ) ;
}
2022-05-16 19:37:38 +08:00
2022-05-16 20:33:15 +08:00
currentStablePath . FadeColour ( OverlayColourProvider . Content2 ) ;
currentStablePath . Text = $"Found installation: {storage.GetFullPath(string.Empty)}" ;
2022-05-16 19:37:38 +08:00
stablePathUpdateCancellation = new CancellationTokenSource ( ) ;
2022-05-16 20:33:15 +08:00
importButton . Enabled . Value = true ;
2022-05-16 19:53:04 +08:00
}
2022-05-16 19:37:38 +08:00
2022-05-16 19:53:04 +08:00
private void runImport ( )
{
importButton . Enabled . Value = false ;
2022-05-16 20:07:42 +08:00
locateStableButton . Enabled . Value = false ;
2022-05-16 19:37:38 +08:00
2022-05-16 19:53:04 +08:00
StableContent importableContent = 0 ;
2022-05-16 19:37:38 +08:00
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:37:38 +08:00
2022-05-16 19:53:04 +08:00
legacyImportManager . ImportFromStableAsync ( importableContent , false ) . ContinueWith ( t = > Schedule ( ( ) = >
2022-05-16 19:37:38 +08:00
{
2022-05-16 19:53:04 +08:00
if ( t . IsCompletedSuccessfully )
importButton . Complete ( ) ;
else
{
importButton . Enabled . Value = true ;
2022-05-16 20:33:15 +08:00
locateStableButton . Enabled . Value = true ;
2022-05-16 19:53:04 +08:00
importButton . Abort ( ) ;
}
2022-05-16 19:37:38 +08:00
} ) ) ;
2022-05-16 18:21:26 +08:00
}
2022-05-16 19:53:04 +08:00
private 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 . Value = true ;
LabelText = title ;
}
public void UpdateCount ( )
{
LabelText = LocalisableString . Interpolate ( $"{title} (calculating...)" ) ;
countUpdateCancellation ? . Cancel ( ) ;
countUpdateCancellation = new CancellationTokenSource ( ) ;
legacyImportManager . GetImportCount ( StableContent , countUpdateCancellation . Token ) . ContinueWith ( task = > Schedule ( ( ) = >
{
if ( task . IsCanceled )
return ;
LabelText = LocalisableString . Interpolate ( $"{title} ({task.GetResultSafely()} items)" ) ;
} ) ) ;
}
2022-05-16 18:21:26 +08:00
}
2022-05-16 20:07:42 +08:00
private class LocateStableScreen : FirstRunSetupScreen
{
private RoundedButton selectionButton = null ! ;
private OsuDirectorySelector directorySelector = null ! ;
protected bool IsValidDirectory ( DirectoryInfo ? info ) = > info ? . GetFiles ( "osu!.*.cfg" ) . Any ( ) ? ? false ;
public LocalisableString HeaderText = > "Please select your osu!stable install location" ;
[BackgroundDependencyLoader]
private void load ( OsuColour colours )
{
// Don't want the scroll content provided by `FirstRunSetupScreen` so we don't use `Content`.
InternalChild = new Container
{
RelativeSizeAxes = Axes . Both ,
Padding = new MarginPadding { Horizontal = CONTENT_PADDING } ,
Children = new Drawable [ ]
{
new GridContainer
{
RelativeSizeAxes = Axes . Both ,
RowDimensions = new [ ]
{
new Dimension ( GridSizeMode . AutoSize ) ,
new Dimension ( ) ,
new Dimension ( GridSizeMode . AutoSize ) ,
} ,
Content = new [ ]
{
new Drawable [ ]
{
new OsuTextFlowContainer ( cp = >
{
cp . Font = OsuFont . Default . With ( size : 24 ) ;
} )
{
Text = HeaderText ,
TextAnchor = Anchor . TopCentre ,
Margin = new MarginPadding ( 10 ) ,
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
}
} ,
new Drawable [ ]
{
directorySelector = new OsuDirectorySelector
{
RelativeSizeAxes = Axes . Both ,
}
} ,
new Drawable [ ]
{
new Container
{
RelativeSizeAxes = Axes . X ,
AutoSizeAxes = Axes . Y ,
Children = new Drawable [ ]
{
new RoundedButton
{
Anchor = Anchor . CentreLeft ,
Origin = Anchor . CentreLeft ,
2022-05-16 20:33:15 +08:00
RelativeSizeAxes = Axes . X ,
Width = 0.45f ,
Height = button_size . Y ,
2022-05-16 20:07:42 +08:00
Margin = new MarginPadding ( 10 ) ,
2022-05-16 20:33:15 +08:00
BackgroundColour = colours . Pink2 ,
2022-05-16 20:07:42 +08:00
Text = CommonStrings . ButtonsCancel ,
Action = this . Exit
} ,
selectionButton = new RoundedButton
{
Anchor = Anchor . CentreRight ,
Origin = Anchor . CentreRight ,
2022-05-16 20:33:15 +08:00
RelativeSizeAxes = Axes . X ,
Width = 0.45f ,
Height = button_size . Y ,
2022-05-16 20:07:42 +08:00
Margin = new MarginPadding ( 10 ) ,
Text = MaintenanceSettingsStrings . SelectDirectory ,
Action = ( ) = >
{
legacyImportManager . UpdateStorage ( directorySelector . CurrentPath . Value . FullName ) ;
this . Exit ( ) ;
}
} ,
}
} ,
}
}
}
}
} ;
}
[Resolved]
private LegacyImportManager legacyImportManager { get ; set ; } = null ! ;
protected override void LoadComplete ( )
{
if ( legacyImportManager . GetCurrentStableStorage ( ) is StableStorage storage )
directorySelector . CurrentPath . Value = new DirectoryInfo ( storage . GetFullPath ( string . Empty ) ) ;
directorySelector . CurrentPath . BindValueChanged ( e = > selectionButton . Enabled . Value = e . NewValue ! = null & & IsValidDirectory ( e . NewValue ) , true ) ;
base . LoadComplete ( ) ;
}
public override void OnSuspending ( ScreenTransitionEvent e )
{
base . OnSuspending ( e ) ;
this . FadeOut ( 250 ) ;
}
}
2022-05-16 18:21:26 +08:00
}
}