mirror of
https://github.com/FoggedLens/deflock-app.git
synced 2026-02-13 01:03:03 +00:00
Suspected location localizations, credit alprwatch
This commit is contained in:
@@ -341,5 +341,40 @@
|
||||
"imperial": "Britisch (mi, ft)",
|
||||
"meters": "Meter",
|
||||
"feet": "Fuß"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "Verdächtige Standorte",
|
||||
"showSuspectedLocations": "Verdächtige Standorte anzeigen",
|
||||
"showSuspectedLocationsSubtitle": "Fragezeichen-Marker für vermutete Überwachungsstandorte aus Versorgungsgenehmigungsdaten anzeigen",
|
||||
"lastUpdated": "Zuletzt aktualisiert",
|
||||
"refreshNow": "Jetzt aktualisieren",
|
||||
"dataSource": "Datenquelle",
|
||||
"dataSourceDescription": "Versorgungsgenehmigungsdaten, die auf potenzielle Installationsstandorte für Überwachungsinfrastruktur hinweisen",
|
||||
"dataSourceCredit": "Datensammlung und -hosting bereitgestellt von alprwatch.org",
|
||||
"minimumDistance": "Mindestabstand zu echten Geräten",
|
||||
"minimumDistanceSubtitle": "Verdächtige Standorte innerhalb von {}m vorhandener Überwachungsgeräte ausblenden",
|
||||
"updating": "Verdächtige Standorte werden aktualisiert",
|
||||
"downloadingAndProcessing": "Daten werden heruntergeladen und verarbeitet...",
|
||||
"updateSuccess": "Verdächtige Standorte erfolgreich aktualisiert",
|
||||
"updateFailed": "Aktualisierung der verdächtigen Standorte fehlgeschlagen",
|
||||
"neverFetched": "Nie abgerufen",
|
||||
"daysAgo": "vor {} Tagen",
|
||||
"hoursAgo": "vor {} Stunden",
|
||||
"minutesAgo": "vor {} Minuten",
|
||||
"justNow": "Gerade eben"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "Verdächtiger Standort #{}",
|
||||
"ticketNo": "Ticket-Nr.",
|
||||
"address": "Adresse",
|
||||
"street": "Straße",
|
||||
"city": "Stadt",
|
||||
"state": "Bundesland",
|
||||
"intersectingStreet": "Kreuzende Straße",
|
||||
"workDoneFor": "Arbeit ausgeführt für",
|
||||
"remarks": "Bemerkungen",
|
||||
"url": "URL",
|
||||
"coordinates": "Koordinaten",
|
||||
"noAddressAvailable": "Keine Adresse verfügbar"
|
||||
}
|
||||
}
|
||||
@@ -341,5 +341,40 @@
|
||||
"imperial": "Imperial (mi, ft)",
|
||||
"meters": "meters",
|
||||
"feet": "feet"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "Suspected Locations",
|
||||
"showSuspectedLocations": "Show Suspected Locations",
|
||||
"showSuspectedLocationsSubtitle": "Show question mark markers for suspected surveillance sites from utility permit data",
|
||||
"lastUpdated": "Last Updated",
|
||||
"refreshNow": "Refresh now",
|
||||
"dataSource": "Data Source",
|
||||
"dataSourceDescription": "Utility permit data indicating potential surveillance infrastructure installation sites",
|
||||
"dataSourceCredit": "Data collection and hosting provided by alprwatch.org",
|
||||
"minimumDistance": "Minimum Distance from Real Nodes",
|
||||
"minimumDistanceSubtitle": "Hide suspected locations within {}m of existing surveillance devices",
|
||||
"updating": "Updating Suspected Locations",
|
||||
"downloadingAndProcessing": "Downloading and processing data...",
|
||||
"updateSuccess": "Suspected locations updated successfully",
|
||||
"updateFailed": "Failed to update suspected locations",
|
||||
"neverFetched": "Never fetched",
|
||||
"daysAgo": "{} days ago",
|
||||
"hoursAgo": "{} hours ago",
|
||||
"minutesAgo": "{} minutes ago",
|
||||
"justNow": "Just now"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "Suspected Location #{}",
|
||||
"ticketNo": "Ticket No",
|
||||
"address": "Address",
|
||||
"street": "Street",
|
||||
"city": "City",
|
||||
"state": "State",
|
||||
"intersectingStreet": "Intersecting Street",
|
||||
"workDoneFor": "Work Done For",
|
||||
"remarks": "Remarks",
|
||||
"url": "URL",
|
||||
"coordinates": "Coordinates",
|
||||
"noAddressAvailable": "No address available"
|
||||
}
|
||||
}
|
||||
@@ -341,5 +341,40 @@
|
||||
"imperial": "Imperial (mi, ft)",
|
||||
"meters": "metros",
|
||||
"feet": "pies"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "Ubicaciones Sospechosas",
|
||||
"showSuspectedLocations": "Mostrar Ubicaciones Sospechosas",
|
||||
"showSuspectedLocationsSubtitle": "Mostrar marcadores de interrogación para sitios de vigilancia sospechosos de datos de permisos de servicios públicos",
|
||||
"lastUpdated": "Última Actualización",
|
||||
"refreshNow": "Actualizar ahora",
|
||||
"dataSource": "Fuente de Datos",
|
||||
"dataSourceDescription": "Datos de permisos de servicios públicos que indican posibles sitios de instalación de infraestructura de vigilancia",
|
||||
"dataSourceCredit": "Recopilación y alojamiento de datos proporcionado por alprwatch.org",
|
||||
"minimumDistance": "Distancia Mínima de Nodos Reales",
|
||||
"minimumDistanceSubtitle": "Ocultar ubicaciones sospechosas dentro de {}m de dispositivos de vigilancia existentes",
|
||||
"updating": "Actualizando Ubicaciones Sospechosas",
|
||||
"downloadingAndProcessing": "Descargando y procesando datos...",
|
||||
"updateSuccess": "Ubicaciones sospechosas actualizadas exitosamente",
|
||||
"updateFailed": "Error al actualizar ubicaciones sospechosas",
|
||||
"neverFetched": "Nunca obtenido",
|
||||
"daysAgo": "hace {} días",
|
||||
"hoursAgo": "hace {} horas",
|
||||
"minutesAgo": "hace {} minutos",
|
||||
"justNow": "Ahora mismo"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "Ubicación Sospechosa #{}",
|
||||
"ticketNo": "No. de Ticket",
|
||||
"address": "Dirección",
|
||||
"street": "Calle",
|
||||
"city": "Ciudad",
|
||||
"state": "Estado",
|
||||
"intersectingStreet": "Calle que Intersecta",
|
||||
"workDoneFor": "Trabajo Realizado Para",
|
||||
"remarks": "Observaciones",
|
||||
"url": "URL",
|
||||
"coordinates": "Coordenadas",
|
||||
"noAddressAvailable": "No hay dirección disponible"
|
||||
}
|
||||
}
|
||||
@@ -341,5 +341,40 @@
|
||||
"imperial": "Impérial (mi, ft)",
|
||||
"meters": "mètres",
|
||||
"feet": "pieds"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "Emplacements Suspects",
|
||||
"showSuspectedLocations": "Afficher les Emplacements Suspects",
|
||||
"showSuspectedLocationsSubtitle": "Afficher des marqueurs en point d'interrogation pour les sites de surveillance suspectés à partir des données de permis de services publics",
|
||||
"lastUpdated": "Dernière Mise à Jour",
|
||||
"refreshNow": "Actualiser maintenant",
|
||||
"dataSource": "Source de Données",
|
||||
"dataSourceDescription": "Données de permis de services publics indiquant des sites d'installation potentiels d'infrastructure de surveillance",
|
||||
"dataSourceCredit": "Collecte et hébergement des données fournis par alprwatch.org",
|
||||
"minimumDistance": "Distance Minimale des Nœuds Réels",
|
||||
"minimumDistanceSubtitle": "Masquer les emplacements suspects dans un rayon de {}m des dispositifs de surveillance existants",
|
||||
"updating": "Mise à Jour des Emplacements Suspects",
|
||||
"downloadingAndProcessing": "Téléchargement et traitement des données...",
|
||||
"updateSuccess": "Emplacements suspects mis à jour avec succès",
|
||||
"updateFailed": "Échec de la mise à jour des emplacements suspects",
|
||||
"neverFetched": "Jamais récupéré",
|
||||
"daysAgo": "il y a {} jours",
|
||||
"hoursAgo": "il y a {} heures",
|
||||
"minutesAgo": "il y a {} minutes",
|
||||
"justNow": "À l'instant"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "Emplacement Suspect #{}",
|
||||
"ticketNo": "N° de Ticket",
|
||||
"address": "Adresse",
|
||||
"street": "Rue",
|
||||
"city": "Ville",
|
||||
"state": "État",
|
||||
"intersectingStreet": "Rue Transversale",
|
||||
"workDoneFor": "Travail Effectué Pour",
|
||||
"remarks": "Remarques",
|
||||
"url": "URL",
|
||||
"coordinates": "Coordonnées",
|
||||
"noAddressAvailable": "Aucune adresse disponible"
|
||||
}
|
||||
}
|
||||
@@ -341,5 +341,40 @@
|
||||
"imperial": "Imperiale (mi, ft)",
|
||||
"meters": "metri",
|
||||
"feet": "piedi"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "Posizioni Sospette",
|
||||
"showSuspectedLocations": "Mostra Posizioni Sospette",
|
||||
"showSuspectedLocationsSubtitle": "Mostra marcatori punto interrogativo per siti di sorveglianza sospetti dai dati dei permessi dei servizi pubblici",
|
||||
"lastUpdated": "Ultimo Aggiornamento",
|
||||
"refreshNow": "Aggiorna ora",
|
||||
"dataSource": "Fonte Dati",
|
||||
"dataSourceDescription": "Dati dei permessi dei servizi pubblici che indicano potenziali siti di installazione di infrastrutture di sorveglianza",
|
||||
"dataSourceCredit": "Raccolta e hosting dei dati forniti da alprwatch.org",
|
||||
"minimumDistance": "Distanza Minima dai Nodi Reali",
|
||||
"minimumDistanceSubtitle": "Nascondi posizioni sospette entro {}m dai dispositivi di sorveglianza esistenti",
|
||||
"updating": "Aggiornamento Posizioni Sospette",
|
||||
"downloadingAndProcessing": "Scaricamento e elaborazione dati...",
|
||||
"updateSuccess": "Posizioni sospette aggiornate con successo",
|
||||
"updateFailed": "Aggiornamento posizioni sospette fallito",
|
||||
"neverFetched": "Mai recuperato",
|
||||
"daysAgo": "{} giorni fa",
|
||||
"hoursAgo": "{} ore fa",
|
||||
"minutesAgo": "{} minuti fa",
|
||||
"justNow": "Proprio ora"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "Posizione Sospetta #{}",
|
||||
"ticketNo": "N. Ticket",
|
||||
"address": "Indirizzo",
|
||||
"street": "Via",
|
||||
"city": "Città",
|
||||
"state": "Stato",
|
||||
"intersectingStreet": "Via che Interseca",
|
||||
"workDoneFor": "Lavoro Svolto Per",
|
||||
"remarks": "Osservazioni",
|
||||
"url": "URL",
|
||||
"coordinates": "Coordinate",
|
||||
"noAddressAvailable": "Nessun indirizzo disponibile"
|
||||
}
|
||||
}
|
||||
@@ -341,5 +341,40 @@
|
||||
"imperial": "Imperial (mi, ft)",
|
||||
"meters": "metros",
|
||||
"feet": "pés"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "Localizações Suspeitas",
|
||||
"showSuspectedLocations": "Mostrar Localizações Suspeitas",
|
||||
"showSuspectedLocationsSubtitle": "Mostrar marcadores de ponto de interrogação para sites de vigilância suspeitos de dados de licenças de serviços públicos",
|
||||
"lastUpdated": "Última Atualização",
|
||||
"refreshNow": "Atualizar agora",
|
||||
"dataSource": "Fonte de Dados",
|
||||
"dataSourceDescription": "Dados de licenças de serviços públicos indicando possíveis locais de instalação de infraestrutura de vigilância",
|
||||
"dataSourceCredit": "Coleta e hospedagem de dados fornecidas por alprwatch.org",
|
||||
"minimumDistance": "Distância Mínima de Nós Reais",
|
||||
"minimumDistanceSubtitle": "Ocultar localizações suspeitas dentro de {}m de dispositivos de vigilância existentes",
|
||||
"updating": "Atualizando Localizações Suspeitas",
|
||||
"downloadingAndProcessing": "Baixando e processando dados...",
|
||||
"updateSuccess": "Localizações suspeitas atualizadas com sucesso",
|
||||
"updateFailed": "Falha ao atualizar localizações suspeitas",
|
||||
"neverFetched": "Nunca buscado",
|
||||
"daysAgo": "{} dias atrás",
|
||||
"hoursAgo": "{} horas atrás",
|
||||
"minutesAgo": "{} minutos atrás",
|
||||
"justNow": "Agora mesmo"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "Localização Suspeita #{}",
|
||||
"ticketNo": "N° do Ticket",
|
||||
"address": "Endereço",
|
||||
"street": "Rua",
|
||||
"city": "Cidade",
|
||||
"state": "Estado",
|
||||
"intersectingStreet": "Rua que Cruza",
|
||||
"workDoneFor": "Trabalho Feito Para",
|
||||
"remarks": "Observações",
|
||||
"url": "URL",
|
||||
"coordinates": "Coordenadas",
|
||||
"noAddressAvailable": "Nenhum endereço disponível"
|
||||
}
|
||||
}
|
||||
@@ -341,5 +341,40 @@
|
||||
"imperial": "英制(英里,英尺)",
|
||||
"meters": "米",
|
||||
"feet": "英尺"
|
||||
},
|
||||
"suspectedLocations": {
|
||||
"title": "疑似位置",
|
||||
"showSuspectedLocations": "显示疑似位置",
|
||||
"showSuspectedLocationsSubtitle": "根据公用事业许可数据显示疑似监控站点的问号标记",
|
||||
"lastUpdated": "最后更新",
|
||||
"refreshNow": "立即刷新",
|
||||
"dataSource": "数据源",
|
||||
"dataSourceDescription": "公用事业许可数据,表明潜在的监控基础设施安装站点",
|
||||
"dataSourceCredit": "数据收集和托管由 alprwatch.org 提供",
|
||||
"minimumDistance": "与真实节点的最小距离",
|
||||
"minimumDistanceSubtitle": "隐藏现有监控设备{}米范围内的疑似位置",
|
||||
"updating": "正在更新疑似位置",
|
||||
"downloadingAndProcessing": "正在下载和处理数据...",
|
||||
"updateSuccess": "疑似位置更新成功",
|
||||
"updateFailed": "疑似位置更新失败",
|
||||
"neverFetched": "从未获取",
|
||||
"daysAgo": "{}天前",
|
||||
"hoursAgo": "{}小时前",
|
||||
"minutesAgo": "{}分钟前",
|
||||
"justNow": "刚刚"
|
||||
},
|
||||
"suspectedLocation": {
|
||||
"title": "疑似位置 #{}",
|
||||
"ticketNo": "工单号",
|
||||
"address": "地址",
|
||||
"street": "街道",
|
||||
"city": "城市",
|
||||
"state": "州/省",
|
||||
"intersectingStreet": "交叉街道",
|
||||
"workDoneFor": "工作完成方",
|
||||
"remarks": "备注",
|
||||
"url": "网址",
|
||||
"coordinates": "坐标",
|
||||
"noAddressAvailable": "无可用地址"
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,4 @@
|
||||
import 'dart:convert';
|
||||
import 'dart:math' as math;
|
||||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
/// A suspected surveillance location from the CSV data
|
||||
@@ -42,36 +41,10 @@ class SuspectedLocation {
|
||||
// Parse GeoJSON if available
|
||||
if (locationString != null && locationString.isNotEmpty) {
|
||||
try {
|
||||
// Only log first few entries to avoid spam
|
||||
final ticketNo = row['ticket_no']?.toString() ?? 'unknown';
|
||||
if (ticketNo.endsWith('0') || ticketNo.endsWith('1') || ticketNo.endsWith('2')) {
|
||||
print('[SuspectedLocation] Raw location string for ticket $ticketNo: ${locationString.substring(0, math.min(100, locationString.length))}...');
|
||||
}
|
||||
if (ticketNo.endsWith('0') || ticketNo.endsWith('1') || ticketNo.endsWith('2')) {
|
||||
if (centroid.latitude != 0 || centroid.longitude != 0) {
|
||||
print('[SuspectedLocation] Successfully parsed centroid: $centroid');
|
||||
} else {
|
||||
print('[SuspectedLocation] Parsed but got zero coordinates');
|
||||
}
|
||||
}
|
||||
geoJson = jsonDecode(locationString) as Map<String, dynamic>;
|
||||
final coordinates = _extractCoordinatesFromGeoJson(geoJson);
|
||||
centroid = coordinates.centroid;
|
||||
bounds = coordinates.bounds;
|
||||
if (ticketNo.endsWith('0') || ticketNo.endsWith('1') || ticketNo.endsWith('2')) {
|
||||
if (centroid.latitude != 0 || centroid.longitude != 0) {
|
||||
print('[SuspectedLocation] Successfully parsed centroid: $centroid');
|
||||
} else {
|
||||
print('[SuspectedLocation] Parsed but got zero coordinates');
|
||||
}
|
||||
}
|
||||
if (ticketNo.endsWith('0') || ticketNo.endsWith('1') || ticketNo.endsWith('2')) {
|
||||
if (centroid.latitude != 0 || centroid.longitude != 0) {
|
||||
print('[SuspectedLocation] Successfully parsed centroid: $centroid');
|
||||
} else {
|
||||
print('[SuspectedLocation] Parsed but got zero coordinates');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
// If GeoJSON parsing fails, use default coordinates
|
||||
print('[SuspectedLocation] Failed to parse GeoJSON for ticket ${row['ticket_no']}: $e');
|
||||
|
||||
@@ -20,18 +20,18 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
|
||||
String getLastFetchText() {
|
||||
if (lastFetch == null) {
|
||||
return 'Never fetched';
|
||||
return locService.t('suspectedLocations.neverFetched');
|
||||
} else {
|
||||
final now = DateTime.now();
|
||||
final diff = now.difference(lastFetch);
|
||||
if (diff.inDays > 0) {
|
||||
return '${diff.inDays} days ago';
|
||||
return locService.t('suspectedLocations.daysAgo', params: [diff.inDays.toString()]);
|
||||
} else if (diff.inHours > 0) {
|
||||
return '${diff.inHours} hours ago';
|
||||
return locService.t('suspectedLocations.hoursAgo', params: [diff.inHours.toString()]);
|
||||
} else if (diff.inMinutes > 0) {
|
||||
return '${diff.inMinutes} minutes ago';
|
||||
return locService.t('suspectedLocations.minutesAgo', params: [diff.inMinutes.toString()]);
|
||||
} else {
|
||||
return 'Just now';
|
||||
return locService.t('suspectedLocations.justNow');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -43,9 +43,9 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
showDialog(
|
||||
context: context,
|
||||
barrierDismissible: false,
|
||||
builder: (progressContext) => const SuspectedLocationProgressDialog(
|
||||
title: 'Updating Suspected Locations',
|
||||
message: 'Downloading and processing data...',
|
||||
builder: (progressContext) => SuspectedLocationProgressDialog(
|
||||
title: locService.t('suspectedLocations.updating'),
|
||||
message: locService.t('suspectedLocations.downloadingAndProcessing'),
|
||||
),
|
||||
);
|
||||
|
||||
@@ -57,13 +57,13 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
Navigator.of(context).pop();
|
||||
|
||||
// Show result snackbar
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
? 'Suspected locations updated successfully'
|
||||
: 'Failed to update suspected locations'),
|
||||
),
|
||||
);
|
||||
ScaffoldMessenger.of(context).showSnackBar(
|
||||
SnackBar(
|
||||
content: Text(success
|
||||
? locService.t('suspectedLocations.updateSuccess')
|
||||
: locService.t('suspectedLocations.updateFailed')),
|
||||
),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -71,7 +71,7 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Suspected Locations',
|
||||
locService.t('suspectedLocations.title'),
|
||||
style: Theme.of(context).textTheme.titleMedium,
|
||||
),
|
||||
const SizedBox(height: 8),
|
||||
@@ -79,8 +79,8 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
// Enable/disable switch
|
||||
ListTile(
|
||||
leading: const Icon(Icons.help_outline),
|
||||
title: const Text('Show Suspected Locations'),
|
||||
subtitle: const Text('Show question mark markers for suspected surveillance sites from utility permit data'),
|
||||
title: Text(locService.t('suspectedLocations.showSuspectedLocations')),
|
||||
subtitle: Text(locService.t('suspectedLocations.showSuspectedLocationsSubtitle')),
|
||||
trailing: Switch(
|
||||
value: isEnabled,
|
||||
onChanged: (enabled) {
|
||||
@@ -95,7 +95,7 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
// Last update time
|
||||
ListTile(
|
||||
leading: const Icon(Icons.schedule),
|
||||
title: const Text('Last Updated'),
|
||||
title: Text(locService.t('suspectedLocations.lastUpdated')),
|
||||
subtitle: Text(getLastFetchText()),
|
||||
trailing: isLoading
|
||||
? const SizedBox(
|
||||
@@ -106,22 +106,35 @@ class SuspectedLocationsSection extends StatelessWidget {
|
||||
: IconButton(
|
||||
icon: const Icon(Icons.refresh),
|
||||
onPressed: handleRefresh,
|
||||
tooltip: 'Refresh now',
|
||||
tooltip: locService.t('suspectedLocations.refreshNow'),
|
||||
),
|
||||
),
|
||||
|
||||
// Data info
|
||||
// Data info with credit
|
||||
ListTile(
|
||||
leading: const Icon(Icons.info_outline),
|
||||
title: const Text('Data Source'),
|
||||
subtitle: const Text('Utility permit data indicating potential surveillance infrastructure installation sites'),
|
||||
title: Text(locService.t('suspectedLocations.dataSource')),
|
||||
subtitle: Column(
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(locService.t('suspectedLocations.dataSourceDescription')),
|
||||
const SizedBox(height: 4),
|
||||
Text(
|
||||
locService.t('suspectedLocations.dataSourceCredit'),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.primary,
|
||||
),
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
|
||||
// Minimum distance setting
|
||||
ListTile(
|
||||
leading: const Icon(Icons.social_distance),
|
||||
title: const Text('Minimum Distance from Real Nodes'),
|
||||
subtitle: Text('Hide suspected locations within ${appState.suspectedLocationMinDistance}m of existing surveillance devices'),
|
||||
title: Text(locService.t('suspectedLocations.minimumDistance')),
|
||||
subtitle: Text(locService.t('suspectedLocations.minimumDistanceSubtitle', params: [appState.suspectedLocationMinDistance.toString()])),
|
||||
trailing: SizedBox(
|
||||
width: 80,
|
||||
child: TextFormField(
|
||||
|
||||
@@ -160,15 +160,9 @@ class SuspectedLocationCache extends ChangeNotifier {
|
||||
validCount++;
|
||||
} else {
|
||||
zeroCoordCount++;
|
||||
if (i < 3) { // Log first few zero coord cases
|
||||
debugPrint('[SuspectedLocationCache] Row $i has zero coordinates: ticket=${rowData['ticket_no']}, location=${rowData['location']?.toString().length} chars');
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
errorCount++;
|
||||
if (errorCount <= 5) { // Log first few errors
|
||||
debugPrint('[SuspectedLocationCache] Row $i error: $e, ticket=${rowData['ticket_no']}');
|
||||
}
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class SuspectedLocationService {
|
||||
factory SuspectedLocationService() => _instance;
|
||||
SuspectedLocationService._();
|
||||
|
||||
static const String _csvUrl = 'https://alprwatch.org/pub/flock_utilities_mini_2025-10-06.csv';
|
||||
static const String _csvUrl = 'https://alprwatch.org/pub/flock_utilities_mini_latest.csv';
|
||||
static const String _prefsKeyEnabled = 'suspected_locations_enabled';
|
||||
static const Duration _maxAge = Duration(days: 7);
|
||||
static const Duration _timeout = Duration(seconds: 30);
|
||||
@@ -187,9 +187,8 @@ class SuspectedLocationService {
|
||||
validRows++;
|
||||
}
|
||||
|
||||
// Log progress every 1000 rows and report to UI
|
||||
// Report progress every 1000 rows
|
||||
if (rowIndex % 1000 == 0) {
|
||||
debugPrint('[SuspectedLocationService] Processing row $rowIndex...');
|
||||
final progress = 0.4 + (rowIndex / dataRows.length) * 0.4; // 40% to 80% of total
|
||||
onProgress?.call('Processing row $rowIndex...', progress);
|
||||
}
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import 'package:flutter/material.dart';
|
||||
import '../services/localization_service.dart';
|
||||
|
||||
class SuspectedLocationProgressDialog extends StatelessWidget {
|
||||
final String title;
|
||||
@@ -46,7 +47,7 @@ class SuspectedLocationProgressDialog extends StatelessWidget {
|
||||
if (onCancel != null)
|
||||
TextButton(
|
||||
onPressed: onCancel,
|
||||
child: const Text('Cancel'),
|
||||
child: Text(LocalizationService.instance.cancel),
|
||||
),
|
||||
],
|
||||
);
|
||||
|
||||
@@ -36,17 +36,17 @@ class SuspectedLocationSheet extends StatelessWidget {
|
||||
}
|
||||
}
|
||||
|
||||
// Create display data map
|
||||
// Create display data map using localized labels
|
||||
final Map<String, String?> displayData = {
|
||||
'Ticket No': location.ticketNo,
|
||||
'Address': location.addr,
|
||||
'Street': location.street,
|
||||
'City': location.city,
|
||||
'State': location.state,
|
||||
'Intersecting Street': location.digSiteIntersectingStreet,
|
||||
'Work Done For': location.digWorkDoneFor,
|
||||
'Remarks': location.digSiteRemarks,
|
||||
'URL': location.urlFull,
|
||||
locService.t('suspectedLocation.ticketNo'): location.ticketNo,
|
||||
locService.t('suspectedLocation.address'): location.addr,
|
||||
locService.t('suspectedLocation.street'): location.street,
|
||||
locService.t('suspectedLocation.city'): location.city,
|
||||
locService.t('suspectedLocation.state'): location.state,
|
||||
locService.t('suspectedLocation.intersectingStreet'): location.digSiteIntersectingStreet,
|
||||
locService.t('suspectedLocation.workDoneFor'): location.digWorkDoneFor,
|
||||
locService.t('suspectedLocation.remarks'): location.digSiteRemarks,
|
||||
locService.t('suspectedLocation.url'): location.urlFull,
|
||||
};
|
||||
|
||||
return SafeArea(
|
||||
@@ -58,7 +58,7 @@ class SuspectedLocationSheet extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Suspected Location #${location.ticketNo}',
|
||||
locService.t('suspectedLocation.title', params: [location.ticketNo]),
|
||||
style: Theme.of(context).textTheme.titleLarge,
|
||||
),
|
||||
const SizedBox(height: 12),
|
||||
@@ -113,7 +113,7 @@ class SuspectedLocationSheet extends StatelessWidget {
|
||||
crossAxisAlignment: CrossAxisAlignment.start,
|
||||
children: [
|
||||
Text(
|
||||
'Coordinates',
|
||||
locService.t('suspectedLocation.coordinates'),
|
||||
style: TextStyle(
|
||||
fontWeight: FontWeight.w500,
|
||||
color: Theme.of(context).colorScheme.onSurface,
|
||||
|
||||
Reference in New Issue
Block a user