l10n: DMS coordinate directions
This commit is contained in:
parent
4ee510d7a0
commit
c74b94fb22
11 changed files with 69 additions and 30 deletions
|
@ -176,6 +176,25 @@
|
||||||
"@coordinateFormatDms": {},
|
"@coordinateFormatDms": {},
|
||||||
"coordinateFormatDecimal": "Decimal degrees",
|
"coordinateFormatDecimal": "Decimal degrees",
|
||||||
"@coordinateFormatDecimal": {},
|
"@coordinateFormatDecimal": {},
|
||||||
|
"coordinateDms": "{coordinate} {direction}",
|
||||||
|
"@coordinateDms": {
|
||||||
|
"placeholders": {
|
||||||
|
"coordinate": {
|
||||||
|
"type": "String"
|
||||||
|
},
|
||||||
|
"direction": {
|
||||||
|
"type": "String"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"coordinateDmsNorth": "N",
|
||||||
|
"@coordinateDmsNorth": {},
|
||||||
|
"coordinateDmsSouth": "S",
|
||||||
|
"@coordinateDmsSouth": {},
|
||||||
|
"coordinateDmsEast": "E",
|
||||||
|
"@coordinateDmsEast": {},
|
||||||
|
"coordinateDmsWest": "W",
|
||||||
|
"@coordinateDmsWest": {},
|
||||||
|
|
||||||
"unitSystemMetric": "Metric",
|
"unitSystemMetric": "Metric",
|
||||||
"@unitSystemMetric": {},
|
"@unitSystemMetric": {},
|
||||||
|
|
|
@ -87,6 +87,11 @@
|
||||||
|
|
||||||
"coordinateFormatDms": "도분초",
|
"coordinateFormatDms": "도분초",
|
||||||
"coordinateFormatDecimal": "소수점",
|
"coordinateFormatDecimal": "소수점",
|
||||||
|
"coordinateDms": "{direction} {coordinate}",
|
||||||
|
"coordinateDmsNorth": "북위",
|
||||||
|
"coordinateDmsSouth": "남위",
|
||||||
|
"coordinateDmsEast": "동경",
|
||||||
|
"coordinateDmsWest": "서경",
|
||||||
|
|
||||||
"unitSystemMetric": "미터법",
|
"unitSystemMetric": "미터법",
|
||||||
"unitSystemImperial": "야드파운드법",
|
"unitSystemImperial": "야드파운드법",
|
||||||
|
|
|
@ -87,6 +87,11 @@
|
||||||
|
|
||||||
"coordinateFormatDms": "Градусы, минуты и секунды",
|
"coordinateFormatDms": "Градусы, минуты и секунды",
|
||||||
"coordinateFormatDecimal": "Десятичные градусы",
|
"coordinateFormatDecimal": "Десятичные градусы",
|
||||||
|
"coordinateDms": "{coordinate} {direction}",
|
||||||
|
"coordinateDmsNorth": "с. ш.",
|
||||||
|
"coordinateDmsSouth": "ю. ш.",
|
||||||
|
"coordinateDmsEast": "в. д.",
|
||||||
|
"coordinateDmsWest": "з. д.",
|
||||||
|
|
||||||
"unitSystemMetric": "Метрические",
|
"unitSystemMetric": "Метрические",
|
||||||
"unitSystemImperial": "Имперские",
|
"unitSystemImperial": "Имперские",
|
||||||
|
|
|
@ -4,8 +4,10 @@ import 'package:aves/model/settings/enums.dart';
|
||||||
import 'package:aves/model/settings/settings.dart';
|
import 'package:aves/model/settings/settings.dart';
|
||||||
import 'package:aves/theme/icons.dart';
|
import 'package:aves/theme/icons.dart';
|
||||||
import 'package:aves/utils/geo_utils.dart';
|
import 'package:aves/utils/geo_utils.dart';
|
||||||
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:flutter/material.dart';
|
import 'package:flutter/material.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:provider/provider.dart';
|
import 'package:provider/provider.dart';
|
||||||
|
|
||||||
|
@ -37,8 +39,9 @@ class CoordinateFilter extends CollectionFilter {
|
||||||
@override
|
@override
|
||||||
EntryFilter get test => (entry) => GeoUtils.contains(sw, ne, entry.latLng);
|
EntryFilter get test => (entry) => GeoUtils.contains(sw, ne, entry.latLng);
|
||||||
|
|
||||||
String _formatBounds(CoordinateFormat format) {
|
String _formatBounds(AppLocalizations l10n, CoordinateFormat format) {
|
||||||
String s(LatLng latLng) => format.format(
|
String s(LatLng latLng) => format.format(
|
||||||
|
l10n,
|
||||||
latLng,
|
latLng,
|
||||||
minuteSecondPadding: minuteSecondPadding,
|
minuteSecondPadding: minuteSecondPadding,
|
||||||
dmsSecondDecimals: 0,
|
dmsSecondDecimals: 0,
|
||||||
|
@ -47,10 +50,10 @@ class CoordinateFilter extends CollectionFilter {
|
||||||
}
|
}
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String get universalLabel => _formatBounds(CoordinateFormat.decimal);
|
String get universalLabel => _formatBounds(lookupAppLocalizations(AppLocalizations.supportedLocales.first), CoordinateFormat.decimal);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
String getLabel(BuildContext context) => _formatBounds(context.read<Settings>().coordinateFormat);
|
String getLabel(BuildContext context) => _formatBounds(context.l10n, context.read<Settings>().coordinateFormat);
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true, bool embossed = false}) => Icon(AIcons.geoBounds, size: size);
|
Widget iconBuilder(BuildContext context, double size, {bool showGenericIcon = true, bool embossed = false}) => Icon(AIcons.geoBounds, size: size);
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
import 'package:aves/utils/geo_utils.dart';
|
import 'package:aves/utils/geo_utils.dart';
|
||||||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||||
import 'package:flutter/widgets.dart';
|
import 'package:flutter/widgets.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
import 'enums.dart';
|
import 'enums.dart';
|
||||||
|
@ -15,12 +16,24 @@ extension ExtraCoordinateFormat on CoordinateFormat {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
String format(LatLng latLng, {bool minuteSecondPadding = false, int dmsSecondDecimals = 2}) {
|
String format(AppLocalizations l10n, LatLng latLng, {bool minuteSecondPadding = false, int dmsSecondDecimals = 2}) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case CoordinateFormat.dms:
|
case CoordinateFormat.dms:
|
||||||
return GeoUtils.toDMS(latLng, minuteSecondPadding: minuteSecondPadding, secondDecimals: dmsSecondDecimals).join(', ');
|
return toDMS(l10n, latLng, minuteSecondPadding: minuteSecondPadding, secondDecimals: dmsSecondDecimals).join(', ');
|
||||||
case CoordinateFormat.decimal:
|
case CoordinateFormat.decimal:
|
||||||
return [latLng.latitude, latLng.longitude].map((n) => n.toStringAsFixed(6)).join(', ');
|
return [latLng.latitude, latLng.longitude].map((n) => n.toStringAsFixed(6)).join(', ');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// returns coordinates formatted as DMS, e.g. ['41° 24′ 12.2″ N', '2° 10′ 26.5″ E']
|
||||||
|
static List<String> toDMS(AppLocalizations l10n, LatLng latLng, {bool minuteSecondPadding = false, int secondDecimals = 2}) {
|
||||||
|
final lat = latLng.latitude;
|
||||||
|
final lng = latLng.longitude;
|
||||||
|
final latSexa = GeoUtils.decimal2sexagesimal(lat, minuteSecondPadding, secondDecimals);
|
||||||
|
final lngSexa = GeoUtils.decimal2sexagesimal(lng, minuteSecondPadding, secondDecimals);
|
||||||
|
return [
|
||||||
|
l10n.coordinateDms(latSexa, lat < 0 ? l10n.coordinateDmsSouth : l10n.coordinateDmsNorth),
|
||||||
|
l10n.coordinateDms(lngSexa, lng < 0 ? l10n.coordinateDmsWest : l10n.coordinateDmsEast),
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -5,7 +5,7 @@ import 'package:intl/intl.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
|
|
||||||
class GeoUtils {
|
class GeoUtils {
|
||||||
static String _decimal2sexagesimal(final double degDecimal, final bool minuteSecondPadding, final int secondDecimals) {
|
static String decimal2sexagesimal(final double degDecimal, final bool minuteSecondPadding, final int secondDecimals) {
|
||||||
List<int> _split(final double value) {
|
List<int> _split(final double value) {
|
||||||
// NumberFormat is necessary to create digit after comma if the value
|
// NumberFormat is necessary to create digit after comma if the value
|
||||||
// has no decimal point (only necessary for browser)
|
// has no decimal point (only necessary for browser)
|
||||||
|
@ -32,16 +32,6 @@ class GeoUtils {
|
||||||
return '$deg° $minText′ $secText″';
|
return '$deg° $minText′ $secText″';
|
||||||
}
|
}
|
||||||
|
|
||||||
// returns coordinates formatted as DMS, e.g. ['41° 24′ 12.2″ N', '2° 10′ 26.5″ E']
|
|
||||||
static List<String> toDMS(LatLng latLng, {bool minuteSecondPadding = false, int secondDecimals = 2}) {
|
|
||||||
final lat = latLng.latitude;
|
|
||||||
final lng = latLng.longitude;
|
|
||||||
return [
|
|
||||||
'${_decimal2sexagesimal(lat, minuteSecondPadding, secondDecimals)} ${lat < 0 ? 'S' : 'N'}',
|
|
||||||
'${_decimal2sexagesimal(lng, minuteSecondPadding, secondDecimals)} ${lng < 0 ? 'W' : 'E'}',
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
static LatLng getLatLngCenter(List<LatLng> points) {
|
static LatLng getLatLngCenter(List<LatLng> points) {
|
||||||
double x = 0;
|
double x = 0;
|
||||||
double y = 0;
|
double y = 0;
|
||||||
|
|
|
@ -121,7 +121,7 @@ class _AddressRowState extends State<_AddressRow> {
|
||||||
? Constants.overlayUnknown
|
? Constants.overlayUnknown
|
||||||
: entry.hasAddress
|
: entry.hasAddress
|
||||||
? entry.shortAddress
|
? entry.shortAddress
|
||||||
: settings.coordinateFormat.format(entry.latLng!));
|
: settings.coordinateFormat.format(context.l10n, entry.latLng!));
|
||||||
return Text(
|
return Text(
|
||||||
location,
|
location,
|
||||||
strutStyle: Constants.overflowStrutStyle,
|
strutStyle: Constants.overflowStrutStyle,
|
||||||
|
|
|
@ -23,6 +23,7 @@ class LanguageSection extends StatelessWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
|
final l10n = context.l10n;
|
||||||
final currentCoordinateFormat = context.select<Settings, CoordinateFormat>((s) => s.coordinateFormat);
|
final currentCoordinateFormat = context.select<Settings, CoordinateFormat>((s) => s.coordinateFormat);
|
||||||
final currentUnitSystem = context.select<Settings, UnitSystem>((s) => s.unitSystem);
|
final currentUnitSystem = context.select<Settings, UnitSystem>((s) => s.unitSystem);
|
||||||
|
|
||||||
|
@ -34,13 +35,13 @@ class LanguageSection extends StatelessWidget {
|
||||||
icon: AIcons.language,
|
icon: AIcons.language,
|
||||||
color: stringToColor('Language'),
|
color: stringToColor('Language'),
|
||||||
),
|
),
|
||||||
title: context.l10n.settingsSectionLanguage,
|
title: l10n.settingsSectionLanguage,
|
||||||
expandedNotifier: expandedNotifier,
|
expandedNotifier: expandedNotifier,
|
||||||
showHighlight: false,
|
showHighlight: false,
|
||||||
children: [
|
children: [
|
||||||
const LocaleTile(),
|
const LocaleTile(),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(context.l10n.settingsCoordinateFormatTile),
|
title: Text(l10n.settingsCoordinateFormatTile),
|
||||||
subtitle: Text(currentCoordinateFormat.getName(context)),
|
subtitle: Text(currentCoordinateFormat.getName(context)),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final value = await showDialog<CoordinateFormat>(
|
final value = await showDialog<CoordinateFormat>(
|
||||||
|
@ -48,8 +49,8 @@ class LanguageSection extends StatelessWidget {
|
||||||
builder: (context) => AvesSelectionDialog<CoordinateFormat>(
|
builder: (context) => AvesSelectionDialog<CoordinateFormat>(
|
||||||
initialValue: currentCoordinateFormat,
|
initialValue: currentCoordinateFormat,
|
||||||
options: Map.fromEntries(CoordinateFormat.values.map((v) => MapEntry(v, v.getName(context)))),
|
options: Map.fromEntries(CoordinateFormat.values.map((v) => MapEntry(v, v.getName(context)))),
|
||||||
optionSubtitleBuilder: (value) => value.format(Constants.pointNemo),
|
optionSubtitleBuilder: (value) => value.format(l10n, Constants.pointNemo),
|
||||||
title: context.l10n.settingsCoordinateFormatTitle,
|
title: l10n.settingsCoordinateFormatTitle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
@ -58,7 +59,7 @@ class LanguageSection extends StatelessWidget {
|
||||||
},
|
},
|
||||||
),
|
),
|
||||||
ListTile(
|
ListTile(
|
||||||
title: Text(context.l10n.settingsUnitSystemTile),
|
title: Text(l10n.settingsUnitSystemTile),
|
||||||
subtitle: Text(currentUnitSystem.getName(context)),
|
subtitle: Text(currentUnitSystem.getName(context)),
|
||||||
onTap: () async {
|
onTap: () async {
|
||||||
final value = await showDialog<UnitSystem>(
|
final value = await showDialog<UnitSystem>(
|
||||||
|
@ -66,7 +67,7 @@ class LanguageSection extends StatelessWidget {
|
||||||
builder: (context) => AvesSelectionDialog<UnitSystem>(
|
builder: (context) => AvesSelectionDialog<UnitSystem>(
|
||||||
initialValue: currentUnitSystem,
|
initialValue: currentUnitSystem,
|
||||||
options: Map.fromEntries(UnitSystem.values.map((v) => MapEntry(v, v.getName(context)))),
|
options: Map.fromEntries(UnitSystem.values.map((v) => MapEntry(v, v.getName(context)))),
|
||||||
title: context.l10n.settingsUnitSystemTitle,
|
title: l10n.settingsUnitSystemTitle,
|
||||||
),
|
),
|
||||||
);
|
);
|
||||||
if (value != null) {
|
if (value != null) {
|
||||||
|
|
|
@ -174,7 +174,7 @@ class _AddressInfoGroupState extends State<_AddressInfoGroup> {
|
||||||
final l10n = context.l10n;
|
final l10n = context.l10n;
|
||||||
return InfoRowGroup(
|
return InfoRowGroup(
|
||||||
info: {
|
info: {
|
||||||
l10n.viewerInfoLabelCoordinates: settings.coordinateFormat.format(entry.latLng!),
|
l10n.viewerInfoLabelCoordinates: settings.coordinateFormat.format(l10n, entry.latLng!),
|
||||||
if (address.isNotEmpty) l10n.viewerInfoLabelAddress: address,
|
if (address.isNotEmpty) l10n.viewerInfoLabelAddress: address,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
|
@ -323,7 +323,7 @@ class _LocationRow extends AnimatedWidget {
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
final location = entry.hasAddress ? entry.shortAddress : settings.coordinateFormat.format(entry.latLng!);
|
final location = entry.hasAddress ? entry.shortAddress : settings.coordinateFormat.format(context.l10n, entry.latLng!);
|
||||||
return Row(
|
return Row(
|
||||||
children: [
|
children: [
|
||||||
const DecoratedIcon(AIcons.location, shadows: Constants.embossShadows, size: _iconSize),
|
const DecoratedIcon(AIcons.location, shadows: Constants.embossShadows, size: _iconSize),
|
||||||
|
|
|
@ -1,14 +1,17 @@
|
||||||
|
import 'package:aves/model/settings/coordinate_format.dart';
|
||||||
import 'package:aves/utils/geo_utils.dart';
|
import 'package:aves/utils/geo_utils.dart';
|
||||||
|
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
|
||||||
import 'package:latlong2/latlong.dart';
|
import 'package:latlong2/latlong.dart';
|
||||||
import 'package:test/test.dart';
|
import 'package:test/test.dart';
|
||||||
|
|
||||||
void main() {
|
void main() {
|
||||||
test('Decimal degrees to DMS (sexagesimal)', () {
|
test('Decimal degrees to DMS (sexagesimal)', () {
|
||||||
expect(GeoUtils.toDMS(LatLng(37.496667, 127.0275)), ['37° 29′ 48.00″ N', '127° 1′ 39.00″ E']); // Gangnam
|
final l10n = lookupAppLocalizations(AppLocalizations.supportedLocales.first);
|
||||||
expect(GeoUtils.toDMS(LatLng(78.9243503, 11.9230465)), ['78° 55′ 27.66″ N', '11° 55′ 22.97″ E']); // Ny-Ålesund
|
expect(ExtraCoordinateFormat.toDMS(l10n, LatLng(37.496667, 127.0275)), ['37° 29′ 48.00″ N', '127° 1′ 39.00″ E']); // Gangnam
|
||||||
expect(GeoUtils.toDMS(LatLng(-38.6965891, 175.9830047)), ['38° 41′ 47.72″ S', '175° 58′ 58.82″ E']); // Taupo
|
expect(ExtraCoordinateFormat.toDMS(l10n, LatLng(78.9243503, 11.9230465)), ['78° 55′ 27.66″ N', '11° 55′ 22.97″ E']); // Ny-Ålesund
|
||||||
expect(GeoUtils.toDMS(LatLng(-64.249391, -56.6556145)), ['64° 14′ 57.81″ S', '56° 39′ 20.21″ W']); // Marambio
|
expect(ExtraCoordinateFormat.toDMS(l10n, LatLng(-38.6965891, 175.9830047)), ['38° 41′ 47.72″ S', '175° 58′ 58.82″ E']); // Taupo
|
||||||
expect(GeoUtils.toDMS(LatLng(0, 0)), ['0° 0′ 0.00″ N', '0° 0′ 0.00″ E']);
|
expect(ExtraCoordinateFormat.toDMS(l10n, LatLng(-64.249391, -56.6556145)), ['64° 14′ 57.81″ S', '56° 39′ 20.21″ W']); // Marambio
|
||||||
|
expect(ExtraCoordinateFormat.toDMS(l10n, LatLng(0, 0)), ['0° 0′ 0.00″ N', '0° 0′ 0.00″ E']);
|
||||||
});
|
});
|
||||||
|
|
||||||
test('bounds center', () {
|
test('bounds center', () {
|
||||||
|
|
Loading…
Reference in a new issue