From 7705a14bb52d161b19c9dc1b6039986de29b47a5 Mon Sep 17 00:00:00 2001 From: Julien Martin Date: Fri, 25 Sep 2026 16:26:04 +0200 Subject: [PATCH] fix(#173): layout bulle selon maquette (Du/Au + pilules larges) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Titre, dates en français sur deux lignes, actions coche/croix en pilules pleine largeur côte à côte. Co-authored-by: Cursor --- .../lib/widgets/quotidien/cartes_feed.dart | 189 ++++++++++-------- 1 file changed, 101 insertions(+), 88 deletions(-) diff --git a/frontend/lib/widgets/quotidien/cartes_feed.dart b/frontend/lib/widgets/quotidien/cartes_feed.dart index 6c8e62d..f827ebb 100644 --- a/frontend/lib/widgets/quotidien/cartes_feed.dart +++ b/frontend/lib/widgets/quotidien/cartes_feed.dart @@ -340,30 +340,26 @@ class _BulleTile extends StatelessWidget { required this.onRefuse, }); - String get _periode { - final d = card.dateDebut; - final f = card.dateFin; - if (d == null && f == null) return ''; - if (d != null && f != null && d == f) return _fmt(d); - return '${_fmt(d)} → ${_fmt(f)}'; - } - - String _fmt(String? iso) { + String _fmtLong(String? iso) { if (iso == null || iso.isEmpty) return '…'; final dt = DateTime.tryParse(iso); if (dt == null) return iso; + const mois = [ + 'janvier', + 'février', + 'mars', + 'avril', + 'mai', + 'juin', + 'juillet', + 'août', + 'septembre', + 'octobre', + 'novembre', + 'décembre', + ]; final jj = dt.day.toString().padLeft(2, '0'); - final mm = dt.month.toString().padLeft(2, '0'); - return '$jj/$mm/${dt.year}'; - } - - /// Pas de « À traiter / Traité » : seulement un indice utile (refus / attente créateur). - String? get _indice { - if (card.statut == CarteStatut.refusee) return 'Refusé'; - if (card.statut == CarteStatut.ouverte && card.isCreator) { - return 'En attente de réponse'; - } - return null; + return '$jj ${mois[dt.month - 1]} ${dt.year}'; } /// Arrêt maladie : reste opaque tant que la période n’est pas finie. @@ -374,53 +370,61 @@ class _BulleTile extends StatelessWidget { @override Widget build(BuildContext context) { - final indice = _indice; + final memeJour = card.dateDebut != null && + card.dateFin != null && + card.dateDebut == card.dateFin; + return Opacity( opacity: _attenuee ? 0.55 : 1, child: Carte( assetPath: card.backgroundAsset, - constraints: const BoxConstraints(minHeight: 96), - padding: const EdgeInsets.fromLTRB(20, 14, 20, 14), + constraints: const BoxConstraints(minHeight: 120), + padding: const EdgeInsets.fromLTRB(22, 16, 22, 16), child: Column( crossAxisAlignment: CrossAxisAlignment.stretch, children: [ - Row( - crossAxisAlignment: CrossAxisAlignment.start, - children: [ - Expanded( - child: Text( - card.titreAffiche, - maxLines: 1, - overflow: TextOverflow.ellipsis, - style: GoogleFonts.merienda( - fontSize: 16, - fontWeight: FontWeight.w700, - color: QuotidienTheme.ink, - ), - ), - ), - if (indice != null) - Text( - indice, - style: GoogleFonts.merriweather( - fontSize: 11, - color: QuotidienTheme.muted, - ), - ), - ], - ), - if (_periode.isNotEmpty) ...[ - const SizedBox(height: 4), - Text( - _periode, - style: GoogleFonts.merriweather( - fontSize: 13, - color: QuotidienTheme.ink, - ), + Text( + card.titreAffiche, + maxLines: 1, + overflow: TextOverflow.ellipsis, + style: GoogleFonts.merienda( + fontSize: 18, + fontWeight: FontWeight.w700, + color: QuotidienTheme.ink, ), + ), + if (card.dateDebut != null || card.dateFin != null) ...[ + const SizedBox(height: 10), + if (memeJour) + Text( + 'Le ${_fmtLong(card.dateDebut)}', + style: GoogleFonts.merriweather( + fontSize: 14, + color: QuotidienTheme.ink, + height: 1.35, + ), + ) + else ...[ + Text( + 'Du ${_fmtLong(card.dateDebut)}', + style: GoogleFonts.merriweather( + fontSize: 14, + color: QuotidienTheme.ink, + height: 1.35, + ), + ), + Text( + 'Au ${_fmtLong(card.dateFin)}', + style: GoogleFonts.merriweather( + fontSize: 14, + color: QuotidienTheme.ink, + height: 1.35, + ), + ), + ], ], if (card.motif != null && card.motif!.trim().isNotEmpty) ...[ - const SizedBox(height: 2), + const SizedBox(height: 6), Text( card.motif!, maxLines: 2, @@ -431,12 +435,13 @@ class _BulleTile extends StatelessWidget { ), ), ], - if (card.statut == CarteStatut.refusee && - card.lastRefuseComment != null && - card.lastRefuseComment!.trim().isNotEmpty) ...[ - const SizedBox(height: 4), + if (card.statut == CarteStatut.refusee) ...[ + const SizedBox(height: 6), Text( - 'Motif : ${card.lastRefuseComment}', + card.lastRefuseComment != null && + card.lastRefuseComment!.trim().isNotEmpty + ? 'Refusé — ${card.lastRefuseComment}' + : 'Refusé', maxLines: 2, overflow: TextOverflow.ellipsis, style: GoogleFonts.merriweather( @@ -445,46 +450,55 @@ class _BulleTile extends StatelessWidget { color: QuotidienTheme.ink, ), ), + ] else if (card.statut == CarteStatut.ouverte && + card.isCreator) ...[ + const SizedBox(height: 6), + Text( + 'En attente de réponse', + style: GoogleFonts.merriweather( + fontSize: 12, + color: QuotidienTheme.muted, + ), + ), ], if (card.peutRepondre) ...[ - const SizedBox(height: 10), + const SizedBox(height: 14), if (busy) - const Align( - alignment: Alignment.centerRight, + const Center( child: SizedBox( - width: 18, - height: 18, + width: 22, + height: 22, child: CircularProgressIndicator(strokeWidth: 2), ), ) - else + else if (card.responseMode == CarteResponseMode.acceptRefuse) Row( - mainAxisAlignment: MainAxisAlignment.end, children: [ - if (card.responseMode == - CarteResponseMode.acceptRefuse) ...[ - _ActionPill( + Expanded( + child: _ActionPill( asset: QuotidienTheme.pillTurquoiseAsset, iconAsset: 'assets/images/coche.png', tooltip: 'Accepter', onTap: onAccept, ), - const SizedBox(width: 10), - _ActionPill( + ), + const SizedBox(width: 12), + Expanded( + child: _ActionPill( asset: QuotidienTheme.pillCorailAsset, iconAsset: 'assets/images/red_cross2.png', tooltip: 'Refuser', onTap: onRefuse, ), - ], - if (card.responseMode == CarteResponseMode.ack) - _ActionPill( - asset: QuotidienTheme.pillTurquoiseAsset, - iconAsset: 'assets/images/coche.png', - tooltip: 'Bien reçu', - onTap: onAck, - ), + ), ], + ) + else if (card.responseMode == CarteResponseMode.ack) + _ActionPill( + asset: QuotidienTheme.pillTurquoiseAsset, + iconAsset: 'assets/images/coche.png', + tooltip: 'Bien reçu', + onTap: onAck, ), ], ], @@ -494,7 +508,7 @@ class _BulleTile extends StatelessWidget { } } -/// Bouton pilule dessiné (fond pastel + coche / croix). +/// Bouton pilule dessiné pleine largeur (fond pastel + coche / croix). class _ActionPill extends StatelessWidget { final String asset; final String iconAsset; @@ -514,10 +528,9 @@ class _ActionPill extends StatelessWidget { message: tooltip, child: InkWell( onTap: onTap, - borderRadius: BorderRadius.circular(20), + borderRadius: BorderRadius.circular(24), child: SizedBox( - width: 52, - height: 32, + height: 40, child: Stack( alignment: Alignment.center, children: [ @@ -526,8 +539,8 @@ class _ActionPill extends StatelessWidget { ), Image.asset( iconAsset, - height: 18, - width: 18, + height: 22, + width: 22, fit: BoxFit.contain, ), ],