From bac086f1e1b6fde9e2cca19535516ca18f419316 Mon Sep 17 00:00:00 2001 From: Thomas Fransolet Date: Tue, 15 Sep 2026 17:33:55 +0200 Subject: [PATCH] =?UTF-8?q?Studio=20lot=206=20:=20mention=20=C2=AB=20image?= =?UTF-8?q?=20g=C3=A9n=C3=A9r=C3=A9e=20par=20IA=20=C2=BB=20chez=20le=20vis?= =?UTF-8?q?iteur?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Une reconstitution n'est pas une photographie d'archive, et rien dans l'image ne le dit : la mention est due au visiteur. Elle est posée au-dessus des trois branches de rendu (réseau, cache hors ligne, URL externe) plutôt qu'à chacune, pour qu'aucun point d'affichage ne puisse l'oublier. Traduite dans les onze langues publiées : l'app visiteur n'a pas d'infrastructure de traduction pour ses propres libellés. Co-Authored-By: Claude Opus 5 (1M context) --- lib/Components/ai_generated_badge.dart | 49 ++++++++++++++++++++++ lib/Components/cached_custom_resource.dart | 21 ++++++++++ 2 files changed, 70 insertions(+) create mode 100644 lib/Components/ai_generated_badge.dart diff --git a/lib/Components/ai_generated_badge.dart b/lib/Components/ai_generated_badge.dart new file mode 100644 index 0000000..120d849 --- /dev/null +++ b/lib/Components/ai_generated_badge.dart @@ -0,0 +1,49 @@ +import 'package:flutter/material.dart'; +import 'package:manager_api_new/api.dart'; + +/// Mention « image générée par IA » posée sur une image produite par le Studio (lot 6). +/// +/// Elle est due au visiteur, pas au client : une reconstitution n'est pas une photographie +/// d'archive, et rien dans l'image ne le dit. Le texte suit la langue de visite — l'app +/// visiteur n'a pas d'infrastructure de traduction pour ses propres libellés, les dix +/// langues publiées sont donc portées ici. +class AiGeneratedBadge extends StatelessWidget { + const AiGeneratedBadge({Key? key, required this.language}) : super(key: key); + + final String? language; + + static const _labels = { + 'FR': 'Image générée par IA', + 'NL': 'Beeld gegenereerd door AI', + 'EN': 'AI-generated image', + 'DE': 'KI-generiertes Bild', + 'ES': 'Imagen generada por IA', + 'IT': 'Immagine generata dall’IA', + 'PL': 'Obraz wygenerowany przez SI', + 'CN': '人工智能生成的图像', + 'AR': 'صورة من إنتاج الذكاء الاصطناعي', + 'UK': 'Зображення, створене ШІ', + 'LB': 'Bild generéiert vun der KI', + }; + + /// Une image générée doit porter la mention ; une image téléversée, jamais. + static bool isGenerated(ResourceDTO? resource) => + resource?.origin == ResourceOrigin.Generated; + + @override + Widget build(BuildContext context) { + final label = _labels[(language ?? 'FR').toUpperCase()] ?? _labels['FR']!; + + return Container( + padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 3), + decoration: BoxDecoration( + color: Colors.black.withValues(alpha: 0.72), + borderRadius: BorderRadius.circular(4), + ), + child: Text( + label, + style: const TextStyle(color: Colors.white, fontSize: 9, letterSpacing: 0.2), + ), + ); + } +} diff --git a/lib/Components/cached_custom_resource.dart b/lib/Components/cached_custom_resource.dart index e4813f5..217c4f4 100644 --- a/lib/Components/cached_custom_resource.dart +++ b/lib/Components/cached_custom_resource.dart @@ -1,6 +1,7 @@ import 'dart:io'; import 'dart:typed_data'; +import 'package:tablet_app/Components/ai_generated_badge.dart'; import 'package:flutter/material.dart'; import 'package:cached_network_image/cached_network_image.dart'; import 'package:manager_api_new/api.dart'; @@ -26,7 +27,27 @@ class CachedCustomResource extends StatelessWidget { }); @override + /// L'image porte sa mention quelle que soit la branche de rendu prise en dessous. + /// Même geste que dans l'app visiteur : la poser ici évite d'y penser à chaque écran. Widget build(BuildContext context) { + final resource = _resource(context); + if (!AiGeneratedBadge.isGenerated(resourceDTO)) return resource; + + final tabletAppContext = + Provider.of(context, listen: false).getContext() as TabletAppContext; + return Stack( + children: [ + Positioned.fill(child: resource), + Positioned( + left: 6, + bottom: 6, + child: AiGeneratedBadge(language: tabletAppContext.language), + ), + ], + ); + } + + Widget _resource(BuildContext context) { final appContext = Provider.of(context); TabletAppContext tabletAppContext = appContext.getContext(); Size size = MediaQuery.of(context).size;