using Avalonia.Platform.Storage; using System.Text; namespace LehrerApp.Desktop.Services; public sealed record ExportFormat(string Label, string Extension, string MimeType) { public static ExportFormat Csv { get; } = new("CSV-Dateien", ".csv", "text/csv"); public static ExportFormat Json { get; } = new("JSON-Dateien", ".json", "application/json"); } public sealed record ExportFile( string DialogTitle, string SuggestedFileName, ExportFormat Format, ReadOnlyMemory Content) { public static ExportFile Csv(string dialogTitle, string suggestedFileName, string content) => FromText(dialogTitle, suggestedFileName, ExportFormat.Csv, content, includeUtf8Bom: true); public static ExportFile Json(string dialogTitle, string suggestedFileName, string content) => FromText(dialogTitle, suggestedFileName, ExportFormat.Json, content); private static ExportFile FromText(string dialogTitle, string suggestedFileName, ExportFormat format, string content, bool includeUtf8Bom = false) { var encoding = new UTF8Encoding(encoderShouldEmitUTF8Identifier: includeUtf8Bom); var preamble = encoding.GetPreamble(); var text = encoding.GetBytes(content); var bytes = new byte[preamble.Length + text.Length]; preamble.CopyTo(bytes, 0); text.CopyTo(bytes, preamble.Length); return new ExportFile(dialogTitle, EnsureExtension(SanitizeFileName(suggestedFileName), format.Extension), format, bytes); } private static string EnsureExtension(string fileName, string extension) => fileName.EndsWith(extension, StringComparison.OrdinalIgnoreCase) ? fileName : fileName + extension; private static string SanitizeFileName(string fileName) { var invalidCharacters = Path.GetInvalidFileNameChars(); return string.Concat(fileName.Select(character => invalidCharacters.Contains(character) ? '_' : character)); } } /// Zentrale Dateiauswahl und Stream-Ausgabe für alle Exportformate. public sealed class ExportService { public async Task SaveAsync(IStorageProvider storageProvider, ExportFile export) { var file = await storageProvider.SaveFilePickerAsync(new FilePickerSaveOptions { Title = export.DialogTitle, SuggestedFileName = export.SuggestedFileName, DefaultExtension = export.Format.Extension.TrimStart('.'), FileTypeChoices = [ new FilePickerFileType(export.Format.Label) { Patterns = [$"*{export.Format.Extension}"], MimeTypes = [export.Format.MimeType], }, ], }); if (file is null) return false; await using var stream = await file.OpenWriteAsync(); if (stream.CanSeek) stream.SetLength(0); await stream.WriteAsync(export.Content); return true; } }