This commit is contained in:
@@ -24,8 +24,13 @@ import '../domain/place_models.dart';
|
|||||||
import 'widgets/place_photo_card.dart';
|
import 'widgets/place_photo_card.dart';
|
||||||
|
|
||||||
String get _mapboxStyle {
|
String get _mapboxStyle {
|
||||||
final style = runtime_config.mapboxStyle();
|
final style = runtime_config.mapboxStyle().trim();
|
||||||
return style.isEmpty ? 'mapbox/standard' : style;
|
if (style.isEmpty ||
|
||||||
|
style == 'mapbox/standard' ||
|
||||||
|
style == mbx.MapboxStyles.STANDARD) {
|
||||||
|
return mbx.MapboxStyles.STANDARD_SATELLITE;
|
||||||
|
}
|
||||||
|
return style;
|
||||||
}
|
}
|
||||||
|
|
||||||
class MapflowShell extends StatelessWidget {
|
class MapflowShell extends StatelessWidget {
|
||||||
@@ -67,6 +72,7 @@ class _MapContentState extends State<_MapContent> {
|
|||||||
final state = widget.state;
|
final state = widget.state;
|
||||||
final selected = state.selectedPlace;
|
final selected = state.selectedPlace;
|
||||||
final userCoordinate = state.userCoordinate;
|
final userCoordinate = state.userCoordinate;
|
||||||
|
final targetCenter = _focusCenter(state);
|
||||||
final placeCubit = context.read<PlaceCubit>();
|
final placeCubit = context.read<PlaceCubit>();
|
||||||
final traitCounts = _countPlaceTraits(state.places);
|
final traitCounts = _countPlaceTraits(state.places);
|
||||||
final availableTraits = [
|
final availableTraits = [
|
||||||
@@ -86,12 +92,13 @@ class _MapContentState extends State<_MapContent> {
|
|||||||
body: Stack(
|
body: Stack(
|
||||||
children: [
|
children: [
|
||||||
_MapboxMapLayer(
|
_MapboxMapLayer(
|
||||||
focusCenter: _focusCenter(state),
|
focusCenter: targetCenter,
|
||||||
places: state.recommendations,
|
places: state.recommendations,
|
||||||
selectedPlaceId: selected?.id,
|
selectedPlaceId: selected?.id,
|
||||||
userCoordinate: userCoordinate,
|
userCoordinate: userCoordinate,
|
||||||
onPlaceTap: (place) => _selectAndShowPlace(context, place),
|
onPlaceTap: (place) => _selectAndShowPlace(context, place),
|
||||||
),
|
),
|
||||||
|
if (targetCenter == null) const _MapTargetLoadingOverlay(),
|
||||||
SafeArea(
|
SafeArea(
|
||||||
child: Align(
|
child: Align(
|
||||||
alignment: Alignment.topLeft,
|
alignment: Alignment.topLeft,
|
||||||
@@ -323,7 +330,7 @@ class _MapboxMapLayer extends StatefulWidget {
|
|||||||
}
|
}
|
||||||
|
|
||||||
class _MapboxMapLayerState extends State<_MapboxMapLayer> {
|
class _MapboxMapLayerState extends State<_MapboxMapLayer> {
|
||||||
static const _worldCenter = LatLng(8.0, 32.0);
|
static const _worldCenter = LatLng(0, 0);
|
||||||
|
|
||||||
mbx.MapboxMap? _mapboxMap;
|
mbx.MapboxMap? _mapboxMap;
|
||||||
var _mapLoaded = false;
|
var _mapLoaded = false;
|
||||||
@@ -351,8 +358,8 @@ class _MapboxMapLayerState extends State<_MapboxMapLayer> {
|
|||||||
styleUri: _mapboxStyleUri,
|
styleUri: _mapboxStyleUri,
|
||||||
viewport: mbx.CameraViewportState(
|
viewport: mbx.CameraViewportState(
|
||||||
center: _mapboxPoint(_worldCenter),
|
center: _mapboxPoint(_worldCenter),
|
||||||
zoom: 0.58,
|
zoom: 0.48,
|
||||||
bearing: -42,
|
bearing: 0,
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
),
|
),
|
||||||
onMapCreated: _onMapCreated,
|
onMapCreated: _onMapCreated,
|
||||||
@@ -425,14 +432,14 @@ class _MapboxMapLayerState extends State<_MapboxMapLayer> {
|
|||||||
_lastFocusCenter = focusCenter;
|
_lastFocusCenter = focusCenter;
|
||||||
final camera = mbx.CameraOptions(
|
final camera = mbx.CameraOptions(
|
||||||
center: _mapboxPoint(focusCenter),
|
center: _mapboxPoint(focusCenter),
|
||||||
zoom: 14.8,
|
zoom: 15.0,
|
||||||
bearing: -16,
|
bearing: -12,
|
||||||
pitch: 62,
|
pitch: 60,
|
||||||
);
|
);
|
||||||
if (_didInitialFlyIn) {
|
if (_didInitialFlyIn) {
|
||||||
_cameraAnimationSequence++;
|
_cameraAnimationSequence++;
|
||||||
unawaited(
|
unawaited(
|
||||||
mapboxMap.easeTo(camera, mbx.MapAnimationOptions(duration: 900)),
|
mapboxMap.easeTo(camera, mbx.MapAnimationOptions(duration: 650)),
|
||||||
);
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@@ -442,27 +449,36 @@ class _MapboxMapLayerState extends State<_MapboxMapLayer> {
|
|||||||
unawaited(
|
unawaited(
|
||||||
mapboxMap.easeTo(
|
mapboxMap.easeTo(
|
||||||
mbx.CameraOptions(
|
mbx.CameraOptions(
|
||||||
center: _mapboxPoint(_worldCenter),
|
center: _mapboxPoint(_targetOrbitCenter(focusCenter)),
|
||||||
zoom: 0.62,
|
zoom: 0.72,
|
||||||
bearing: 26,
|
bearing: _targetOrbitBearing(focusCenter),
|
||||||
pitch: 0,
|
pitch: 0,
|
||||||
),
|
),
|
||||||
mbx.MapAnimationOptions(duration: 1100),
|
mbx.MapAnimationOptions(duration: 850),
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
_initialFlyInTimer?.cancel();
|
_initialFlyInTimer?.cancel();
|
||||||
_initialFlyInTimer = Timer(const Duration(milliseconds: 760), () {
|
_initialFlyInTimer = Timer(const Duration(milliseconds: 520), () {
|
||||||
if (!mounted ||
|
if (!mounted ||
|
||||||
animationSequence != _cameraAnimationSequence ||
|
animationSequence != _cameraAnimationSequence ||
|
||||||
_mapboxMap != mapboxMap) {
|
_mapboxMap != mapboxMap) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
unawaited(
|
unawaited(
|
||||||
mapboxMap.flyTo(camera, mbx.MapAnimationOptions(duration: 4600)),
|
mapboxMap.flyTo(camera, mbx.MapAnimationOptions(duration: 2800)),
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
LatLng _targetOrbitCenter(LatLng target) {
|
||||||
|
final latitude = (target.latitude * 0.18).clamp(-18.0, 18.0);
|
||||||
|
return LatLng(latitude, target.longitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
double _targetOrbitBearing(LatLng target) {
|
||||||
|
return (-target.longitude * 0.34).clamp(-64.0, 64.0);
|
||||||
|
}
|
||||||
|
|
||||||
Future<void> _projectMarkers() async {
|
Future<void> _projectMarkers() async {
|
||||||
final mapboxMap = _mapboxMap;
|
final mapboxMap = _mapboxMap;
|
||||||
if (!_mapLoaded || mapboxMap == null) {
|
if (!_mapLoaded || mapboxMap == null) {
|
||||||
@@ -1499,6 +1515,49 @@ class _MapLoading extends StatelessWidget {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class _MapTargetLoadingOverlay extends StatelessWidget {
|
||||||
|
const _MapTargetLoadingOverlay();
|
||||||
|
|
||||||
|
@override
|
||||||
|
Widget build(BuildContext context) {
|
||||||
|
final tokens = context.mapflowTokens;
|
||||||
|
return IgnorePointer(
|
||||||
|
child: SafeArea(
|
||||||
|
child: Align(
|
||||||
|
alignment: Alignment.topCenter,
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.only(top: 18),
|
||||||
|
child: DecoratedBox(
|
||||||
|
decoration: BoxDecoration(
|
||||||
|
color: tokens.mapPanel.withValues(alpha: 0.84),
|
||||||
|
borderRadius: BorderRadius.circular(999),
|
||||||
|
boxShadow: [
|
||||||
|
BoxShadow(
|
||||||
|
color: Colors.black.withValues(alpha: 0.24),
|
||||||
|
blurRadius: 22,
|
||||||
|
offset: const Offset(0, 10),
|
||||||
|
),
|
||||||
|
],
|
||||||
|
),
|
||||||
|
child: Padding(
|
||||||
|
padding: const EdgeInsets.all(10),
|
||||||
|
child: SizedBox.square(
|
||||||
|
dimension: 28,
|
||||||
|
child: CircularProgressIndicator(
|
||||||
|
strokeWidth: 2.5,
|
||||||
|
color: tokens.voiceAccent,
|
||||||
|
backgroundColor: tokens.onDark.withValues(alpha: 0.12),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
class _MapError extends StatelessWidget {
|
class _MapError extends StatelessWidget {
|
||||||
const _MapError({required this.message});
|
const _MapError({required this.message});
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user