feat: Refactor note editor dialog and delete confirmation for improved readability and reusability

This commit is contained in:
2026-05-21 16:26:31 +02:00
parent 49fc33edc0
commit 28f4ede4aa
3 changed files with 518 additions and 458 deletions
+178 -74
View File
@@ -316,12 +316,6 @@ class _HomeScreenState extends State<HomeScreen> {
final Widget body = _isLoading final Widget body = _isLoading
? const Center(child: CircularProgressIndicator()) ? const Center(child: CircularProgressIndicator())
: visibleNotes.isEmpty
? _EmptyState(
showDeletedNotes: _showDeletedNotes,
categoryName: currentCategory?.name,
searchQuery: _searchQuery,
)
: RefreshIndicator( : RefreshIndicator(
onRefresh: () async { onRefresh: () async {
await widget.onRequestSync(); await widget.onRequestSync();
@@ -330,32 +324,60 @@ class _HomeScreenState extends State<HomeScreen> {
cursor: _isDragging cursor: _isDragging
? SystemMouseCursors.grabbing ? SystemMouseCursors.grabbing
: SystemMouseCursors.basic, : SystemMouseCursors.basic,
child: MasonryGridView.count( child: CustomScrollView(
physics: const AlwaysScrollableScrollPhysics(),
slivers: visibleNotes.isEmpty
? [
SliverFillRemaining(
hasScrollBody: false,
child: _EmptyState(
showDeletedNotes: _showDeletedNotes,
categoryName: currentCategory?.name,
searchQuery: _searchQuery,
),
),
]
: [
SliverPadding(
padding: const EdgeInsets.only(bottom: 8),
sliver: SliverMasonryGrid.count(
crossAxisCount: crossAxisCount, crossAxisCount: crossAxisCount,
mainAxisSpacing: 10, mainAxisSpacing: 10,
crossAxisSpacing: 10, crossAxisSpacing: 10,
itemCount: visibleNotes.length, childCount: visibleNotes.length,
itemBuilder: (BuildContext context, int index) { itemBuilder: (BuildContext context, int index) {
final List<Note> filteredNotes = visibleNotes; final List<Note> filteredNotes = visibleNotes;
return DragTarget<int>( return DragTarget<int>(
onAcceptWithDetails: (DragTargetDetails<int> details) { onAcceptWithDetails:
final Note targetNote = filteredNotes[index]; (DragTargetDetails<int> details) {
final int originalTargetIndex = _notes.indexOf( final Note targetNote =
targetNote, filteredNotes[index];
final int originalTargetIndex = _notes
.indexOf(targetNote);
_reorderNote(
details.data,
originalTargetIndex,
); );
_reorderNote(details.data, originalTargetIndex);
}, },
builder: (context, candidateData, rejectedData) { builder: (context, candidateData, rejectedData) {
return LayoutBuilder( return LayoutBuilder(
builder: (context, constraints) { builder: (context, constraints) {
final double cellWidth = constraints.maxWidth; final double cellWidth =
constraints.maxWidth;
final bool requiresLongPressToDrag = final bool requiresLongPressToDrag =
_requiresLongPressToDrag(_lastPointerKind); _requiresLongPressToDrag(
_lastPointerKind,
);
final Widget draggableNote = requiresLongPressToDrag final Widget draggableNote =
requiresLongPressToDrag
? LongPressDraggable<int>( ? LongPressDraggable<int>(
data: _notes.indexOf(filteredNotes[index]), data: _notes.indexOf(
delay: const Duration(milliseconds: 280), filteredNotes[index],
),
delay: const Duration(
milliseconds: 280,
),
onDragStarted: () { onDragStarted: () {
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {
@@ -375,29 +397,42 @@ class _HomeScreenState extends State<HomeScreen> {
}); });
}, },
feedback: MouseRegion( feedback: MouseRegion(
cursor: SystemMouseCursors.grabbing, cursor:
SystemMouseCursors.grabbing,
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
elevation: 8, elevation: 8,
child: SizedBox( child: SizedBox(
width: cellWidth, width: cellWidth,
child: TweenAnimationBuilder<double>( child: TweenAnimationBuilder<double>(
tween: Tween(begin: 0.97, end: 1.0), tween: Tween(
begin: 0.97,
end: 1.0,
),
duration: const Duration( duration: const Duration(
milliseconds: 180, milliseconds: 180,
), ),
curve: Curves.easeOutCubic, curve:
builder: (context, scale, child) { Curves.easeOutCubic,
builder:
(
context,
scale,
child,
) {
return Transform.scale( return Transform.scale(
scale: scale, scale: scale,
alignment: Alignment.topLeft, alignment:
Alignment
.topLeft,
child: child, child: child,
); );
}, },
child: Opacity( child: Opacity(
opacity: 0.95, opacity: 0.95,
child: NoteCard( child: NoteCard(
note: filteredNotes[index], note:
filteredNotes[index],
onTap: () {}, onTap: () {},
isDragging: true, isDragging: true,
), ),
@@ -407,19 +442,25 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
), ),
childWhenDragging: MouseRegion( childWhenDragging: MouseRegion(
cursor: SystemMouseCursors.grabbing, cursor:
SystemMouseCursors.grabbing,
child: Opacity( child: Opacity(
opacity: 0.3, opacity: 0.3,
child: Container( child: Container(
padding: const EdgeInsets.all(16), padding:
const EdgeInsets.all(
16,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color.fromRGBO( color:
const Color.fromRGBO(
24, 24,
25, 25,
26, 26,
1, 1,
), ),
borderRadius: BorderRadius.circular( borderRadius:
BorderRadius.circular(
12, 12,
), ),
border: Border.all( border: Border.all(
@@ -429,27 +470,40 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
child: Column( child: Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment
mainAxisSize: MainAxisSize.min, .start,
mainAxisSize:
MainAxisSize.min,
children: [ children: [
Text( Text(
filteredNotes[index].title, filteredNotes[index]
style: const TextStyle( .title,
color: Colors.white, style:
const TextStyle(
color: Colors
.white,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight:
FontWeight
.bold,
), ),
maxLines: 2, maxLines: 2,
), ),
const SizedBox(height: 8), const SizedBox(
height: 8,
),
Text( Text(
filteredNotes[index].body, filteredNotes[index]
style: const TextStyle( .body,
color: Colors.white70, style:
const TextStyle(
color: Colors
.white70,
fontSize: 14, fontSize: 14,
), ),
maxLines: 20, maxLines: 20,
overflow: TextOverflow.clip, overflow:
TextOverflow.clip,
), ),
], ],
), ),
@@ -458,27 +512,34 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: candidateData.isNotEmpty border:
candidateData.isNotEmpty
? Border.all( ? Border.all(
color: Colors.blue.shade400, color: Colors
.blue
.shade400,
width: 2, width: 2,
) )
: null, : null,
borderRadius: BorderRadius.circular(12), borderRadius:
BorderRadius.circular(12),
), ),
child: NoteCard( child: NoteCard(
key: ValueKey<String>( key: ValueKey<String>(
filteredNotes[index].id, filteredNotes[index].id,
), ),
note: filteredNotes[index], note: filteredNotes[index],
onTap: () => onTap: () => _openNoteEditor(
_openNoteEditor(filteredNotes[index]), filteredNotes[index],
),
isDragging: _isDragging, isDragging: _isDragging,
), ),
), ),
) )
: Draggable<int>( : Draggable<int>(
data: _notes.indexOf(filteredNotes[index]), data: _notes.indexOf(
filteredNotes[index],
),
onDragStarted: () { onDragStarted: () {
if (!mounted) return; if (!mounted) return;
setState(() { setState(() {
@@ -498,29 +559,42 @@ class _HomeScreenState extends State<HomeScreen> {
}); });
}, },
feedback: MouseRegion( feedback: MouseRegion(
cursor: SystemMouseCursors.grabbing, cursor:
SystemMouseCursors.grabbing,
child: Material( child: Material(
color: Colors.transparent, color: Colors.transparent,
elevation: 8, elevation: 8,
child: SizedBox( child: SizedBox(
width: cellWidth, width: cellWidth,
child: TweenAnimationBuilder<double>( child: TweenAnimationBuilder<double>(
tween: Tween(begin: 0.97, end: 1.0), tween: Tween(
begin: 0.97,
end: 1.0,
),
duration: const Duration( duration: const Duration(
milliseconds: 180, milliseconds: 180,
), ),
curve: Curves.easeOutCubic, curve:
builder: (context, scale, child) { Curves.easeOutCubic,
builder:
(
context,
scale,
child,
) {
return Transform.scale( return Transform.scale(
scale: scale, scale: scale,
alignment: Alignment.topLeft, alignment:
Alignment
.topLeft,
child: child, child: child,
); );
}, },
child: Opacity( child: Opacity(
opacity: 0.95, opacity: 0.95,
child: NoteCard( child: NoteCard(
note: filteredNotes[index], note:
filteredNotes[index],
onTap: () {}, onTap: () {},
isDragging: true, isDragging: true,
), ),
@@ -530,19 +604,25 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
), ),
childWhenDragging: MouseRegion( childWhenDragging: MouseRegion(
cursor: SystemMouseCursors.grabbing, cursor:
SystemMouseCursors.grabbing,
child: Opacity( child: Opacity(
opacity: 0.3, opacity: 0.3,
child: Container( child: Container(
padding: const EdgeInsets.all(16), padding:
const EdgeInsets.all(
16,
),
decoration: BoxDecoration( decoration: BoxDecoration(
color: const Color.fromRGBO( color:
const Color.fromRGBO(
24, 24,
25, 25,
26, 26,
1, 1,
), ),
borderRadius: BorderRadius.circular( borderRadius:
BorderRadius.circular(
12, 12,
), ),
border: Border.all( border: Border.all(
@@ -552,28 +632,42 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
child: Column( child: Column(
crossAxisAlignment: crossAxisAlignment:
CrossAxisAlignment.start, CrossAxisAlignment
mainAxisSize: MainAxisSize.min, .start,
mainAxisSize:
MainAxisSize.min,
children: [ children: [
Text( Text(
filteredNotes[index].title, filteredNotes[index]
style: const TextStyle( .title,
color: Colors.white, style:
const TextStyle(
color: Colors
.white,
fontSize: 16, fontSize: 16,
fontWeight: FontWeight.bold, fontWeight:
FontWeight
.bold,
), ),
maxLines: 2, maxLines: 2,
overflow: TextOverflow.ellipsis, overflow: TextOverflow
.ellipsis,
),
const SizedBox(
height: 8,
), ),
const SizedBox(height: 8),
Text( Text(
filteredNotes[index].body, filteredNotes[index]
style: const TextStyle( .body,
color: Colors.white70, style:
const TextStyle(
color: Colors
.white70,
fontSize: 14, fontSize: 14,
), ),
maxLines: 20, maxLines: 20,
overflow: TextOverflow.clip, overflow:
TextOverflow.clip,
), ),
], ],
), ),
@@ -582,29 +676,36 @@ class _HomeScreenState extends State<HomeScreen> {
), ),
child: Container( child: Container(
decoration: BoxDecoration( decoration: BoxDecoration(
border: candidateData.isNotEmpty border:
candidateData.isNotEmpty
? Border.all( ? Border.all(
color: Colors.blue.shade400, color: Colors
.blue
.shade400,
width: 2, width: 2,
) )
: null, : null,
borderRadius: BorderRadius.circular(12), borderRadius:
BorderRadius.circular(12),
), ),
child: NoteCard( child: NoteCard(
key: ValueKey<String>( key: ValueKey<String>(
filteredNotes[index].id, filteredNotes[index].id,
), ),
note: filteredNotes[index], note: filteredNotes[index],
onTap: () => onTap: () => _openNoteEditor(
_openNoteEditor(filteredNotes[index]), filteredNotes[index],
),
isDragging: _isDragging, isDragging: _isDragging,
), ),
), ),
); );
return Listener( return Listener(
onPointerDown: (PointerDownEvent event) { onPointerDown:
if (_lastPointerKind == event.kind) { (PointerDownEvent event) {
if (_lastPointerKind ==
event.kind) {
return; return;
} }
@@ -621,6 +722,9 @@ class _HomeScreenState extends State<HomeScreen> {
}, },
), ),
), ),
],
),
),
); );
return Scaffold( return Scaffold(
+52 -119
View File
@@ -28,12 +28,11 @@ class NoteEditorScreen extends StatefulWidget {
@override @override
State<NoteEditorScreen> createState() => _NoteEditorScreenState(); State<NoteEditorScreen> createState() => _NoteEditorScreenState();
static Future<dynamic> showDialog( static Future<dynamic> _showGeneralEditorDialog(
BuildContext context, { BuildContext context, {
Note? note, Note? note,
String? categoryId, String? categoryId,
}) { }) {
if (isAndroid || isIOS) {
return showGeneralDialog<dynamic>( return showGeneralDialog<dynamic>(
context: context, context: context,
barrierDismissible: false, barrierDismissible: false,
@@ -48,19 +47,25 @@ class NoteEditorScreen extends StatefulWidget {
); );
} }
static Future<dynamic> showDialog(
BuildContext context, {
Note? note,
String? categoryId,
}) {
if (isAndroid || isIOS) {
return _showGeneralEditorDialog(
context,
note: note,
categoryId: categoryId,
);
}
final OverlayState? overlayState = Overlay.of(context, rootOverlay: true); final OverlayState? overlayState = Overlay.of(context, rootOverlay: true);
if (overlayState == null) { if (overlayState == null) {
return showGeneralDialog<dynamic>( return _showGeneralEditorDialog(
context: context, context,
barrierDismissible: false, note: note,
barrierColor: Colors.transparent, categoryId: categoryId,
transitionDuration: const Duration(milliseconds: 200),
pageBuilder: (context, animation, secondaryAnimation) {
return NoteEditorScreen(note: note, categoryId: categoryId);
},
transitionBuilder: (context, animation, secondaryAnimation, child) {
return ScaleTransition(scale: animation, child: child);
},
); );
} }
@@ -161,15 +166,11 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
_complete(updatedNote); _complete(updatedNote);
} }
Future<bool> _showDeleteConfirmation() async { Widget _buildDeleteConfirmationDialog({
required ValueChanged<bool> onConfirmed,
}) {
final bool isDeletedNote = _currentNote.isDeleted; final bool isDeletedNote = _currentNote.isDeleted;
if (_isMobileLayout) {
final bool? confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
barrierColor: Colors.transparent,
builder: (BuildContext dialogContext) {
return AlertDialog( return AlertDialog(
backgroundColor: const Color(0xFF303134), backgroundColor: const Color(0xFF303134),
title: Text( title: Text(
@@ -184,14 +185,14 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
), ),
actions: [ actions: [
TextButton( TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false), onPressed: () => onConfirmed(false),
child: const Text( child: const Text(
'Cancelar', 'Cancelar',
style: TextStyle(color: Colors.white70), style: TextStyle(color: Colors.white70),
), ),
), ),
TextButton( TextButton(
onPressed: () => Navigator.of(dialogContext).pop(true), onPressed: () => onConfirmed(true),
child: Text( child: Text(
isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar', isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar',
style: const TextStyle(color: Colors.red), style: const TextStyle(color: Colors.red),
@@ -199,6 +200,19 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
), ),
], ],
); );
}
Future<bool> _showDeleteConfirmation() async {
if (_isMobileLayout) {
final bool? confirmed = await showDialog<bool>(
context: context,
barrierDismissible: false,
barrierColor: Colors.transparent,
builder: (BuildContext dialogContext) {
return _buildDeleteConfirmationDialog(
onConfirmed: (bool confirmed) =>
Navigator.of(dialogContext).pop(confirmed),
);
}, },
); );
@@ -212,34 +226,9 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
barrierDismissible: false, barrierDismissible: false,
barrierColor: Colors.transparent, barrierColor: Colors.transparent,
builder: (BuildContext dialogContext) { builder: (BuildContext dialogContext) {
return AlertDialog( return _buildDeleteConfirmationDialog(
backgroundColor: const Color(0xFF303134), onConfirmed: (bool confirmed) =>
title: Text( Navigator.of(dialogContext).pop(confirmed),
isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar nota',
style: const TextStyle(color: Colors.white),
),
content: Text(
isDeletedNote
? 'Esta nota ya está borrada. Si la eliminas ahora, se borrará permanentemente.'
: '¿Estás seguro de que deseas eliminar esta nota?',
style: const TextStyle(color: Colors.white70),
),
actions: [
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(false),
child: const Text(
'Cancelar',
style: TextStyle(color: Colors.white70),
),
),
TextButton(
onPressed: () => Navigator.of(dialogContext).pop(true),
child: Text(
isDeletedNote ? 'Eliminar permanentemente' : 'Eliminar',
style: const TextStyle(color: Colors.red),
),
),
],
); );
}, },
); );
@@ -251,7 +240,9 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
late final OverlayEntry entry; late final OverlayEntry entry;
bool didRemove = false; bool didRemove = false;
void close(bool confirmed) { entry = OverlayEntry(
builder: (BuildContext overlayContext) {
final ValueChanged<bool> close = (bool confirmed) {
if (!completer.isCompleted) { if (!completer.isCompleted) {
completer.complete(confirmed); completer.complete(confirmed);
} }
@@ -259,10 +250,8 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
didRemove = true; didRemove = true;
entry.remove(); entry.remove();
} }
} };
entry = OverlayEntry(
builder: (BuildContext overlayContext) {
return Material( return Material(
color: Colors.transparent, color: Colors.transparent,
child: Stack( child: Stack(
@@ -276,39 +265,7 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
Center( Center(
child: ConstrainedBox( child: ConstrainedBox(
constraints: const BoxConstraints(maxWidth: 420), constraints: const BoxConstraints(maxWidth: 420),
child: AlertDialog( child: _buildDeleteConfirmationDialog(onConfirmed: close),
backgroundColor: const Color(0xFF303134),
title: Text(
isDeletedNote
? 'Eliminar permanentemente'
: 'Eliminar nota',
style: const TextStyle(color: Colors.white),
),
content: Text(
isDeletedNote
? 'Esta nota ya está borrada. Si la eliminas ahora, se borrará permanentemente.'
: '¿Estás seguro de que deseas eliminar esta nota?',
style: const TextStyle(color: Colors.white70),
),
actions: [
TextButton(
onPressed: () => close(false),
child: const Text(
'Cancelar',
style: TextStyle(color: Colors.white70),
),
),
TextButton(
onPressed: () => close(true),
child: Text(
isDeletedNote
? 'Eliminar permanentemente'
: 'Eliminar',
style: const TextStyle(color: Colors.red),
),
),
],
),
), ),
), ),
], ],
@@ -351,26 +308,15 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
return Column( return Column(
children: [ children: [
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
horizontal: 16,
vertical: 12,
),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(bottom: BorderSide(color: Colors.white12, width: 1)),
bottom: BorderSide(
color: Colors.white12,
width: 1,
),
),
), ),
child: Row( child: Row(
children: [ children: [
IconButton( IconButton(
onPressed: _closeWithoutSaving, onPressed: _closeWithoutSaving,
icon: const Icon( icon: const Icon(Icons.close, color: Colors.white70),
Icons.close,
color: Colors.white70,
),
tooltip: 'Cerrar sin guardar', tooltip: 'Cerrar sin guardar',
), ),
const SizedBox(width: 8), const SizedBox(width: 8),
@@ -434,9 +380,7 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
), ),
decoration: const InputDecoration( decoration: const InputDecoration(
hintText: 'Escribe tu nota...', hintText: 'Escribe tu nota...',
hintStyle: TextStyle( hintStyle: TextStyle(color: Colors.white30),
color: Colors.white30,
),
border: InputBorder.none, border: InputBorder.none,
contentPadding: EdgeInsets.zero, contentPadding: EdgeInsets.zero,
), ),
@@ -447,14 +391,9 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
), ),
), ),
Container( Container(
padding: const EdgeInsets.symmetric( padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
horizontal: 16,
vertical: 12,
),
decoration: BoxDecoration( decoration: BoxDecoration(
border: Border( border: Border(top: BorderSide(color: Colors.white12, width: 1)),
top: BorderSide(color: Colors.white12, width: 1),
),
), ),
child: Row( child: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween, mainAxisAlignment: MainAxisAlignment.spaceBetween,
@@ -462,18 +401,12 @@ class _NoteEditorScreenState extends State<NoteEditorScreen> {
if (!_isNewNote) if (!_isNewNote)
IconButton( IconButton(
onPressed: _deleteNote, onPressed: _deleteNote,
icon: const Icon( icon: const Icon(Icons.delete_outline, color: Colors.red),
Icons.delete_outline,
color: Colors.red,
),
tooltip: 'Eliminar nota', tooltip: 'Eliminar nota',
) )
else else
const SizedBox(width: 48), const SizedBox(width: 48),
FilledButton( FilledButton(onPressed: _saveNote, child: const Text('Guardar')),
onPressed: _saveNote,
child: const Text('Guardar'),
),
], ],
), ),
), ),
+30 -7
View File
@@ -45,11 +45,8 @@ class MenuDrawer extends StatelessWidget {
child: Column( child: Column(
children: categories.map((category) { children: categories.map((category) {
final categoryId = 'category_${category.id}'; final categoryId = 'category_${category.id}';
final IconData categoryIcon = category.iconCodePoint == null final IconData categoryIcon = _iconForCodePoint(
? Icons.folder_outlined category.iconCodePoint,
: IconData(
category.iconCodePoint!,
fontFamily: 'MaterialIcons',
); );
return _MenuItemTile( return _MenuItemTile(
@@ -102,6 +99,31 @@ class MenuDrawer extends StatelessWidget {
} }
} }
IconData _iconForCodePoint(int? codePoint) {
if (codePoint == null) {
return Icons.folder_outlined;
}
const List<IconData> icons = [
Icons.folder,
Icons.work,
Icons.star,
Icons.home,
Icons.school,
Icons.book,
Icons.music_note,
Icons.lightbulb,
];
for (final IconData icon in icons) {
if (icon.codePoint == codePoint) {
return icon;
}
}
return Icons.folder_outlined;
}
class _MenuItemTile extends StatelessWidget { class _MenuItemTile extends StatelessWidget {
const _MenuItemTile({ const _MenuItemTile({
required this.icon, required this.icon,
@@ -136,7 +158,7 @@ class _MenuItemTile extends StatelessWidget {
top: 2, top: 2,
bottom: 2, bottom: 2,
), ),
decoration: BoxDecoration( child: Material(
color: backgroundColor, color: backgroundColor,
borderRadius: selected borderRadius: selected
? const BorderRadius.only( ? const BorderRadius.only(
@@ -144,7 +166,7 @@ class _MenuItemTile extends StatelessWidget {
bottomRight: Radius.circular(999), bottomRight: Radius.circular(999),
) )
: BorderRadius.circular(12), : BorderRadius.circular(12),
), clipBehavior: Clip.antiAlias,
child: ListTile( child: ListTile(
leading: Icon(icon, color: iconColor ?? foregroundColor), leading: Icon(icon, color: iconColor ?? foregroundColor),
trailing: trailing, trailing: trailing,
@@ -155,6 +177,7 @@ class _MenuItemTile extends StatelessWidget {
onTap: onTap, onTap: onTap,
hoverColor: Colors.white.withValues(alpha: 0.1), hoverColor: Colors.white.withValues(alpha: 0.1),
), ),
),
); );
} }
} }