Merge FB-06: always-interactive map with recenter control
# Conflicts: # docs/feedback/FB-06-always-interactive-map-recenter.md
This commit is contained in:
@@ -27,6 +27,7 @@ import '../../domain/models.dart';
|
||||
import '../../geo/geo.dart' as geo;
|
||||
import '../../tiles/tile_config.dart';
|
||||
import '../theme.dart' show ripprRadiusLarge;
|
||||
import 'glass_panel.dart';
|
||||
import 'pulsing_location_marker.dart';
|
||||
import 'skeleton_map_layer.dart';
|
||||
|
||||
@@ -267,11 +268,12 @@ class _RideMapState extends State<RideMap> with WidgetsBindingObserver {
|
||||
? (widget.ambientPosition == null ? 2 : ambientZoom)
|
||||
: (bounds.isDegenerate ? shortRideZoom : maxTileZoom),
|
||||
maxZoom: maxTileZoom,
|
||||
interactionOptions: hasPoints
|
||||
? const InteractionOptions(
|
||||
flags: InteractiveFlag.pinchZoom | InteractiveFlag.drag,
|
||||
)
|
||||
: const InteractionOptions(flags: InteractiveFlag.none),
|
||||
// FB-06: pan/zoom must always be available, idle or recording -- the old
|
||||
// `hasPoints` gate locked the map to `InteractiveFlag.none` whenever no trip
|
||||
// was recording, which is exactly the "can't zoom and move around" report.
|
||||
interactionOptions: const InteractionOptions(
|
||||
flags: InteractiveFlag.pinchZoom | InteractiveFlag.drag,
|
||||
),
|
||||
onPositionChanged: !widget.follow
|
||||
? null
|
||||
: (position, hasGesture) {
|
||||
@@ -326,7 +328,43 @@ class _RideMapState extends State<RideMap> with WidgetsBindingObserver {
|
||||
),
|
||||
);
|
||||
|
||||
return _sized(child: map);
|
||||
// FB-06: the recenter control only ever makes sense once there is a `follow`
|
||||
// mode to return to and the rider has actually panned away from it -- a static
|
||||
// (non-following) map, like a finished ride in Trip Detail, never shows this.
|
||||
final showRecenter = widget.follow && !_following;
|
||||
|
||||
return _sized(
|
||||
child: Stack(
|
||||
children: [
|
||||
map,
|
||||
if (showRecenter)
|
||||
Positioned(
|
||||
right: 16,
|
||||
bottom: 16,
|
||||
child: GlassPanel(
|
||||
borderRadius: const BorderRadius.all(Radius.circular(999)),
|
||||
child: IconButton(
|
||||
key: const Key('recenter-button'),
|
||||
icon: const Icon(Icons.my_location),
|
||||
onPressed: _recenter,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/// FB-06: return the camera to the rider's latest known position and resume
|
||||
/// following new updates. Zoom is left untouched -- the rider may have
|
||||
/// deliberately zoomed in or out, and recenter should not undo that.
|
||||
void _recenter() {
|
||||
final ll.LatLng? target = widget.points.isNotEmpty
|
||||
? ll.LatLng(widget.points.last.latitude, widget.points.last.longitude)
|
||||
: widget.ambientPosition;
|
||||
if (target == null) return;
|
||||
setState(() => _following = true);
|
||||
_controller.move(target, _controller.camera.zoom);
|
||||
}
|
||||
|
||||
/// One polyline per speed run within each segment.
|
||||
|
||||
Reference in New Issue
Block a user