diff --git a/lib/dev_config.dart b/lib/dev_config.dart index adb9e51..4f6a5f2 100644 --- a/lib/dev_config.dart +++ b/lib/dev_config.dart @@ -1,4 +1,6 @@ // lib/dev_config.dart +import 'package:flutter/material.dart'; + /// Developer/build-time configuration for global/non-user-tunable constants. const int kWorldMinZoom = 1; const int kWorldMaxZoom = 5; @@ -7,8 +9,9 @@ const int kWorldMaxZoom = 5; const double kTileEstimateKb = 25.0; // Direction cone for map view -const double kDirectionConeHalfAngle = 20.0; // degrees -const double kDirectionConeBaseLength = 0.0012; // multiplier +const double kDirectionConeHalfAngle = 30.0; // degrees +const double kDirectionConeBaseLength = 0.001; // multiplier +const Color kDirectionConeColor = Color(0xFF111111); // FOV cone color // Margin (bottom) for positioning the floating bottom button bar const double kBottomButtonBarMargin = 4.0; @@ -18,12 +21,12 @@ const double kAttributionBottomOffset = 110.0; const double kZoomIndicatorBottomOffset = 142.0; const double kScaleBarBottomOffset = 170.0; -// Add Camera pin vertical offset (for pin tip to match coordinate on map) -const double kAddPinYOffset = -16.0; +// Add Camera icon vertical offset (no offset needed since circle is centered) +const double kAddPinYOffset = 0.0; // Client name and version for OSM uploads ("created_by" tag) const String kClientName = 'FlockMap'; -const String kClientVersion = '0.8.3'; +const String kClientVersion = '0.8.10'; // Marker/camera interaction const int kCameraMinZoomLevel = 10; // Minimum zoom to show cameras or warning @@ -43,5 +46,13 @@ const int kTileFetchJitter3Ms = 5000; const int kMaxUserDownloadZoomSpan = 7; // Download area limits and constants -const int kMaxReasonableTileCount = 10000; +const int kMaxReasonableTileCount = 20000; const int kAbsoluteMaxZoom = 19; + +// Camera icon configuration +const double kCameraIconDiameter = 20.0; +const double kCameraRingThickness = 4.0; +const double kCameraDotOpacity = 0.4; // Opacity for the grey dot interior +const Color kCameraRingColorReal = Color(0xC43F55F3); // Real cameras from OSM - blue +const Color kCameraRingColorMock = Color(0xC4FFFFFF); // Add camera mock point - white +const Color kCameraRingColorPending = Color(0xC49C27B0); // Submitted/pending cameras - purple diff --git a/lib/widgets/camera_icon.dart b/lib/widgets/camera_icon.dart new file mode 100644 index 0000000..2282862 --- /dev/null +++ b/lib/widgets/camera_icon.dart @@ -0,0 +1,42 @@ +import 'package:flutter/material.dart'; +import '../dev_config.dart'; + +enum CameraIconType { + real, // Blue ring - real cameras from OSM + mock, // White ring - add camera mock point + pending, // Purple ring - submitted/pending cameras +} + +/// Simple camera icon with grey dot and colored ring +class CameraIcon extends StatelessWidget { + final CameraIconType type; + + const CameraIcon({super.key, required this.type}); + + Color get _ringColor { + switch (type) { + case CameraIconType.real: + return kCameraRingColorReal; + case CameraIconType.mock: + return kCameraRingColorMock; + case CameraIconType.pending: + return kCameraRingColorPending; + } + } + + @override + Widget build(BuildContext context) { + return Container( + width: kCameraIconDiameter, + height: kCameraIconDiameter, + decoration: BoxDecoration( + shape: BoxShape.circle, + color: Colors.black.withOpacity(kCameraDotOpacity), + border: Border.all( + color: _ringColor, + width: kCameraRingThickness, + ), + ), + ); + } +} \ No newline at end of file diff --git a/lib/widgets/map/camera_markers.dart b/lib/widgets/map/camera_markers.dart index 44d4738..40110eb 100644 --- a/lib/widgets/map/camera_markers.dart +++ b/lib/widgets/map/camera_markers.dart @@ -6,6 +6,7 @@ import 'package:latlong2/latlong.dart'; import '../../dev_config.dart'; import '../../models/osm_camera_node.dart'; import '../camera_tag_sheet.dart'; +import '../camera_icon.dart'; /// Smart marker widget for camera with single/double tap distinction class CameraMapMarker extends StatefulWidget { @@ -52,9 +53,8 @@ class _CameraMapMarkerState extends State { return GestureDetector( onTap: _onTap, onDoubleTap: _onDoubleTap, - child: Icon( - Icons.videocam, - color: isPending ? Colors.purple : Colors.orange, + child: CameraIcon( + type: isPending ? CameraIconType.pending : CameraIconType.real, ), ); } @@ -73,8 +73,8 @@ class CameraMarkersBuilder { .where(_isValidCameraCoordinate) .map((n) => Marker( point: n.coord, - width: 24, - height: 24, + width: kCameraIconDiameter, + height: kCameraIconDiameter, child: CameraMapMarker(node: n, mapController: mapController), )), diff --git a/lib/widgets/map/direction_cones.dart b/lib/widgets/map/direction_cones.dart index 1a02131..005b19f 100644 --- a/lib/widgets/map/direction_cones.dart +++ b/lib/widgets/map/direction_cones.dart @@ -33,7 +33,6 @@ class DirectionConesBuilder { n.coord, n.directionDeg!, zoom, - isPending: _isPendingUpload(n), )) ); @@ -58,9 +57,13 @@ class DirectionConesBuilder { double bearingDeg, double zoom, { bool isPending = false, + bool isSession = false, }) { final halfAngle = kDirectionConeHalfAngle; final length = kDirectionConeBaseLength * math.pow(2, 15 - zoom); + + // Number of points to create the arc (more = smoother curve) + const int arcPoints = 12; LatLng project(double deg) { final rad = deg * math.pi / 180; @@ -70,16 +73,22 @@ class DirectionConesBuilder { return LatLng(origin.latitude + dLat, origin.longitude + dLon); } - final left = project(bearingDeg - halfAngle); - final right = project(bearingDeg + halfAngle); - - // Use purple color for pending uploads - final color = isPending ? Colors.purple : Colors.redAccent; + // Build pizza slice with curved edge + final points = [origin]; + + // Add arc points from left to right + for (int i = 0; i <= arcPoints; i++) { + final angle = bearingDeg - halfAngle + (i * 2 * halfAngle / arcPoints); + points.add(project(angle)); + } + + // Close the shape back to origin + points.add(origin); return Polygon( - points: [origin, left, right, origin], - color: color.withOpacity(0.25), - borderColor: color, + points: points, + color: kDirectionConeColor.withOpacity(0.25), + borderColor: kDirectionConeColor, borderStrokeWidth: 1, ); } diff --git a/lib/widgets/map/map_overlays.dart b/lib/widgets/map/map_overlays.dart index c508aea..b3c2118 100644 --- a/lib/widgets/map/map_overlays.dart +++ b/lib/widgets/map/map_overlays.dart @@ -3,6 +3,7 @@ import 'package:flutter_map/flutter_map.dart'; import '../../app_state.dart'; import '../../dev_config.dart'; +import '../camera_icon.dart'; import 'layer_selector_button.dart'; /// Widget that renders all map overlay UI elements @@ -135,7 +136,7 @@ class MapOverlays extends StatelessWidget { child: Center( child: Transform.translate( offset: const Offset(0, kAddPinYOffset), - child: const Icon(Icons.place, size: 40, color: Colors.redAccent), + child: const CameraIcon(type: CameraIconType.mock), ), ), ),