diff --git a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs index 5c20f46787..7a5f6dbd7c 100644 --- a/osu.Game.Tests/Skins/IO/ImportSkinTest.cs +++ b/osu.Game.Tests/Skins/IO/ImportSkinTest.cs @@ -15,6 +15,7 @@ using osu.Framework.Platform; using osu.Game.Database; using osu.Game.Extensions; using osu.Game.IO; +using osu.Game.Overlays; using osu.Game.Skinning; using SharpCompress.Archives.Zip; @@ -122,7 +123,7 @@ namespace osu.Game.Tests.Skins.IO import1.PerformRead(s => { - new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); + new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream); }); string exportFilename = import1.GetDisplayString(); @@ -204,7 +205,7 @@ namespace osu.Game.Tests.Skins.IO Assert.IsFalse(s.Protected); Assert.AreEqual(typeof(ArgonSkin), s.CreateInstance(skinManager).GetType()); - new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); + new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream); Assert.Greater(exportStream.Length, 0); }); @@ -239,7 +240,7 @@ namespace osu.Game.Tests.Skins.IO Assert.IsFalse(s.Protected); Assert.AreEqual(typeof(DefaultLegacySkin), s.CreateInstance(skinManager).GetType()); - new LegacySkinExporter(osu.Dependencies.Get()).ExportModelTo(s, exportStream); + new LegacySkinExporter(osu.Dependencies.Get(), osu.Dependencies.Get()).ExportModelTo(s, exportStream); Assert.Greater(exportStream.Length, 0); }); diff --git a/osu.Game/Database/LegacyBeatmapExporter.cs b/osu.Game/Database/LegacyBeatmapExporter.cs index d064b9ed58..3e11e898f3 100644 --- a/osu.Game/Database/LegacyBeatmapExporter.cs +++ b/osu.Game/Database/LegacyBeatmapExporter.cs @@ -1,10 +1,9 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Platform; using osu.Game.Beatmaps; +using osu.Game.Overlays; namespace osu.Game.Database { @@ -12,8 +11,8 @@ namespace osu.Game.Database { protected override string FileExtension => ".osz"; - public LegacyBeatmapExporter(Storage storage) - : base(storage) + public LegacyBeatmapExporter(Storage storage, INotificationOverlay? notificationOverlay) + : base(storage, notificationOverlay) { } } diff --git a/osu.Game/Database/LegacyExporter.cs b/osu.Game/Database/LegacyExporter.cs index 16d7441dde..ed16e4bc80 100644 --- a/osu.Game/Database/LegacyExporter.cs +++ b/osu.Game/Database/LegacyExporter.cs @@ -1,11 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.IO; +using System.Threading.Tasks; using osu.Framework.Platform; using osu.Game.Extensions; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using SharpCompress.Archives.Zip; namespace osu.Game.Database @@ -25,10 +26,17 @@ namespace osu.Game.Database private readonly Storage exportStorage; - protected LegacyExporter(Storage storage) + private readonly INotificationOverlay? notificationOverlay; + + protected ProgressNotification Notification = null!; + + private string filename = null!; + + protected LegacyExporter(Storage storage, INotificationOverlay? notificationOverlay) { exportStorage = storage.GetStorageForDirectory(@"exports"); UserFileStorage = storage.GetStorageForDirectory(@"files"); + this.notificationOverlay = notificationOverlay; } /// @@ -37,12 +45,25 @@ namespace osu.Game.Database /// The item to export. public void Export(TModel item) { - string filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}"; + filename = $"{item.GetDisplayString().GetValidFilename()}{FileExtension}"; - using (var stream = exportStorage.CreateFileSafely(filename)) - ExportModelTo(item, stream); + Stream stream = exportStorage.CreateFileSafely(filename); - exportStorage.PresentFileExternally(filename); + Notification = new ProgressNotification + { + State = ProgressNotificationState.Active, + Text = "Exporting...", + CompletionText = "Export completed" + }; + Notification.CompletionClickAction += () => exportStorage.PresentFileExternally(filename); + Notification.CancelRequested += () => + { + stream.Dispose(); + return true; + }; + + ExportModelTo(item, stream); + notificationOverlay?.Post(Notification); } /// @@ -57,7 +78,24 @@ namespace osu.Game.Database foreach (var file in model.Files) archive.AddEntry(file.Filename, UserFileStorage.GetStream(file.File.GetStoragePath())); - archive.SaveTo(outputStream); + Task.Factory.StartNew(() => + { + archive.SaveTo(outputStream); + }, Notification.CancellationToken).ContinueWith(t => + { + if (t.IsCompletedSuccessfully) + { + outputStream.Dispose(); + Notification.State = ProgressNotificationState.Completed; + } + else + { + if (Notification.State == ProgressNotificationState.Cancelled) return; + + Notification.State = ProgressNotificationState.Cancelled; + Notification.Text = "Export Failed"; + } + }); } } } diff --git a/osu.Game/Database/LegacyScoreExporter.cs b/osu.Game/Database/LegacyScoreExporter.cs index 6fa02b957d..1564c7b077 100644 --- a/osu.Game/Database/LegacyScoreExporter.cs +++ b/osu.Game/Database/LegacyScoreExporter.cs @@ -1,12 +1,12 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System.IO; using System.Linq; using osu.Framework.Platform; using osu.Game.Extensions; +using osu.Game.Overlays; +using osu.Game.Overlays.Notifications; using osu.Game.Scoring; namespace osu.Game.Database @@ -15,8 +15,8 @@ namespace osu.Game.Database { protected override string FileExtension => ".osr"; - public LegacyScoreExporter(Storage storage) - : base(storage) + public LegacyScoreExporter(Storage storage, INotificationOverlay? notificationOverlay) + : base(storage, notificationOverlay) { } @@ -28,6 +28,9 @@ namespace osu.Game.Database using (var inputStream = UserFileStorage.GetStream(file.File.GetStoragePath())) inputStream.CopyTo(outputStream); + + Notification.State = ProgressNotificationState.Completed; + outputStream.Dispose(); } } } diff --git a/osu.Game/Database/LegacyScoreImporter.cs b/osu.Game/Database/LegacyScoreImporter.cs index f61241141e..131b4ffb0e 100644 --- a/osu.Game/Database/LegacyScoreImporter.cs +++ b/osu.Game/Database/LegacyScoreImporter.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using System; using System.Collections.Generic; using System.IO; diff --git a/osu.Game/Database/LegacySkinExporter.cs b/osu.Game/Database/LegacySkinExporter.cs index 1d5364fb8d..a78d69e7b9 100644 --- a/osu.Game/Database/LegacySkinExporter.cs +++ b/osu.Game/Database/LegacySkinExporter.cs @@ -1,9 +1,8 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Framework.Platform; +using osu.Game.Overlays; using osu.Game.Skinning; namespace osu.Game.Database @@ -12,8 +11,8 @@ namespace osu.Game.Database { protected override string FileExtension => ".osk"; - public LegacySkinExporter(Storage storage) - : base(storage) + public LegacySkinExporter(Storage storage, INotificationOverlay? notificationOverlay) + : base(storage, notificationOverlay) { } } diff --git a/osu.Game/Database/LegacySkinImporter.cs b/osu.Game/Database/LegacySkinImporter.cs index 42b2f2e1d8..2f05ccae45 100644 --- a/osu.Game/Database/LegacySkinImporter.cs +++ b/osu.Game/Database/LegacySkinImporter.cs @@ -1,8 +1,6 @@ // Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. -#nullable disable - using osu.Game.Skinning; namespace osu.Game.Database diff --git a/osu.Game/Database/RealmAccess.cs b/osu.Game/Database/RealmAccess.cs index 1a938c12e5..5a7ead1c59 100644 --- a/osu.Game/Database/RealmAccess.cs +++ b/osu.Game/Database/RealmAccess.cs @@ -173,11 +173,6 @@ namespace osu.Game.Database if (!Filename.EndsWith(realm_extension, StringComparison.Ordinal)) Filename += realm_extension; -#if DEBUG - if (!DebugUtils.IsNUnitRunning) - applyFilenameSchemaSuffix(ref Filename); -#endif - string newerVersionFilename = $"{Filename.Replace(realm_extension, string.Empty)}_newer_version{realm_extension}"; // Attempt to recover a newer database version if available. diff --git a/osu.Game/Online/Leaderboards/LeaderboardScore.cs b/osu.Game/Online/Leaderboards/LeaderboardScore.cs index a7b6bd044d..72f1a94ec8 100644 --- a/osu.Game/Online/Leaderboards/LeaderboardScore.cs +++ b/osu.Game/Online/Leaderboards/LeaderboardScore.cs @@ -75,6 +75,9 @@ namespace osu.Game.Online.Leaderboards [Resolved] private Storage storage { get; set; } + [Resolved] + private INotificationOverlay notificationOverlay { get; set; } + public ITooltip GetCustomTooltip() => new LeaderboardScoreTooltip(); public virtual ScoreInfo TooltipContent => Score; @@ -427,7 +430,7 @@ namespace osu.Game.Online.Leaderboards if (Score.Files.Count > 0) { - items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage).Export(Score))); + items.Add(new OsuMenuItem("Export", MenuItemType.Standard, () => new LegacyScoreExporter(storage, notificationOverlay).Export(Score))); items.Add(new OsuMenuItem(CommonStrings.ButtonsDelete, MenuItemType.Destructive, () => dialogOverlay?.Push(new LocalScoreDeleteDialog(Score)))); } diff --git a/osu.Game/Overlays/Settings/Sections/SkinSection.cs b/osu.Game/Overlays/Settings/Sections/SkinSection.cs index f602b73065..df6f719b1e 100644 --- a/osu.Game/Overlays/Settings/Sections/SkinSection.cs +++ b/osu.Game/Overlays/Settings/Sections/SkinSection.cs @@ -141,11 +141,16 @@ namespace osu.Game.Overlays.Settings.Sections [Resolved] private Storage storage { get; set; } + [CanBeNull] + private INotificationOverlay notificationOverlay; + private Bindable currentSkin; [BackgroundDependencyLoader] - private void load() + private void load(INotificationOverlay notificationOverlay) { + this.notificationOverlay = notificationOverlay; + Text = SkinSettingsStrings.ExportSkinButton; Action = export; } @@ -162,7 +167,7 @@ namespace osu.Game.Overlays.Settings.Sections { try { - currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage).Export(s)); + currentSkin.Value.SkinInfo.PerformRead(s => new LegacySkinExporter(storage, notificationOverlay).Export(s)); } catch (Exception e) { diff --git a/osu.Game/Screens/Edit/Editor.cs b/osu.Game/Screens/Edit/Editor.cs index bb390dfbf3..03bdd69f34 100644 --- a/osu.Game/Screens/Edit/Editor.cs +++ b/osu.Game/Screens/Edit/Editor.cs @@ -93,6 +93,9 @@ namespace osu.Game.Screens.Edit [Resolved] private Storage storage { get; set; } + [Resolved] + private INotificationOverlay notificationOverlay { get; set; } + [Resolved(canBeNull: true)] private IDialogOverlay dialogOverlay { get; set; } @@ -938,7 +941,7 @@ namespace osu.Game.Screens.Edit private void exportBeatmap() { Save(); - new LegacyBeatmapExporter(storage).Export(Beatmap.Value.BeatmapSetInfo); + new LegacyBeatmapExporter(storage, notificationOverlay).Export(Beatmap.Value.BeatmapSetInfo); } ///