From ed882f83e50ef421109239e8f09e2710ef648875 Mon Sep 17 00:00:00 2001 From: Ionite Date: Tue, 10 Oct 2023 03:20:48 -0400 Subject: [PATCH] Fix crashes during gallery operations if file is externally deleted --- .../Inference/ImageFolderCardViewModel.cs | 52 ++++++++++++++----- 1 file changed, 39 insertions(+), 13 deletions(-) diff --git a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs index e8097834..f88ebd6d 100644 --- a/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs +++ b/StabilityMatrix.Avalonia/ViewModels/Inference/ImageFolderCardViewModel.cs @@ -4,7 +4,6 @@ using System.Reactive.Linq; using System.Threading.Tasks; using AsyncAwaitBestPractices; using AsyncImageLoader; -using Avalonia; using Avalonia.Controls.Notifications; using Avalonia.Platform.Storage; using Avalonia.Threading; @@ -120,20 +119,50 @@ public partial class ImageFolderCardViewModel : ViewModelBase imageIndexService.RefreshIndexForAllCollections().SafeFireAndForget(); } + /// + /// Gets the image path if it exists, returns null. + /// If the image path is resolved but the file doesn't exist, it will be removed from the index. + /// + private FilePath? GetImagePathIfExists(LocalImageFile item) + { + if (item.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath) + { + return null; + } + + var imageFile = new FilePath(imagePath); + + if (!imageFile.Exists) + { + // Remove from index + imageIndexService.InferenceImages.Remove(item); + + // Invalidate cache + if (ImageLoader.AsyncImageLoader is FallbackRamCachedWebImageLoader loader) + { + loader.RemoveAllNamesFromCache(imageFile.Name); + } + + return null; + } + + return imageFile; + } + /// /// Handles image clicks to show preview /// [RelayCommand] private async Task OnImageClick(LocalImageFile item) { - if (item.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath) + if (GetImagePathIfExists(item) is not { } imageFile) { return; } var currentIndex = LocalImages.IndexOf(item); - var image = new ImageSource(new FilePath(imagePath)); + var image = new ImageSource(imageFile); // Preload await image.GetBitmapAsync(); @@ -163,7 +192,7 @@ public partial class ImageFolderCardViewModel : ViewModelBase // Preload await newImageSource.GetBitmapAsync(); - var oldImageSource = sender.ImageSource; + // var oldImageSource = sender.ImageSource; sender.ImageSource = newImageSource; sender.LocalImageFile = newImage; @@ -185,13 +214,12 @@ public partial class ImageFolderCardViewModel : ViewModelBase [RelayCommand] private async Task OnImageDelete(LocalImageFile? item) { - if (item?.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath) + if (item is null || GetImagePathIfExists(item) is not { } imageFile) { return; } // Delete the file - var imageFile = new FilePath(imagePath); var result = await notificationService.TryAsync(imageFile.DeleteAsync()); if (!result.IsSuccessful) @@ -215,14 +243,14 @@ public partial class ImageFolderCardViewModel : ViewModelBase [RelayCommand] private async Task OnImageCopy(LocalImageFile? item) { - if (item?.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath) + if (item is null || GetImagePathIfExists(item) is not { } imageFile) { return; } var clipboard = App.Clipboard; - await clipboard.SetFileDataObjectAsync(imagePath); + await clipboard.SetFileDataObjectAsync(imageFile.FullPath); } /// @@ -231,12 +259,12 @@ public partial class ImageFolderCardViewModel : ViewModelBase [RelayCommand] private async Task OnImageOpen(LocalImageFile? item) { - if (item?.GetFullPath(settingsManager.ImagesDirectory) is not { } imagePath) + if (item is null || GetImagePathIfExists(item) is not { } imageFile) { return; } - await ProcessRunner.OpenFileBrowser(imagePath); + await ProcessRunner.OpenFileBrowser(imageFile); } /// @@ -248,13 +276,11 @@ public partial class ImageFolderCardViewModel : ViewModelBase bool includeMetadata = false ) { - if (item?.GetFullPath(settingsManager.ImagesDirectory) is not { } sourcePath) + if (item is null || GetImagePathIfExists(item) is not { } sourceFile) { return; } - var sourceFile = new FilePath(sourcePath); - var formatName = format.ToString(); var storageFile = await App.StorageProvider.SaveFilePickerAsync(