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 markers, required List polylines, required bool isFollowMode, required MapConfig config, required ValueChanged? onPositionChanged, required VoidCallback? onUserInteraction, }) { final centerLl = ll.LatLng(center.latitude, center.longitude); if (isFollowMode) { final now = DateTime.now(); final shouldMove = _lastFollowPos == null || _lastFollowTime == null || now.difference(_lastFollowTime!).inMilliseconds > 400 || (centerLl.latitude - _lastFollowPos!.latitude).abs() > 0.00005 || (centerLl.longitude - _lastFollowPos!.longitude).abs() > 0.00005; if (shouldMove) { _lastFollowPos = centerLl; _lastFollowTime = now; WidgetsBinding.instance.addPostFrameCallback((_) { try { _mapController.move(centerLl, zoom); } catch (_) {} }); } } return FlutterMap( mapController: _mapController, options: MapOptions( initialCenter: centerLl, initialZoom: zoom, minZoom: config.minZoom, maxZoom: config.maxZoom, 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, userAgentPackageName: 'com.example.motorcycle_dash', ), 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), ), ], ), ], ); } }