Proper centering for all node sheets. still jumps between tags and edit.

This commit is contained in:
stopflock
2025-10-01 12:34:02 -05:00
parent adec4b175f
commit 96b82ef416
3 changed files with 66 additions and 19 deletions
+33 -2
View File
@@ -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<HomeScreen> 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<HomeScreen> 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<HomeScreen> 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<AppState>();
@@ -144,7 +172,9 @@ class _HomeScreenState extends State<HomeScreen> 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<HomeScreen> with TickerProviderStateMixin {
controller: _mapController,
followMeMode: appState.followMeMode,
sheetHeight: activeSheetHeight,
onNodeTap: openNodeTagSheet,
onUserGesture: () {
if (appState.followMeMode != FollowMeMode.off) {
appState.setFollowMeMode(FollowMeMode.off);
+28 -7
View File
@@ -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<CameraMapMarker> createState() => _CameraMapMarkerState();
@@ -25,11 +32,20 @@ class _CameraMapMarkerState extends State<CameraMapMarker> {
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<OsmNode> cameras,
required MapController mapController,
LatLng? userLocation,
void Function(OsmNode)? onNodeTap,
}) {
final markers = <Marker>[
// 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
+5 -10
View File
@@ -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<MapView> createState() => MapViewState();
@@ -308,16 +310,8 @@ class MapViewState extends State<MapView> {
} 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<CameraProviderWithCache>(
@@ -336,6 +330,7 @@ class MapViewState extends State<MapView> {
cameras: cameras,
mapController: _controller.mapController,
userLocation: _gpsController.currentLocation,
onNodeTap: widget.onNodeTap,
);
// Get current zoom level for direction cones