Add offline-first tile system with per-provider caching and error retry

- Add ServicePolicy framework with OSM-specific rate limiting and TTL
- Add per-provider disk tile cache (ProviderTileCacheStore) with O(1)
  lookup, oldest-modified eviction, and ETag/304 revalidation
- Rewrite DeflockTileProvider with two paths: common (NetworkTileProvider)
  and offline-first (disk cache -> local tiles -> network with caching)
- Add zoom-aware offline routing so tiles outside offline area zoom ranges
  use the efficient common path instead of the overhead-heavy offline path
- Fix HTTP client lifecycle: dispose() is now a no-op for flutter_map
  widget recycling; shutdown() handles permanent teardown
- Add TileLayerManager with exponential backoff retry (2s->60s cap),
  provider switch detection, and backoff reset
- Guard null provider/tileType in download dialog with localized error
- Fix Nominatim cache key to use normalized viewbox values
- Comprehensive test coverage (1800+ lines across 6 test files)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Doug Borg
2026-03-07 12:34:01 -07:00
co-authored by Claude Opus 4.6
parent be446fbcbc
commit 2d92214bed
36 changed files with 3940 additions and 351 deletions
+9 -3
View File
@@ -181,7 +181,10 @@
"offlineModeWarning": "Çevrimdışı moddayken indirmeler devre dışı. Yeni alanları indirmek için çevrimdışı modu devre dışı bırakın.",
"areaTooBigMessage": "Çevrimdışı alanları indirmek için en az {} seviyesine yakınlaştırın. Büyük alan indirmeleri uygulamanın yanıt vermemesine neden olabilir.",
"downloadStarted": "İndirme başladı! Döşemeler ve düğümler getiriliyor...",
"downloadFailed": "İndirme başlatılamadı: {}"
"downloadFailed": "İndirme başlatılamadı: {}",
"offlineNotPermitted": "{} sunucusu çevrimdışı indirmelere izin vermiyor. Çevrimdışı kullanıma izin veren bir döşeme sağlayıcısına geçin (ör. Bing Maps, Mapbox veya kendi barındırdığınız bir döşeme sunucusu).",
"currentTileProvider": "mevcut döşeme",
"noTileProviderSelected": "Döşeme sağlayıcı seçilmedi. Çevrimdışı alan indirmeden önce lütfen bir harita stili seçin."
},
"downloadStarted": {
"title": "İndirme Başladı",
@@ -335,7 +338,10 @@
"mapTiles": {
"title": "Harita Döşemeleri",
"manageProviders": "Sağlayıcıları Yönet",
"attribution": "Harita Atfı"
"attribution": "Harita Atfı",
"mapAttribution": "Harita kaynağı: {}",
"couldNotOpenLink": "Bağlantı açılamadı",
"openLicense": "Lisansı aç: {}"
},
"profileEditor": {
"viewProfile": "Profili Görüntüle",
@@ -552,4 +558,4 @@
"metricDescription": "Metrik (km, m)",
"imperialDescription": "İmperial (mil, ft)"
}
}
}