53 lines
1.7 KiB
Dart
53 lines
1.7 KiB
Dart
import 'dart:convert';
|
|
|
|
import 'package:http/http.dart' as http;
|
|
|
|
/// Geocoding de moradas via Nominatim (OpenStreetMap) — converte texto
|
|
/// livre em coordenadas. Serviço gratuito e público; a política de uso da
|
|
/// Nominatim exige no máximo ~1 pedido/segundo e um `User-Agent`
|
|
/// identificável, por isso só chamamos isto quando o utilizador guarda a
|
|
/// morada (nunca em cada abertura de ecrã).
|
|
class GeocodingService {
|
|
const GeocodingService._();
|
|
|
|
static const String _endpoint = 'https://nominatim.openstreetmap.org/search';
|
|
static const String _userAgent = 'CheckTeethKids/1.0 (caducorreia740@gmail.com)';
|
|
|
|
/// Devolve as coordenadas da morada, ou `null` se a Nominatim não
|
|
/// encontrar nenhum resultado, a ligação falhar ou expirar o tempo
|
|
/// limite — quem chama decide como reagir (ex.: mostrar erro no campo).
|
|
static Future<({double lat, double lon})?> geocodeAddress(
|
|
String address,
|
|
) async {
|
|
final uri = Uri.parse(_endpoint).replace(
|
|
queryParameters: {
|
|
'q': address,
|
|
'format': 'jsonv2',
|
|
'limit': '1',
|
|
},
|
|
);
|
|
|
|
try {
|
|
final response = await http
|
|
.get(uri, headers: {'User-Agent': _userAgent})
|
|
.timeout(const Duration(seconds: 12));
|
|
|
|
if (response.statusCode != 200) return null;
|
|
|
|
final results = jsonDecode(response.body);
|
|
if (results is! List || results.isEmpty) return null;
|
|
|
|
final first = results.first;
|
|
if (first is! Map) return null;
|
|
|
|
final lat = double.tryParse('${first['lat']}');
|
|
final lon = double.tryParse('${first['lon']}');
|
|
if (lat == null || lon == null) return null;
|
|
|
|
return (lat: lat, lon: lon);
|
|
} catch (_) {
|
|
return null;
|
|
}
|
|
}
|
|
}
|