Files
anyway/frontend/lib/presentation/utils/trip_location_utils.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';
}