refactor(#93): uniformiser la ligne utilisateur et afficher Modifier au survol

Met le rendu des lignes sur une seule ligne (icone, nom, infos) et n’affiche l’action Modifier qu’au hover pour alléger visuellement les listes.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
MARTIN Julien 2026-02-20 15:10:27 +01:00
parent 5da2ab9005
commit aec1990ec9
2 changed files with 101 additions and 66 deletions

View File

@ -89,13 +89,6 @@ class _AdminManagementWidgetState extends State<AdminManagementWidget> {
// TODO: Modifier admin // TODO: Modifier admin
}, },
), ),
IconButton(
icon: const Icon(Icons.delete),
tooltip: 'Supprimer',
onPressed: () {
// TODO: Supprimer admin
},
),
], ],
); );
}, },

View File

@ -1,6 +1,6 @@
import 'package:flutter/material.dart'; import 'package:flutter/material.dart';
class AdminUserCard extends StatelessWidget { class AdminUserCard extends StatefulWidget {
final String title; final String title;
final List<String> subtitleLines; final List<String> subtitleLines;
final String? avatarUrl; final String? avatarUrl;
@ -16,27 +16,50 @@ class AdminUserCard extends StatelessWidget {
this.actions = const [], this.actions = const [],
}); });
@override
State<AdminUserCard> createState() => _AdminUserCardState();
}
class _AdminUserCardState extends State<AdminUserCard> {
bool _isHovered = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
return Card( final infoLine =
widget.subtitleLines.where((e) => e.trim().isNotEmpty).join(' ');
final actionsWidth =
widget.actions.isNotEmpty ? widget.actions.length * 30.0 : 0.0;
return MouseRegion(
onEnter: (_) => setState(() => _isHovered = true),
onExit: (_) => setState(() => _isHovered = false),
child: Material(
color: Colors.transparent,
borderRadius: BorderRadius.circular(10),
child: InkWell(
onTap: () {},
borderRadius: BorderRadius.circular(10),
hoverColor: const Color(0x149CC5C0),
child: Card(
margin: const EdgeInsets.only(bottom: 12), margin: const EdgeInsets.only(bottom: 12),
elevation: 0, elevation: 0,
shape: RoundedRectangleBorder( shape: RoundedRectangleBorder(
borderRadius: BorderRadius.circular(8), borderRadius: BorderRadius.circular(10),
side: BorderSide(color: Colors.grey.shade300), side: BorderSide(color: Colors.grey.shade300),
), ),
child: Padding( child: Padding(
padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 10), padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 9),
child: Row( child: Row(
children: [ children: [
CircleAvatar( CircleAvatar(
radius: 14, radius: 14,
backgroundColor: const Color(0xFFEDE5FA), backgroundColor: const Color(0xFFEDE5FA),
backgroundImage: backgroundImage: widget.avatarUrl != null
avatarUrl != null ? NetworkImage(avatarUrl!) : null, ? NetworkImage(widget.avatarUrl!)
child: avatarUrl == null : null,
child: widget.avatarUrl == null
? Icon( ? Icon(
fallbackIcon, widget.fallbackIcon,
size: 16, size: 16,
color: const Color(0xFF6B3FA0), color: const Color(0xFF6B3FA0),
) )
@ -44,32 +67,45 @@ class AdminUserCard extends StatelessWidget {
), ),
const SizedBox(width: 10), const SizedBox(width: 10),
Expanded( Expanded(
child: Column( child: Row(
crossAxisAlignment: CrossAxisAlignment.start,
children: [ children: [
Text( Flexible(
title.isNotEmpty ? title : 'Sans nom', fit: FlexFit.loose,
child: Text(
widget.title.isNotEmpty ? widget.title : 'Sans nom',
style: const TextStyle( style: const TextStyle(
fontWeight: FontWeight.w600, fontWeight: FontWeight.w600,
fontSize: 14, fontSize: 14,
), ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
const SizedBox(height: 2), ),
...subtitleLines.map( const SizedBox(width: 10),
(line) => Text( Expanded(
line, child: Text(
infoLine,
style: const TextStyle( style: const TextStyle(
color: Colors.black54, color: Colors.black54,
fontSize: 12, fontSize: 12,
), ),
maxLines: 1,
overflow: TextOverflow.ellipsis,
), ),
), ),
], ],
), ),
), ),
if (actions.isNotEmpty) if (widget.actions.isNotEmpty)
IconTheme( SizedBox(
data: const IconThemeData(size: 18), width: actionsWidth,
child: AnimatedOpacity(
duration: const Duration(milliseconds: 120),
opacity: _isHovered ? 1 : 0,
child: IgnorePointer(
ignoring: !_isHovered,
child: IconTheme(
data: const IconThemeData(size: 17),
child: IconButtonTheme( child: IconButtonTheme(
data: IconButtonThemeData( data: IconButtonThemeData(
style: IconButton.styleFrom( style: IconButton.styleFrom(
@ -80,13 +116,19 @@ class AdminUserCard extends StatelessWidget {
), ),
child: Row( child: Row(
mainAxisSize: MainAxisSize.min, mainAxisSize: MainAxisSize.min,
children: actions, children: widget.actions,
),
),
),
), ),
), ),
), ),
], ],
), ),
), ),
),
),
),
); );
} }
} }