diff --git a/src/PicView.Avalonia/Navigation/ImageIterator.cs b/src/PicView.Avalonia/Navigation/ImageIterator.cs index b7ca5789..2b21f4c6 100644 --- a/src/PicView.Avalonia/Navigation/ImageIterator.cs +++ b/src/PicView.Avalonia/Navigation/ImageIterator.cs @@ -442,7 +442,7 @@ public int GetIteration(int index, NavigateTo navigateTo, bool skip1 = false, bo return next; } - public async Task NextIteration(NavigateTo navigateTo) + public async Task NextIteration(NavigateTo navigateTo, CancellationToken cancellationToken = default) { var index = GetIteration(CurrentIndex, navigateTo, SettingsHelper.Settings.ImageScaling.ShowImageSideBySide); if (index < 0) @@ -452,11 +452,11 @@ public async Task NextIteration(NavigateTo navigateTo) if (!MainKeyboardShortcuts.IsKeyHeldDown) { - await IterateToIndex(index); + await IterateToIndex(index, cancellationToken).ConfigureAwait(false); } else { - await TimerIteration(index); + await TimerIteration(index).ConfigureAwait(false); } } @@ -472,16 +472,15 @@ public async Task Next100Iteration(bool forwards) await IterateToIndex(index).ConfigureAwait(false); } - public async Task IterateToIndex(int index) + public async Task IterateToIndex(int index, CancellationToken cancellationToken = default) { - SetTitleHelper.SetLoadingTitle(_vm); - if (index < 0 || index >= ImagePaths.Count) { ErrorHandling.ShowStartUpMenu(_vm); return; } + using var cts = CancellationTokenSource.CreateLinkedTokenSource(cancellationToken); // UI is more responsive when started in new thread await Task.Run(async () => { @@ -500,10 +499,11 @@ await Task.Run(async () => while (preloadValue.IsLoading) { - await Task.Delay(20).ConfigureAwait(false); + await Task.Delay(20, cancellationToken).ConfigureAwait(false); if (CurrentIndex != index) { // Skip loading if user went to next value + await cts.CancelAsync(); return; } } @@ -517,6 +517,7 @@ await Task.Run(async () => if (CurrentIndex != index) { // Skip loading if user went to next value + await cts.CancelAsync(); return; } @@ -527,6 +528,7 @@ await Task.Run(async () => if (CurrentIndex != index) { // Skip loading if user went to next value + await cts.CancelAsync(); return; } @@ -534,11 +536,13 @@ await Task.Run(async () => { _vm.SecondaryImageSource = nextPreloadValue.ImageModel?.Image; } + cancellationToken.ThrowIfCancellationRequested(); await UpdateImage.UpdateSource(_vm, index, ImagePaths, IsReversed, preloadValue, nextPreloadValue) .ConfigureAwait(false); } else { + cancellationToken.ThrowIfCancellationRequested(); await UpdateImage.UpdateSource(_vm, index, ImagePaths, IsReversed, preloadValue) .ConfigureAwait(false); } @@ -553,7 +557,7 @@ await Dispatcher.UIThread.InvokeAsync(() => }); } - await PreLoader.PreLoadAsync(CurrentIndex, ImagePaths.Count, IsReversed, ImagePaths) + await PreLoader.PreLoadAsync(CurrentIndex, ImagePaths.Count, IsReversed, ImagePaths, cancellationToken) .ConfigureAwait(false); } @@ -581,6 +585,8 @@ await PreLoader.PreLoadAsync(CurrentIndex, ImagePaths.Count, IsReversed, ImagePa void TryShowPreview(PreLoadValue preloadValue) { + SetTitleHelper.SetLoadingTitle(_vm); + if (preloadValue is null) { return; @@ -600,7 +606,7 @@ void TryShowPreview(PreLoadValue preloadValue) _vm.ImageSource = null; _vm.SecondaryImageSource = null; } - }); + }, cancellationToken); } private static Timer? _timer; @@ -627,7 +633,7 @@ internal async Task TimerIteration(int index) _timer.Interval = TimeSpan.FromSeconds(SettingsHelper.Settings.UIProperties.NavSpeed).TotalMilliseconds; _timer.Start(); - await IterateToIndex(index); + await IterateToIndex(index).ConfigureAwait(false); } public void UpdateFileListAndIndex(List fileList, int index) diff --git a/src/PicView.Avalonia/Navigation/NavigationHelper.cs b/src/PicView.Avalonia/Navigation/NavigationHelper.cs index a2531812..663e5ccf 100644 --- a/src/PicView.Avalonia/Navigation/NavigationHelper.cs +++ b/src/PicView.Avalonia/Navigation/NavigationHelper.cs @@ -24,6 +24,7 @@ namespace PicView.Avalonia.Navigation; /// public static class NavigationHelper { + private static CancellationTokenSource? _cancellationTokenSource; #region Navigation @@ -59,7 +60,8 @@ public static async Task Navigate(bool next, MainViewModel vm) else { var navigateTo = next ? NavigateTo.Next : NavigateTo.Previous; - await vm.ImageIterator.NextIteration(navigateTo).ConfigureAwait(false); + _cancellationTokenSource = new CancellationTokenSource(); + await vm.ImageIterator.NextIteration(navigateTo, _cancellationTokenSource.Token).ConfigureAwait(false); } } @@ -147,6 +149,10 @@ public static async Task GoToNextFolder(bool next, MainViewModel vm) return; } SetTitleHelper.SetLoadingTitle(vm); + if (_cancellationTokenSource is not null) + { + await _cancellationTokenSource.CancelAsync(); + } var fileList = await GetNextFolderFileList(next, vm).ConfigureAwait(false); if (fileList is null) @@ -180,6 +186,11 @@ public static async Task LoadPicFromStringAsync(string source, MainViewModel vm) UIHelper.CloseMenus(vm); vm.IsLoading = true; SetTitleHelper.SetLoadingTitle(vm); + + if (_cancellationTokenSource is not null) + { + await _cancellationTokenSource.CancelAsync(); + } // Starting in new task makes it more responsive and works better await Task.Run(async () => @@ -263,6 +274,11 @@ public static async Task LoadPicFromFile(string fileName, MainViewModel vm, File { vm.PlatformService.StopTaskbarProgress(); } + + if (_cancellationTokenSource is not null) + { + await _cancellationTokenSource.CancelAsync(); + } if (vm.ImageIterator is not null) { @@ -313,6 +329,11 @@ public static async Task LoadPicFromFile(string fileName, MainViewModel vm, File /// public static async Task LoadPicFromArchiveAsync(string path, MainViewModel vm) { + if (_cancellationTokenSource is not null) + { + await _cancellationTokenSource.CancelAsync(); + } + var extraction = await ArchiveExtraction.ExtractArchiveAsync(path, vm.PlatformService.ExtractWithLocalSoftwareAsync).ConfigureAwait(false); if (!extraction) { @@ -349,6 +370,11 @@ public static async Task LoadPicFromArchiveAsync(string path, MainViewModel vm) /// A task representing the asynchronous operation. public static async Task LoadPicFromUrlAsync(string url, MainViewModel vm) { + if (_cancellationTokenSource is not null) + { + await _cancellationTokenSource.CancelAsync(); + } + string destination; try @@ -466,6 +492,11 @@ public static async Task LoadPicFromDirectoryAsync(string file, MainViewModel vm vm.IsLoading = true; SetTitleHelper.SetLoadingTitle(vm); + if (_cancellationTokenSource is not null) + { + await _cancellationTokenSource.CancelAsync(); + } + if (SettingsHelper.Settings.UIProperties.IsTaskbarProgressEnabled) { vm.PlatformService.StopTaskbarProgress(); diff --git a/src/PicView.Avalonia/Views/ImageViewer.axaml.cs b/src/PicView.Avalonia/Views/ImageViewer.axaml.cs index 1ed5b4b0..cba53195 100644 --- a/src/PicView.Avalonia/Views/ImageViewer.axaml.cs +++ b/src/PicView.Avalonia/Views/ImageViewer.axaml.cs @@ -14,7 +14,6 @@ using PicView.Core.Config; using PicView.Core.ImageDecoding; using PicView.Core.ImageTransformations; -using PicView.Core.Navigation; using Point = Avalonia.Point; namespace PicView.Avalonia.Views; @@ -185,13 +184,18 @@ async Task LoadNextPic() { return; } - var navigateTo = SettingsHelper.Settings.Zoom.HorizontalReverseScroll ? NavigateTo.Previous : NavigateTo.Next; + + bool next; if (reverse) { - navigateTo = SettingsHelper.Settings.Zoom.HorizontalReverseScroll ? NavigateTo.Next : NavigateTo.Previous; + next = SettingsHelper.Settings.Zoom.HorizontalReverseScroll; + } + else + { + next = !SettingsHelper.Settings.Zoom.HorizontalReverseScroll; } - await mainViewModel.ImageIterator.NextIteration(navigateTo).ConfigureAwait(false); + await NavigationHelper.Navigate(next, mainViewModel).ConfigureAwait(false); } }