using System; using System.Collections.Generic; using System.Linq; using System.Runtime.CompilerServices; using System.Threading.Tasks; using AsyncAwaitBestPractices; using Avalonia.Input; using Avalonia.Media; using Avalonia.Platform.Storage; using Avalonia.Threading; using CommunityToolkit.Mvvm.ComponentModel; using NLog; using StabilityMatrix.Avalonia.Controls; using StabilityMatrix.Avalonia.Models; using StabilityMatrix.Avalonia.Services; using StabilityMatrix.Avalonia.ViewModels.Base; using StabilityMatrix.Core.Attributes; using StabilityMatrix.Core.Extensions; using StabilityMatrix.Core.Helper; using StabilityMatrix.Core.Models.Database; using Size = System.Drawing.Size; namespace StabilityMatrix.Avalonia.ViewModels.Inference; [View(typeof(SelectImageCard))] [ManagedService] [Transient] public partial class SelectImageCardViewModel : ViewModelBase, IDropTarget { private static readonly Logger Logger = LogManager.GetCurrentClassLogger(); private readonly INotificationService notificationService; [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsSelectionAvailable))] private ImageSource? imageSource; [ObservableProperty] [NotifyPropertyChangedFor(nameof(CurrentBitmapSize))] private IImage? currentBitmap; [ObservableProperty] [NotifyPropertyChangedFor(nameof(IsSelectionAvailable))] private bool isSelectionEnabled = true; public bool IsSelectionAvailable => IsSelectionEnabled && ImageSource == null; public Size? CurrentBitmapSize => new Size( Convert.ToInt32(CurrentBitmap?.Size.Width ?? 0), Convert.ToInt32(CurrentBitmap?.Size.Height ?? 0) ); public SelectImageCardViewModel(INotificationService notificationService) { this.notificationService = notificationService; } [MethodImpl(MethodImplOptions.Synchronized)] private void LoadUserImage(ImageSource image) { var current = ImageSource; ImageSource = image; current?.Dispose(); // Cache the hash for later upload use image.GetBlake3HashAsync().SafeFireAndForget(); } /// public void DragOver(object? sender, DragEventArgs e) { // 1. Context drop for LocalImageFile if (e.Data.GetDataFormats().Contains("Context")) { if (e.Data.Get("Context") is LocalImageFile imageFile) { e.Handled = true; return; } e.DragEffects = DragDropEffects.None; } // 2. OS Files if (e.Data.GetDataFormats().Contains(DataFormats.Files)) { e.Handled = true; return; } e.DragEffects = DragDropEffects.None; } /// public void Drop(object? sender, DragEventArgs e) { // 1. Context drop for LocalImageFile if (e.Data.GetDataFormats().Contains("Context")) { if (e.Data.Get("Context") is LocalImageFile imageFile) { e.Handled = true; Dispatcher.UIThread.Post( () => LoadUserImage(new ImageSource(imageFile.AbsolutePath)) ); return; } } // 2. OS Files if (e.Data.GetDataFormats().Contains(DataFormats.Files)) { e.Handled = true; try { if (e.Data.Get(DataFormats.Files) is IEnumerable files) { var path = files.Select(f => f.Path.LocalPath).FirstOrDefault(); if (string.IsNullOrWhiteSpace(path)) { return; } Dispatcher.UIThread.Post(() => LoadUserImage(new ImageSource(path))); } } catch (Exception ex) { Logger.Warn(ex, "Failed to load image from drop"); notificationService.ShowPersistent("Failed to load source image", ex.Message); } } } }