import 'package:flutter/widgets.dart'; import 'package:intl/intl.dart'; import 'package:manager_app/l10n/app_localizations.dart'; import 'package:manager_api_new/api.dart'; /// Extension réelle d'une ressource, dans l'ordre : le nom de fichier stocké s'il /// existe, sinon celle que le type impose. Le téléchargement forçait `.json` pour /// tout le monde — un PNG arrivait en `label.json`, illisible sans renommage. const Map _extensionByType = { ResourceType.Image: '.jpg', ResourceType.ImageUrl: '.jpg', ResourceType.Audio: '.mp3', ResourceType.Video: '.mp4', ResourceType.VideoUrl: '.mp4', ResourceType.Pdf: '.pdf', ResourceType.Json: '.json', ResourceType.JsonUrl: '.json', ResourceType.Image360: '.jpg', ResourceType.Video360: '.mp4', ResourceType.Model3D: '.glb', }; /// Type d'une ressource locale, déduit de son extension. Un seul endroit : le /// dialogue d'ajout l'affiche en pastille, `create()` l'enregistre. Avant, le /// dialogue posait `ResourceType.Image` pour tout fichier et `create()` le /// recalculait — à la lecture, un MP3 semblait parti pour être une image. ResourceType? resourceTypeForExtension(String? extension) { switch (extension?.toLowerCase()) { case 'jpg': case 'jpeg': case 'png': case 'gif': return ResourceType.Image; case 'mp3': return ResourceType.Audio; case 'mp4': case 'webm': return ResourceType.Video; case 'pdf': return ResourceType.Pdf; case 'json': return ResourceType.Json; // Un .glb n'est jamais autre chose qu'un modèle 3D — contrairement à un .jpg, // qui peut être plat ou équirectangulaire sans que le fichier le dise. case 'glb': return ResourceType.Model3D; default: return null; } } String mimeTypeForExtension(String? extension) { switch (extension?.toLowerCase()) { case 'jpg': case 'jpeg': return 'image/jpeg'; case 'png': return 'image/png'; case 'gif': return 'image/gif'; case 'mp3': return 'audio/mpeg'; case 'mp4': return 'video/mp4'; case 'webm': return 'video/webm'; case 'pdf': return 'application/pdf'; case 'json': return 'application/json'; case 'glb': return 'model/gltf-binary'; default: return 'application/octet-stream'; } } /// Libellé lisible d'un type, dans la langue du manager. String resourceTypeLabel(AppLocalizations l, ResourceType? type) { switch (type) { case ResourceType.Image: return l.resourceTypeImage; case ResourceType.ImageUrl: return l.resourceTypeImageUrl; case ResourceType.Video: return l.resourceTypeVideo; case ResourceType.VideoUrl: return l.resourceTypeVideoUrl; case ResourceType.Audio: return l.resourceTypeAudio; case ResourceType.Pdf: return l.resourceTypePdf; case ResourceType.Json: return l.resourceTypeJson; case ResourceType.JsonUrl: return l.resourceTypeJsonUrl; case ResourceType.Image360: return l.resourceTypeImage360; case ResourceType.Video360: return l.resourceTypeVideo360; case ResourceType.Model3D: return l.resourceTypeModel3D; default: return '—'; } } String downloadFileNameFor(ResourceDTO resource) { final fileName = resource.fileName; if (fileName != null && fileName.trim().isNotEmpty) { return fileName; } final label = (resource.label ?? 'ressource').trim(); final extension = _extensionByType[resource.type] ?? ''; return label.toLowerCase().endsWith(extension) ? label : '$label$extension'; } /// L'unité suit la langue : « Ko » en français, « KB » en anglais. String formatBytes(BuildContext context, int? bytes) { final l = AppLocalizations.of(context)!; if (bytes == null || bytes <= 0) return '—'; if (bytes < 1024) return l.mediaSizeBytes('$bytes'); if (bytes < 1024 * 1024) return l.mediaSizeKilobytes((bytes / 1024).toStringAsFixed(0)); return l.mediaSizeMegabytes((bytes / (1024 * 1024)).toStringAsFixed(1)); } /// Mois et dates passent par `intl` avec la locale courante — une liste de mois /// écrite en dur ne se traduit pas et ne suit pas l'ordre jour/mois de l'anglais. String formatMonth(BuildContext context, DateTime? date) { if (date == null) return AppLocalizations.of(context)!.mediaNoDate; final locale = Localizations.localeOf(context).toString(); final label = DateFormat.yMMMM(locale).format(date); return label.isEmpty ? label : label[0].toUpperCase() + label.substring(1); } String formatDate(BuildContext context, DateTime? date) => date == null ? '—' : DateFormat.yMd(Localizations.localeOf(context).toString()).format(date); String monthKey(DateTime? date) => date == null ? '0000-00' : '${date.year}-${date.month.toString().padLeft(2, '0')}';