using System.IO; using CommunityToolkit.Mvvm.ComponentModel; using MarcusLaw.OutlookAddin.Core.Models; namespace MarcusLaw.OutlookAddin.UI.ViewModels { public sealed partial class AttachmentRowViewModel : ObservableObject { public EspoAttachment Data { get; } [ObservableProperty] private bool isSelected = true; /// /// Frozen at construction from the original filename. The user /// edits only the base name; the extension always tags along. /// public string Extension { get; } /// /// Editable base name without the extension. Setting this rewrites /// as <basename><Extension>. /// public string BaseName { get => Path.GetFileNameWithoutExtension(Data.Name) ?? string.Empty; set { var newBase = (value ?? string.Empty).Trim(); var newFull = newBase + Extension; if (Data.Name == newFull) return; Data.Name = newFull; OnPropertyChanged(); OnPropertyChanged(nameof(FileName)); } } /// /// Full filename including extension — what actually goes to the /// server. Read-only mirror of . /// public string FileName => Data.Name; public string SizeDisplay { get; } public AttachmentRowViewModel(EspoAttachment data) { Data = data; Extension = Path.GetExtension(data.Name) ?? string.Empty; SizeDisplay = ComputeSize(data.ContentBase64); } private static string ComputeSize(string base64) { if (string.IsNullOrEmpty(base64)) return string.Empty; // Base64 expands binary 4-for-3, ignoring padding chars. var padding = 0; if (base64.Length > 0 && base64[base64.Length - 1] == '=') padding++; if (base64.Length > 1 && base64[base64.Length - 2] == '=') padding++; var bytes = (long)((base64.Length * 3) / 4) - padding; return FormatBytes(bytes); } private static string FormatBytes(long bytes) { if (bytes < 1024) return bytes + " B"; if (bytes < 1024 * 1024) return (bytes / 1024.0).ToString("F1") + " KB"; return (bytes / (1024.0 * 1024.0)).ToString("F1") + " MB"; } } }