add dev_config to centralize hardcoded stuff into one place.

This commit is contained in:
stopflock
2025-08-10 23:31:17 -05:00
parent 312f71af4b
commit 160bc8f9f2
5 changed files with 42 additions and 13 deletions

View File

@@ -0,0 +1,25 @@
// lib/dev_config.dart
/// Developer/build-time configuration for global/non-user-tunable constants.
const int kWorldMinZoom = 1;
const int kWorldMaxZoom = 4;
// Example: Default tile storage estimate (KB per tile), for size estimates
const double kTileEstimateKb = 25.0;
// Direction cone for map view
const double kDirectionConeHalfAngle = 15.0; // degrees
const double kDirectionConeBaseLength = 0.0012; // multiplier
// Marker/camera interaction
const Duration kMarkerTapTimeout = Duration(milliseconds: 250);
const Duration kDebounceCameraRefresh = Duration(milliseconds: 500);
const Duration kDebounceTileLayerUpdate = Duration(milliseconds: 50);
// Tile/Network fetch retry parameters (for tunable dev backoff)
const int kTileFetchMaxAttempts = 3;
const int kTileFetchInitialDelayMs = 4000;
const int kTileFetchJitter1Ms = 1000;
const int kTileFetchSecondDelayMs = 15000;
const int kTileFetchJitter2Ms = 4000;
const int kTileFetchThirdDelayMs = 60000;
const int kTileFetchJitter3Ms = 5000;

View File

@@ -2,6 +2,7 @@ import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:latlong2/latlong.dart';
import 'package:flock_map_app/dev_config.dart';
import '../app_state.dart';
import '../widgets/map_view.dart';
import 'package:flutter_map/flutter_map.dart';
@@ -133,8 +134,7 @@ class _DownloadAreaDialogState extends State<DownloadAreaDialog> {
final minZoom = findDynamicMinZoom(bounds);
final maxZoom = _zoom.toInt();
final nTiles = computeTileList(bounds, minZoom, maxZoom).length;
const kbPerTile = 25.0; // Empirically ~6.5kB average for OSM tiles at z=1-19
final totalMb = (nTiles * kbPerTile) / 1024.0;
final totalMb = (nTiles * kTileEstimateKb) / 1024.0;
setState(() {
_minZoom = minZoom;
_tileCount = nTiles;

View File

@@ -3,6 +3,7 @@ import 'dart:io';
import 'dart:async';
import 'package:http/http.dart' as http;
import 'package:flutter/foundation.dart';
import 'package:flock_map_app/dev_config.dart';
/// Global semaphore to limit simultaneous tile fetches
final _tileFetchSemaphore = _SimpleSemaphore(4); // Max 4 concurrent
@@ -15,13 +16,13 @@ Future<List<int>> fetchOSMTile({
required int y,
}) async {
final url = 'https://tile.openstreetmap.org/$z/$x/$y.png';
const int maxAttempts = 3;
const int maxAttempts = kTileFetchMaxAttempts;
int attempt = 0;
final random = Random();
final delays = [
4000 + random.nextInt(1000), // 4-5s after 1st failure
15000 + random.nextInt(4000), // 15-19s after 2nd
60000 + random.nextInt(5000), // 60-65s after 3rd
kTileFetchInitialDelayMs + random.nextInt(kTileFetchJitter1Ms),
kTileFetchSecondDelayMs + random.nextInt(kTileFetchJitter2Ms),
kTileFetchThirdDelayMs + random.nextInt(kTileFetchJitter3Ms),
];
while (true) {
await _tileFetchSemaphore.acquire();

View File

@@ -11,6 +11,7 @@ import '../models/osm_camera_node.dart';
import '../app_state.dart';
import 'map_data_provider.dart';
import 'map_data_submodules/cameras_from_overpass.dart';
import 'package:flock_map_app/dev_config.dart';
/// Service for managing download, storage, and retrieval of offline map areas and cameras.
class OfflineAreaService {
@@ -98,7 +99,7 @@ class OfflineAreaService {
for (final a in _areas) {
if (a.isPermanent) { world = a; break; }
}
final Set<List<int>> expectedTiles = computeTileList(worldBounds, 1, 4);
final Set<List<int>> expectedTiles = computeTileList(worldBounds, kWorldMinZoom, kWorldMaxZoom);
if (world != null) {
int filesFound = 0;
List<List<int>> missingTiles = [];
@@ -198,7 +199,7 @@ class OfflineAreaService {
try {
Set<List<int>> allTiles;
if (area.isPermanent) {
allTiles = computeTileList(globalWorldBounds(), 1, 4);
allTiles = computeTileList(globalWorldBounds(), kWorldMinZoom, kWorldMaxZoom);
} else {
allTiles = computeTileList(bounds, minZoom, maxZoom);
}

View File

@@ -20,6 +20,7 @@ import '../models/osm_camera_node.dart';
import 'debouncer.dart';
import 'camera_tag_sheet.dart';
import 'tile_provider_with_cache.dart';
import 'package:flock_map_app/dev_config.dart';
// --- Smart marker widget for camera with single/double tap distinction
class _CameraMapMarker extends StatefulWidget {
@@ -33,7 +34,8 @@ class _CameraMapMarker extends StatefulWidget {
class _CameraMapMarkerState extends State<_CameraMapMarker> {
Timer? _tapTimer;
static const Duration tapTimeout = Duration(milliseconds: 250);
// From dev_config.dart for build-time parameters
static const Duration tapTimeout = kMarkerTapTimeout;
void _onTap() {
_tapTimer = Timer(tapTimeout, () {
@@ -85,7 +87,7 @@ class MapView extends StatefulWidget {
class _MapViewState extends State<MapView> {
late final MapController _controller;
final MapDataProvider _mapDataProvider = MapDataProvider();
final Debouncer _debounce = Debouncer(const Duration(milliseconds: 500));
final Debouncer _debounce = Debouncer(kDebounceCameraRefresh);
Debouncer? _debounceTileLayerUpdate;
StreamSubscription<Position>? _positionSub;
@@ -113,7 +115,7 @@ class _MapViewState extends State<MapView> {
@override
void initState() {
super.initState();
_debounceTileLayerUpdate = Debouncer(const Duration(milliseconds: 50),);
_debounceTileLayerUpdate = Debouncer(kDebounceTileLayerUpdate);
// Kick off offline area loading as soon as map loads
OfflineAreaService();
_controller = widget.controller;
@@ -391,8 +393,8 @@ class _MapViewState extends State<MapView> {
}
Polygon _buildCone(LatLng origin, double bearingDeg, double zoom) {
const halfAngle = 15.0;
final length = 0.0012 * math.pow(2, 15 - zoom);
final halfAngle = kDirectionConeHalfAngle;
final length = kDirectionConeBaseLength * math.pow(2, 15 - zoom);
LatLng _project(double deg) {
final rad = deg * math.pi / 180;