fix(location): single-color route, contrasting arrows, time labels on endpoints
This commit is contained in:
@@ -3,17 +3,18 @@ import 'dart:math' as math;
|
||||
import 'package:control_panel/control_panel.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
import 'package:flutter_map/flutter_map.dart';
|
||||
import 'package:intl/intl.dart';
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
const _clusterBaseDegrees = 0.5;
|
||||
const _clusterBaseZoom = 8;
|
||||
|
||||
const routeColor = Color(0xFF329E95);
|
||||
const routeArrowColor = Color(0xFFFF6D00);
|
||||
const routeStartColor = Color(0xFF4CAF50);
|
||||
|
||||
bool _hasValidCoords(PositionEntity p) => p.latitude != 0 || p.longitude != 0;
|
||||
const routeEndColor = Color(0xFFF44336);
|
||||
|
||||
Color routeGradient(double t) => Color.lerp(routeStartColor, routeEndColor, t)!;
|
||||
bool _hasValidCoords(PositionEntity p) => p.latitude != 0 || p.longitude != 0;
|
||||
|
||||
class RouteHistoryLayer extends StatelessWidget {
|
||||
final List<PositionEntity> positionHistory;
|
||||
@@ -39,24 +40,16 @@ class RouteHistoryLayer extends StatelessWidget {
|
||||
List<Polyline> buildRouteSegments() {
|
||||
if (positionHistory.length < 2) return [];
|
||||
|
||||
final segments = <Polyline>[];
|
||||
for (int i = 0; i < positionHistory.length - 1; i++) {
|
||||
final t = i / (positionHistory.length - 1);
|
||||
segments.add(
|
||||
Polyline(
|
||||
points: [
|
||||
LatLng(positionHistory[i].latitude, positionHistory[i].longitude),
|
||||
LatLng(
|
||||
positionHistory[i + 1].latitude,
|
||||
positionHistory[i + 1].longitude,
|
||||
),
|
||||
],
|
||||
color: routeGradient(t),
|
||||
strokeWidth: 4.0,
|
||||
),
|
||||
);
|
||||
}
|
||||
return segments;
|
||||
final points = positionHistory
|
||||
.where(_hasValidCoords)
|
||||
.map((p) => LatLng(p.latitude, p.longitude))
|
||||
.toList();
|
||||
|
||||
if (points.length < 2) return [];
|
||||
|
||||
return [
|
||||
Polyline(points: points, color: routeColor, strokeWidth: 4.0),
|
||||
];
|
||||
}
|
||||
|
||||
List<Marker> _buildDirectionArrows() {
|
||||
@@ -66,26 +59,27 @@ class RouteHistoryLayer extends StatelessWidget {
|
||||
for (int i = 0; i < positionHistory.length - 1; i++) {
|
||||
final from = positionHistory[i];
|
||||
final to = positionHistory[i + 1];
|
||||
if (!_hasValidCoords(from)) continue;
|
||||
if (!_hasValidCoords(to)) continue;
|
||||
if (!_hasValidCoords(from) || !_hasValidCoords(to)) continue;
|
||||
|
||||
final midLat = (from.latitude + to.latitude) / 2;
|
||||
final midLng = (from.longitude + to.longitude) / 2;
|
||||
final angle = math.atan2(
|
||||
final bearing = math.atan2(
|
||||
to.longitude - from.longitude,
|
||||
to.latitude - from.latitude,
|
||||
);
|
||||
|
||||
final t = i / (positionHistory.length - 1);
|
||||
|
||||
arrows.add(
|
||||
Marker(
|
||||
point: LatLng(midLat, midLng),
|
||||
width: 16,
|
||||
height: 16,
|
||||
width: 18,
|
||||
height: 18,
|
||||
child: Transform.rotate(
|
||||
angle: -angle,
|
||||
child: Icon(Icons.navigation, color: routeGradient(t), size: 16),
|
||||
angle: bearing,
|
||||
child: const Icon(
|
||||
Icons.navigation,
|
||||
color: routeArrowColor,
|
||||
size: 18,
|
||||
),
|
||||
),
|
||||
rotate: false,
|
||||
),
|
||||
@@ -149,18 +143,17 @@ class RouteHistoryLayer extends StatelessWidget {
|
||||
for (final cluster in clustered) {
|
||||
final firstIdx = cluster.first;
|
||||
final position = intermediates[firstIdx];
|
||||
final originalIdx = firstIdx + 1;
|
||||
final t = originalIdx / (positionHistory.length - 1);
|
||||
final color = routeGradient(t);
|
||||
|
||||
if (cluster.length == 1) {
|
||||
markers.add(_buildIntermediateMarker(position: position, color: color));
|
||||
markers.add(
|
||||
_buildIntermediateMarker(position: position, color: routeColor),
|
||||
);
|
||||
} else {
|
||||
markers.add(
|
||||
_buildClusterMarker(
|
||||
position: position,
|
||||
count: cluster.length,
|
||||
color: color,
|
||||
color: routeColor,
|
||||
),
|
||||
);
|
||||
}
|
||||
@@ -174,16 +167,41 @@ class RouteHistoryLayer extends StatelessWidget {
|
||||
required Color color,
|
||||
required IconData icon,
|
||||
}) {
|
||||
final time = DateFormat.Hm().format(
|
||||
DateTime.fromMillisecondsSinceEpoch(position.createdAt),
|
||||
);
|
||||
|
||||
return Marker(
|
||||
point: LatLng(position.latitude, position.longitude),
|
||||
width: 32,
|
||||
height: 32,
|
||||
width: 64,
|
||||
height: 52,
|
||||
child: GestureDetector(
|
||||
onTap: () => onPositionTap(position),
|
||||
child: _CircleMarkerIcon(
|
||||
color: color,
|
||||
size: 32,
|
||||
child: Icon(icon, color: Colors.white, size: 18),
|
||||
child: Column(
|
||||
mainAxisSize: MainAxisSize.min,
|
||||
children: [
|
||||
_CircleMarkerIcon(
|
||||
color: color,
|
||||
size: 32,
|
||||
child: Icon(icon, color: Colors.white, size: 18),
|
||||
),
|
||||
const SizedBox(height: 2),
|
||||
Container(
|
||||
padding: const EdgeInsets.symmetric(horizontal: 4, vertical: 1),
|
||||
decoration: BoxDecoration(
|
||||
color: color,
|
||||
borderRadius: BorderRadius.circular(4),
|
||||
),
|
||||
child: Text(
|
||||
time,
|
||||
style: const TextStyle(
|
||||
color: Colors.white,
|
||||
fontSize: 9,
|
||||
fontWeight: FontWeight.w700,
|
||||
),
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
rotate: true,
|
||||
|
||||
@@ -38,6 +38,7 @@ dependencies:
|
||||
flutter_svg: ^2.2.2
|
||||
uuid: ^4.5.3
|
||||
share_plus: ^10.1.4
|
||||
intl: ^0.20.2
|
||||
|
||||
dev_dependencies:
|
||||
flutter_test:
|
||||
|
||||
Reference in New Issue
Block a user