From 6a5b0770e05574652883e0393a0b386123f9ba1e Mon Sep 17 00:00:00 2001 From: Thibault Deckers Date: Mon, 13 Jan 2025 10:40:23 +0100 Subject: [PATCH] #1382 DDM coordinate format --- CHANGELOG.md | 4 ++ lib/l10n/app_en.arb | 1 + lib/model/filters/coordinate.dart | 15 +++++--- .../settings/enums/coordinate_format.dart | 37 +++++++++++++++++-- lib/view/src/settings/enums.dart | 1 + .../aves_model/lib/src/settings/enums.dart | 2 +- .../aves_video_mpv/lib/src/controller.dart | 6 +++ test/utils/geo_utils_test.dart | 12 ++++++ 8 files changed, 68 insertions(+), 10 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 31d4e2074..568674e5f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. ## [Unreleased] +### Added + +- DDM coordinate format option + ### Changed - Video: use `media-kit` instead of `ffmpeg-kit` for metadata fetch diff --git a/lib/l10n/app_en.arb b/lib/l10n/app_en.arb index 7ab3fc430..2cced4ee7 100644 --- a/lib/l10n/app_en.arb +++ b/lib/l10n/app_en.arb @@ -210,6 +210,7 @@ "albumTierRegular": "Others", "coordinateFormatDms": "DMS", + "coordinateFormatDdm": "DDM", "coordinateFormatDecimal": "Decimal degrees", "coordinateDms": "{coordinate} {direction}", "@coordinateDms": { diff --git a/lib/model/filters/coordinate.dart b/lib/model/filters/coordinate.dart index c8ba7f2a7..3eea4e5d8 100644 --- a/lib/model/filters/coordinate.dart +++ b/lib/model/filters/coordinate.dart @@ -60,12 +60,15 @@ class CoordinateFilter extends CollectionFilter { @override String getLabel(BuildContext context) { - return _formatBounds((latLng) => settings.coordinateFormat.format( - context, - latLng, - minuteSecondPadding: minuteSecondPadding, - dmsSecondDecimals: 0, - )); + return _formatBounds((latLng) { + final format = settings.coordinateFormat; + return format.format( + context, + latLng, + minuteSecondPadding: minuteSecondPadding, + dmsSecondDecimals: format == CoordinateFormat.ddm ? 2 : 0, + ); + }); } @override diff --git a/lib/model/settings/enums/coordinate_format.dart b/lib/model/settings/enums/coordinate_format.dart index bf3a5b6ec..2572bacfb 100644 --- a/lib/model/settings/enums/coordinate_format.dart +++ b/lib/model/settings/enums/coordinate_format.dart @@ -8,15 +8,17 @@ import 'package:latlong2/latlong.dart'; extension ExtraCoordinateFormat on CoordinateFormat { static const _separator = ', '; - String format(BuildContext context, LatLng latLng, {bool minuteSecondPadding = false, int dmsSecondDecimals = 2}) { + String format(BuildContext context, LatLng latLng, {bool minuteSecondPadding = false, int? dmsSecondDecimals}) { final text = formatWithoutDirectionality(context.l10n, latLng, minuteSecondPadding: minuteSecondPadding, dmsSecondDecimals: dmsSecondDecimals); return context.applyDirectionality(text); } - String formatWithoutDirectionality(AppLocalizations l10n, LatLng latLng, {bool minuteSecondPadding = false, int dmsSecondDecimals = 2}) { + String formatWithoutDirectionality(AppLocalizations l10n, LatLng latLng, {bool minuteSecondPadding = false, int? dmsSecondDecimals}) { switch (this) { case CoordinateFormat.dms: - return toDMS(l10n, latLng, minuteSecondPadding: minuteSecondPadding, secondDecimals: dmsSecondDecimals).join(_separator); + return toDMS(l10n, latLng, minuteSecondPadding: minuteSecondPadding, secondDecimals: dmsSecondDecimals ?? 2).join(_separator); + case CoordinateFormat.ddm: + return toDDM(l10n, latLng, minutePadding: minuteSecondPadding, minuteDecimals: dmsSecondDecimals ?? 4).join(_separator); case CoordinateFormat.decimal: return _toDecimal(l10n, latLng).join(_separator); } @@ -35,6 +37,19 @@ extension ExtraCoordinateFormat on CoordinateFormat { ]; } + // returns coordinates formatted as DDM, e.g. ['41° 24.2028′ N', '2° 10.4418′ E'] + static List toDDM(AppLocalizations l10n, LatLng latLng, {bool minutePadding = false, int minuteDecimals = 4}) { + final locale = l10n.localeName; + final lat = latLng.latitude; + final lng = latLng.longitude; + final latSexa = _decimal2ddm(lat, minutePadding, minuteDecimals, locale); + final lngSexa = _decimal2ddm(lng, minutePadding, minuteDecimals, locale); + return [ + l10n.coordinateDms(latSexa, lat < 0 ? l10n.coordinateDmsSouth : l10n.coordinateDmsNorth), + l10n.coordinateDms(lngSexa, lng < 0 ? l10n.coordinateDmsWest : l10n.coordinateDmsEast), + ]; + } + static String _decimal2sexagesimal( double degDecimal, bool minuteSecondPadding, @@ -54,6 +69,22 @@ extension ExtraCoordinateFormat on CoordinateFormat { return '$degText° $minText′ $secText″'; } + static String _decimal2ddm( + double degDecimal, + bool minutePadding, + int minuteDecimals, + String locale, + ) { + final degAbs = degDecimal.abs(); + final deg = degAbs.toInt(); + final min = (degAbs - deg) * 60; + + final degText = NumberFormat('0', locale).format(deg); + final minText = NumberFormat('${'0' * (minutePadding ? 2 : 1)}${minuteDecimals > 0 ? '.${'0' * minuteDecimals}' : ''}', locale).format(min); + + return '$degText° $minText′'; + } + static List _toDecimal(AppLocalizations l10n, LatLng latLng) { final coordinateFormatter = NumberFormat('0.000000°', l10n.localeName); return [ diff --git a/lib/view/src/settings/enums.dart b/lib/view/src/settings/enums.dart index 10854be4c..93aec5091 100644 --- a/lib/view/src/settings/enums.dart +++ b/lib/view/src/settings/enums.dart @@ -45,6 +45,7 @@ extension ExtraCoordinateFormatView on CoordinateFormat { final l10n = context.l10n; return switch (this) { CoordinateFormat.dms => l10n.coordinateFormatDms, + CoordinateFormat.ddm => l10n.coordinateFormatDdm, CoordinateFormat.decimal => l10n.coordinateFormatDecimal, }; } diff --git a/plugins/aves_model/lib/src/settings/enums.dart b/plugins/aves_model/lib/src/settings/enums.dart index 196d57774..73bf6dbaa 100644 --- a/plugins/aves_model/lib/src/settings/enums.dart +++ b/plugins/aves_model/lib/src/settings/enums.dart @@ -8,7 +8,7 @@ enum AvesThemeColorMode { monochrome, polychrome } enum ConfirmationDialog { createVault, deleteForever, moveToBin, moveUndatedItems } -enum CoordinateFormat { dms, decimal } +enum CoordinateFormat { dms, ddm, decimal } enum DisplayRefreshRateMode { auto, highest, lowest } diff --git a/plugins/aves_video_mpv/lib/src/controller.dart b/plugins/aves_video_mpv/lib/src/controller.dart index 621f23506..b16920865 100644 --- a/plugins/aves_video_mpv/lib/src/controller.dart +++ b/plugins/aves_video_mpv/lib/src/controller.dart @@ -162,6 +162,12 @@ class MpvVideoController extends AvesVideoController { Future _init({int startMillis = 0}) async { final playing = _instance.state.playing; + // Audio quality is better with `audiotrack` than `opensles` (the default). + // Calling `setAudioDevice` does not seem to work. + // As of 2025/01/13, directly setting audio output via property works for some files but not all, + // and switching from a supported file to an unsupported file crashes: + // cf https://github.com/media-kit/media-kit/issues/1061 + await _applyLoop(); await _instance.open(Media(entry.uri), play: playing); await _instance.setSubtitleTrack(SubtitleTrack.no()); diff --git a/test/utils/geo_utils_test.dart b/test/utils/geo_utils_test.dart index 11f862a32..c34381364 100644 --- a/test/utils/geo_utils_test.dart +++ b/test/utils/geo_utils_test.dart @@ -18,6 +18,18 @@ void main() { expect(ExtraCoordinateFormat.toDMS(l10n, const LatLng(0, 0), secondDecimals: 4), ['0° 0′ 0.0000″ N', '0° 0′ 0.0000″ E']); }); + test('Decimal degrees to DDM', () { + final l10n = lookupAppLocalizations(AvesApp.supportedLocales.first); + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(37.496667, 127.0275)), ['37° 29.8000′ N', '127° 1.6500′ E']); // Gangnam + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(78.9243503, 11.9230465)), ['78° 55.4610′ N', '11° 55.3828′ E']); // Ny-Ålesund + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(-38.6965891, 175.9830047)), ['38° 41.7953′ S', '175° 58.9803′ E']); // Taupo + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(-64.249391, -56.6556145)), ['64° 14.9635′ S', '56° 39.3369′ W']); // Marambio + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(0, 0)), ['0° 0.0000′ N', '0° 0.0000′ E']); + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(0, 0), minutePadding: true), ['0° 00.0000′ N', '0° 00.0000′ E']); + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(0, 0), minuteDecimals: 0), ['0° 0′ N', '0° 0′ E']); + expect(ExtraCoordinateFormat.toDDM(l10n, const LatLng(0, 0), minuteDecimals: 6), ['0° 0.000000′ N', '0° 0.000000′ E']); + }); + test('bounds center', () { expect(GeoUtils.getLatLngCenter(const [LatLng(10, 30), LatLng(30, 50)]), const LatLng(20.28236664671092, 39.351653000319956)); expect(GeoUtils.getLatLngCenter(const [LatLng(10, -179), LatLng(30, 179)]), const LatLng(20.00279344048298, -179.9358157370226));