From 1aeae18ebca3ec451cb6e15db7e61e3b8f919938 Mon Sep 17 00:00:00 2001 From: stopflock Date: Wed, 1 Oct 2025 13:27:17 -0500 Subject: [PATCH] Better handoff from tags to edit sheet --- lib/screens/home_screen.dart | 71 ++++++++++++++++++++++--------- lib/widgets/map/map_overlays.dart | 23 +++++++--- lib/widgets/node_tag_sheet.dart | 12 ++++-- 3 files changed, 77 insertions(+), 29 deletions(-) diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index d27a58e..a97202a 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -34,6 +34,9 @@ class _HomeScreenState extends State with TickerProviderStateMixin { double _addSheetHeight = 0.0; double _editSheetHeight = 0.0; double _tagSheetHeight = 0.0; + + // Flag to prevent map bounce when transitioning from tag sheet to edit sheet + bool _transitioningToEdit = false; @override void initState() { @@ -113,6 +116,9 @@ class _HomeScreenState extends State with TickerProviderStateMixin { // Disable follow-me when editing a camera so the map doesn't jump around appState.setFollowMeMode(FollowMeMode.off); + // Set transition flag to prevent map bounce + _transitioningToEdit = true; + // Close any existing tag sheet first if (_tagSheetHeight > 0) { Navigator.of(context).pop(); @@ -120,21 +126,32 @@ class _HomeScreenState extends State with TickerProviderStateMixin { final session = appState.editSession!; // should be non-null when this is called - final controller = _scaffoldKey.currentState!.showBottomSheet( - (ctx) => MeasuredSheet( - onHeightChanged: (height) { - setState(() { - _editSheetHeight = height; - }); - }, - child: EditNodeSheet(session: session), - ), - ); - - // Reset height when sheet is dismissed - controller.closed.then((_) { - setState(() { - _editSheetHeight = 0.0; + // Small delay to let tag sheet close smoothly + Future.delayed(const Duration(milliseconds: 150), () { + if (!mounted) return; + + final controller = _scaffoldKey.currentState!.showBottomSheet( + (ctx) => MeasuredSheet( + onHeightChanged: (height) { + setState(() { + _editSheetHeight = height; + // Clear transition flag and reset tag sheet height once edit sheet starts sizing + if (height > 0 && _transitioningToEdit) { + _transitioningToEdit = false; + _tagSheetHeight = 0.0; // Now safe to reset + } + }); + }, + child: EditNodeSheet(session: session), + ), + ); + + // Reset height when sheet is dismissed + controller.closed.then((_) { + setState(() { + _editSheetHeight = 0.0; + _transitioningToEdit = false; + }); }); }); } @@ -147,15 +164,25 @@ class _HomeScreenState extends State with TickerProviderStateMixin { _tagSheetHeight = height; }); }, - child: NodeTagSheet(node: node), + child: NodeTagSheet( + node: node, + onEditPressed: () { + final appState = context.read(); + appState.startEditSession(node); + // This will trigger _openEditNodeSheet via the existing auto-show logic + }, + ), ), ); - // Reset height when sheet is dismissed + // Reset height when sheet is dismissed (unless transitioning to edit) controller.closed.then((_) { - setState(() { - _tagSheetHeight = 0.0; - }); + if (!_transitioningToEdit) { + setState(() { + _tagSheetHeight = 0.0; + }); + } + // If transitioning to edit, keep the height until edit sheet takes over }); } @@ -174,7 +201,9 @@ class _HomeScreenState extends State with TickerProviderStateMixin { // Pass the active sheet height directly to the map final activeSheetHeight = _addSheetHeight > 0 ? _addSheetHeight - : (_editSheetHeight > 0 ? _editSheetHeight : _tagSheetHeight); + : (_editSheetHeight > 0 + ? _editSheetHeight + : _tagSheetHeight); return MultiProvider( providers: [ diff --git a/lib/widgets/map/map_overlays.dart b/lib/widgets/map/map_overlays.dart index 417f40a..53b39fa 100644 --- a/lib/widgets/map/map_overlays.dart +++ b/lib/widgets/map/map_overlays.dart @@ -69,7 +69,12 @@ class MapOverlays extends StatelessWidget { ), child: Builder( builder: (context) { - final zoom = mapController.camera.zoom; + double zoom = 15.0; // fallback + try { + zoom = mapController.camera.zoom; + } catch (_) { + // Map controller not ready yet + } return Text( 'Zoom: ${zoom.toStringAsFixed(2)}', style: const TextStyle( @@ -118,8 +123,12 @@ class MapOverlays extends StatelessWidget { mini: true, heroTag: "zoom_in", onPressed: () { - final zoom = mapController.camera.zoom; - mapController.move(mapController.camera.center, zoom + 1); + try { + final zoom = mapController.camera.zoom; + mapController.move(mapController.camera.center, zoom + 1); + } catch (_) { + // Map controller not ready yet + } }, child: const Icon(Icons.add), ), @@ -129,8 +138,12 @@ class MapOverlays extends StatelessWidget { mini: true, heroTag: "zoom_out", onPressed: () { - final zoom = mapController.camera.zoom; - mapController.move(mapController.camera.center, zoom - 1); + try { + final zoom = mapController.camera.zoom; + mapController.move(mapController.camera.center, zoom - 1); + } catch (_) { + // Map controller not ready yet + } }, child: const Icon(Icons.remove), ), diff --git a/lib/widgets/node_tag_sheet.dart b/lib/widgets/node_tag_sheet.dart index 0774bf4..1763689 100644 --- a/lib/widgets/node_tag_sheet.dart +++ b/lib/widgets/node_tag_sheet.dart @@ -6,8 +6,9 @@ import '../services/localization_service.dart'; class NodeTagSheet extends StatelessWidget { final OsmNode node; + final VoidCallback? onEditPressed; - const NodeTagSheet({super.key, required this.node}); + const NodeTagSheet({super.key, required this.node, this.onEditPressed}); @override Widget build(BuildContext context) { @@ -26,8 +27,13 @@ class NodeTagSheet extends StatelessWidget { node.tags['_pending_deletion'] != 'true'); void _openEditSheet() { - Navigator.pop(context); // Close this sheet first - appState.startEditSession(node); // HomeScreen will auto-show the edit sheet + if (onEditPressed != null) { + onEditPressed!(); // Use callback if provided + } else { + // Fallback behavior + Navigator.pop(context); // Close this sheet first + appState.startEditSession(node); // HomeScreen will auto-show the edit sheet + } } void _deleteNode() async {