79 lines
2.5 KiB
Dart
79 lines
2.5 KiB
Dart
import 'package:anyway/domain/entities/trip.dart';
|
|
import 'package:geocoding/geocoding.dart';
|
|
|
|
class TripLocationUtils {
|
|
const TripLocationUtils._();
|
|
|
|
static List<double>? startCoordinates(Trip trip) {
|
|
if (trip.landmarks.isEmpty) {
|
|
return null;
|
|
}
|
|
final coords = trip.landmarks.first.location;
|
|
if (coords.length < 2) {
|
|
return null;
|
|
}
|
|
return coords;
|
|
}
|
|
|
|
static Future<TripLocaleInfo> resolveLocaleInfo(Trip trip) async {
|
|
final coords = startCoordinates(trip);
|
|
if (coords == null) {
|
|
return const TripLocaleInfo();
|
|
}
|
|
|
|
if (GeocodingPlatform.instance == null) {
|
|
final fallbackCity = '${coords[0].toStringAsFixed(2)}, ${coords[1].toStringAsFixed(2)}';
|
|
return TripLocaleInfo(cityName: fallbackCity, coordinates: coords);
|
|
}
|
|
|
|
try {
|
|
final placemarks = await placemarkFromCoordinates(coords[0], coords[1]);
|
|
if (placemarks.isEmpty) {
|
|
return TripLocaleInfo(coordinates: coords);
|
|
}
|
|
final placemark = placemarks.first;
|
|
final city = placemark.locality ?? placemark.subAdministrativeArea;
|
|
final country = placemark.country;
|
|
final isoCountryCode = placemark.isoCountryCode;
|
|
return TripLocaleInfo(cityName: city, countryName: country, countryCode: isoCountryCode, flagEmoji: _flagEmoji(isoCountryCode), coordinates: coords);
|
|
} catch (_) {
|
|
return TripLocaleInfo(coordinates: coords);
|
|
}
|
|
}
|
|
|
|
static Future<String> resolveCityName(Trip trip) async {
|
|
final localeInfo = await resolveLocaleInfo(trip);
|
|
return localeInfo.cityName ?? 'Unknown';
|
|
}
|
|
|
|
static String? _flagEmoji(String? countryCode) {
|
|
if (countryCode == null || countryCode.length != 2) {
|
|
return null;
|
|
}
|
|
final upper = countryCode.toUpperCase();
|
|
final first = upper.codeUnitAt(0);
|
|
final second = upper.codeUnitAt(1);
|
|
if (!_isAsciiLetter(first) || !_isAsciiLetter(second)) {
|
|
return null;
|
|
}
|
|
const base = 0x1F1E6;
|
|
final firstFlag = base + (first - 0x41);
|
|
final secondFlag = base + (second - 0x41);
|
|
return String.fromCharCodes([firstFlag, secondFlag]);
|
|
}
|
|
|
|
static bool _isAsciiLetter(int codeUnit) => codeUnit >= 0x41 && codeUnit <= 0x5A;
|
|
}
|
|
|
|
class TripLocaleInfo {
|
|
const TripLocaleInfo({this.cityName, this.countryName, this.countryCode, this.flagEmoji, this.coordinates});
|
|
|
|
final String? cityName;
|
|
final String? countryName;
|
|
final String? countryCode;
|
|
final String? flagEmoji;
|
|
final List<double>? coordinates;
|
|
|
|
bool get hasResolvedCity => cityName != null && cityName!.trim().isNotEmpty && cityName != 'Unknown';
|
|
}
|