settings: unit system
This commit is contained in:
parent
9a2451ea0c
commit
718b4749a0
10 changed files with 96 additions and 9 deletions
|
@ -173,6 +173,11 @@
|
|||
"coordinateFormatDecimal": "Decimal degrees",
|
||||
"@coordinateFormatDecimal": {},
|
||||
|
||||
"unitSystemMetric": "Metric",
|
||||
"@unitSystemMetric": {},
|
||||
"unitSystemImperial": "Imperial",
|
||||
"@unitSystemImperial": {},
|
||||
|
||||
"videoLoopModeNever": "Never",
|
||||
"@videoLoopModeNever": {},
|
||||
"videoLoopModeShortOnly": "Short videos only",
|
||||
|
@ -835,6 +840,10 @@
|
|||
"@settingsCoordinateFormatTile": {},
|
||||
"settingsCoordinateFormatTitle": "Coordinate Format",
|
||||
"@settingsCoordinateFormatTitle": {},
|
||||
"settingsUnitSystemTile": "Units",
|
||||
"@settingsUnitSystemTile": {},
|
||||
"settingsUnitSystemTitle": "Units",
|
||||
"@settingsUnitSystemTitle": {},
|
||||
|
||||
"statsPageTitle": "Stats",
|
||||
"@statsPageTitle": {},
|
||||
|
|
|
@ -86,6 +86,9 @@
|
|||
"coordinateFormatDms": "도분초",
|
||||
"coordinateFormatDecimal": "소수점",
|
||||
|
||||
"unitSystemMetric": "미터법",
|
||||
"unitSystemImperial": "야드파운드법",
|
||||
|
||||
"videoLoopModeNever": "반복 안 함",
|
||||
"videoLoopModeShortOnly": "짧은 동영상만 반복",
|
||||
"videoLoopModeAlways": "항상 반복",
|
||||
|
@ -409,6 +412,8 @@
|
|||
"settingsLanguage": "언어",
|
||||
"settingsCoordinateFormatTile": "좌표 표현",
|
||||
"settingsCoordinateFormatTitle": "좌표 표현",
|
||||
"settingsUnitSystemTile": "단위법",
|
||||
"settingsUnitSystemTitle": "단위법",
|
||||
|
||||
"statsPageTitle": "통계",
|
||||
"statsImage": "{count, plural, other{사진}}",
|
||||
|
|
|
@ -82,6 +82,7 @@ class SettingsDefaults {
|
|||
static const infoMapStyle = EntryMapStyle.stamenWatercolor; // `infoMapStyle` has a contextual default value
|
||||
static const infoMapZoom = 12.0;
|
||||
static const coordinateFormat = CoordinateFormat.dms;
|
||||
static const unitSystem = UnitSystem.metric;
|
||||
|
||||
// rendering
|
||||
static const imageBackground = EntryBackground.white;
|
||||
|
|
|
@ -13,4 +13,6 @@ enum EntryMapStyle { googleNormal, googleHybrid, googleTerrain, osmHot, stamenTo
|
|||
|
||||
enum KeepScreenOn { never, viewerOnly, always }
|
||||
|
||||
enum UnitSystem { metric, imperial }
|
||||
|
||||
enum VideoLoopMode { never, shortOnly, always }
|
||||
|
|
|
@ -98,6 +98,7 @@ class Settings extends ChangeNotifier {
|
|||
static const infoMapStyleKey = 'info_map_style';
|
||||
static const infoMapZoomKey = 'info_map_zoom';
|
||||
static const coordinateFormatKey = 'coordinates_format';
|
||||
static const unitSystemKey = 'unit_system';
|
||||
|
||||
// rendering
|
||||
static const imageBackgroundKey = 'image_background';
|
||||
|
@ -379,6 +380,10 @@ class Settings extends ChangeNotifier {
|
|||
|
||||
set coordinateFormat(CoordinateFormat newValue) => setAndNotify(coordinateFormatKey, newValue.toString());
|
||||
|
||||
UnitSystem get unitSystem => getEnumOrDefault(unitSystemKey, SettingsDefaults.unitSystem, UnitSystem.values);
|
||||
|
||||
set unitSystem(UnitSystem newValue) => setAndNotify(unitSystemKey, newValue.toString());
|
||||
|
||||
// rendering
|
||||
|
||||
EntryBackground get imageBackground => getEnumOrDefault(imageBackgroundKey, SettingsDefaults.imageBackground, EntryBackground.values);
|
||||
|
@ -574,6 +579,7 @@ class Settings extends ChangeNotifier {
|
|||
case subtitleTextAlignmentKey:
|
||||
case infoMapStyleKey:
|
||||
case coordinateFormatKey:
|
||||
case unitSystemKey:
|
||||
case imageBackgroundKey:
|
||||
case accessibilityAnimationsKey:
|
||||
case timeToTakeActionKey:
|
||||
|
|
15
lib/model/settings/unit_system.dart
Normal file
15
lib/model/settings/unit_system.dart
Normal file
|
@ -0,0 +1,15 @@
|
|||
import 'package:aves/widgets/common/extensions/build_context.dart';
|
||||
import 'package:flutter/widgets.dart';
|
||||
|
||||
import 'enums.dart';
|
||||
|
||||
extension ExtraUnitSystem on UnitSystem {
|
||||
String getName(BuildContext context) {
|
||||
switch (this) {
|
||||
case UnitSystem.metric:
|
||||
return context.l10n.unitSystemMetric;
|
||||
case UnitSystem.imperial:
|
||||
return context.l10n.unitSystemImperial;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ import 'dart:async';
|
|||
|
||||
import 'package:aves/model/entry.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/theme/durations.dart';
|
||||
import 'package:aves/utils/debouncer.dart';
|
||||
import 'package:aves/widgets/common/map/buttons.dart';
|
||||
|
@ -163,7 +164,9 @@ class _EntryLeafletMapState extends State<EntryLeafletMap> with TickerProviderSt
|
|||
mapController: _leafletMapController,
|
||||
nonRotatedChildren: [
|
||||
ScaleLayerWidget(
|
||||
options: ScaleLayerOptions(),
|
||||
options: ScaleLayerOptions(
|
||||
unitSystem: settings.unitSystem,
|
||||
),
|
||||
),
|
||||
],
|
||||
children: [
|
||||
|
|
|
@ -1,5 +1,4 @@
|
|||
import 'dart:math';
|
||||
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/widgets/common/basic/outlined_text.dart';
|
||||
import 'package:aves/widgets/common/map/leaflet/scalebar_utils.dart';
|
||||
import 'package:flutter/material.dart';
|
||||
|
@ -7,10 +6,12 @@ import 'package:flutter_map/flutter_map.dart';
|
|||
import 'package:flutter_map/plugin_api.dart';
|
||||
|
||||
class ScaleLayerOptions extends LayerOptions {
|
||||
final UnitSystem unitSystem;
|
||||
final Widget Function(double width, String distance) builder;
|
||||
|
||||
ScaleLayerOptions({
|
||||
Key? key,
|
||||
this.unitSystem = UnitSystem.metric,
|
||||
this.builder = defaultBuilder,
|
||||
rebuild,
|
||||
}) : super(key: key, rebuild: rebuild);
|
||||
|
@ -41,7 +42,7 @@ class ScaleLayer extends StatelessWidget {
|
|||
|
||||
// ignore: prefer_void_to_null
|
||||
final Stream<Null> stream;
|
||||
final scale = [
|
||||
static const List<double> scaleMeters = [
|
||||
25000000,
|
||||
15000000,
|
||||
8000000,
|
||||
|
@ -67,6 +68,10 @@ class ScaleLayer extends StatelessWidget {
|
|||
5,
|
||||
];
|
||||
|
||||
static const double metersInAKilometer = 1000;
|
||||
static const double metersInAMile = 1609.344;
|
||||
static const double metersInAFoot = 0.3048;
|
||||
|
||||
ScaleLayer(this.scaleLayerOpts, this.map, this.stream) : super(key: scaleLayerOpts.key);
|
||||
|
||||
@override
|
||||
|
@ -83,11 +88,33 @@ class ScaleLayer extends StatelessWidget {
|
|||
: latitude > 60
|
||||
? 3
|
||||
: 2);
|
||||
final distance = scale[max(0, min(20, level))].toDouble();
|
||||
final scaleLevel = level.clamp(0, 20);
|
||||
late final double distanceMeters;
|
||||
late final String displayDistance;
|
||||
switch (scaleLayerOpts.unitSystem) {
|
||||
case UnitSystem.metric:
|
||||
// meters
|
||||
distanceMeters = scaleMeters[scaleLevel];
|
||||
displayDistance = distanceMeters >= metersInAKilometer ? '${(distanceMeters / metersInAKilometer).toStringAsFixed(0)} km' : '${distanceMeters.toStringAsFixed(0)} m';
|
||||
break;
|
||||
case UnitSystem.imperial:
|
||||
if (scaleLevel < 15) {
|
||||
// miles
|
||||
final distanceMiles = scaleMeters[scaleLevel + 1] / 1000;
|
||||
distanceMeters = distanceMiles * metersInAMile;
|
||||
displayDistance = '${distanceMiles.toStringAsFixed(0)} mi';
|
||||
} else {
|
||||
// feet
|
||||
final distanceFeet = scaleMeters[scaleLevel - 1];
|
||||
distanceMeters = distanceFeet * metersInAFoot;
|
||||
displayDistance = '${distanceFeet.toStringAsFixed(0)} ft';
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
final start = map.project(center);
|
||||
final targetPoint = ScaleBarUtils.calculateEndingGlobalCoordinates(center, 90, distance);
|
||||
final targetPoint = ScaleBarUtils.calculateEndingGlobalCoordinates(center, 90, distanceMeters);
|
||||
final end = map.project(targetPoint);
|
||||
final displayDistance = distance > 999 ? '${(distance / 1000).toStringAsFixed(0)} km' : '${distance.toStringAsFixed(0)} m';
|
||||
final width = end.x - (start.x as double);
|
||||
|
||||
return scaleLayerOpts.builder(width, displayDistance);
|
||||
|
|
|
@ -3,7 +3,7 @@ import 'dart:math';
|
|||
import 'package:latlong2/latlong.dart';
|
||||
|
||||
class ScaleBarUtils {
|
||||
static LatLng calculateEndingGlobalCoordinates(LatLng start, double startBearing, double distance) {
|
||||
static LatLng calculateEndingGlobalCoordinates(LatLng start, double startBearing, double distanceMeters) {
|
||||
var mSemiMajorAxis = 6378137.0; //WGS84 major axis
|
||||
var mSemiMinorAxis = (1.0 - 1.0 / 298.257223563) * 6378137.0;
|
||||
var mFlattening = 1.0 / 298.257223563;
|
||||
|
@ -18,7 +18,7 @@ class ScaleBarUtils {
|
|||
var alpha1 = degToRadian(startBearing);
|
||||
var cosAlpha1 = cos(alpha1);
|
||||
var sinAlpha1 = sin(alpha1);
|
||||
var s = distance;
|
||||
var s = distanceMeters;
|
||||
var tanU1 = (1.0 - f) * tan(phi1);
|
||||
var cosU1 = 1.0 / sqrt(1.0 + tanU1 * tanU1);
|
||||
var sinU1 = tanU1 * cosU1;
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
import 'package:aves/model/settings/coordinate_format.dart';
|
||||
import 'package:aves/model/settings/enums.dart';
|
||||
import 'package:aves/model/settings/settings.dart';
|
||||
import 'package:aves/model/settings/unit_system.dart';
|
||||
import 'package:aves/theme/icons.dart';
|
||||
import 'package:aves/utils/color_utils.dart';
|
||||
import 'package:aves/utils/constants.dart';
|
||||
|
@ -23,6 +24,7 @@ class LanguageSection extends StatelessWidget {
|
|||
@override
|
||||
Widget build(BuildContext context) {
|
||||
final currentCoordinateFormat = context.select<Settings, CoordinateFormat>((s) => s.coordinateFormat);
|
||||
final currentUnitSystem = context.select<Settings, UnitSystem>((s) => s.unitSystem);
|
||||
|
||||
return AvesExpansionTile(
|
||||
// use a fixed value instead of the title to identify this expansion tile
|
||||
|
@ -55,6 +57,23 @@ class LanguageSection extends StatelessWidget {
|
|||
}
|
||||
},
|
||||
),
|
||||
ListTile(
|
||||
title: Text(context.l10n.settingsUnitSystemTile),
|
||||
subtitle: Text(currentUnitSystem.getName(context)),
|
||||
onTap: () async {
|
||||
final value = await showDialog<UnitSystem>(
|
||||
context: context,
|
||||
builder: (context) => AvesSelectionDialog<UnitSystem>(
|
||||
initialValue: currentUnitSystem,
|
||||
options: Map.fromEntries(UnitSystem.values.map((v) => MapEntry(v, v.getName(context)))),
|
||||
title: context.l10n.settingsUnitSystemTitle,
|
||||
),
|
||||
);
|
||||
if (value != null) {
|
||||
settings.unitSystem = value;
|
||||
}
|
||||
},
|
||||
),
|
||||
],
|
||||
);
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue