mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-02-12 16:52:51 +00:00
Fix north-up UX
This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import 'dart:async';
|
||||
import 'dart:math';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
@@ -21,10 +22,16 @@ class CompassIndicator extends StatefulWidget {
|
||||
}
|
||||
|
||||
class _CompassIndicatorState extends State<CompassIndicator> {
|
||||
Timer? _animationTimer;
|
||||
|
||||
@override
|
||||
void dispose() {
|
||||
_animationTimer?.cancel();
|
||||
super.dispose();
|
||||
}
|
||||
@override
|
||||
Widget build(BuildContext context) {
|
||||
return Consumer<AppState>(
|
||||
builder: (context, appState, child) {
|
||||
final appState = context.watch<AppState>();
|
||||
// Get current map rotation in degrees
|
||||
double rotationDegrees = 0.0;
|
||||
try {
|
||||
@@ -46,6 +53,10 @@ class _CompassIndicatorState extends State<CompassIndicator> {
|
||||
onTap: isDisabled ? null : () {
|
||||
// Animate to north-up orientation
|
||||
try {
|
||||
// Cancel any existing animation timer
|
||||
_animationTimer?.cancel();
|
||||
|
||||
// Start animation
|
||||
widget.mapController.animateTo(
|
||||
dest: widget.mapController.mapController.camera.center,
|
||||
zoom: widget.mapController.mapController.camera.zoom,
|
||||
@@ -53,6 +64,23 @@ class _CompassIndicatorState extends State<CompassIndicator> {
|
||||
duration: const Duration(milliseconds: 500),
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
|
||||
// Start timer to force compass updates during animation
|
||||
// Update every 16ms (~60fps) for smooth visual rotation
|
||||
_animationTimer = Timer.periodic(const Duration(milliseconds: 16), (timer) {
|
||||
if (mounted) {
|
||||
setState(() {});
|
||||
}
|
||||
});
|
||||
|
||||
// Stop the timer after animation completes (with small buffer)
|
||||
Timer(const Duration(milliseconds: 550), () {
|
||||
_animationTimer?.cancel();
|
||||
_animationTimer = null;
|
||||
if (mounted) {
|
||||
setState(() {}); // Final update to ensure correct end state
|
||||
}
|
||||
});
|
||||
} catch (_) {
|
||||
// Controller not ready, ignore
|
||||
}
|
||||
@@ -132,7 +160,5 @@ class _CompassIndicatorState extends State<CompassIndicator> {
|
||||
),
|
||||
),
|
||||
);
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,7 @@ class GpsController {
|
||||
required FollowMeMode newMode,
|
||||
required FollowMeMode oldMode,
|
||||
required AnimatedMapController controller,
|
||||
VoidCallback? onMapMovedProgrammatically,
|
||||
}) {
|
||||
debugPrint('[GpsController] Follow-me mode changed: $oldMode → $newMode');
|
||||
|
||||
@@ -62,6 +63,7 @@ class GpsController {
|
||||
duration: kFollowMeAnimationDuration,
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
onMapMovedProgrammatically?.call();
|
||||
} else if (newMode == FollowMeMode.rotating) {
|
||||
// When switching to rotating mode, reset to north-up first
|
||||
controller.animateTo(
|
||||
@@ -71,6 +73,7 @@ class GpsController {
|
||||
duration: kFollowMeAnimationDuration,
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
onMapMovedProgrammatically?.call();
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[GpsController] MapController not ready for follow-me change: $e');
|
||||
@@ -89,6 +92,8 @@ class GpsController {
|
||||
int proximityAlertDistance = 200,
|
||||
List<OsmNode> nearbyNodes = const [],
|
||||
List<NodeProfile> enabledProfiles = const [],
|
||||
// Optional callback when map is moved programmatically
|
||||
VoidCallback? onMapMovedProgrammatically,
|
||||
|
||||
}) {
|
||||
final latLng = LatLng(position.latitude, position.longitude);
|
||||
@@ -121,6 +126,9 @@ class GpsController {
|
||||
duration: kFollowMeAnimationDuration,
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
|
||||
// Notify that we moved the map programmatically (for node refresh)
|
||||
onMapMovedProgrammatically?.call();
|
||||
} else if (followMeMode == FollowMeMode.rotating) {
|
||||
// Follow position and rotation based on heading
|
||||
final heading = position.heading;
|
||||
@@ -137,6 +145,9 @@ class GpsController {
|
||||
duration: kFollowMeAnimationDuration,
|
||||
curve: Curves.easeOut,
|
||||
);
|
||||
|
||||
// Notify that we moved the map programmatically (for node refresh)
|
||||
onMapMovedProgrammatically?.call();
|
||||
}
|
||||
} catch (e) {
|
||||
debugPrint('[GpsController] MapController not ready for position animation: $e');
|
||||
@@ -155,6 +166,7 @@ class GpsController {
|
||||
required int Function() getProximityAlertDistance,
|
||||
required List<OsmNode> Function() getNearbyNodes,
|
||||
required List<NodeProfile> Function() getEnabledProfiles,
|
||||
VoidCallback? onMapMovedProgrammatically,
|
||||
|
||||
}) async {
|
||||
final perm = await Geolocator.requestPermission();
|
||||
@@ -180,6 +192,7 @@ class GpsController {
|
||||
proximityAlertDistance: proximityAlertDistance,
|
||||
nearbyNodes: nearbyNodes,
|
||||
enabledProfiles: enabledProfiles,
|
||||
onMapMovedProgrammatically: onMapMovedProgrammatically,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ class MapOverlays extends StatelessWidget {
|
||||
final EditNodeSession? editSession;
|
||||
final String? attribution; // Attribution for current tile provider
|
||||
final VoidCallback? onSearchPressed; // Callback for search button
|
||||
|
||||
const MapOverlays({
|
||||
super.key,
|
||||
required this.mapController,
|
||||
|
||||
@@ -78,6 +78,8 @@ class MapViewState extends State<MapView> {
|
||||
|
||||
// State for proximity alert banner
|
||||
bool _showProximityBanner = false;
|
||||
|
||||
|
||||
|
||||
@override
|
||||
void initState() {
|
||||
@@ -180,6 +182,10 @@ class MapViewState extends State<MapView> {
|
||||
}
|
||||
return [];
|
||||
},
|
||||
onMapMovedProgrammatically: () {
|
||||
// Refresh nodes when GPS controller moves the map
|
||||
_refreshNodesFromProvider();
|
||||
},
|
||||
|
||||
);
|
||||
|
||||
@@ -302,6 +308,9 @@ class MapViewState extends State<MapView> {
|
||||
newMode: widget.followMeMode,
|
||||
oldMode: oldWidget.followMeMode,
|
||||
controller: _controller,
|
||||
onMapMovedProgrammatically: () {
|
||||
_refreshNodesFromProvider();
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user