From f83aae50bed297a99f389ee55fd014fa14eba448 Mon Sep 17 00:00:00 2001 From: Ben Olden-Cooligan Date: Sun, 14 Jan 2024 22:34:14 -0800 Subject: [PATCH] Optimize session loading --- .../EtoForms/Desktop/DesktopController.cs | 9 +++------ .../Desktop/DesktopImagesController.cs | 7 +++++++ NAPS2.Lib/Operation/OperationBase.cs | 12 ++++++++++++ NAPS2.Lib/Recovery/RecoverableFolder.cs | 19 ++++++++++++++++--- NAPS2.Lib/Recovery/RecoveryOperation.cs | 9 ++++++--- NAPS2.Lib/Recovery/RecoveryParams.cs | 7 +++++++ 6 files changed, 51 insertions(+), 12 deletions(-) diff --git a/NAPS2.Lib/EtoForms/Desktop/DesktopController.cs b/NAPS2.Lib/EtoForms/Desktop/DesktopController.cs index c4d334da2b..4861c28091 100644 --- a/NAPS2.Lib/EtoForms/Desktop/DesktopController.cs +++ b/NAPS2.Lib/EtoForms/Desktop/DesktopController.cs @@ -306,13 +306,10 @@ private void ShowRecoveryPrompt() AutoSessionRestore = _config.Get(c => c.KeepSession), ThumbnailSize = _thumbnailController.RenderSize }; - if (op.Start(_desktopImagesController.ReceiveScannedImage(), recoveryParams)) + if (op.Start(_desktopImagesController.ReceiveScannedImage(), _desktopImagesController.AppendImageBatch, + recoveryParams)) { - if (recoveryParams.AutoSessionRestore) - { - _operationProgress.ShowBackgroundProgress(op); - } - else + if (!recoveryParams.AutoSessionRestore) { _operationProgress.ShowProgress(op); } diff --git a/NAPS2.Lib/EtoForms/Desktop/DesktopImagesController.cs b/NAPS2.Lib/EtoForms/Desktop/DesktopImagesController.cs index c28c3e4c3a..b794ba6fe4 100644 --- a/NAPS2.Lib/EtoForms/Desktop/DesktopImagesController.cs +++ b/NAPS2.Lib/EtoForms/Desktop/DesktopImagesController.cs @@ -28,4 +28,11 @@ public Action ReceiveScannedImage() } }; } + + public void AppendImageBatch(IEnumerable images) + { + _imageList.Mutate( + new ImageListMutation.Append(images.Select(image => new UiImage(image))), + isPassiveInteraction: true); + } } \ No newline at end of file diff --git a/NAPS2.Lib/Operation/OperationBase.cs b/NAPS2.Lib/Operation/OperationBase.cs index 85c4d45547..f6fd7fa907 100644 --- a/NAPS2.Lib/Operation/OperationBase.cs +++ b/NAPS2.Lib/Operation/OperationBase.cs @@ -56,6 +56,18 @@ protected void RunAsync(Func action) StartTask(() => Task.FromResult(action())); } + protected void RunSync(Func action) + { + try + { + _tcs.TrySetResult(action()); + } + catch (Exception ex) + { + _tcs.TrySetException(ex); + } + } + private void StartTask(Func> action) { Task.Run(async () => diff --git a/NAPS2.Lib/Recovery/RecoverableFolder.cs b/NAPS2.Lib/Recovery/RecoverableFolder.cs index 2cc24158f3..f6e832f413 100644 --- a/NAPS2.Lib/Recovery/RecoverableFolder.cs +++ b/NAPS2.Lib/Recovery/RecoverableFolder.cs @@ -102,8 +102,8 @@ public void TryDelete() } } - public bool TryRecover(Action imageCallback, RecoveryParams recoveryParams, - ProgressHandler progress) + public bool TryRecover(Action imageCallback, Action> imageBatchCallback, + RecoveryParams recoveryParams, ProgressHandler progress) { if (_disposed) throw new ObjectDisposedException(nameof(RecoverableFolder)); @@ -111,6 +111,8 @@ public bool TryRecover(Action imageCallback, RecoveryParams reco int totalProgress = ImageCount; progress.Report(currentProgress, totalProgress); + var recoveredImages = new List(); + foreach (RecoveryIndexImage indexImage in _recoveryIndex.Images) { if (progress.IsCancellationRequested) @@ -145,11 +147,22 @@ public bool TryRecover(Action imageCallback, RecoveryParams reco var storage = new ImageFileStorage(newPath); var recoveredImage = CreateRecoveredImage(recoveryParams, storage, indexImage); - imageCallback(recoveredImage); + if (!recoveryParams.AutoSessionRestore) + { + imageCallback(recoveredImage); + } + else + { + recoveredImages.Add(recoveredImage); + } currentProgress++; progress.Report(currentProgress, totalProgress); } + if (recoveryParams.AutoSessionRestore) + { + imageBatchCallback(recoveredImages); + } // Now that we've recovered successfully, we can safely delete the old folder TryDelete(); return true; diff --git a/NAPS2.Lib/Recovery/RecoveryOperation.cs b/NAPS2.Lib/Recovery/RecoveryOperation.cs index 641fedd986..c8dd7cf8fd 100644 --- a/NAPS2.Lib/Recovery/RecoveryOperation.cs +++ b/NAPS2.Lib/Recovery/RecoveryOperation.cs @@ -18,7 +18,8 @@ public RecoveryOperation(IFormFactory formFactory, RecoveryManager recoveryManag AllowBackground = true; } - public bool Start(Action imageCallback, RecoveryParams recoveryParams) + public bool Start(Action imageCallback, Action> imageBatchCallback, + RecoveryParams recoveryParams) { Status = new OperationStatus { @@ -35,11 +36,13 @@ public bool Start(Action imageCallback, RecoveryParams recoveryP switch (recoveryParams.AutoSessionRestore ? RecoverAction.Recover : PromptToRecover(recoverableFolder)) { case RecoverAction.Recover: - RunAsync(() => + Action> runFunc = recoveryParams.AutoSessionRestore ? RunSync : RunAsync; + runFunc(() => { try { - return recoverableFolder.TryRecover(imageCallback, recoveryParams, ProgressHandler); + return recoverableFolder.TryRecover(imageCallback, imageBatchCallback, recoveryParams, + ProgressHandler); } finally { diff --git a/NAPS2.Lib/Recovery/RecoveryParams.cs b/NAPS2.Lib/Recovery/RecoveryParams.cs index 2040b5424e..7a617e2d01 100644 --- a/NAPS2.Lib/Recovery/RecoveryParams.cs +++ b/NAPS2.Lib/Recovery/RecoveryParams.cs @@ -2,6 +2,13 @@ public class RecoveryParams { + // In case the user has the "Keep images across sessions" option, we want to make the recovery operation feel more + // seamless. This means a few things: + // - Image files are moved instead of copied. This is destructive (higher risk of data loss) but fast. + // - Thumbnails rendering is deferred. + // - No operation progress is displayed. + // - The operation is run synchronously (with only moving files + no thumbnail rendering it should be trivially fast). + // - Images are sent back to the UI as a single batch (speeds up UI rendering). public bool AutoSessionRestore { get; set; } public int? ThumbnailSize { get; set; }