mirror of https://github.com/ppy/osu
Merge pull request #30402 from peppy/import-paused-visibility
Update notification text when import is paused due to gameplay
This commit is contained in:
commit
53f0befc05
|
@ -40,15 +40,13 @@ public void TestSceneMissingBeatmapWithOnlineAvailable()
|
|||
|
||||
AddStep("import score", () =>
|
||||
{
|
||||
using (var resourceStream = TestResources.OpenResource("Replays/mania-replay.osr"))
|
||||
{
|
||||
var importTask = new ImportTask(resourceStream, "replay.osr");
|
||||
var resourceStream = TestResources.OpenResource("Replays/mania-replay.osr");
|
||||
var importTask = new ImportTask(resourceStream, "replay.osr");
|
||||
|
||||
Game.ScoreManager.Import(new[] { importTask });
|
||||
}
|
||||
Game.ScoreManager.Import(new[] { importTask });
|
||||
});
|
||||
|
||||
AddUntilStep("Replay missing notification show", () => Game.Notifications.ChildrenOfType<MissingBeatmapNotification>().Any());
|
||||
AddUntilStep("Replay missing notification shown", () => Game.Notifications.ChildrenOfType<MissingBeatmapNotification>().Any());
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -58,15 +56,13 @@ public void TestSceneMissingBeatmapWithOnlineUnavailable()
|
|||
|
||||
AddStep("import score", () =>
|
||||
{
|
||||
using (var resourceStream = TestResources.OpenResource("Replays/mania-replay.osr"))
|
||||
{
|
||||
var importTask = new ImportTask(resourceStream, "replay.osr");
|
||||
var resourceStream = TestResources.OpenResource("Replays/mania-replay.osr");
|
||||
var importTask = new ImportTask(resourceStream, "replay.osr");
|
||||
|
||||
Game.ScoreManager.Import(new[] { importTask });
|
||||
}
|
||||
Game.ScoreManager.Import(new[] { importTask });
|
||||
});
|
||||
|
||||
AddUntilStep("Replay missing notification not show", () => !Game.Notifications.ChildrenOfType<MissingBeatmapNotification>().Any());
|
||||
AddUntilStep("Replay missing notification not shown", () => !Game.Notifications.ChildrenOfType<MissingBeatmapNotification>().Any());
|
||||
}
|
||||
|
||||
private void setupBeatmapResponse(APIBeatmap b)
|
||||
|
|
|
@ -68,18 +68,23 @@ protected bool Download(T model, bool minimiseDownloadSize, TModel? originalMode
|
|||
{
|
||||
Task.Factory.StartNew(async () =>
|
||||
{
|
||||
bool importSuccessful;
|
||||
bool importSuccessful = false;
|
||||
|
||||
if (originalModel != null)
|
||||
importSuccessful = (await importer.ImportAsUpdate(notification, new ImportTask(filename), originalModel).ConfigureAwait(false)) != null;
|
||||
else
|
||||
importSuccessful = (await importer.Import(notification, new[] { new ImportTask(filename) }).ConfigureAwait(false)).Any();
|
||||
try
|
||||
{
|
||||
if (originalModel != null)
|
||||
importSuccessful = (await importer.ImportAsUpdate(notification, new ImportTask(filename), originalModel).ConfigureAwait(false)) != null;
|
||||
else
|
||||
importSuccessful = (await importer.Import(notification, new[] { new ImportTask(filename) }).ConfigureAwait(false)).Any();
|
||||
}
|
||||
finally
|
||||
{
|
||||
// for now a failed import will be marked as a failed download for simplicity.
|
||||
if (!importSuccessful)
|
||||
DownloadFailed?.Invoke(request);
|
||||
|
||||
// for now a failed import will be marked as a failed download for simplicity.
|
||||
if (!importSuccessful)
|
||||
DownloadFailed?.Invoke(request);
|
||||
|
||||
CurrentDownloads.Remove(request);
|
||||
CurrentDownloads.Remove(request);
|
||||
}
|
||||
}, TaskCreationOptions.LongRunning);
|
||||
};
|
||||
|
||||
|
|
|
@ -105,7 +105,6 @@ public async Task<IEnumerable<Live<TModel>>> Import(ProgressNotification notific
|
|||
}
|
||||
|
||||
notification.Progress = 0;
|
||||
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is initialising...";
|
||||
|
||||
int current = 0;
|
||||
|
||||
|
@ -113,65 +112,78 @@ public async Task<IEnumerable<Live<TModel>>> Import(ProgressNotification notific
|
|||
|
||||
parameters.Batch |= tasks.Length >= minimum_items_considered_batch_import;
|
||||
|
||||
await Task.WhenAll(tasks.Select(async task =>
|
||||
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is initialising...";
|
||||
notification.State = ProgressNotificationState.Active;
|
||||
|
||||
await pauseIfNecessaryAsync(parameters, notification, notification.CancellationToken).ConfigureAwait(false);
|
||||
|
||||
try
|
||||
{
|
||||
if (notification.CancellationToken.IsCancellationRequested)
|
||||
return;
|
||||
|
||||
try
|
||||
await Parallel.ForEachAsync(tasks, notification.CancellationToken, async (task, cancellation) =>
|
||||
{
|
||||
var model = await Import(task, parameters, notification.CancellationToken).ConfigureAwait(false);
|
||||
cancellation.ThrowIfCancellationRequested();
|
||||
|
||||
lock (imported)
|
||||
try
|
||||
{
|
||||
if (model != null)
|
||||
imported.Add(model);
|
||||
current++;
|
||||
await pauseIfNecessaryAsync(parameters, notification, cancellation).ConfigureAwait(false);
|
||||
|
||||
notification.Text = $"Imported {current} of {tasks.Length} {HumanisedModelName}s";
|
||||
notification.Progress = (float)current / tasks.Length;
|
||||
var model = await Import(task, parameters, cancellation).ConfigureAwait(false);
|
||||
|
||||
lock (imported)
|
||||
{
|
||||
if (model != null)
|
||||
imported.Add(model);
|
||||
current++;
|
||||
|
||||
notification.Text = $"Imported {current} of {tasks.Length} {HumanisedModelName}s";
|
||||
notification.Progress = (float)current / tasks.Length;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
throw;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database);
|
||||
}
|
||||
}).ConfigureAwait(false);
|
||||
}
|
||||
finally
|
||||
{
|
||||
if (imported.Count == 0)
|
||||
{
|
||||
if (notification.CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
}
|
||||
else
|
||||
{
|
||||
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import failed! Check logs for more information.";
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
}
|
||||
}
|
||||
catch (OperationCanceledException)
|
||||
{
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Logger.Error(e, $@"Could not import ({task})", LoggingTarget.Database);
|
||||
}
|
||||
})).ConfigureAwait(false);
|
||||
|
||||
if (imported.Count == 0)
|
||||
{
|
||||
if (notification.CancellationToken.IsCancellationRequested)
|
||||
{
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
return imported;
|
||||
}
|
||||
|
||||
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import failed! Check logs for more information.";
|
||||
notification.State = ProgressNotificationState.Cancelled;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (tasks.Length > imported.Count)
|
||||
notification.CompletionText = $"Imported {imported.Count} of {tasks.Length} {HumanisedModelName}s.";
|
||||
else if (imported.Count > 1)
|
||||
notification.CompletionText = $"Imported {imported.Count} {HumanisedModelName}s!";
|
||||
else
|
||||
notification.CompletionText = $"Imported {imported.First().GetDisplayString()}!";
|
||||
|
||||
if (imported.Count > 0 && PresentImport != null)
|
||||
{
|
||||
notification.CompletionText += " Click to view.";
|
||||
notification.CompletionClickAction = () =>
|
||||
{
|
||||
PresentImport?.Invoke(imported);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
if (tasks.Length > imported.Count)
|
||||
notification.CompletionText = $"Imported {imported.Count} of {tasks.Length} {HumanisedModelName}s.";
|
||||
else if (imported.Count > 1)
|
||||
notification.CompletionText = $"Imported {imported.Count} {HumanisedModelName}s!";
|
||||
else
|
||||
notification.CompletionText = $"Imported {imported.First().GetDisplayString()}!";
|
||||
|
||||
notification.State = ProgressNotificationState.Completed;
|
||||
if (imported.Count > 0 && PresentImport != null)
|
||||
{
|
||||
notification.CompletionText += " Click to view.";
|
||||
notification.CompletionClickAction = () =>
|
||||
{
|
||||
PresentImport?.Invoke(imported);
|
||||
return true;
|
||||
};
|
||||
}
|
||||
|
||||
notification.State = ProgressNotificationState.Completed;
|
||||
}
|
||||
}
|
||||
|
||||
return imported;
|
||||
|
@ -286,8 +298,6 @@ public async Task<ExternalEditOperation<TModel>> BeginExternalEditing(TModel mod
|
|||
/// <param name="cancellationToken">An optional cancellation token.</param>
|
||||
public virtual Live<TModel>? ImportModel(TModel item, ArchiveReader? archive = null, ImportParameters parameters = default, CancellationToken cancellationToken = default) => Realm.Run(realm =>
|
||||
{
|
||||
pauseIfNecessary(parameters, cancellationToken);
|
||||
|
||||
TModel? existing;
|
||||
|
||||
if (parameters.Batch && archive != null)
|
||||
|
@ -528,7 +538,8 @@ protected virtual void PostImport(TModel model, Realm realm, ImportParameters pa
|
|||
/// <param name="model">The new model proposed for import.</param>
|
||||
/// <param name="realm">The current realm context.</param>
|
||||
/// <returns>An existing model which matches the criteria to skip importing, else null.</returns>
|
||||
protected TModel? CheckForExisting(TModel model, Realm realm) => string.IsNullOrEmpty(model.Hash) ? null : realm.All<TModel>().OrderBy(b => b.DeletePending).FirstOrDefault(b => b.Hash == model.Hash);
|
||||
protected TModel? CheckForExisting(TModel model, Realm realm) =>
|
||||
string.IsNullOrEmpty(model.Hash) ? null : realm.All<TModel>().OrderBy(b => b.DeletePending).FirstOrDefault(b => b.Hash == model.Hash);
|
||||
|
||||
/// <summary>
|
||||
/// Whether import can be skipped after finding an existing import early in the process.
|
||||
|
@ -575,21 +586,29 @@ protected virtual void UndeleteForReuse(TModel existing)
|
|||
/// <returns>Whether to perform deletion.</returns>
|
||||
protected virtual bool ShouldDeleteArchive(string path) => false;
|
||||
|
||||
private void pauseIfNecessary(ImportParameters importParameters, CancellationToken cancellationToken)
|
||||
private async Task pauseIfNecessaryAsync(ImportParameters importParameters, ProgressNotification notification, CancellationToken cancellationToken)
|
||||
{
|
||||
if (!PauseImports || importParameters.ImportImmediately)
|
||||
return;
|
||||
|
||||
Logger.Log($@"{GetType().Name} is being paused.");
|
||||
|
||||
// A paused state could obviously be entered mid-import (during the `Task.WhenAll` below),
|
||||
// but in order to keep things simple let's focus on the most common scenario.
|
||||
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is paused due to gameplay...";
|
||||
notification.State = ProgressNotificationState.Queued;
|
||||
|
||||
while (PauseImports)
|
||||
{
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Thread.Sleep(500);
|
||||
await Task.Delay(500, cancellationToken).ConfigureAwait(false);
|
||||
}
|
||||
|
||||
cancellationToken.ThrowIfCancellationRequested();
|
||||
Logger.Log($@"{GetType().Name} is being resumed.");
|
||||
|
||||
notification.Text = $"{HumanisedModelName.Humanize(LetterCasing.Title)} import is resuming...";
|
||||
notification.State = ProgressNotificationState.Active;
|
||||
}
|
||||
|
||||
private IEnumerable<string> getIDs(IEnumerable<INamedFile> files)
|
||||
|
|
Loading…
Reference in New Issue