|
|
@@ -12,491 +12,494 @@ using PicView.Core.Gallery;
|
|
|
using PicView.Core.Navigation;
|
|
|
using Timer = System.Timers.Timer;
|
|
|
|
|
|
-namespace PicView.Avalonia.Navigation;
|
|
|
-
|
|
|
-public sealed class ImageIterator : IDisposable
|
|
|
+namespace PicView.Avalonia.Navigation
|
|
|
{
|
|
|
- #region Properties
|
|
|
+ public sealed class ImageIterator : IDisposable
|
|
|
+ {
|
|
|
+ #region Properties
|
|
|
|
|
|
- private bool _disposed;
|
|
|
+ private bool _disposed;
|
|
|
|
|
|
- public List<string> ImagePaths { get; private set; }
|
|
|
+ public List<string> ImagePaths { get; private set; }
|
|
|
|
|
|
- public int CurrentIndex { get; private set; }
|
|
|
-
|
|
|
- public int NextIndex => GetIteration(CurrentIndex, NavigateTo.Next);
|
|
|
+ public int CurrentIndex { get; private set; }
|
|
|
|
|
|
- public FileInfo InitialFileInfo { get; private set; } = null!;
|
|
|
- public bool IsReversed { get; private set; }
|
|
|
- private PreLoader PreLoader { get; } = new();
|
|
|
+ public int NextIndex => GetIteration(CurrentIndex, NavigateTo.Next);
|
|
|
|
|
|
- private static FileSystemWatcher? _watcher;
|
|
|
- public bool IsRunning { get; private set; }
|
|
|
- private readonly MainViewModel? _vm;
|
|
|
+ public FileInfo InitialFileInfo { get; private set; } = null!;
|
|
|
+ public bool IsReversed { get; private set; }
|
|
|
+ private PreLoader PreLoader { get; } = new();
|
|
|
|
|
|
- #endregion
|
|
|
+ private static FileSystemWatcher? _watcher;
|
|
|
+ public bool IsRunning { get; private set; }
|
|
|
+ private readonly MainViewModel? _vm;
|
|
|
|
|
|
- #region Constructors
|
|
|
+ #endregion
|
|
|
|
|
|
- public ImageIterator(FileInfo fileInfo, MainViewModel vm)
|
|
|
- {
|
|
|
- ArgumentNullException.ThrowIfNull(fileInfo);
|
|
|
- _vm = vm;
|
|
|
- ImagePaths = vm.PlatformService.GetFiles(fileInfo);
|
|
|
- CurrentIndex = Directory.Exists(fileInfo.FullName) ? 0 : ImagePaths.IndexOf(fileInfo.FullName);
|
|
|
- InitiateFileSystemWatcher(fileInfo);
|
|
|
- }
|
|
|
+ #region Constructors
|
|
|
|
|
|
- public ImageIterator(FileInfo fileInfo, List<string> imagePaths, int currentIndex, MainViewModel vm)
|
|
|
- {
|
|
|
- ArgumentNullException.ThrowIfNull(fileInfo);
|
|
|
- _vm = vm;
|
|
|
- ImagePaths = imagePaths;
|
|
|
- CurrentIndex = currentIndex;
|
|
|
- InitiateFileSystemWatcher(fileInfo);
|
|
|
- }
|
|
|
+ public ImageIterator(FileInfo fileInfo, MainViewModel vm)
|
|
|
+ {
|
|
|
+ ArgumentNullException.ThrowIfNull(fileInfo);
|
|
|
+ _vm = vm;
|
|
|
+ ImagePaths = vm.PlatformService.GetFiles(fileInfo);
|
|
|
+ CurrentIndex = Directory.Exists(fileInfo.FullName) ? 0 : ImagePaths.IndexOf(fileInfo.FullName);
|
|
|
+ InitiateFileSystemWatcher(fileInfo);
|
|
|
+ }
|
|
|
+
|
|
|
+ public ImageIterator(FileInfo fileInfo, List<string> imagePaths, int currentIndex, MainViewModel vm)
|
|
|
+ {
|
|
|
+ ArgumentNullException.ThrowIfNull(fileInfo);
|
|
|
+ _vm = vm;
|
|
|
+ ImagePaths = imagePaths;
|
|
|
+ CurrentIndex = currentIndex;
|
|
|
+ InitiateFileSystemWatcher(fileInfo);
|
|
|
+ }
|
|
|
|
|
|
- #endregion
|
|
|
+ #endregion
|
|
|
|
|
|
- #region File Watcher
|
|
|
+ #region File Watcher
|
|
|
|
|
|
- private void InitiateFileSystemWatcher(FileInfo fileInfo)
|
|
|
- {
|
|
|
- InitialFileInfo = fileInfo;
|
|
|
- if (_watcher is not null)
|
|
|
+ private void InitiateFileSystemWatcher(FileInfo fileInfo)
|
|
|
{
|
|
|
- _watcher.Dispose();
|
|
|
- _watcher = null;
|
|
|
- }
|
|
|
+ InitialFileInfo = fileInfo;
|
|
|
+ if (_watcher is not null)
|
|
|
+ {
|
|
|
+ _watcher.Dispose();
|
|
|
+ _watcher = null;
|
|
|
+ }
|
|
|
|
|
|
- _watcher = new FileSystemWatcher();
|
|
|
+ _watcher = new FileSystemWatcher();
|
|
|
#if DEBUG
|
|
|
- Debug.Assert(fileInfo.DirectoryName != null);
|
|
|
+ Debug.Assert(fileInfo.DirectoryName != null);
|
|
|
#endif
|
|
|
- _watcher.Path = fileInfo.DirectoryName;
|
|
|
- _watcher.EnableRaisingEvents = true;
|
|
|
- _watcher.Filter = "*.*";
|
|
|
- _watcher.IncludeSubdirectories = SettingsHelper.Settings.Sorting.IncludeSubDirectories;
|
|
|
- _watcher.Created += async (_, e) => await OnFileAdded(e);
|
|
|
- _watcher.Deleted += async (_, e) => await OnFileDeleted(e);
|
|
|
- _watcher.Renamed += async (_, e) => await OnFileRenamed(e);
|
|
|
- }
|
|
|
-
|
|
|
- private async Task OnFileAdded(FileSystemEventArgs e)
|
|
|
- {
|
|
|
- if (ImagePaths.Contains(e.FullPath))
|
|
|
- {
|
|
|
- return;
|
|
|
+ _watcher.Path = fileInfo.DirectoryName;
|
|
|
+ _watcher.EnableRaisingEvents = true;
|
|
|
+ _watcher.Filter = "*.*";
|
|
|
+ _watcher.IncludeSubdirectories = SettingsHelper.Settings.Sorting.IncludeSubDirectories;
|
|
|
+ _watcher.Created += async (_, e) => await OnFileAdded(e);
|
|
|
+ _watcher.Deleted += async (_, e) => await OnFileDeleted(e);
|
|
|
+ _watcher.Renamed += async (_, e) => await OnFileRenamed(e);
|
|
|
}
|
|
|
|
|
|
- if (e.FullPath.IsSupported() == false)
|
|
|
+ private async Task OnFileAdded(FileSystemEventArgs e)
|
|
|
{
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (ImagePaths.Contains(e.FullPath))
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- var fileInfo = new FileInfo(e.FullPath);
|
|
|
- if (fileInfo.Exists == false)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (e.FullPath.IsSupported() == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- var retries = 0;
|
|
|
- while (IsRunning && retries < 10)
|
|
|
- {
|
|
|
- await Task.Delay(200);
|
|
|
- retries++;
|
|
|
- }
|
|
|
+ var fileInfo = new FileInfo(e.FullPath);
|
|
|
+ if (fileInfo.Exists == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- IsRunning = true;
|
|
|
-
|
|
|
- var sourceFileInfo = SettingsHelper.Settings.Sorting.IncludeSubDirectories ? new FileInfo(_watcher.Path) : fileInfo;
|
|
|
+ var retries = 0;
|
|
|
+ while (IsRunning && retries < 10)
|
|
|
+ {
|
|
|
+ await Task.Delay(200);
|
|
|
+ retries++;
|
|
|
+ }
|
|
|
|
|
|
- var newList = await Task.FromResult(_vm.PlatformService.GetFiles(sourceFileInfo));
|
|
|
- if (newList.Count == 0)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ IsRunning = true;
|
|
|
|
|
|
- if (newList.Count == ImagePaths.Count)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ var sourceFileInfo = SettingsHelper.Settings.Sorting.IncludeSubDirectories
|
|
|
+ ? new FileInfo(_watcher.Path)
|
|
|
+ : fileInfo;
|
|
|
|
|
|
- if (fileInfo.Exists == false)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ var newList = await Task.FromResult(_vm.PlatformService.GetFiles(sourceFileInfo));
|
|
|
+ if (newList.Count == 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- ImagePaths = newList;
|
|
|
-
|
|
|
- SetTitleHelper.RefreshTitle(_vm);
|
|
|
+ if (newList.Count == ImagePaths.Count)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- var index = ImagePaths.IndexOf(e.FullPath);
|
|
|
- if (index < 0)
|
|
|
- {
|
|
|
- IsRunning = false;
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (fileInfo.Exists == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- var nextIndex = index + 1;
|
|
|
- if (index >= ImagePaths.Count)
|
|
|
- {
|
|
|
- nextIndex = 0;
|
|
|
- }
|
|
|
+ ImagePaths = newList;
|
|
|
|
|
|
- var prevIndex = index - 1;
|
|
|
- if (prevIndex < 0)
|
|
|
- {
|
|
|
- prevIndex = ImagePaths.Count - 1;
|
|
|
- }
|
|
|
+ SetTitleHelper.RefreshTitle(_vm);
|
|
|
|
|
|
- var cleared = false;
|
|
|
- if (PreLoader.Contains(index, ImagePaths) || PreLoader.Contains(nextIndex, ImagePaths) ||
|
|
|
- PreLoader.Contains(prevIndex, ImagePaths))
|
|
|
- {
|
|
|
- PreLoader.RefreshAllFileInfo(ImagePaths);
|
|
|
- cleared = true;
|
|
|
- }
|
|
|
-
|
|
|
- IsRunning = false;
|
|
|
+ var index = ImagePaths.IndexOf(e.FullPath);
|
|
|
+ if (index < 0)
|
|
|
+ {
|
|
|
+ IsRunning = false;
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- var isGalleryItemAdded = await GalleryFunctions.AddGalleryItem(index, fileInfo, _vm);
|
|
|
- if (isGalleryItemAdded)
|
|
|
- {
|
|
|
- if (SettingsHelper.Settings.Gallery.IsBottomGalleryShown && ImagePaths.Count > 1)
|
|
|
+ var nextIndex = index + 1;
|
|
|
+ if (index >= ImagePaths.Count)
|
|
|
+ {
|
|
|
+ nextIndex = 0;
|
|
|
+ }
|
|
|
+
|
|
|
+ var prevIndex = index - 1;
|
|
|
+ if (prevIndex < 0)
|
|
|
+ {
|
|
|
+ prevIndex = ImagePaths.Count - 1;
|
|
|
+ }
|
|
|
+
|
|
|
+ var cleared = false;
|
|
|
+ if (PreLoader.Contains(index, ImagePaths) || PreLoader.Contains(nextIndex, ImagePaths) ||
|
|
|
+ PreLoader.Contains(prevIndex, ImagePaths))
|
|
|
+ {
|
|
|
+ PreLoader.RefreshAllFileInfo(ImagePaths);
|
|
|
+ cleared = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ IsRunning = false;
|
|
|
+
|
|
|
+ var isGalleryItemAdded = await GalleryFunctions.AddGalleryItem(index, fileInfo, _vm);
|
|
|
+ if (isGalleryItemAdded)
|
|
|
{
|
|
|
- if (_vm.GalleryMode is GalleryMode.BottomToClosed or GalleryMode.FullToClosed)
|
|
|
+ if (SettingsHelper.Settings.Gallery.IsBottomGalleryShown && ImagePaths.Count > 1)
|
|
|
{
|
|
|
- _vm.GalleryMode = GalleryMode.ClosedToBottom;
|
|
|
+ if (_vm.GalleryMode is GalleryMode.BottomToClosed or GalleryMode.FullToClosed)
|
|
|
+ {
|
|
|
+ _vm.GalleryMode = GalleryMode.ClosedToBottom;
|
|
|
+ }
|
|
|
}
|
|
|
+
|
|
|
+ GalleryNavigation.CenterScrollToSelectedItem(_vm);
|
|
|
}
|
|
|
|
|
|
- GalleryNavigation.CenterScrollToSelectedItem(_vm);
|
|
|
+ if (cleared)
|
|
|
+ {
|
|
|
+ await Preload();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- if (cleared)
|
|
|
+ private async Task OnFileDeleted(FileSystemEventArgs e)
|
|
|
{
|
|
|
- await Preload();
|
|
|
- }
|
|
|
- }
|
|
|
+ if (e.FullPath.IsSupported() == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- private async Task OnFileDeleted(FileSystemEventArgs e)
|
|
|
- {
|
|
|
- if (e.FullPath.IsSupported() == false)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
+ if (ImagePaths.Contains(e.FullPath) == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (ImagePaths.Contains(e.FullPath) == false)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- var index = ImagePaths.IndexOf(e.FullPath);
|
|
|
- if (index < 0)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
- var isSameFile = CurrentIndex == index;
|
|
|
- var isCleared = false;
|
|
|
+ var index = ImagePaths.IndexOf(e.FullPath);
|
|
|
+ if (index < 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (PreLoader.Contains(index, ImagePaths))
|
|
|
- {
|
|
|
- await PreLoader.ClearAsync();
|
|
|
- isCleared = true;
|
|
|
- }
|
|
|
-
|
|
|
- if (!ImagePaths.Remove(e.FullPath))
|
|
|
- {
|
|
|
+ var isSameFile = CurrentIndex == index;
|
|
|
+ var isCleared = false;
|
|
|
+
|
|
|
+ if (PreLoader.Contains(index, ImagePaths))
|
|
|
+ {
|
|
|
+ await PreLoader.ClearAsync();
|
|
|
+ isCleared = true;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (!ImagePaths.Remove(e.FullPath))
|
|
|
+ {
|
|
|
#if DEBUG
|
|
|
- Console.WriteLine($"Failed to remove {e.FullPath}");
|
|
|
+ Console.WriteLine($"Failed to remove {e.FullPath}");
|
|
|
#endif
|
|
|
- return;
|
|
|
- }
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (isSameFile)
|
|
|
- {
|
|
|
- if (ImagePaths.Count <= 0)
|
|
|
+ if (isSameFile)
|
|
|
{
|
|
|
- ErrorHandling.ShowStartUpMenu(_vm);
|
|
|
- return;
|
|
|
+ if (ImagePaths.Count <= 0)
|
|
|
+ {
|
|
|
+ ErrorHandling.ShowStartUpMenu(_vm);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ await NavigationHelper.Iterate(false, _vm);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ SetTitleHelper.SetTitle(_vm);
|
|
|
}
|
|
|
|
|
|
- await NavigationHelper.Iterate(false, _vm);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- SetTitleHelper.SetTitle(_vm);
|
|
|
+ var removed = GalleryFunctions.RemoveGalleryItem(index, _vm);
|
|
|
+ if (removed)
|
|
|
+ {
|
|
|
+ if (SettingsHelper.Settings.Gallery.IsBottomGalleryShown)
|
|
|
+ {
|
|
|
+ if (ImagePaths.Count == 1)
|
|
|
+ {
|
|
|
+ _vm.GalleryMode = GalleryMode.BottomToClosed;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ var indexOf = ImagePaths.IndexOf(_vm.FileInfo.FullName);
|
|
|
+ _vm.SelectedGalleryItemIndex = indexOf; // Fixes deselection bug
|
|
|
+ CurrentIndex = indexOf;
|
|
|
+ GalleryNavigation.CenterScrollToSelectedItem(_vm);
|
|
|
+ }
|
|
|
+
|
|
|
+ FileHistoryNavigation.Remove(e.FullPath);
|
|
|
+ if (isCleared)
|
|
|
+ {
|
|
|
+ await Preload();
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- var removed = GalleryFunctions.RemoveGalleryItem(index, _vm);
|
|
|
- if (removed)
|
|
|
+ private async Task OnFileRenamed(RenamedEventArgs e)
|
|
|
{
|
|
|
- if (SettingsHelper.Settings.Gallery.IsBottomGalleryShown)
|
|
|
+ if (e.FullPath.IsSupported() == false)
|
|
|
{
|
|
|
- if (ImagePaths.Count == 1)
|
|
|
+ if (ImagePaths.Contains(e.OldFullPath))
|
|
|
{
|
|
|
- _vm.GalleryMode = GalleryMode.BottomToClosed;
|
|
|
+ ImagePaths.Remove(e.OldFullPath);
|
|
|
}
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- var indexOf = ImagePaths.IndexOf(_vm.FileInfo.FullName);
|
|
|
- _vm.SelectedGalleryItemIndex = indexOf; // Fixes deselection bug
|
|
|
- CurrentIndex = indexOf;
|
|
|
- GalleryNavigation.CenterScrollToSelectedItem(_vm);
|
|
|
- }
|
|
|
+ if (IsRunning)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- FileHistoryNavigation.Remove(e.FullPath);
|
|
|
- if (isCleared)
|
|
|
- {
|
|
|
- await Preload();
|
|
|
- }
|
|
|
- }
|
|
|
+ IsRunning = true;
|
|
|
|
|
|
- private async Task OnFileRenamed(RenamedEventArgs e)
|
|
|
- {
|
|
|
- if (e.FullPath.IsSupported() == false)
|
|
|
- {
|
|
|
- if (ImagePaths.Contains(e.OldFullPath))
|
|
|
+ var oldIndex = ImagePaths.IndexOf(e.OldFullPath);
|
|
|
+ var sameFile = CurrentIndex == oldIndex;
|
|
|
+ var fileInfo = new FileInfo(e.FullPath);
|
|
|
+ if (fileInfo.Exists == false)
|
|
|
{
|
|
|
- ImagePaths.Remove(e.OldFullPath);
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- return;
|
|
|
- }
|
|
|
+ var sourceFileInfo = SettingsHelper.Settings.Sorting.IncludeSubDirectories
|
|
|
+ ? new FileInfo(_watcher.Path)
|
|
|
+ : fileInfo;
|
|
|
+ var newList = FileListHelper.RetrieveFiles(sourceFileInfo).ToList();
|
|
|
+ if (newList.Count == 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- if (IsRunning)
|
|
|
- {
|
|
|
- return;
|
|
|
+ if (fileInfo.Exists == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ ImagePaths = newList;
|
|
|
+
|
|
|
+ var index = ImagePaths.IndexOf(e.FullPath);
|
|
|
+ if (index < 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (fileInfo.Exists == false)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ await PreLoader.RefreshFileInfo(oldIndex, ImagePaths);
|
|
|
+ if (sameFile)
|
|
|
+ {
|
|
|
+ _vm.FileInfo = fileInfo;
|
|
|
+ }
|
|
|
+
|
|
|
+ SetTitleHelper.SetTitle(_vm);
|
|
|
+
|
|
|
+ IsRunning = false;
|
|
|
+ FileHistoryNavigation.Rename(e.OldFullPath, e.FullPath);
|
|
|
+ await Dispatcher.UIThread.InvokeAsync(() =>
|
|
|
+ GalleryFunctions.RenameGalleryItem(oldIndex, Path.GetFileNameWithoutExtension(e.Name), e.FullPath,
|
|
|
+ _vm));
|
|
|
}
|
|
|
|
|
|
- IsRunning = true;
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region Preloader
|
|
|
|
|
|
- var oldIndex = ImagePaths.IndexOf(e.OldFullPath);
|
|
|
- var sameFile = CurrentIndex == oldIndex;
|
|
|
- var fileInfo = new FileInfo(e.FullPath);
|
|
|
- if (fileInfo.Exists == false)
|
|
|
+ public void Clear()
|
|
|
{
|
|
|
- return;
|
|
|
+ PreLoader.Clear();
|
|
|
}
|
|
|
|
|
|
- var sourceFileInfo = SettingsHelper.Settings.Sorting.IncludeSubDirectories ? new FileInfo(_watcher.Path) : fileInfo;
|
|
|
- var newList = FileListHelper.RetrieveFiles(sourceFileInfo).ToList();
|
|
|
- if (newList.Count == 0)
|
|
|
+ public async Task Preload()
|
|
|
{
|
|
|
- return;
|
|
|
+ await PreLoader.PreLoadAsync(CurrentIndex, IsReversed, ImagePaths).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
|
- if (fileInfo.Exists == false)
|
|
|
+ public async Task AddAsync(int index, ImageModel imageModel)
|
|
|
{
|
|
|
- return;
|
|
|
+ await PreLoader.AddAsync(index, ImagePaths, imageModel).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
|
- ImagePaths = newList;
|
|
|
-
|
|
|
- var index = ImagePaths.IndexOf(e.FullPath);
|
|
|
- if (index < 0)
|
|
|
+ public PreLoadValue? GetPreLoadValue(int index)
|
|
|
{
|
|
|
- return;
|
|
|
+ return PreLoader.Get(index, ImagePaths);
|
|
|
}
|
|
|
|
|
|
- if (fileInfo.Exists == false)
|
|
|
+ public async Task<PreLoadValue?> GetPreLoadValueAsync(int index)
|
|
|
{
|
|
|
- return;
|
|
|
+ return await PreLoader.GetAsync(index, ImagePaths);
|
|
|
}
|
|
|
|
|
|
- await PreLoader.RefreshFileInfo(oldIndex, ImagePaths);
|
|
|
- if (sameFile)
|
|
|
+ public PreLoadValue? GetCurrentPreLoadValue()
|
|
|
{
|
|
|
- _vm.FileInfo = fileInfo;
|
|
|
+ return PreLoader.Get(CurrentIndex, ImagePaths);
|
|
|
}
|
|
|
|
|
|
- SetTitleHelper.SetTitle(_vm);
|
|
|
-
|
|
|
- IsRunning = false;
|
|
|
- FileHistoryNavigation.Rename(e.OldFullPath, e.FullPath);
|
|
|
- await Dispatcher.UIThread.InvokeAsync(() => GalleryFunctions.RenameGalleryItem(oldIndex, Path.GetFileNameWithoutExtension(e.Name), e.FullPath, _vm));
|
|
|
- }
|
|
|
+ public async Task<PreLoadValue?> GetCurrentPreLoadValueAsync()
|
|
|
+ {
|
|
|
+ return await PreLoader.GetAsync(CurrentIndex, ImagePaths);
|
|
|
+ }
|
|
|
|
|
|
- #endregion
|
|
|
+ public PreLoadValue? GetNextPreLoadValue()
|
|
|
+ {
|
|
|
+ var nextIndex = GetIteration(CurrentIndex, IsReversed ? NavigateTo.Previous : NavigateTo.Next);
|
|
|
+ return PreLoader.Get(nextIndex, ImagePaths);
|
|
|
+ }
|
|
|
|
|
|
- #region Preloader
|
|
|
+ public async Task<PreLoadValue?>? GetNextPreLoadValueAsync()
|
|
|
+ {
|
|
|
+ var nextIndex = GetIteration(CurrentIndex, NavigateTo.Next);
|
|
|
+ return await PreLoader.GetAsync(nextIndex, ImagePaths);
|
|
|
+ }
|
|
|
|
|
|
- public void Clear()
|
|
|
- {
|
|
|
- PreLoader.Clear();
|
|
|
- }
|
|
|
+ public void RemoveItemFromPreLoader(int index)
|
|
|
+ {
|
|
|
+ PreLoader.Remove(index, ImagePaths);
|
|
|
+ }
|
|
|
|
|
|
- public async Task Preload()
|
|
|
- {
|
|
|
- await PreLoader.PreLoadAsync(CurrentIndex, IsReversed, ImagePaths).ConfigureAwait(false);
|
|
|
- }
|
|
|
+ public void RemoveCurrentItemFromPreLoader()
|
|
|
+ {
|
|
|
+ PreLoader.Remove(CurrentIndex, ImagePaths);
|
|
|
+ }
|
|
|
|
|
|
- public async Task AddAsync(int index, ImageModel imageModel)
|
|
|
- {
|
|
|
- await PreLoader.AddAsync(index, ImagePaths, imageModel).ConfigureAwait(false);
|
|
|
- }
|
|
|
+ public bool RefreshAllFileInfo()
|
|
|
+ {
|
|
|
+ return PreLoader.RefreshAllFileInfo(ImagePaths);
|
|
|
+ }
|
|
|
|
|
|
- public PreLoadValue? GetPreLoadValue(int index)
|
|
|
- {
|
|
|
- return PreLoader.Get(index, ImagePaths);
|
|
|
- }
|
|
|
+ #endregion
|
|
|
|
|
|
- public async Task<PreLoadValue?> GetPreLoadValueAsync(int index)
|
|
|
- {
|
|
|
- return await PreLoader.GetAsync(index, ImagePaths);
|
|
|
- }
|
|
|
+ #region Navigation
|
|
|
|
|
|
- public PreLoadValue? GetCurrentPreLoadValue()
|
|
|
- {
|
|
|
- return PreLoader.Get(CurrentIndex, ImagePaths);
|
|
|
- }
|
|
|
+ public async Task ReloadFileList()
|
|
|
+ {
|
|
|
+ ImagePaths = await Task.FromResult(_vm.PlatformService.GetFiles(InitialFileInfo)).ConfigureAwait(false);
|
|
|
+ CurrentIndex = ImagePaths.IndexOf(_vm.FileInfo.FullName);
|
|
|
|
|
|
- public async Task<PreLoadValue?> GetCurrentPreLoadValueAsync()
|
|
|
- {
|
|
|
- return await PreLoader.GetAsync(CurrentIndex, ImagePaths);
|
|
|
- }
|
|
|
+ InitiateFileSystemWatcher(InitialFileInfo);
|
|
|
+ }
|
|
|
|
|
|
- public PreLoadValue? GetNextPreLoadValue()
|
|
|
- {
|
|
|
- var nextIndex = GetIteration(CurrentIndex, IsReversed ? NavigateTo.Previous : NavigateTo.Next);
|
|
|
- return PreLoader.Get(nextIndex, ImagePaths);
|
|
|
- }
|
|
|
+ public async Task QuickReload()
|
|
|
+ {
|
|
|
+ RemoveCurrentItemFromPreLoader();
|
|
|
+ await IterateToIndex(CurrentIndex, new CancellationTokenSource()).ConfigureAwait(false);
|
|
|
+ }
|
|
|
|
|
|
- public async Task<PreLoadValue?>? GetNextPreLoadValueAsync()
|
|
|
- {
|
|
|
- var nextIndex = GetIteration(CurrentIndex, NavigateTo.Next);
|
|
|
- return await PreLoader.GetAsync(nextIndex, ImagePaths);
|
|
|
- }
|
|
|
+ public int GetIteration(int index, NavigateTo navigateTo, bool skip1 = false, bool skip10 = false,
|
|
|
+ bool skip100 = false)
|
|
|
+ {
|
|
|
+ int next;
|
|
|
|
|
|
- public void RemoveItemFromPreLoader(int index)
|
|
|
- {
|
|
|
- PreLoader.Remove(index, ImagePaths);
|
|
|
- }
|
|
|
+ if (skip100)
|
|
|
+ {
|
|
|
+ if (ImagePaths.Count > PreLoader.MaxCount)
|
|
|
+ {
|
|
|
+ PreLoader.Clear();
|
|
|
+ }
|
|
|
+ }
|
|
|
|
|
|
- public void RemoveCurrentItemFromPreLoader()
|
|
|
- {
|
|
|
- PreLoader.Remove(CurrentIndex, ImagePaths);
|
|
|
- }
|
|
|
+ // Determine skipAmount based on input flags
|
|
|
+ var skipAmount = skip100 ? 100 : skip10 ? 10 : skip1 ? 2 : 1;
|
|
|
|
|
|
- public bool RefreshAllFileInfo()
|
|
|
- {
|
|
|
- return PreLoader.RefreshAllFileInfo(ImagePaths);
|
|
|
- }
|
|
|
+ switch (navigateTo)
|
|
|
+ {
|
|
|
+ case NavigateTo.Next:
|
|
|
+ case NavigateTo.Previous:
|
|
|
+ var indexChange = navigateTo == NavigateTo.Next ? skipAmount : -skipAmount;
|
|
|
+ IsReversed = navigateTo == NavigateTo.Previous;
|
|
|
|
|
|
- #endregion
|
|
|
+ if (SettingsHelper.Settings.UIProperties.Looping)
|
|
|
+ {
|
|
|
+ // Calculate new index with looping
|
|
|
+ next = (index + indexChange + ImagePaths.Count) % ImagePaths.Count;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ // Calculate new index without looping and ensure bounds
|
|
|
+ var newIndex = index + indexChange;
|
|
|
+ if (newIndex < 0)
|
|
|
+ {
|
|
|
+ return 0;
|
|
|
+ }
|
|
|
|
|
|
- #region Navigation
|
|
|
+ if (newIndex >= ImagePaths.Count)
|
|
|
+ {
|
|
|
+ return ImagePaths.Count - 1;
|
|
|
+ }
|
|
|
|
|
|
- public async Task ReloadFileList()
|
|
|
- {
|
|
|
- ImagePaths = await Task.FromResult(_vm.PlatformService.GetFiles(InitialFileInfo)).ConfigureAwait(false);
|
|
|
- CurrentIndex = ImagePaths.IndexOf(_vm.FileInfo.FullName);
|
|
|
+ next = newIndex;
|
|
|
+ }
|
|
|
|
|
|
- InitiateFileSystemWatcher(InitialFileInfo);
|
|
|
- }
|
|
|
+ break;
|
|
|
|
|
|
- public async Task QuickReload()
|
|
|
- {
|
|
|
- RemoveCurrentItemFromPreLoader();
|
|
|
- await IterateToIndex(CurrentIndex, new CancellationTokenSource()).ConfigureAwait(false);
|
|
|
- }
|
|
|
+ case NavigateTo.First:
|
|
|
+ case NavigateTo.Last:
|
|
|
+ if (ImagePaths.Count > PreLoader.MaxCount)
|
|
|
+ {
|
|
|
+ PreLoader.Clear();
|
|
|
+ }
|
|
|
|
|
|
- public int GetIteration(int index, NavigateTo navigateTo, bool skip1 = false, bool skip10 = false, bool skip100 = false)
|
|
|
- {
|
|
|
- int next;
|
|
|
+ next = navigateTo == NavigateTo.First ? 0 : ImagePaths.Count - 1;
|
|
|
+ break;
|
|
|
|
|
|
- if (skip100)
|
|
|
- {
|
|
|
- if (ImagePaths.Count > PreLoader.MaxCount)
|
|
|
- {
|
|
|
- PreLoader.Clear();
|
|
|
+ default:
|
|
|
+ return -1;
|
|
|
}
|
|
|
- }
|
|
|
-
|
|
|
- // Determine skipAmount based on input flags
|
|
|
- var skipAmount = skip100 ? 100 : skip10 ? 10 : skip1 ? 2 : 1;
|
|
|
-
|
|
|
- switch (navigateTo)
|
|
|
- {
|
|
|
- case NavigateTo.Next:
|
|
|
- case NavigateTo.Previous:
|
|
|
- var indexChange = navigateTo == NavigateTo.Next ? skipAmount : -skipAmount;
|
|
|
- IsReversed = navigateTo == NavigateTo.Previous;
|
|
|
|
|
|
- if (SettingsHelper.Settings.UIProperties.Looping)
|
|
|
- {
|
|
|
- // Calculate new index with looping
|
|
|
- next = (index + indexChange + ImagePaths.Count) % ImagePaths.Count;
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- // Calculate new index without looping and ensure bounds
|
|
|
- var newIndex = index + indexChange;
|
|
|
- if (newIndex < 0) return 0;
|
|
|
- if (newIndex >= ImagePaths.Count) return ImagePaths.Count - 1;
|
|
|
-
|
|
|
- next = newIndex;
|
|
|
- }
|
|
|
- break;
|
|
|
-
|
|
|
- case NavigateTo.First:
|
|
|
- case NavigateTo.Last:
|
|
|
- if (ImagePaths.Count > PreLoader.MaxCount)
|
|
|
- {
|
|
|
- PreLoader.Clear();
|
|
|
- }
|
|
|
- next = navigateTo == NavigateTo.First ? 0 : ImagePaths.Count - 1;
|
|
|
- break;
|
|
|
-
|
|
|
- default:
|
|
|
- return -1;
|
|
|
+ return next;
|
|
|
}
|
|
|
|
|
|
- return next;
|
|
|
- }
|
|
|
-
|
|
|
- public async Task NextIteration(NavigateTo navigateTo, CancellationTokenSource cts)
|
|
|
- {
|
|
|
- var index = GetIteration(CurrentIndex, navigateTo, SettingsHelper.Settings.ImageScaling.ShowImageSideBySide);
|
|
|
- if (index < 0)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!MainKeyboardShortcuts.IsKeyHeldDown)
|
|
|
- {
|
|
|
- await IterateToIndex(index, cts).ConfigureAwait(false);
|
|
|
- }
|
|
|
- else
|
|
|
+ public async Task NextIteration(NavigateTo navigateTo, CancellationTokenSource cts)
|
|
|
{
|
|
|
- await TimerIteration(index, cts).ConfigureAwait(false);
|
|
|
- }
|
|
|
- }
|
|
|
+ var index = GetIteration(CurrentIndex, navigateTo,
|
|
|
+ SettingsHelper.Settings.ImageScaling.ShowImageSideBySide);
|
|
|
+ if (index < 0)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
|
|
|
- public async Task IterateToIndex(int index, CancellationTokenSource cts)
|
|
|
- {
|
|
|
- if (index < 0 || index >= ImagePaths.Count)
|
|
|
- {
|
|
|
- ErrorHandling.ShowStartUpMenu(_vm);
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- // UI is more responsive when started in new thread
|
|
|
- var isMainThread = Dispatcher.UIThread.CheckAccess();
|
|
|
- if (isMainThread)
|
|
|
- {
|
|
|
- await Task.Run(async () => { await Iterate(); }, cts.Token).ConfigureAwait(false);
|
|
|
- }
|
|
|
- else
|
|
|
- {
|
|
|
- await Iterate().ConfigureAwait(false);
|
|
|
+ if (!MainKeyboardShortcuts.IsKeyHeldDown)
|
|
|
+ {
|
|
|
+ await IterateToIndex(index, cts).ConfigureAwait(false);
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+ await TimerIteration(index, cts).ConfigureAwait(false);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- return;
|
|
|
-
|
|
|
- async Task Iterate()
|
|
|
+ public async Task IterateToIndex(int index, CancellationTokenSource cts)
|
|
|
{
|
|
|
+ if (index < 0 || index >= ImagePaths.Count)
|
|
|
+ {
|
|
|
+ ErrorHandling.ShowStartUpMenu(_vm);
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
try
|
|
|
{
|
|
|
CurrentIndex = index;
|
|
|
@@ -507,7 +510,7 @@ public sealed class ImageIterator : IDisposable
|
|
|
{
|
|
|
if (preloadValue.IsLoading)
|
|
|
{
|
|
|
- TryShowPreview(preloadValue);
|
|
|
+ TryShowPreview();
|
|
|
}
|
|
|
|
|
|
while (preloadValue.IsLoading)
|
|
|
@@ -523,7 +526,7 @@ public sealed class ImageIterator : IDisposable
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- TryShowPreview(preloadValue);
|
|
|
+ TryShowPreview();
|
|
|
preloadValue = await PreLoader.GetAsync(CurrentIndex, ImagePaths).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
|
@@ -549,15 +552,20 @@ public sealed class ImageIterator : IDisposable
|
|
|
{
|
|
|
_vm.SecondaryImageSource = nextPreloadValue.ImageModel?.Image;
|
|
|
}
|
|
|
- cts.Token.ThrowIfCancellationRequested();
|
|
|
- await UpdateImage.UpdateSource(_vm, index, ImagePaths, IsReversed, preloadValue, nextPreloadValue)
|
|
|
- .ConfigureAwait(false);
|
|
|
+
|
|
|
+ if (!cts.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ await UpdateImage.UpdateSource(_vm, index, ImagePaths, IsReversed, preloadValue, nextPreloadValue)
|
|
|
+ .ConfigureAwait(false);
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- cts.Token.ThrowIfCancellationRequested();
|
|
|
- await UpdateImage.UpdateSource(_vm, index, ImagePaths, IsReversed, preloadValue)
|
|
|
- .ConfigureAwait(false);
|
|
|
+ if (!cts.IsCancellationRequested)
|
|
|
+ {
|
|
|
+ await UpdateImage.UpdateSource(_vm, index, ImagePaths, IsReversed, preloadValue)
|
|
|
+ .ConfigureAwait(false);
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
if (ImagePaths.Count > 1)
|
|
|
@@ -603,97 +611,81 @@ public sealed class ImageIterator : IDisposable
|
|
|
|
|
|
return;
|
|
|
|
|
|
- void TryShowPreview(PreLoadValue preloadValue)
|
|
|
+ void TryShowPreview()
|
|
|
{
|
|
|
SetTitleHelper.SetLoadingTitle(_vm);
|
|
|
-
|
|
|
- if (preloadValue is null)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (!preloadValue.IsLoading)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
- if (index != CurrentIndex)
|
|
|
- {
|
|
|
- return;
|
|
|
- }
|
|
|
-
|
|
|
_vm.IsLoading = true;
|
|
|
_vm.ImageSource = null;
|
|
|
_vm.SecondaryImageSource = null;
|
|
|
}
|
|
|
}
|
|
|
- }
|
|
|
|
|
|
- private static Timer? _timer;
|
|
|
+ private static Timer? _timer;
|
|
|
|
|
|
- internal async Task TimerIteration(int index, CancellationTokenSource cts)
|
|
|
- {
|
|
|
- if (_timer is null)
|
|
|
+ private async Task TimerIteration(int index, CancellationTokenSource cts)
|
|
|
{
|
|
|
- _timer = new Timer
|
|
|
+ if (_timer is null)
|
|
|
{
|
|
|
- AutoReset = false,
|
|
|
- Enabled = true
|
|
|
- };
|
|
|
- }
|
|
|
- else if (_timer.Enabled)
|
|
|
- {
|
|
|
- if (!MainKeyboardShortcuts.IsKeyHeldDown)
|
|
|
+ _timer = new Timer
|
|
|
+ {
|
|
|
+ AutoReset = false,
|
|
|
+ Enabled = true
|
|
|
+ };
|
|
|
+ }
|
|
|
+ else if (_timer.Enabled)
|
|
|
{
|
|
|
- _timer = null;
|
|
|
+ if (!MainKeyboardShortcuts.IsKeyHeldDown)
|
|
|
+ {
|
|
|
+ _timer = null;
|
|
|
+ }
|
|
|
+
|
|
|
+ return;
|
|
|
}
|
|
|
|
|
|
- return;
|
|
|
+ _timer.Interval = TimeSpan.FromSeconds(SettingsHelper.Settings.UIProperties.NavSpeed).TotalMilliseconds;
|
|
|
+ _timer.Start();
|
|
|
+ await IterateToIndex(index, cts).ConfigureAwait(false);
|
|
|
}
|
|
|
|
|
|
- _timer.Interval = TimeSpan.FromSeconds(SettingsHelper.Settings.UIProperties.NavSpeed).TotalMilliseconds;
|
|
|
- _timer.Start();
|
|
|
- await IterateToIndex(index, cts).ConfigureAwait(false);
|
|
|
- }
|
|
|
-
|
|
|
- public void UpdateFileListAndIndex(List<string> fileList, int index)
|
|
|
- {
|
|
|
- ImagePaths = fileList;
|
|
|
- CurrentIndex = index;
|
|
|
- }
|
|
|
+ public void UpdateFileListAndIndex(List<string> fileList, int index)
|
|
|
+ {
|
|
|
+ ImagePaths = fileList;
|
|
|
+ CurrentIndex = index;
|
|
|
+ }
|
|
|
|
|
|
- #endregion
|
|
|
+ #endregion
|
|
|
|
|
|
- #region IDisposable
|
|
|
+ #region IDisposable
|
|
|
|
|
|
- public void Dispose()
|
|
|
- {
|
|
|
- Dispose(true);
|
|
|
- GC.SuppressFinalize(this);
|
|
|
- }
|
|
|
-
|
|
|
- private void Dispose(bool disposing)
|
|
|
- {
|
|
|
- if (_disposed)
|
|
|
+ public void Dispose()
|
|
|
{
|
|
|
- return;
|
|
|
+ Dispose(true);
|
|
|
+ GC.SuppressFinalize(this);
|
|
|
}
|
|
|
|
|
|
- if (disposing)
|
|
|
+ private void Dispose(bool disposing)
|
|
|
{
|
|
|
- _watcher?.Dispose();
|
|
|
- Clear();
|
|
|
- _timer?.Dispose();
|
|
|
- PreLoader.Dispose();
|
|
|
+ if (_disposed)
|
|
|
+ {
|
|
|
+ return;
|
|
|
+ }
|
|
|
+
|
|
|
+ if (disposing)
|
|
|
+ {
|
|
|
+ _watcher?.Dispose();
|
|
|
+ Clear();
|
|
|
+ _timer?.Dispose();
|
|
|
+ PreLoader.Dispose();
|
|
|
+ }
|
|
|
+
|
|
|
+ _disposed = true;
|
|
|
}
|
|
|
|
|
|
- _disposed = true;
|
|
|
- }
|
|
|
+ ~ImageIterator()
|
|
|
+ {
|
|
|
+ Dispose(false);
|
|
|
+ }
|
|
|
|
|
|
- ~ImageIterator()
|
|
|
- {
|
|
|
- Dispose(false);
|
|
|
+ #endregion
|
|
|
}
|
|
|
-
|
|
|
- #endregion
|
|
|
}
|