MotorSignal-App/lib/services/map/open_street_map_provider.dart

125 lines
3.8 KiB
Dart

import 'dart:math' as math;
import 'package:flutter/material.dart';
import 'package:flutter_map/flutter_map.dart';
import 'package:latlong2/latlong.dart' as ll;
import 'map_provider_interface.dart';
class OpenStreetMapProvider implements AppMapProvider {
final MapController _mapController = MapController();
ll.LatLng? _lastFollowPos;
DateTime? _lastFollowTime;
@override
AppMapType get type => AppMapType.openStreetMap;
@override
String get name => 'OpenStreetMap';
@override
Widget buildMapView({
required BuildContext context,
required AppLatLng center,
required double zoom,
required List<AppMapMarker> markers,
required List<AppPolyline> polylines,
required bool isFollowMode,
required MapConfig config,
required ValueChanged<AppLatLng>? onPositionChanged,
required VoidCallback? onUserInteraction,
}) {
final centerLl = ll.LatLng(center.latitude, center.longitude);
if (isFollowMode) {
final now = DateTime.now();
final posDelta = _lastFollowPos == null
? 1.0
: (centerLl.latitude - _lastFollowPos!.latitude).abs() +
(centerLl.longitude - _lastFollowPos!.longitude).abs();
final shouldMove = _lastFollowPos == null ||
(posDelta > 0.00005 && (_lastFollowTime == null || now.difference(_lastFollowTime!).inMilliseconds > 500));
if (shouldMove) {
_lastFollowPos = centerLl;
_lastFollowTime = now;
WidgetsBinding.instance.addPostFrameCallback((_) {
try {
_mapController.move(centerLl, zoom);
} catch (_) {}
});
}
}
final media = MediaQuery.of(context);
final sizeKey = '${media.orientation}_${media.size.width.toInt()}x${media.size.height.toInt()}';
return FlutterMap(
key: ValueKey('osm_map_$sizeKey'),
mapController: _mapController,
options: MapOptions(
initialCenter: centerLl,
initialZoom: zoom,
minZoom: config.minZoom,
maxZoom: config.maxZoom,
backgroundColor: const Color(0xFF0F0F0F),
onPositionChanged: (position, hasGesture) {
if (hasGesture) {
onUserInteraction?.call();
}
if (onPositionChanged != null) {
final c = position.center;
onPositionChanged(AppLatLng(c.latitude, c.longitude));
}
},
),
children: [
TileLayer(
urlTemplate: config.tileUrlTemplate,
subdomains: config.subdomains,
userAgentPackageName: 'com.example.motorcycle_dash',
maxZoom: 20,
maxNativeZoom: 19,
),
PolylineLayer(
polylines: polylines.map((p) {
return Polyline(
points: p.points.map((pt) => ll.LatLng(pt.latitude, pt.longitude)).toList(),
strokeWidth: p.width,
color: p.color,
);
}).toList(),
),
MarkerLayer(
markers: markers.map((m) {
return Marker(
point: ll.LatLng(m.position.latitude, m.position.longitude),
width: 50,
height: 50,
child: GestureDetector(
onTap: m.onTap,
child: Transform.rotate(
angle: (m.heading * math.pi) / 180.0,
child: m.iconWidget ??
const Icon(
Icons.navigation,
color: Colors.cyanAccent,
size: 36,
),
),
),
);
}).toList(),
),
RichAttributionWidget(
attributions: [
TextSourceAttribution(
config.attributionText,
textStyle: const TextStyle(color: Colors.white70, fontSize: 10),
),
],
),
],
);
}
}