diff --git a/osu.Game/Screens/Import/FileImportScreen.cs b/osu.Game/Screens/Import/FileImportScreen.cs index 1bdacae87f..bd35b8131e 100644 --- a/osu.Game/Screens/Import/FileImportScreen.cs +++ b/osu.Game/Screens/Import/FileImportScreen.cs @@ -3,6 +3,7 @@ #nullable disable +using System.Collections.Generic; using System.IO; using System.Linq; using System.Threading.Tasks; @@ -29,6 +30,7 @@ namespace osu.Game.Screens.Import private TextFlowContainer currentFileText; private RoundedButton importButton; + private RoundedButton importAllButton; private const float duration = 300; private const float button_height = 50; @@ -74,7 +76,7 @@ namespace osu.Game.Screens.Import new Container { RelativeSizeAxes = Axes.Both, - Padding = new MarginPadding { Bottom = button_height + button_vertical_margin * 2 }, + Padding = new MarginPadding { Bottom = button_height * 2 + button_vertical_margin * 3 }, Child = new OsuScrollContainer { RelativeSizeAxes = Axes.Both, @@ -97,14 +99,27 @@ namespace osu.Game.Screens.Import }, importButton = new RoundedButton { - Text = "Import", + Text = "Import selected file", Anchor = Anchor.BottomCentre, Origin = Anchor.BottomCentre, RelativeSizeAxes = Axes.X, Height = button_height, Width = 0.9f, - Margin = new MarginPadding { Vertical = button_vertical_margin }, + Margin = new MarginPadding { Bottom = button_height + button_vertical_margin * 2 }, Action = () => startImport(fileSelector.CurrentFile.Value?.FullName) + }, + + importAllButton = new RoundedButton + { + Text = "Import all files from directory", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = button_height, + Width = 0.9f, + TooltipText = "Imports all osu files from selected directory", + Margin = new MarginPadding { Vertical = button_vertical_margin }, + Action = () => startDirectoryImport(fileSelector.CurrentPath.Value?.FullName) } } } @@ -131,10 +146,20 @@ namespace osu.Game.Screens.Import return base.OnExiting(e); } - private void directoryChanged(ValueChangedEvent _) + private void directoryChanged(ValueChangedEvent directoryChangedEvent) { // this should probably be done by the selector itself, but let's do it here for now. fileSelector.CurrentFile.Value = null; + + DirectoryInfo newDirectory = directoryChangedEvent.NewValue; + importAllButton.Enabled.Value = + // this will be `null` if the user clicked the "Computer" option (showing drives) + // handling that is difficult due to platform differences, and nobody sane wants that to work with the "import all" button anyway + newDirectory != null + // extra safety against various I/O errors (lack of access, deleted directory, etc.) + && newDirectory.Exists + // there must be at least one file in the current directory for the game to import (non-recursive) + && newDirectory.EnumerateFiles().Any(file => game.HandledExtensions.Contains(file.Extension)); } private void fileChanged(ValueChangedEvent selectedFile) @@ -143,14 +168,14 @@ namespace osu.Game.Screens.Import currentFileText.Text = selectedFile.NewValue?.Name ?? "Select a file"; } - private void startImport(string path) + private void startImport(params string[] paths) { - if (string.IsNullOrEmpty(path)) + if (paths.Length == 0) return; Task.Factory.StartNew(async () => { - await game.Import(path).ConfigureAwait(false); + await game.Import(paths).ConfigureAwait(false); // some files will be deleted after successful import, so we want to refresh the view. Schedule(() => @@ -160,5 +185,19 @@ namespace osu.Game.Screens.Import }); }, TaskCreationOptions.LongRunning); } + + private void startDirectoryImport(string path) + { + if (string.IsNullOrEmpty(path)) + return; + + // get only files that match extensions handled by the game + IEnumerable filesToImport = Directory.EnumerateFiles(path) + .Where(file => game.HandledExtensions.Contains(Path.GetExtension(file))); + if (!filesToImport.Any()) + return; + + startImport(filesToImport.ToArray()); + } } }