min zoom 1, max cameras 8, extract node from way

This commit is contained in:
stopflock
2025-11-19 22:46:09 -06:00
parent 1ac43b0c4e
commit 95fad14261
20 changed files with 219 additions and 67 deletions
+5 -3
View File
@@ -88,10 +88,12 @@ class AddNodeSheet extends StatelessWidget {
icon: Icon(
Icons.add,
size: 20,
color: requiresDirection ? null : Theme.of(context).disabledColor,
color: requiresDirection && session.directions.length < 8 ? null : Theme.of(context).disabledColor,
),
onPressed: requiresDirection ? () => appState.addDirection() : null,
tooltip: requiresDirection ? 'Add new direction' : 'Direction not required for this profile',
onPressed: requiresDirection && session.directions.length < 8 ? () => appState.addDirection() : null,
tooltip: requiresDirection
? (session.directions.length >= 8 ? 'Maximum 8 directions allowed' : 'Add new direction')
: 'Direction not required for this profile',
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: kDirectionButtonMinWidth, minHeight: kDirectionButtonMinHeight),
),
+31 -14
View File
@@ -90,10 +90,12 @@ class EditNodeSheet extends StatelessWidget {
icon: Icon(
Icons.add,
size: 20,
color: requiresDirection ? null : Theme.of(context).disabledColor,
color: requiresDirection && session.directions.length < 8 ? null : Theme.of(context).disabledColor,
),
onPressed: requiresDirection ? () => appState.addDirection() : null,
tooltip: requiresDirection ? 'Add new direction' : 'Direction not required for this profile',
onPressed: requiresDirection && session.directions.length < 8 ? () => appState.addDirection() : null,
tooltip: requiresDirection
? (session.directions.length >= 8 ? 'Maximum 8 directions allowed' : 'Add new direction')
: 'Direction not required for this profile',
padding: EdgeInsets.zero,
constraints: const BoxConstraints(minWidth: kDirectionButtonMinWidth, minHeight: kDirectionButtonMinHeight),
),
@@ -217,19 +219,34 @@ class EditNodeSheet extends StatelessWidget {
padding: const EdgeInsets.fromLTRB(16, 0, 16, 12),
child: Column(
children: [
Row(
children: [
const Icon(Icons.info_outline, size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(
locService.t('editNode.cannotMoveConstrainedNode'),
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
// Extract from way checkbox
CheckboxListTile(
title: Text(locService.t('editNode.extractFromWay')),
subtitle: Text(locService.t('editNode.extractFromWaySubtitle')),
value: session.extractFromWay,
onChanged: (value) {
appState.updateEditSession(extractFromWay: value);
},
controlAffinity: ListTileControlAffinity.leading,
contentPadding: EdgeInsets.zero,
),
const SizedBox(height: 8),
// Constraint info message (only show if extract is not checked)
if (!session.extractFromWay) ...[
Row(
children: [
const Icon(Icons.info_outline, size: 20),
const SizedBox(width: 8),
Expanded(
child: Text(
locService.t('editNode.cannotMoveConstrainedNode'),
style: Theme.of(context).textTheme.bodyMedium,
),
),
],
),
const SizedBox(height: 8),
],
Row(
mainAxisAlignment: MainAxisAlignment.end,
children: [
+21 -7
View File
@@ -263,11 +263,11 @@ class MapViewState extends State<MapView> {
}
/// Get interaction options for the map based on whether we're editing a constrained node.
/// Allows zoom and rotation but disables all forms of panning for constrained nodes.
/// Allows zoom and rotation but disables all forms of panning for constrained nodes unless extract is enabled.
InteractionOptions _getInteractionOptions(EditNodeSession? editSession) {
// Check if we're editing a constrained node
if (editSession?.originalNode.isConstrained == true) {
// Constrained node: only allow pinch zoom and rotation, disable ALL panning
// Check if we're editing a constrained node that's not being extracted
if (editSession?.originalNode.isConstrained == true && editSession?.extractFromWay != true) {
// Constrained node (not extracting): only allow pinch zoom and rotation, disable ALL panning
return const InteractionOptions(
enableMultiFingerGestureRace: true,
flags: InteractiveFlag.pinchZoom | InteractiveFlag.rotate,
@@ -379,6 +379,19 @@ class MapViewState extends State<MapView> {
} catch (_) {/* controller not ready yet */}
}
// Check for pending snap backs (when extract checkbox is unchecked)
final snapBackTarget = appState.consumePendingSnapBack();
if (snapBackTarget != null) {
WidgetsBinding.instance.addPostFrameCallback((_) {
_controller.animateTo(
dest: snapBackTarget,
zoom: _controller.mapController.camera.zoom,
curve: Curves.easeOut,
duration: const Duration(milliseconds: 250),
);
});
}
// Edit sessions don't need to center - we're already centered from the node tap
// SheetAwareMap handles the visual positioning
@@ -575,6 +588,7 @@ class MapViewState extends State<MapView> {
options: MapOptions(
initialCenter: _gpsController.currentLocation ?? _positionManager.initialLocation ?? LatLng(37.7749, -122.4194),
initialZoom: _positionManager.initialZoom ?? 15,
minZoom: 1.0,
maxZoom: (appState.selectedTileType?.maxZoom ?? 18).toDouble(),
interactionOptions: _getInteractionOptions(editSession),
onPositionChanged: (pos, gesture) {
@@ -587,8 +601,8 @@ class MapViewState extends State<MapView> {
appState.updateSession(target: pos.center);
}
if (editSession != null) {
// For constrained nodes, always snap back to original position
if (editSession.originalNode.isConstrained) {
// For constrained nodes that are not being extracted, always snap back to original position
if (editSession.originalNode.isConstrained && !editSession.extractFromWay) {
final originalPos = editSession.originalNode.coord;
// Always keep session target as original position
@@ -599,7 +613,7 @@ class MapViewState extends State<MapView> {
_constrainedNodeSnapBack(() {
// Only animate if we're still in a constrained edit session and still drifted
final currentEditSession = appState.editSession;
if (currentEditSession?.originalNode.isConstrained == true) {
if (currentEditSession?.originalNode.isConstrained == true && currentEditSession?.extractFromWay != true) {
final currentPos = _controller.mapController.camera.center;
if (currentPos.latitude != originalPos.latitude || currentPos.longitude != originalPos.longitude) {
_controller.animateTo(