mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-09-29 04:21:44 +02:00
long press to add node
This commit is contained in:
@@ -1,7 +1,8 @@
|
|||||||
{
|
{
|
||||||
"2.10.2": {
|
"2.10.2": {
|
||||||
"content": [
|
"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": {
|
"2.10.1": {
|
||||||
@@ -13,7 +14,7 @@
|
|||||||
},
|
},
|
||||||
"2.10.0": {
|
"2.10.0": {
|
||||||
"content": [
|
"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": {
|
"2.9.2": {
|
||||||
|
|||||||
@@ -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 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 int kMinZoomForOfflineDownload = 10; // Minimum zoom to download offline areas (prevents large area crashes)
|
||||||
const Duration kMarkerTapTimeout = Duration(milliseconds: 250);
|
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);
|
const Duration kDebounceCameraRefresh = Duration(milliseconds: 500);
|
||||||
|
|
||||||
// Pre-fetch area configuration
|
// Pre-fetch area configuration
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map_animations/flutter_map_animations.dart';
|
import 'package:flutter_map_animations/flutter_map_animations.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../../app_state.dart';
|
import '../../app_state.dart';
|
||||||
@@ -125,4 +126,50 @@ class MapInteractionHandler {
|
|||||||
// Clear suspected location selection
|
// Clear suspected location selection
|
||||||
appState.clearSuspectedLocationSelection();
|
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();
|
||||||
|
});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter_map_animations/flutter_map_animations.dart';
|
import 'package:flutter_map_animations/flutter_map_animations.dart';
|
||||||
import 'package:flutter_svg/flutter_svg.dart';
|
import 'package:flutter_svg/flutter_svg.dart';
|
||||||
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
import '../app_state.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) {
|
void _handleNodeDeepLink(OsmNode node) {
|
||||||
try {
|
try {
|
||||||
_mapController.animateTo(
|
_mapController.animateTo(
|
||||||
@@ -520,6 +536,7 @@ class _HomeScreenState extends State<HomeScreen> with TickerProviderStateMixin {
|
|||||||
// Re-render when location status changes (for follow-me button state)
|
// Re-render when location status changes (for follow-me button state)
|
||||||
setState(() {});
|
setState(() {});
|
||||||
},
|
},
|
||||||
|
onMapLongPress: _onMapLongPress,
|
||||||
onUserGesture: () {
|
onUserGesture: () {
|
||||||
// Only clear selected node if tag sheet is not open
|
// 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
|
// This prevents nodes from losing their grey-out when map is moved while viewing tags
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ class MapView extends StatefulWidget {
|
|||||||
this.onSearchPressed,
|
this.onSearchPressed,
|
||||||
this.onNodeLimitChanged,
|
this.onNodeLimitChanged,
|
||||||
this.onLocationStatusChanged,
|
this.onLocationStatusChanged,
|
||||||
|
this.onMapLongPress,
|
||||||
});
|
});
|
||||||
|
|
||||||
final FollowMeMode followMeMode;
|
final FollowMeMode followMeMode;
|
||||||
@@ -54,6 +55,7 @@ class MapView extends StatefulWidget {
|
|||||||
final VoidCallback? onSearchPressed;
|
final VoidCallback? onSearchPressed;
|
||||||
final void Function(bool isLimited)? onNodeLimitChanged;
|
final void Function(bool isLimited)? onNodeLimitChanged;
|
||||||
final VoidCallback? onLocationStatusChanged;
|
final VoidCallback? onLocationStatusChanged;
|
||||||
|
final void Function(LatLng)? onMapLongPress;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
State<MapView> createState() => MapViewState();
|
State<MapView> createState() => MapViewState();
|
||||||
@@ -514,6 +516,15 @@ class MapViewState extends State<MapView> {
|
|||||||
_dataManager.showZoomWarningIfNeeded(context, pos.zoom, appState.uploadMode);
|
_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: [
|
children: [
|
||||||
_tileManager.buildTileLayer(
|
_tileManager.buildTileLayer(
|
||||||
|
|||||||
Reference in New Issue
Block a user