feat: Convert _MenuItemTile to StatefulWidget for hover effect support

This commit is contained in:
2026-05-21 17:16:54 +02:00
parent 48d09fe170
commit 63f0079a5a
+28 -15
View File
@@ -124,7 +124,7 @@ IconData _iconForCodePoint(int? codePoint) {
return Icons.folder_outlined; return Icons.folder_outlined;
} }
class _MenuItemTile extends StatelessWidget { class _MenuItemTile extends StatefulWidget {
const _MenuItemTile({ const _MenuItemTile({
required this.icon, required this.icon,
required this.label, required this.label,
@@ -143,39 +143,52 @@ class _MenuItemTile extends StatelessWidget {
final Color? textColor; final Color? textColor;
final Widget? trailing; final Widget? trailing;
@override
State<_MenuItemTile> createState() => _MenuItemTileState();
}
class _MenuItemTileState extends State<_MenuItemTile> {
bool _hovering = false;
@override @override
Widget build(BuildContext context) { Widget build(BuildContext context) {
final Color backgroundColor = selected final bool active = widget.selected || _hovering;
final Color backgroundColor = active
? Colors.white.withValues(alpha: 0.10) ? Colors.white.withValues(alpha: 0.10)
: Colors.transparent; : Colors.transparent;
final Color foregroundColor = selected ? Colors.white : Colors.white70; final Color foregroundColor = active ? Colors.white : Colors.white70;
return AnimatedContainer( return MouseRegion(
onEnter: (_) {
setState(() => _hovering = true);
},
onExit: (_) {
setState(() => _hovering = false);
},
child: AnimatedContainer(
duration: const Duration(milliseconds: 180), duration: const Duration(milliseconds: 180),
curve: Curves.easeOutCubic, curve: Curves.easeOutCubic,
margin: EdgeInsets.only( margin: const EdgeInsets.only(
right: 8, right: 8,
top: 2, top: 2,
bottom: 2, bottom: 2,
), ),
child: Material( child: Material(
color: backgroundColor, color: backgroundColor,
borderRadius: selected borderRadius: const BorderRadius.only(
? const BorderRadius.only(
topRight: Radius.circular(999), topRight: Radius.circular(999),
bottomRight: Radius.circular(999), bottomRight: Radius.circular(999),
) ),
: BorderRadius.circular(12),
clipBehavior: Clip.antiAlias, clipBehavior: Clip.antiAlias,
child: ListTile( child: ListTile(
leading: Icon(icon, color: iconColor ?? foregroundColor), leading: Icon(widget.icon, color: widget.iconColor ?? foregroundColor),
trailing: trailing, trailing: widget.trailing,
title: Text( title: Text(
label, widget.label,
style: TextStyle(color: textColor ?? foregroundColor, fontSize: 14), style: TextStyle(color: widget.textColor ?? foregroundColor, fontSize: 14),
),
onTap: widget.onTap,
), ),
onTap: onTap,
hoverColor: Colors.white.withValues(alpha: 0.1),
), ),
), ),
); );