From 96b82ef416191c3ca0731622eb96661eb3836b00 Mon Sep 17 00:00:00 2001 From: stopflock Date: Wed, 1 Oct 2025 12:34:02 -0500 Subject: [PATCH] Proper centering for all node sheets. still jumps between tags and edit. --- lib/screens/home_screen.dart | 35 +++++++++++++++++++++++++++-- lib/widgets/map/camera_markers.dart | 35 +++++++++++++++++++++++------ lib/widgets/map_view.dart | 15 +++++-------- 3 files changed, 66 insertions(+), 19 deletions(-) diff --git a/lib/screens/home_screen.dart b/lib/screens/home_screen.dart index 5c2d2aa..d27a58e 100644 --- a/lib/screens/home_screen.dart +++ b/lib/screens/home_screen.dart @@ -11,9 +11,11 @@ import '../services/localization_service.dart'; import '../widgets/add_node_sheet.dart'; import '../widgets/edit_node_sheet.dart'; +import '../widgets/node_tag_sheet.dart'; import '../widgets/camera_provider_with_cache.dart'; import '../widgets/download_area_dialog.dart'; import '../widgets/measured_sheet.dart'; +import '../models/osm_node.dart'; class HomeScreen extends StatefulWidget { const HomeScreen({super.key}); @@ -28,9 +30,10 @@ class _HomeScreenState extends State with TickerProviderStateMixin { late final AnimatedMapController _mapController; bool _editSheetShown = false; - // Track sheet heights for map padding + // Track sheet heights for map positioning double _addSheetHeight = 0.0; double _editSheetHeight = 0.0; + double _tagSheetHeight = 0.0; @override void initState() { @@ -110,6 +113,11 @@ class _HomeScreenState extends State with TickerProviderStateMixin { // Disable follow-me when editing a camera so the map doesn't jump around appState.setFollowMeMode(FollowMeMode.off); + // Close any existing tag sheet first + if (_tagSheetHeight > 0) { + Navigator.of(context).pop(); + } + final session = appState.editSession!; // should be non-null when this is called final controller = _scaffoldKey.currentState!.showBottomSheet( @@ -131,6 +139,26 @@ class _HomeScreenState extends State with TickerProviderStateMixin { }); } + void openNodeTagSheet(OsmNode node) { + final controller = _scaffoldKey.currentState!.showBottomSheet( + (ctx) => MeasuredSheet( + onHeightChanged: (height) { + setState(() { + _tagSheetHeight = height; + }); + }, + child: NodeTagSheet(node: node), + ), + ); + + // Reset height when sheet is dismissed + controller.closed.then((_) { + setState(() { + _tagSheetHeight = 0.0; + }); + }); + } + @override Widget build(BuildContext context) { final appState = context.watch(); @@ -144,7 +172,9 @@ class _HomeScreenState extends State with TickerProviderStateMixin { } // Pass the active sheet height directly to the map - final activeSheetHeight = _addSheetHeight > 0 ? _addSheetHeight : _editSheetHeight; + final activeSheetHeight = _addSheetHeight > 0 + ? _addSheetHeight + : (_editSheetHeight > 0 ? _editSheetHeight : _tagSheetHeight); return MultiProvider( providers: [ @@ -190,6 +220,7 @@ class _HomeScreenState extends State with TickerProviderStateMixin { controller: _mapController, followMeMode: appState.followMeMode, sheetHeight: activeSheetHeight, + onNodeTap: openNodeTagSheet, onUserGesture: () { if (appState.followMeMode != FollowMeMode.off) { appState.setFollowMeMode(FollowMeMode.off); diff --git a/lib/widgets/map/camera_markers.dart b/lib/widgets/map/camera_markers.dart index 7672f94..c639289 100644 --- a/lib/widgets/map/camera_markers.dart +++ b/lib/widgets/map/camera_markers.dart @@ -12,7 +12,14 @@ import '../camera_icon.dart'; class CameraMapMarker extends StatefulWidget { final OsmNode node; final MapController mapController; - const CameraMapMarker({required this.node, required this.mapController, Key? key}) : super(key: key); + final void Function(OsmNode)? onNodeTap; + + const CameraMapMarker({ + required this.node, + required this.mapController, + this.onNodeTap, + Key? key, + }) : super(key: key); @override State createState() => _CameraMapMarkerState(); @@ -25,11 +32,20 @@ class _CameraMapMarkerState extends State { void _onTap() { _tapTimer = Timer(tapTimeout, () { - showModalBottomSheet( - context: context, - builder: (_) => NodeTagSheet(node: widget.node), - showDragHandle: true, - ); + // Center on the node when opening the tag sheet + // This prevents jumping when transitioning to edit mode + widget.mapController.move(widget.node.coord, widget.mapController.camera.zoom); + + // Use callback if provided, otherwise fallback to direct modal + if (widget.onNodeTap != null) { + widget.onNodeTap!(widget.node); + } else { + showModalBottomSheet( + context: context, + builder: (_) => NodeTagSheet(node: widget.node), + showDragHandle: true, + ); + } }); } @@ -79,6 +95,7 @@ class CameraMarkersBuilder { required List cameras, required MapController mapController, LatLng? userLocation, + void Function(OsmNode)? onNodeTap, }) { final markers = [ // Camera markers @@ -88,7 +105,11 @@ class CameraMarkersBuilder { point: n.coord, width: kCameraIconDiameter, height: kCameraIconDiameter, - child: CameraMapMarker(node: n, mapController: mapController), + child: CameraMapMarker( + node: n, + mapController: mapController, + onNodeTap: onNodeTap, + ), )), // User location marker diff --git a/lib/widgets/map_view.dart b/lib/widgets/map_view.dart index 27bde7b..b6c8e1a 100644 --- a/lib/widgets/map_view.dart +++ b/lib/widgets/map_view.dart @@ -35,11 +35,13 @@ class MapView extends StatefulWidget { required this.followMeMode, required this.onUserGesture, this.sheetHeight = 0.0, + this.onNodeTap, }); final FollowMeMode followMeMode; final VoidCallback onUserGesture; final double sheetHeight; + final void Function(OsmNode)? onNodeTap; @override State createState() => MapViewState(); @@ -308,16 +310,8 @@ class MapViewState extends State { } catch (_) {/* controller not ready yet */} } - // For edit sessions, center the map on the camera being edited initially - if (editSession != null && _controller.mapController.camera.center != editSession.target) { - WidgetsBinding.instance.addPostFrameCallback( - (_) { - try { - _controller.mapController.move(editSession.target, _controller.mapController.camera.zoom); - } catch (_) {/* controller not ready yet */} - }, - ); - } + // Edit sessions don't need to center - we're already centered from the node tap + // SheetAwareMap handles the visual positioning // Fetch cached cameras for current map bounds (using Consumer so overlays redraw instantly) Widget cameraLayers = Consumer( @@ -336,6 +330,7 @@ class MapViewState extends State { cameras: cameras, mapController: _controller.mapController, userLocation: _gpsController.currentLocation, + onNodeTap: widget.onNodeTap, ); // Get current zoom level for direction cones