long press to add node

This commit is contained in:
stopflock
2026-06-14 21:20:17 -05:00
parent d87a112c0a
commit 0b812bdaea
5 changed files with 79 additions and 2 deletions
+3 -2
View File
@@ -1,7 +1,8 @@
{
"2.10.2": {
"content": [
"• Fixed Flutter deprecation warnings for profile reordering"
"• Added tap and hold gesture on empty map area to add a node at that location",
"• Added ability to accept direct links to a specific node for callbacks from e.g. FlockHopper"
]
},
"2.10.1": {
@@ -13,7 +14,7 @@
},
"2.10.0": {
"content": [
"• Simplified profile FOVs; there is now only a checkbox for '360'",
"• Simplified profile FOVs; there is now only a checkbox for '360'"
]
},
"2.9.2": {
+1
View File
@@ -96,6 +96,7 @@ const int kOsmApiMinZoomLevel = 13; // Minimum zoom for OSM API bbox queries (sa
const int kMinZoomForNodeEditingSheets = 16; // Minimum zoom to open add/edit node sheets
const int kMinZoomForOfflineDownload = 10; // Minimum zoom to download offline areas (prevents large area crashes)
const Duration kMarkerTapTimeout = Duration(milliseconds: 250);
const Duration kMapLongPressTimeout = Duration(milliseconds: 600); // Duration to trigger "add node here" on empty map area
const Duration kDebounceCameraRefresh = Duration(milliseconds: 500);
// Pre-fetch area configuration
@@ -1,5 +1,6 @@
import 'package:flutter/material.dart';
import 'package:flutter_map_animations/flutter_map_animations.dart';
import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart';
import '../../app_state.dart';
@@ -125,4 +126,50 @@ class MapInteractionHandler {
// Clear suspected location selection
appState.clearSuspectedLocationSelection();
}
/// Handle long press on empty map area (add node here)
void handleMapLongPress({
required BuildContext context,
required LatLng tapLocation,
required AnimatedMapController mapController,
required VoidCallback onAddNode,
}) {
final appState = context.read<AppState>();
debugPrint('[MapInteractionHandler] Long press at: ${tapLocation.latitude}, ${tapLocation.longitude}');
// Check if we should handle this long press
// Don't handle if any sheet is open or if in search mode
if (appState.isInSearchMode || appState.showingOverview) {
debugPrint('[MapInteractionHandler] Long press ignored - in search/navigation mode');
return;
}
// Don't handle if any session is active (add/edit sheets are open)
if (appState.session != null || appState.editSession != null) {
debugPrint('[MapInteractionHandler] Long press ignored - node sheet already open');
return;
}
// Disable follow-me when user long presses
appState.setFollowMeMode(FollowMeMode.off);
// First, center the map on the tap location
try {
mapController.animateTo(
dest: tapLocation,
zoom: mapController.mapController.camera.zoom,
duration: const Duration(milliseconds: 300),
curve: Curves.easeOut,
);
} catch (e) {
debugPrint('[MapInteractionHandler] Could not center map on long press location: $e');
}
// After a short delay to let the map center, open the add node sheet
// This matches the existing pattern used for node taps
Future.delayed(const Duration(milliseconds: 350), () {
onAddNode();
});
}
}
+17
View File
@@ -1,6 +1,7 @@
import 'package:flutter/material.dart';
import 'package:flutter_map_animations/flutter_map_animations.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:latlong2/latlong.dart';
import 'package:provider/provider.dart';
import '../app_state.dart';
@@ -289,6 +290,21 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
);
}
void _onMapLongPress(LatLng location) {
// Don't handle long press if tag sheet is open
if (_sheetCoordinator.tagSheetHeight > 0) {
debugPrint('[HomeScreen] Long press ignored - tag sheet is open');
return;
}
_mapInteractionHandler.handleMapLongPress(
context: context,
tapLocation: location,
mapController: _mapController,
onAddNode: _openAddNodeSheet,
);
}
void _handleNodeDeepLink(OsmNode node) {
try {
_mapController.animateTo(
@@ -520,6 +536,7 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
// Re-render when location status changes (for follow-me button state)
setState(() {});
},
onMapLongPress: _onMapLongPress,
onUserGesture: () {
// Only clear selected node if tag sheet is not open
// This prevents nodes from losing their grey-out when map is moved while viewing tags
+11
View File
@@ -43,6 +43,7 @@ class MapView extends StatefulWidget {
this.onSearchPressed,
this.onNodeLimitChanged,
this.onLocationStatusChanged,
this.onMapLongPress,
});
final FollowMeMode followMeMode;
@@ -54,6 +55,7 @@ class MapView extends StatefulWidget {
final VoidCallback? onSearchPressed;
final void Function(bool isLimited)? onNodeLimitChanged;
final VoidCallback? onLocationStatusChanged;
final void Function(LatLng)? onMapLongPress;
@override
State<MapView> createState() => MapViewState();
@@ -514,6 +516,15 @@ class MapViewState extends State<MapView> {
_dataManager.showZoomWarningIfNeeded(context, pos.zoom, appState.uploadMode);
}
},
onTap: (tapPosition, point) {
// Handle tap on empty map area - currently no action needed
debugPrint('[MapView] Tap at: $point');
},
onLongPress: (tapPosition, point) {
// Handle long press on empty map area - add node here
debugPrint('[MapView] Long press at: $point');
widget.onMapLongPress?.call(point);
},
),
children: [
_tileManager.buildTileLayer(