CTK 1.1.0
This commit is contained in:
103
lib/consultorios/clinic.dart
Normal file
103
lib/consultorios/clinic.dart
Normal file
@@ -0,0 +1,103 @@
|
||||
import '../strings/consultorios_strings.dart';
|
||||
|
||||
/// Um consultório dentário devolvido pela Overpass API. Os campos de texto
|
||||
/// nunca são nulos — qualquer tag em falta no OpenStreetMap já é resolvida
|
||||
/// para um texto de substituição aqui — mas [hasPhone]/[hasOpeningHours]
|
||||
/// dizem se esse texto é um valor real ou só o substituto, para os widgets
|
||||
/// decidirem o que é "acionável" (ex.: só ligar quando há telefone real).
|
||||
class Clinic {
|
||||
const Clinic({
|
||||
required this.id,
|
||||
required this.name,
|
||||
required this.lat,
|
||||
required this.lon,
|
||||
required this.address,
|
||||
required this.phone,
|
||||
required this.hasPhone,
|
||||
required this.openingHours,
|
||||
required this.hasOpeningHours,
|
||||
this.distanceKm,
|
||||
});
|
||||
|
||||
final String id;
|
||||
final String name;
|
||||
final double lat;
|
||||
final double lon;
|
||||
final String address;
|
||||
final String phone;
|
||||
final bool hasPhone;
|
||||
final String openingHours;
|
||||
final bool hasOpeningHours;
|
||||
|
||||
/// Distância (km) até à morada guardada — só preenchida depois de
|
||||
/// [OverpassService.fetchNearbyClinics] a calcular; `null` até lá.
|
||||
final double? distanceKm;
|
||||
|
||||
Clinic copyWithDistance(double distanceKm) {
|
||||
return Clinic(
|
||||
id: id,
|
||||
name: name,
|
||||
lat: lat,
|
||||
lon: lon,
|
||||
address: address,
|
||||
phone: phone,
|
||||
hasPhone: hasPhone,
|
||||
openingHours: openingHours,
|
||||
hasOpeningHours: hasOpeningHours,
|
||||
distanceKm: distanceKm,
|
||||
);
|
||||
}
|
||||
|
||||
/// Constrói a partir de um elemento da resposta da Overpass API (`node`
|
||||
/// ou `way`, com `out center tags;` para que `way` também tenha
|
||||
/// coordenadas via `element['center']`).
|
||||
factory Clinic.fromOverpassElement(Map<String, dynamic> element) {
|
||||
final tags = (element['tags'] as Map?)?.cast<String, dynamic>() ?? const {};
|
||||
|
||||
final double lat;
|
||||
final double lon;
|
||||
if (element['type'] == 'node') {
|
||||
lat = (element['lat'] as num).toDouble();
|
||||
lon = (element['lon'] as num).toDouble();
|
||||
} else {
|
||||
final center = (element['center'] as Map?)?.cast<String, dynamic>() ?? const {};
|
||||
lat = ((center['lat'] as num?) ?? 0).toDouble();
|
||||
lon = ((center['lon'] as num?) ?? 0).toDouble();
|
||||
}
|
||||
|
||||
final name = (tags['name'] as String?)?.trim();
|
||||
|
||||
final addressParts = [
|
||||
[
|
||||
tags['addr:street'],
|
||||
tags['addr:housenumber'],
|
||||
].whereType<String>().join(', '),
|
||||
tags['addr:postcode'],
|
||||
(tags['addr:city'] ?? tags['addr:suburb']),
|
||||
].whereType<String>().where((s) => s.trim().isNotEmpty).toList();
|
||||
|
||||
final phone = (tags['phone'] as String?)?.trim() ??
|
||||
(tags['contact:phone'] as String?)?.trim();
|
||||
final openingHours = (tags['opening_hours'] as String?)?.trim();
|
||||
final hasPhone = phone != null && phone.isNotEmpty;
|
||||
final hasOpeningHours = openingHours != null && openingHours.isNotEmpty;
|
||||
|
||||
return Clinic(
|
||||
id: '${element['type']}/${element['id']}',
|
||||
name: (name != null && name.isNotEmpty)
|
||||
? name
|
||||
: ConsultoriosStrings.unnamedClinic,
|
||||
lat: lat,
|
||||
lon: lon,
|
||||
address: addressParts.isNotEmpty
|
||||
? addressParts.join(' • ')
|
||||
: ConsultoriosStrings.noAddress,
|
||||
phone: hasPhone ? phone : ConsultoriosStrings.noPhone,
|
||||
hasPhone: hasPhone,
|
||||
openingHours: hasOpeningHours
|
||||
? openingHours
|
||||
: ConsultoriosStrings.noOpeningHours,
|
||||
hasOpeningHours: hasOpeningHours,
|
||||
);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user