From 6035e3bc18ad9571bca2a770d2f00aefd8f0f3a5 Mon Sep 17 00:00:00 2001 From: Marcos Date: Tue, 19 May 2026 20:24:03 +0200 Subject: [PATCH] feat: Implement menu open/close functionality in HomeScreen for improved user interaction --- lib/screens/home_screen.dart | 136 +++++++++++++++++++++++------------ 1 file changed, 91 insertions(+), 45 deletions(-) diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index bbfddcd..72c60ba 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -50,6 +50,26 @@ class _HomeScreenState extends State { bool _showDeletedNotes = false; PointerDeviceKind _lastPointerKind = PointerDeviceKind.mouse; + void _openMenu() { + if (_isMenuOpen) { + return; + } + + setState(() { + _isMenuOpen = true; + }); + } + + void _closeMenu() { + if (!_isMenuOpen) { + return; + } + + setState(() { + _isMenuOpen = false; + }); + } + bool _requiresLongPressToDrag(PointerDeviceKind kind) { return kind == PointerDeviceKind.touch || kind == PointerDeviceKind.stylus || @@ -172,9 +192,7 @@ class _HomeScreenState extends State { } Future _handleMenuItemTapped(String item) async { - setState(() { - _isMenuOpen = false; - }); + _closeMenu(); if (item == 'settings') { widget.onOpenSettings(); @@ -209,8 +227,8 @@ class _HomeScreenState extends State { final Widget body = _isLoading ? const Center(child: CircularProgressIndicator()) : _notes.isEmpty - ? _EmptyState(showDeletedNotes: _showDeletedNotes) - : RefreshIndicator( + ? _EmptyState(showDeletedNotes: _showDeletedNotes) + : RefreshIndicator( onRefresh: () async { await widget.onRequestSync(); }, @@ -546,53 +564,81 @@ class _HomeScreenState extends State { }, ), Expanded( - child: Stack( - children: [ - Padding( - padding: const EdgeInsets.symmetric( - horizontal: 12.0, - vertical: 8.0, + child: Listener( + onPointerDown: (PointerDownEvent event) { + if (_lastPointerKind == event.kind) { + return; + } + + setState(() { + _lastPointerKind = event.kind; + }); + }, + child: Stack( + children: [ + Padding( + padding: const EdgeInsets.symmetric( + horizontal: 12.0, + vertical: 8.0, + ), + child: body, ), - child: body, - ), - Positioned.fill( - child: IgnorePointer( - ignoring: !_isMenuOpen, - child: AnimatedOpacity( - duration: const Duration(milliseconds: 300), - opacity: _isMenuOpen ? 0.5 : 0.0, - curve: Curves.easeOutCubic, + Positioned( + left: 0, + top: 0, + bottom: 0, + width: 28, + child: IgnorePointer( + ignoring: + _isMenuOpen || + !_requiresLongPressToDrag(_lastPointerKind), child: GestureDetector( - behavior: HitTestBehavior.opaque, - onTap: () { - setState(() { - _isMenuOpen = false; - }); - }, - child: Container(color: Colors.black), + behavior: HitTestBehavior.translucent, + onHorizontalDragUpdate: + (DragUpdateDetails details) { + if ((details.primaryDelta ?? 0) > 6) { + _openMenu(); + } + }, + child: const SizedBox.expand(), ), ), ), - ), - AnimatedPositioned( - duration: const Duration(milliseconds: 300), - curve: Curves.easeOutCubic, - left: _isMenuOpen ? 0 : -280, - top: 0, - bottom: 0, - width: 280, - child: Material( - color: const Color.fromRGBO(24, 25, 26, 1), - elevation: 8, - child: MenuDrawer( - onMenuItemTapped: _handleMenuItemTapped, - selectedItem: _showDeletedNotes - ? 'deleted_notes' - : 'all_notes', + Positioned.fill( + child: IgnorePointer( + ignoring: !_isMenuOpen, + child: AnimatedOpacity( + duration: const Duration(milliseconds: 300), + opacity: _isMenuOpen ? 0.5 : 0.0, + curve: Curves.easeOutCubic, + child: GestureDetector( + behavior: HitTestBehavior.opaque, + onTap: _closeMenu, + child: Container(color: Colors.black), + ), + ), ), ), - ), - ], + AnimatedPositioned( + duration: const Duration(milliseconds: 300), + curve: Curves.easeOutCubic, + left: _isMenuOpen ? 0 : -280, + top: 0, + bottom: 0, + width: 280, + child: Material( + color: const Color.fromRGBO(24, 25, 26, 1), + elevation: 8, + child: MenuDrawer( + onMenuItemTapped: _handleMenuItemTapped, + selectedItem: _showDeletedNotes + ? 'deleted_notes' + : 'all_notes', + ), + ), + ), + ], + ), ), ), ],