From a5b44175a31b78dda9fd1ada396ec8e7b9c23514 Mon Sep 17 00:00:00 2001 From: Dennis Guse Date: Tue, 26 Apr 2022 22:00:53 +0200 Subject: [PATCH] Convert metricUnits boolean into an enum. Fixes #1199. --- ...ule.java => PreferenceUnitSystemRule.java} | 15 +- .../opentracks/chart/ChartPointTest.java | 11 +- .../data/models/DistanceFormatterTest.java | 6 +- .../data/models/SpeedFormatterTest.java | 12 +- ...cordingServiceNotificationManagerTest.java | 3 +- .../VoiceAnnouncementUtilsTest.java | 19 +- .../viewmodels/StatisticDataBuilderTest.java | 5 +- .../de/dennisguse/opentracks/Startup.java | 6 +- .../opentracks/TrackListActivity.java | 7 +- .../opentracks/chart/ChartFragment.java | 9 +- .../opentracks/chart/ChartPoint.java | 11 +- .../opentracks/chart/ChartValueSeries.java | 15 +- .../opentracks/chart/ChartView.java | 31 +-- .../opentracks/data/models/Distance.java | 37 +++- .../data/models/DistanceFormatter.java | 56 ++++-- .../opentracks/data/models/Speed.java | 33 +-- .../data/models/SpeedFormatter.java | 36 ++-- .../fragments/StatisticsRecordedFragment.java | 13 +- .../StatisticsRecordingFragment.java | 7 +- ...ckRecordingServiceNotificationManager.java | 13 +- .../announcement/VoiceAnnouncement.java | 7 +- .../announcement/VoiceAnnouncementUtils.java | 46 +++-- .../settings/DefaultsSettingsFragment.java | 17 +- .../settings/GpsSettingsFragment.java | 4 +- .../opentracks/settings/PreferencesUtils.java | 190 +++++++++++------- .../opentracks/settings/UnitSystem.java | 23 +++ .../share/DescriptionGenerator.java | 5 +- .../AggregatedStatisticsAdapter.java | 11 +- .../intervals/IntervalStatisticsAdapter.java | 19 +- .../ui/intervals/IntervalStatisticsModel.java | 13 +- .../ui/intervals/IntervalsFragment.java | 29 +-- .../opentracks/util/StringUtils.java | 37 +--- .../viewmodels/StatisticDataBuilder.java | 31 +-- .../viewmodels/StatisticsDataModel.java | 5 +- 34 files changed, 464 insertions(+), 318 deletions(-) rename src/androidTest/java/de/dennisguse/opentracks/{PreferenceMetricUnitRule.java => PreferenceUnitSystemRule.java} (56%) create mode 100644 src/main/java/de/dennisguse/opentracks/settings/UnitSystem.java diff --git a/src/androidTest/java/de/dennisguse/opentracks/PreferenceMetricUnitRule.java b/src/androidTest/java/de/dennisguse/opentracks/PreferenceUnitSystemRule.java similarity index 56% rename from src/androidTest/java/de/dennisguse/opentracks/PreferenceMetricUnitRule.java rename to src/androidTest/java/de/dennisguse/opentracks/PreferenceUnitSystemRule.java index d382c6262..0e5fedaec 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/PreferenceMetricUnitRule.java +++ b/src/androidTest/java/de/dennisguse/opentracks/PreferenceUnitSystemRule.java @@ -5,12 +5,13 @@ import org.junit.runner.Description; import org.junit.runners.model.Statement; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; -public class PreferenceMetricUnitRule implements TestRule { - private final boolean metricUnits; +public class PreferenceUnitSystemRule implements TestRule { + private final UnitSystem unit; - public PreferenceMetricUnitRule(boolean metricUnits) { - this.metricUnits = metricUnits; + public PreferenceUnitSystemRule(UnitSystem unit) { + this.unit = unit; } @Override @@ -18,13 +19,13 @@ public class PreferenceMetricUnitRule implements TestRule { return new Statement() { @Override public void evaluate() throws Throwable { - final boolean previousMetricUnits = PreferencesUtils.isMetricUnits(); + final UnitSystem previousUnitSystem = PreferencesUtils.getUnitSystem(); try { - PreferencesUtils.setMetricUnits(metricUnits); + PreferencesUtils.setUnit(unit); base.evaluate(); } finally { - PreferencesUtils.setMetricUnits(previousMetricUnits); + PreferencesUtils.setUnit(previousUnitSystem); } } }; diff --git a/src/androidTest/java/de/dennisguse/opentracks/chart/ChartPointTest.java b/src/androidTest/java/de/dennisguse/opentracks/chart/ChartPointTest.java index 0777e16bf..70ce05e71 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/chart/ChartPointTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/chart/ChartPointTest.java @@ -14,6 +14,7 @@ import de.dennisguse.opentracks.data.models.Altitude; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.TrackStatistics; @RunWith(AndroidJUnit4.class) @@ -26,7 +27,7 @@ public class ChartPointTest { statistics.setTotalTime(Duration.ofSeconds(1000)); // when - ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), Altitude.EGM2008.of(0), false, false); + ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), Altitude.EGM2008.of(0), false, UnitSystem.IMPERIAL); // then assertEquals(1000000, (long) point.getTimeOrDistance()); @@ -39,7 +40,7 @@ public class ChartPointTest { statistics.setTotalDistance(Distance.of(1000)); // when - ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), Altitude.EGM2008.of(0), true, true); + ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(0), Altitude.EGM2008.of(0), true, UnitSystem.METRIC); // then assertEquals(1, (long) point.getTimeOrDistance()); @@ -51,7 +52,7 @@ public class ChartPointTest { TrackStatistics statistics = new TrackStatistics(); // when - ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), Altitude.EGM2008.of(50), false, true); + ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), Altitude.EGM2008.of(50), false, UnitSystem.METRIC); // then assertEquals(50, point.getAltitude(), 0.01); @@ -65,7 +66,7 @@ public class ChartPointTest { TrackStatistics statistics = new TrackStatistics(); // when - ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), Altitude.EGM2008.of(50), false, true); + ChartPoint point = new ChartPoint(statistics, TrackStubUtils.createDefaultTrackPoint(), Speed.of(10), Altitude.EGM2008.of(50), false, UnitSystem.METRIC); // then assertNull(point.getHeartRate()); @@ -84,7 +85,7 @@ public class ChartPointTest { TrackStatistics statistics = new TrackStatistics(); // when - ChartPoint point = new ChartPoint(statistics, trackPoint, Speed.of(10), Altitude.EGM2008.of(50), false, true); + ChartPoint point = new ChartPoint(statistics, trackPoint, Speed.of(10), Altitude.EGM2008.of(50), false, UnitSystem.METRIC); // then assertEquals(100.0, point.getHeartRate(), 0.01); diff --git a/src/androidTest/java/de/dennisguse/opentracks/data/models/DistanceFormatterTest.java b/src/androidTest/java/de/dennisguse/opentracks/data/models/DistanceFormatterTest.java index 3af78a129..95eff8d34 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/data/models/DistanceFormatterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/data/models/DistanceFormatterTest.java @@ -10,6 +10,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import de.dennisguse.opentracks.settings.UnitSystem; + @RunWith(AndroidJUnit4.class) public class DistanceFormatterTest { @@ -19,7 +21,7 @@ public class DistanceFormatterTest { public void testFormatDistance_metric() { DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(true) + .setUnit(UnitSystem.METRIC) .build(context); // A large number in metric @@ -32,7 +34,7 @@ public class DistanceFormatterTest { public void testFormatDistance_imperial() { DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(false) + .setUnit(UnitSystem.IMPERIAL) .build(context); // A large number in imperial diff --git a/src/androidTest/java/de/dennisguse/opentracks/data/models/SpeedFormatterTest.java b/src/androidTest/java/de/dennisguse/opentracks/data/models/SpeedFormatterTest.java index ac5c2acb6..c9ce7ee1f 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/data/models/SpeedFormatterTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/data/models/SpeedFormatterTest.java @@ -10,6 +10,8 @@ import androidx.test.ext.junit.runners.AndroidJUnit4; import org.junit.Test; import org.junit.runner.RunWith; +import de.dennisguse.opentracks.settings.UnitSystem; + @RunWith(AndroidJUnit4.class) public class SpeedFormatterTest { @@ -19,7 +21,7 @@ public class SpeedFormatterTest { public void testGetSpeedParts_pace_metric() { SpeedFormatter formatter = SpeedFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(true) + .setUnit(UnitSystem.METRIC) .setReportSpeedOrPace(false) .build(context); @@ -33,7 +35,7 @@ public class SpeedFormatterTest { public void testGetSpeedParts_pace_imperial() { SpeedFormatter formatter = SpeedFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(false) + .setUnit(UnitSystem.IMPERIAL) .setReportSpeedOrPace(false) .build(context); @@ -47,7 +49,7 @@ public class SpeedFormatterTest { public void testGetSpeedParts_speed_metric() { SpeedFormatter formatter = SpeedFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(true) + .setUnit(UnitSystem.METRIC) .setReportSpeedOrPace(true) .build(context); @@ -59,7 +61,7 @@ public class SpeedFormatterTest { public void testGetSpeedParts_speed_imperial() { SpeedFormatter formatter = SpeedFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(false) + .setUnit(UnitSystem.IMPERIAL) .setReportSpeedOrPace(true) .build(context); @@ -71,7 +73,7 @@ public class SpeedFormatterTest { public void testFormatSpeed() { SpeedFormatter formatter = SpeedFormatter.Builder() .setDecimalCount(2) - .setMetricUnits(true) + .setUnit(UnitSystem.METRIC) .setReportSpeedOrPace(false) .build(context); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManagerTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManagerTest.java index f5d27efbe..7bb1a8140 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManagerTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManagerTest.java @@ -19,6 +19,7 @@ import org.mockito.junit.MockitoJUnitRunner; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.TrackPoint; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.TrackStatistics; @RunWith(MockitoJUnitRunner.class) @@ -48,7 +49,7 @@ public class TrackRecordingServiceNotificationManagerTest { .thenReturn(notificationCompatBuilder); TrackRecordingServiceNotificationManager subject = new TrackRecordingServiceNotificationManager(notificationManager, notificationCompatBuilder); - subject.setMetricUnits(true); + subject.setUnitSystem(UnitSystem.METRIC); // when subject.updateTrackPoint(context, trackStatisticsMock, trackPointMock, Distance.of(100)); diff --git a/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java b/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java index a0807d274..7e74d523f 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtilsTest.java @@ -25,6 +25,7 @@ import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.ui.intervals.IntervalStatistics; @@ -54,7 +55,7 @@ public class VoiceAnnouncementUtilsTest { stats.setTotalAltitudeGain(6000f); // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, null, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.METRIC, true, null, null).toString(); // then assertEquals("Total distance 20.00 kilometers. 1 hour 5 minutes 10 seconds. Speed 18.4 kilometers per hour.", announcement); @@ -76,7 +77,7 @@ public class VoiceAnnouncementUtilsTest { } // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.METRIC, true, lastInterval, null).toString(); // then assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour.", announcement); @@ -92,7 +93,7 @@ public class VoiceAnnouncementUtilsTest { stats.setTotalAltitudeGain(6000f); // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, false, null, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.METRIC, false, null, null).toString(); // then assertEquals("Total distance 20.00 kilometers. 1 hour 5 minutes 10 seconds. Pace 3 minutes 15 seconds per kilometer.", announcement); @@ -114,7 +115,7 @@ public class VoiceAnnouncementUtilsTest { } // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, false, lastInterval, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.METRIC, false, lastInterval, null).toString(); // then assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Pace 1 minute 10 seconds per kilometer. Lap time 1 minute 10 seconds per kilometer.", announcement); @@ -130,7 +131,7 @@ public class VoiceAnnouncementUtilsTest { stats.setTotalAltitudeGain(6000f); // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, true, null, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, true, null, null).toString(); // then assertEquals("Total distance 12.43 miles. 1 hour 5 minutes 10 seconds. Speed 11.4 miles per hour.", announcement); @@ -152,7 +153,7 @@ public class VoiceAnnouncementUtilsTest { } // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, true, lastInterval, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, true, lastInterval, null).toString(); // then assertEquals("Total distance 8.83 miles. 16 minutes 39 seconds. Speed 31.8 miles per hour. Lap speed 31.8 miles per hour.", announcement); @@ -168,7 +169,7 @@ public class VoiceAnnouncementUtilsTest { stats.setTotalAltitudeGain(6000f); // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, false, null, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, false, null, null).toString(); // then assertEquals("Total distance 12.43 miles. 1 hour 5 minutes 10 seconds. Pace 5 minutes 15 seconds per mile.", announcement); @@ -190,7 +191,7 @@ public class VoiceAnnouncementUtilsTest { } // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, false, false, lastInterval, null).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.IMPERIAL, false, lastInterval, null).toString(); // then assertEquals("Total distance 8.83 miles. 16 minutes 39 seconds. Pace 1 minute 53 seconds per mile. Lap time 1 minute 53 seconds per mile.", announcement); @@ -215,7 +216,7 @@ public class VoiceAnnouncementUtilsTest { SensorStatistics sensorStatistics = new SensorStatistics(HeartRate.of(180f), HeartRate.of(180f), null, null, null); // when - String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, true, true, lastInterval, sensorStatistics).toString(); + String announcement = VoiceAnnouncementUtils.getAnnouncement(context, stats, UnitSystem.METRIC, true, lastInterval, sensorStatistics).toString(); // then assertEquals("Total distance 14.21 kilometers. 16 minutes 39 seconds. Speed 51.2 kilometers per hour. Lap speed 51.2 kilometers per hour. Average heart rate 180 bpm. Current heart rate 133 bpm.", announcement); diff --git a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilderTest.java b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilderTest.java index 7206c227e..8f504ffe7 100644 --- a/src/androidTest/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilderTest.java +++ b/src/androidTest/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilderTest.java @@ -23,6 +23,7 @@ import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Power; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.services.RecordingData; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.ui.customRecordingLayout.Layout; @@ -61,7 +62,7 @@ public class StatisticDataBuilderTest extends TestCase { layout.addField(context.getString(R.string.stats_custom_layout_max_speed_key), context.getString(R.string.stats_max_speed), false, true, false); // when - List statisticDataList = StatisticDataBuilder.fromRecordingData(context, recordingDataMock, layout, true); + List statisticDataList = StatisticDataBuilder.fromRecordingData(context, recordingDataMock, layout, UnitSystem.METRIC); // then assertEquals(statisticDataList.size(), 3); @@ -100,7 +101,7 @@ public class StatisticDataBuilderTest extends TestCase { layout.addField(context.getString(R.string.stats_custom_layout_power_key), context.getString(R.string.stats_sensors_power), true, true, false); // when - List statisticDataList = StatisticDataBuilder.fromRecordingData(context, recordingDataMock, layout, true); + List statisticDataList = StatisticDataBuilder.fromRecordingData(context, recordingDataMock, layout, UnitSystem.METRIC); // then assertEquals(statisticDataList.size(), 18); diff --git a/src/main/java/de/dennisguse/opentracks/Startup.java b/src/main/java/de/dennisguse/opentracks/Startup.java index 74d4003c9..c06287bca 100644 --- a/src/main/java/de/dennisguse/opentracks/Startup.java +++ b/src/main/java/de/dennisguse/opentracks/Startup.java @@ -4,8 +4,6 @@ import android.app.Application; import android.os.StrictMode; import android.util.Log; -import java.util.Locale; - import de.dennisguse.opentracks.settings.PreferencesUtils; /** @@ -28,9 +26,7 @@ public class Startup extends Application { PreferencesUtils.initPreferences(this, getResources()); // Set default values of preferences on first start. PreferencesUtils.resetPreferences(this, false); - if (PreferencesUtils.getString( R.string.stats_units_key, "").equals("")) { - PreferencesUtils.setMetricUnits(!Locale.US.equals(Locale.getDefault())); - } + PreferencesUtils.applyDefaultUnit(); PreferencesUtils.applyNightMode(); diff --git a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java index 02fd3dc10..e898227fa 100644 --- a/src/main/java/de/dennisguse/opentracks/TrackListActivity.java +++ b/src/main/java/de/dennisguse/opentracks/TrackListActivity.java @@ -59,6 +59,7 @@ import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.services.handlers.GpsStatusValue; import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.SettingsActivity; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.share.ShareUtils; import de.dennisguse.opentracks.ui.aggregatedStatistics.AggregatedStatisticsActivity; import de.dennisguse.opentracks.ui.aggregatedStatistics.ConfirmDeleteDialogFragment; @@ -88,7 +89,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co private final TrackLoaderCallBack loaderCallbacks = new TrackLoaderCallBack(); // Preferences - private boolean metricUnits = true; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private GpsStatusValue gpsStatusValue = TrackRecordingService.STATUS_GPS_DEFAULT; private RecordingStatus recordingStatus = TrackRecordingService.STATUS_DEFAULT; @@ -112,7 +113,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co private final OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> { if (PreferencesUtils.isKey(R.string.stats_units_key, key)) { - metricUnits = PreferencesUtils.isMetricUnits(); + unitSystem = PreferencesUtils.getUnitSystem(); } if (key != null) { runOnUiThread(() -> { @@ -192,7 +193,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co String name = cursor.getString(nameIndex); String totalTime = StringUtils.formatElapsedTime(Duration.ofMillis(cursor.getLong(totalTimeIndex))); String totalDistance = DistanceFormatter.Builder() - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(TrackListActivity.this).formatDistance(Distance.of(cursor.getDouble(totalDistanceIndex))); int markerCount = cursor.getInt(markerCountIndex); long startTime = cursor.getLong(startTimeIndex); diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java b/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java index 8d89f8109..566f27f59 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartFragment.java @@ -39,6 +39,7 @@ import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.databinding.ChartBinding; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.stats.TrackStatisticsUpdater; @@ -77,9 +78,9 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener { @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (PreferencesUtils.isKey(R.string.stats_units_key, key)) { - boolean metricUnits = PreferencesUtils.isMetricUnits(); - if (metricUnits != viewBinding.chartView.getMetricUnits()) { - viewBinding.chartView.setMetricUnits(metricUnits); + UnitSystem unitSystem = PreferencesUtils.getUnitSystem(); + if (unitSystem != viewBinding.chartView.getUnitSystem()) { + viewBinding.chartView.setUnitSystem(unitSystem); runOnUiThread(() -> { if (isResumed()) { viewBinding.chartView.requestLayout(); @@ -189,7 +190,7 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener { public void onSampledInTrackPoint(@NonNull TrackPoint trackPoint, @NonNull TrackStatistics trackStatistics, Speed smoothedSpeed, Altitude smoothedAltitude) { if (isResumed()) { - ChartPoint point = new ChartPoint(trackStatistics, trackPoint, smoothedSpeed, smoothedAltitude, chartByDistance, viewBinding.chartView.getMetricUnits()); + ChartPoint point = new ChartPoint(trackStatistics, trackPoint, smoothedSpeed, smoothedAltitude, chartByDistance, viewBinding.chartView.getUnitSystem()); pendingPoints.add(point); } } diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java b/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java index 1cd365678..8868abc78 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartPoint.java @@ -8,6 +8,7 @@ import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.models.UnitConversions; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.TrackStatistics; public class ChartPoint { @@ -28,20 +29,20 @@ public class ChartPoint { this.altitude = altitude; } - public ChartPoint(@NonNull TrackStatistics trackStatistics, @NonNull TrackPoint trackPoint, Speed smoothedSpeed, Altitude smoothedAltitude, boolean chartByDistance, boolean metricUnits) { + public ChartPoint(@NonNull TrackStatistics trackStatistics, @NonNull TrackPoint trackPoint, Speed smoothedSpeed, Altitude smoothedAltitude, boolean chartByDistance, UnitSystem unitSystem) { if (chartByDistance) { - timeOrDistance = trackStatistics.getTotalDistance().toKM_Miles(metricUnits); + timeOrDistance = trackStatistics.getTotalDistance().toKM_Miles(unitSystem); } else { timeOrDistance = trackStatistics.getTotalTime().toMillis(); } if (smoothedAltitude != null) { - altitude = Distance.of(smoothedAltitude.toM()).toM_FT(metricUnits); + altitude = Distance.of(smoothedAltitude.toM()).toM_FT(unitSystem); } if (smoothedSpeed != null) { - speed = smoothedSpeed.to(metricUnits); - pace = smoothedSpeed.toPace(metricUnits).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN; + speed = smoothedSpeed.to(unitSystem); + pace = smoothedSpeed.toPace(unitSystem).toMillis() * UnitConversions.MS_TO_S * UnitConversions.S_TO_MIN; } if (trackPoint.hasHeartRate()) { heartRate = (double) trackPoint.getHeartRate().getBPM(); diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartValueSeries.java b/src/main/java/de/dennisguse/opentracks/chart/ChartValueSeries.java index ab29f7887..dcdd57df1 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartValueSeries.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartValueSeries.java @@ -27,6 +27,7 @@ import androidx.annotation.NonNull; import java.text.NumberFormat; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.ExtremityMonitor; /** @@ -217,11 +218,15 @@ abstract class ChartValueSeries { return maxMarkerValue; } - /** - * Gets the title id. - */ - int getTitleId(boolean metricUnits) { - return metricUnits ? metricTitleId : imperialTitleId; + int getTitleId(UnitSystem unitSystem) { + switch (unitSystem) { + case METRIC: + return metricTitleId; + case IMPERIAL: + return imperialTitleId; + default: + throw new RuntimeException("Not implemented"); + } } /** diff --git a/src/main/java/de/dennisguse/opentracks/chart/ChartView.java b/src/main/java/de/dennisguse/opentracks/chart/ChartView.java index 48ca46274..3ed5e2188 100644 --- a/src/main/java/de/dennisguse/opentracks/chart/ChartView.java +++ b/src/main/java/de/dennisguse/opentracks/chart/ChartView.java @@ -46,6 +46,7 @@ import java.util.List; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Marker; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.ExtremityMonitor; import de.dennisguse.opentracks.ui.markers.MarkerDetailActivity; import de.dennisguse.opentracks.ui.markers.MarkerUtils; @@ -116,7 +117,7 @@ public class ChartView extends View { private int effectiveHeight = 0; private boolean chartByDistance = false; - private boolean metricUnits = true; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private boolean reportSpeed = true; private boolean showPointer = false; @@ -371,17 +372,12 @@ public class ChartView extends View { this.chartByDistance = chartByDistance; } - public boolean getMetricUnits() { - return metricUnits; + public UnitSystem getUnitSystem() { + return unitSystem; } - /** - * Sets metric units. - * - * @param value true to use metric units - */ - public void setMetricUnits(boolean value) { - metricUnits = value; + public void setUnitSystem(UnitSystem value) { + unitSystem = value; } public boolean getReportSpeed() { @@ -677,7 +673,7 @@ public class ChartView extends View { for (ChartValueSeries chartValueSeries : seriesList) { if (chartValueSeries.isEnabled() && chartValueSeries.hasData() || allowIfEmpty(chartValueSeries)) { count++; - String title = getContext().getString(chartValueSeries.getTitleId(metricUnits)); + String title = getContext().getString(chartValueSeries.getTitleId(unitSystem)); Paint paint = chartValueSeries.getTitlePaint(); int x = (int) (0.5 * width) + getScrollX(); int y = topBorder - spacer - (lines - count) * (lineHeight + spacer); @@ -696,7 +692,7 @@ public class ChartView extends View { for (ChartValueSeries chartValueSeries : seriesList) { if (chartValueSeries.isEnabled() && chartValueSeries.hasData() || allowIfEmpty(chartValueSeries)) { lines++; - String title = getContext().getString(chartValueSeries.getTitleId(metricUnits)); + String title = getContext().getString(chartValueSeries.getTitleId(unitSystem)); Rect rect = getRect(chartValueSeries.getTitlePaint(), title); if (rect.height() > lineHeight) { lineHeight = rect.height(); @@ -731,7 +727,14 @@ public class ChartView extends View { private String getXAxisLabel() { Context context = getContext(); if (chartByDistance) { - return metricUnits ? context.getString(R.string.unit_kilometer) : context.getString(R.string.unit_mile); + switch (unitSystem) { + case METRIC: + return context.getString(R.string.unit_kilometer); + case IMPERIAL: + return context.getString(R.string.unit_mile); + default: + throw new RuntimeException("Not implemented"); + } } else { return context.getString(R.string.description_time); } @@ -986,7 +989,7 @@ public class ChartView extends View { private double getMarkerXValue(Marker marker) { if (chartByDistance) { - return marker.getLength().toKM_Miles(metricUnits); + return marker.getLength().toKM_Miles(unitSystem); } else { return marker.getDuration().toMillis(); } diff --git a/src/main/java/de/dennisguse/opentracks/data/models/Distance.java b/src/main/java/de/dennisguse/opentracks/data/models/Distance.java index fb0d41564..6f14452fc 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/Distance.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/Distance.java @@ -5,6 +5,8 @@ import androidx.annotation.Nullable; import java.util.Objects; +import de.dennisguse.opentracks.settings.UnitSystem; + public class Distance { public static Distance of(double distance_m) { @@ -43,11 +45,14 @@ public class Distance { return of(0.1 * distance_dm); } - public static Distance one(boolean metricUnit) { - if (metricUnit) { - return Distance.ofKilometer(1); - } else { - return Distance.ofMile(1); + public static Distance one(UnitSystem unitSystem) { + switch (unitSystem) { + case METRIC: + return Distance.ofKilometer(1); + case IMPERIAL: + return Distance.ofMile(1); + default: + throw new RuntimeException("Not implemented"); } } @@ -109,12 +114,26 @@ public class Distance { return toKM() * UnitConversions.KM_TO_MI; } - public double toKM_Miles(boolean metricUnit) { - return metricUnit ? toKM() : toMI(); + public double toKM_Miles(UnitSystem unitSystem) { + switch (unitSystem) { + case METRIC: + return toKM(); + case IMPERIAL: + return toMI(); + default: + throw new RuntimeException("Not implemented"); + } } - public double toM_FT(boolean metricUnit) { - return metricUnit ? toM() : toFT(); + public double toM_FT(UnitSystem unitSystem) { + switch (unitSystem) { + case METRIC: + return toM(); + case IMPERIAL: + return toFT(); + default: + throw new RuntimeException("Not implemented"); + } } @Override diff --git a/src/main/java/de/dennisguse/opentracks/data/models/DistanceFormatter.java b/src/main/java/de/dennisguse/opentracks/data/models/DistanceFormatter.java index ebd5f38ea..717858890 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/DistanceFormatter.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/DistanceFormatter.java @@ -4,7 +4,10 @@ import android.content.Context; import android.content.res.Resources; import android.util.Pair; +import androidx.annotation.Nullable; + import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.util.StringUtils; public class DistanceFormatter { @@ -13,12 +16,13 @@ public class DistanceFormatter { private final int decimalCount; - private final boolean metricUnits; + private final UnitSystem unitSystem; - private DistanceFormatter(Resources resources, int decimalCount, boolean metricUnits) { + private DistanceFormatter(Resources resources, int decimalCount, UnitSystem unitSystem) { this.resources = resources; this.decimalCount = decimalCount; - this.metricUnits = metricUnits; + this.unitSystem = unitSystem; + assert unitSystem != null; } public String formatDistance(Distance distance) { @@ -34,26 +38,35 @@ public class DistanceFormatter { /** * Get the formatted distance with unit. * - * @param metricUnits true to use metric unit * @return the formatted distance (or null) and it's unit as {@link Pair} */ public Pair getDistanceParts(Distance distance) { if (distance.isInvalid()) { - return new Pair<>(null, resources.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet)); + switch (unitSystem) { + case METRIC: + return new Pair<>(null, resources.getString(R.string.unit_meter)); + case IMPERIAL: + return new Pair<>(null, resources.getString(R.string.unit_feet)); + default: + throw new RuntimeException("Not implemented"); + } } - if (metricUnits) { - if (distance.greaterThan(Distance.of(500))) { - return new Pair<>(StringUtils.formatDecimal(distance.toKM(), decimalCount), resources.getString(R.string.unit_kilometer)); - } else { - return new Pair<>(StringUtils.formatDecimal(distance.toM(), decimalCount), resources.getString(R.string.unit_meter)); - } - } else { - if (distance.greaterThan(Distance.ofMile(0.5))) { - return new Pair<>(StringUtils.formatDecimal(distance.toMI(), decimalCount), resources.getString(R.string.unit_mile)); - } else { - return new Pair<>(StringUtils.formatDecimal(distance.toFT(), decimalCount), resources.getString(R.string.unit_feet)); - } + switch (unitSystem) { + case METRIC: + if (distance.greaterThan(Distance.of(500))) { + return new Pair<>(StringUtils.formatDecimal(distance.toKM(), decimalCount), resources.getString(R.string.unit_kilometer)); + } else { + return new Pair<>(StringUtils.formatDecimal(distance.toM(), decimalCount), resources.getString(R.string.unit_meter)); + } + case IMPERIAL: + if (distance.greaterThan(Distance.ofMile(0.5))) { + return new Pair<>(StringUtils.formatDecimal(distance.toMI(), decimalCount), resources.getString(R.string.unit_mile)); + } else { + return new Pair<>(StringUtils.formatDecimal(distance.toFT(), decimalCount), resources.getString(R.string.unit_feet)); + } + default: + throw new RuntimeException("Not implemented"); } } @@ -65,11 +78,10 @@ public class DistanceFormatter { private int decimalCount; - private boolean metricUnits; + private UnitSystem unitSystem; public Builder() { decimalCount = 2; - metricUnits = true; } public Builder setDecimalCount(int decimalCount) { @@ -77,13 +89,13 @@ public class DistanceFormatter { return this; } - public Builder setMetricUnits(boolean metricUnits) { - this.metricUnits = metricUnits; + public Builder setUnit(@Nullable UnitSystem unitSystem) { + this.unitSystem = unitSystem; return this; } public DistanceFormatter build(Resources resource) { - return new DistanceFormatter(resource, decimalCount, metricUnits); + return new DistanceFormatter(resource, decimalCount, unitSystem); } public DistanceFormatter build(Context context) { diff --git a/src/main/java/de/dennisguse/opentracks/data/models/Speed.java b/src/main/java/de/dennisguse/opentracks/data/models/Speed.java index 3478b77d9..f6decb183 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/Speed.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/Speed.java @@ -6,6 +6,7 @@ import java.time.Duration; import java.util.Objects; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; public class Speed { @@ -92,35 +93,37 @@ public class Speed { return toKMH() * UnitConversions.KM_TO_MI; } - public Duration toPace(boolean metricUnit) { + public Duration toPace(UnitSystem unitSystem) { if (isZero()) { return Duration.ofSeconds(0); } - double distance = speed_mps * (metricUnit ? UnitConversions.M_TO_KM : UnitConversions.M_TO_MI); + double distance = speed_mps; + switch (unitSystem) { //TODO Can we use to(UnitSystem)? + case METRIC: + distance *= UnitConversions.M_TO_KM; + break; + case IMPERIAL: + distance *= UnitConversions.M_TO_MI; + break; + default: + throw new RuntimeException("Not implemented"); + } + return Duration.ofSeconds(Math.round(1 / distance)); } - public double to(boolean metricUnit) { - return to(metricUnit ? Unit.KMH : Unit.MPH); - } - - public double to(Unit unit) { - switch (unit) { - case KMH: + public double to(UnitSystem unitSystem) { + switch (unitSystem) { + case METRIC: return toKMH(); - case MPH: + case IMPERIAL: return toMPH(); default: throw new RuntimeException("Not implemented"); } } - public enum Unit { - KMH, - MPH, - } - @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/src/main/java/de/dennisguse/opentracks/data/models/SpeedFormatter.java b/src/main/java/de/dennisguse/opentracks/data/models/SpeedFormatter.java index 20556dce6..e33975f11 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/SpeedFormatter.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/SpeedFormatter.java @@ -4,7 +4,10 @@ import android.content.Context; import android.content.res.Resources; import android.util.Pair; +import androidx.annotation.NonNull; + import de.dennisguse.opentracks.R; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.util.StringUtils; public class SpeedFormatter { @@ -13,14 +16,14 @@ public class SpeedFormatter { private final int decimalCount; - private final boolean metricUnits; + private final UnitSystem unitSystem; private final boolean reportSpeedOrPace; - private SpeedFormatter(Resources resources, int decimalCount, boolean metricUnits, boolean reportSpeedOrPace) { + private SpeedFormatter(Resources resources, int decimalCount, UnitSystem unitSystem, boolean reportSpeedOrPace) { this.resources = resources; this.decimalCount = decimalCount; - this.metricUnits = metricUnits; + this.unitSystem = unitSystem; this.reportSpeedOrPace = reportSpeedOrPace; } @@ -37,11 +40,17 @@ public class SpeedFormatter { */ public Pair getSpeedParts(Speed speed) { int unitId; - if (metricUnits) { - unitId = reportSpeedOrPace ? R.string.unit_kilometer_per_hour : R.string.unit_minute_per_kilometer; - } else { - unitId = reportSpeedOrPace ? R.string.unit_mile_per_hour : R.string.unit_minute_per_mile; + switch (unitSystem) { + case METRIC: + unitId = reportSpeedOrPace ? R.string.unit_kilometer_per_hour : R.string.unit_minute_per_kilometer; + break; + case IMPERIAL: + unitId = reportSpeedOrPace ? R.string.unit_mile_per_hour : R.string.unit_minute_per_mile; + break; + default: + throw new RuntimeException("Not implemented"); } + String unitString = resources.getString(unitId); if (speed == null) { @@ -49,10 +58,10 @@ public class SpeedFormatter { } if (reportSpeedOrPace) { - return new Pair<>(StringUtils.formatDecimal(speed.to(metricUnits), 1), unitString); + return new Pair<>(StringUtils.formatDecimal(speed.to(unitSystem), 1), unitString); } - int pace = (int) speed.toPace(metricUnits).getSeconds(); + int pace = (int) speed.toPace(unitSystem).getSeconds(); int minutes = pace / 60; int seconds = pace % 60; @@ -67,13 +76,12 @@ public class SpeedFormatter { private int decimalCount; - private boolean metricUnits; + private UnitSystem unitSystem; private boolean reportSpeedOrPace; public Builder() { decimalCount = 2; - metricUnits = true; reportSpeedOrPace = true; } @@ -82,8 +90,8 @@ public class SpeedFormatter { return this; } - public Builder setMetricUnits(boolean metricUnits) { - this.metricUnits = metricUnits; + public Builder setUnit(@NonNull UnitSystem unitSystem) { + this.unitSystem = unitSystem; return this; } @@ -93,7 +101,7 @@ public class SpeedFormatter { } public SpeedFormatter build(Resources resource) { - return new SpeedFormatter(resource, decimalCount, metricUnits, reportSpeedOrPace); + return new SpeedFormatter(resource, decimalCount, unitSystem, reportSpeedOrPace); } public SpeedFormatter build(Context context) { diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java index 58cc36fab..e186f9e61 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordedFragment.java @@ -42,6 +42,7 @@ import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.databinding.StatisticsRecordedBinding; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.util.StringUtils; @@ -81,7 +82,7 @@ public class StatisticsRecordedFragment extends Fragment { private StatisticsRecordedBinding viewBinding; - private boolean preferenceMetricUnits; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private boolean preferenceReportSpeed; private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> { @@ -89,7 +90,7 @@ public class StatisticsRecordedFragment extends Fragment { if (PreferencesUtils.isKey(R.string.stats_units_key, key)) { updateUInecessary = true; - preferenceMetricUnits = PreferencesUtils.isMetricUnits(); + unitSystem = PreferencesUtils.getUnitSystem(); } if (PreferencesUtils.isKey(R.string.stats_rate_key, key) && track != null) { @@ -189,7 +190,7 @@ public class StatisticsRecordedFragment extends Fragment { // Set total distance { Pair parts = DistanceFormatter.Builder() - .setMetricUnits(preferenceMetricUnits) + .setUnit(unitSystem) .build(getContext()).getDistanceParts(trackStatistics.getTotalDistance()); viewBinding.statsDistanceValue.setText(parts.first); @@ -208,7 +209,7 @@ public class StatisticsRecordedFragment extends Fragment { viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(trackStatistics.getTotalTime())); } - SpeedFormatter formatter = SpeedFormatter.Builder().setMetricUnits(preferenceMetricUnits).setReportSpeedOrPace(preferenceReportSpeed).build(getContext()); + SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(preferenceReportSpeed).build(getContext()); // Set average speed/pace { viewBinding.statsAverageSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_speed : R.string.stats_average_pace); @@ -243,11 +244,11 @@ public class StatisticsRecordedFragment extends Fragment { Pair parts; - parts = StringUtils.getAltitudeChangeParts(getContext(), altitudeGain_m, preferenceMetricUnits); + parts = StringUtils.getAltitudeParts(getContext(), altitudeGain_m, unitSystem); viewBinding.statsAltitudeGainValue.setText(parts.first); viewBinding.statsAltitudeGainUnit.setText(parts.second); - parts = StringUtils.getAltitudeChangeParts(getContext(), altitudeLoss_m, preferenceMetricUnits); + parts = StringUtils.getAltitudeParts(getContext(), altitudeLoss_m, unitSystem); viewBinding.statsAltitudeLossValue.setText(parts.first); viewBinding.statsAltitudeLossUnit.setText(parts.second); diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index e3c0846f8..a0de16c8b 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -25,6 +25,7 @@ import de.dennisguse.opentracks.services.RecordingData; import de.dennisguse.opentracks.services.TrackRecordingService; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.ui.customRecordingLayout.Layout; import de.dennisguse.opentracks.viewmodels.StatisticData; import de.dennisguse.opentracks.viewmodels.StatisticsDataModel; @@ -55,14 +56,14 @@ public class StatisticsRecordingFragment extends Fragment { private StatisticsDataModel viewModel; private LiveData> statisticsLiveData; - private boolean preferenceMetricUnits; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> { boolean updateUInecessary = false; if (PreferencesUtils.isKey(R.string.stats_units_key, key)) { updateUInecessary = true; - preferenceMetricUnits = PreferencesUtils.isMetricUnits(); + unitSystem = PreferencesUtils.getUnitSystem(); } if (PreferencesUtils.isKey(R.string.stats_custom_layouts_key, key) || PreferencesUtils.isKey(R.string.stats_custom_layout_selected_layout_key, key)) { @@ -157,7 +158,7 @@ public class StatisticsRecordingFragment extends Fragment { private void updateUI() { if (isResumed()) { - viewModel.update(recordingData, layout, preferenceMetricUnits); + viewModel.update(recordingData, layout, unitSystem); } } diff --git a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java index 29a167a64..c3513bf71 100644 --- a/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java +++ b/src/main/java/de/dennisguse/opentracks/services/TrackRecordingServiceNotificationManager.java @@ -24,6 +24,7 @@ import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.util.IntentUtils; @@ -42,7 +43,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh private boolean previousLocationWasAccurate = true; - private Boolean metricUnits = null; + private UnitSystem unitSystem = null; TrackRecordingServiceNotificationManager(Context context) { PreferencesUtils.registerOnSharedPreferenceChangeListener(this); @@ -85,7 +86,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh String formattedAccuracy = context.getString(R.string.value_none); DistanceFormatter formatter = DistanceFormatter.Builder() - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(context); if (trackPoint.hasHorizontalAccuracy()) { formattedAccuracy = formatter.formatDistance(trackPoint.getHorizontalAccuracy()); @@ -97,7 +98,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh } notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, formatter.formatDistance(trackStatistics.getTotalDistance()))); - String formattedSpeed = SpeedFormatter.Builder().setMetricUnits(metricUnits).setReportSpeedOrPace(true).build(context).formatSpeed(trackPoint.getSpeed()); + String formattedSpeed = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(true).build(context).formatSpeed(trackPoint.getSpeed()); notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, formattedSpeed)); notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy)); updateNotification(); @@ -149,8 +150,8 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh notificationManager.cancel(NOTIFICATION_ID); } - void setMetricUnits(boolean metricUnits) { - this.metricUnits = metricUnits; + void setUnitSystem(UnitSystem unitSystem) { + this.unitSystem = unitSystem; } private void updateNotification() { @@ -164,7 +165,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh @Override public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) { if (PreferencesUtils.isKey(R.string.stats_units_key, key)) { - setMetricUnits(PreferencesUtils.isMetricUnits()); + setUnitSystem(PreferencesUtils.getUnitSystem()); } } } diff --git a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java index 5338200b2..a17338385 100644 --- a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java +++ b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncement.java @@ -35,6 +35,7 @@ import de.dennisguse.opentracks.data.TrackPointIterator; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.ui.intervals.IntervalStatistics; @@ -165,12 +166,12 @@ public class VoiceAnnouncement { } - boolean isMetricUnits = PreferencesUtils.isMetricUnits(); + UnitSystem unitSystem = PreferencesUtils.getUnitSystem(); boolean isReportSpeed = PreferencesUtils.isReportSpeed(track.getCategory()); //TODO Do not load all trackpoints for every announcement TrackPointIterator trackPointIterator = contentProviderUtils.getTrackPointLocationIterator(track.getId(), null); - IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.one(isMetricUnits)); + IntervalStatistics intervalStatistics = new IntervalStatistics(Distance.one(unitSystem)); intervalStatistics.addTrackPoints(trackPointIterator); IntervalStatistics.Interval lastInterval = intervalStatistics.getLastInterval(); SensorStatistics sensorStatistics = null; @@ -178,7 +179,7 @@ public class VoiceAnnouncement { sensorStatistics = contentProviderUtils.getSensorStats(track.getId()); } - Spannable announcement = VoiceAnnouncementUtils.getAnnouncement(context, track.getTrackStatistics(), isMetricUnits, isReportSpeed, lastInterval, sensorStatistics); + Spannable announcement = VoiceAnnouncementUtils.getAnnouncement(context, track.getTrackStatistics(), unitSystem, isReportSpeed, lastInterval, sensorStatistics); // We don't care about the utterance id. It is supplied here to force onUtteranceCompleted to be called. tts.speak(announcement, TextToSpeech.QUEUE_FLUSH, null, "not used"); diff --git a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java index 8c0666c96..a665920c4 100644 --- a/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java +++ b/src/main/java/de/dennisguse/opentracks/services/announcement/VoiceAnnouncementUtils.java @@ -16,6 +16,7 @@ import java.time.Duration; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Speed; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.ui.intervals.IntervalStatistics; @@ -25,15 +26,37 @@ class VoiceAnnouncementUtils { private VoiceAnnouncementUtils() { } - static Spannable getAnnouncement(Context context, TrackStatistics trackStatistics, boolean isMetricUnits, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) { + static Spannable getAnnouncement(Context context, TrackStatistics trackStatistics, UnitSystem unitSystem, boolean isReportSpeed, @Nullable IntervalStatistics.Interval currentInterval, @Nullable SensorStatistics sensorStatistics) { SpannableStringBuilder builder = new SpannableStringBuilder(); Distance distance = trackStatistics.getTotalDistance(); Speed distancePerTime = trackStatistics.getAverageMovingSpeed(); Speed currentDistancePerTime = currentInterval != null ? currentInterval.getSpeed() : null; - int perUnitStringId = isMetricUnits ? R.string.voice_per_kilometer : R.string.voice_per_mile; - double distanceInUnit = distance.toKM_Miles(isMetricUnits); - int distanceId = isMetricUnits ? R.plurals.voiceDistanceKilometers : R.plurals.voiceDistanceMiles; + int perUnitStringId; + int distanceId; + int speedId; + String unitDistanceTTS; + String unitSpeedTTS; + switch (unitSystem) { + case METRIC: + perUnitStringId = R.string.voice_per_kilometer; + distanceId = R.plurals.voiceDistanceKilometers; + speedId = R.plurals.voiceSpeedKilometersPerHour; + unitDistanceTTS = "kilometer"; + unitSpeedTTS = "kilometer per hour"; + break; + case IMPERIAL: + perUnitStringId = R.string.voice_per_mile; + distanceId = R.plurals.voiceDistanceMiles; + speedId = R.plurals.voiceSpeedMilesPerHour; + unitDistanceTTS = "mile"; + unitSpeedTTS = "mile per hour"; + break; + default: + throw new RuntimeException("Not implemented"); + } + + double distanceInUnit = distance.toKM_Miles(unitSystem); builder.append(context.getString(R.string.total_distance)); long distanceIntegerPart = (long) distanceInUnit; @@ -41,7 +64,7 @@ class VoiceAnnouncementUtils { String distanceFractionalPart = String.format("%.2f", (distanceInUnit - distanceIntegerPart)).substring(2); // Units should always be english singular for TTS. // See https://developer.android.com/reference/android/text/style/TtsSpan?hl=en#TYPE_MEASURE - appendDecimalUnit(builder, context.getResources().getQuantityString(distanceId, getQuantityCount(distanceInUnit), distanceInUnit), distanceIntegerPart, distanceFractionalPart, isMetricUnits ? "kilometer" : "mile"); + appendDecimalUnit(builder, context.getResources().getQuantityString(distanceId, getQuantityCount(distanceInUnit), distanceInUnit), distanceIntegerPart, distanceFractionalPart, unitDistanceTTS); // Punctuation helps introduce natural pauses in TTS builder.append("."); if (distance.isZero()) { @@ -56,19 +79,18 @@ class VoiceAnnouncementUtils { } if (isReportSpeed) { - int speedId = isMetricUnits ? R.plurals.voiceSpeedKilometersPerHour : R.plurals.voiceSpeedMilesPerHour; - double speedInUnit = distancePerTime.to(isMetricUnits); + double speedInUnit = distancePerTime.to(unitSystem); builder.append(" ") .append(context.getString(R.string.speed)); long speedIntegerPart = (long) speedInUnit; // Extract the decimal part String speedFractionalPart = String.format("%.1f", (speedInUnit - speedIntegerPart)).substring(2); - appendDecimalUnit(builder, context.getResources().getQuantityString(speedId, getQuantityCount(speedInUnit), speedInUnit), speedIntegerPart, speedFractionalPart, isMetricUnits ? "kilometer per hour" : "mile per hour"); + appendDecimalUnit(builder, context.getResources().getQuantityString(speedId, getQuantityCount(speedInUnit), speedInUnit), speedIntegerPart, speedFractionalPart, unitSpeedTTS); builder.append("."); if (currentDistancePerTime != null) { - double currentDistancePerTimeInUnit = currentDistancePerTime.to(isMetricUnits); + double currentDistancePerTimeInUnit = currentDistancePerTime.to(unitSystem); if (currentDistancePerTimeInUnit > 0) { @@ -77,12 +99,12 @@ class VoiceAnnouncementUtils { long currentDistanceIntegerPart = (long) currentDistancePerTimeInUnit; // Extract the decimal part String currentDistanceFractionalPart = String.format("%.1f", (currentDistancePerTimeInUnit - currentDistanceIntegerPart)).substring(2); - appendDecimalUnit(builder, context.getResources().getQuantityString(speedId, getQuantityCount(currentDistancePerTimeInUnit), currentDistancePerTimeInUnit), currentDistanceIntegerPart, currentDistanceFractionalPart, isMetricUnits ? "kilometer per hour" : "mile per hour"); + appendDecimalUnit(builder, context.getResources().getQuantityString(speedId, getQuantityCount(currentDistancePerTimeInUnit), currentDistancePerTimeInUnit), currentDistanceIntegerPart, currentDistanceFractionalPart, unitSpeedTTS); builder.append("."); } } } else { - Duration time = distancePerTime.toPace(isMetricUnits); + Duration time = distancePerTime.toPace(unitSystem); builder.append(" ") .append(context.getString(R.string.pace)); appendDuration(context, builder, time); @@ -90,7 +112,7 @@ class VoiceAnnouncementUtils { .append(context.getString(perUnitStringId)) .append("."); - Duration currentTime = currentDistancePerTime != null ? currentDistancePerTime.toPace(isMetricUnits) : Duration.ofMillis(0); + Duration currentTime = currentDistancePerTime != null ? currentDistancePerTime.toPace(unitSystem) : Duration.ofMillis(0); if (!currentTime.isZero()) { builder.append(" ") .append(context.getString(R.string.lap_time)); diff --git a/src/main/java/de/dennisguse/opentracks/settings/DefaultsSettingsFragment.java b/src/main/java/de/dennisguse/opentracks/settings/DefaultsSettingsFragment.java index bdbfd7a56..66208a964 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/DefaultsSettingsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/settings/DefaultsSettingsFragment.java @@ -64,10 +64,23 @@ public class DefaultsSettingsFragment extends PreferenceFragmentCompat implement } private void updateUnits() { - boolean metricUnits = PreferencesUtils.isMetricUnits(); + UnitSystem unitSystem = PreferencesUtils.getUnitSystem(); ListPreference statsRatePreferences = findPreference(getString(R.string.stats_rate_key)); - String[] entries = getResources().getStringArray(metricUnits ? R.array.stats_rate_metric_options : R.array.stats_rate_imperial_options); + + int entriesId; + switch (unitSystem) { + case METRIC: + entriesId = R.array.stats_rate_metric_options; + break; + case IMPERIAL: + entriesId = R.array.stats_rate_imperial_options; + break; + default: + throw new RuntimeException("Not implemented"); + } + + String[] entries = getResources().getStringArray(entriesId); statsRatePreferences.setEntries(entries); HackUtils.invalidatePreference(statsRatePreferences); diff --git a/src/main/java/de/dennisguse/opentracks/settings/GpsSettingsFragment.java b/src/main/java/de/dennisguse/opentracks/settings/GpsSettingsFragment.java index 9dcc81556..eff92ab98 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/GpsSettingsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/settings/GpsSettingsFragment.java @@ -17,11 +17,11 @@ public class GpsSettingsFragment extends PreferenceFragmentCompat { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.settings_gps); - boolean metricUnits = PreferencesUtils.isMetricUnits(); + UnitSystem unitSystem = PreferencesUtils.getUnitSystem(); final DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(0) - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(getContext()); findPreference(getString(R.string.recording_distance_interval_key)) diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index e53d9f4d2..4d6d1e1c1 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -32,7 +32,9 @@ import androidx.preference.PreferenceManager; import java.time.Duration; import java.util.ArrayList; +import java.util.Arrays; import java.util.List; +import java.util.Locale; import java.util.Optional; import java.util.stream.Collectors; import java.util.stream.Stream; @@ -193,19 +195,30 @@ public class PreferencesUtils { return getBoolean(R.string.publicapi_dashboard_enabled_key, resources.getBoolean(R.bool.publicapi_dashboard_enabled_default)); } - public static boolean isMetricUnits() { - final String STATS_UNIT = resources.getString(R.string.stats_units_default); - return STATS_UNIT.equals(getString(R.string.stats_units_key, STATS_UNIT)); + public static UnitSystem getUnitSystem() { + final String STATS_UNIT_DEFAULT = resources.getString(R.string.stats_units_default); + + final String VALUE = getString(R.string.stats_units_key, STATS_UNIT_DEFAULT); + return Arrays.stream(UnitSystem.values()) + .filter(d -> VALUE.equals(getString(d.getPreferenceId(), STATS_UNIT_DEFAULT))) + .findFirst() + .orElse(UnitSystem.defaultUnitSystem()); //TODO This AGAIN defines the default } - public static void setMetricUnits(boolean metricUnits) { - String unit; - if (metricUnits) { - unit = resources.getString(R.string.stats_units_metric); - } else { - unit = resources.getString(R.string.stats_units_imperial); + public static void setUnit(UnitSystem unitSystem) { + setString(R.string.stats_units_key, unitSystem.getPreferenceId()); + } + + //TODO Check if actually needed or can be superseeded by a flexible default in getUnit() + public static void applyDefaultUnit() { + if (getString(R.string.stats_units_key, "").equals("")) { + + if (!Locale.US.equals(Locale.getDefault())) { + setUnit(UnitSystem.METRIC); + } else { + setUnit(UnitSystem.IMPERIAL); + } } - setString(R.string.stats_units_key, unit); } public static boolean isReportSpeed(String category) { @@ -292,31 +305,31 @@ public class PreferencesUtils { } /** - * @return Result depends on isMetricUnits + * @return Result depends on getUnitSystem */ public static Distance getVoiceAnnouncementDistance() { final float DEFAULT = Integer.parseInt(resources.getString(R.string.voice_announcement_distance_default)); float value = getFloat(R.string.voice_announcement_distance_key, DEFAULT); - return Distance.one(isMetricUnits()).multipliedBy(value); + return Distance.one(getUnitSystem()).multipliedBy(value); } /** - * @return Result depends on isMetricUnits + * @return Result depends on getUnitSystem */ static String[] getVoiceAnnouncementDistanceEntries() { String[] values = resources.getStringArray(R.array.voice_announcement_distance_values); String[] options = new String[values.length]; - boolean metricUnits = isMetricUnits(); + UnitSystem unitSystem = getUnitSystem(); DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(0) - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(resources); for (int i = 0; i < values.length; i++) { if (resources.getString(R.string.announcement_off).equals(values[i])) { options[i] = resources.getString(R.string.value_off); } else { - Distance distance = Distance.one(metricUnits).multipliedBy(Double.parseDouble(values[i])); + Distance distance = Distance.one(unitSystem).multipliedBy(Double.parseDouble(values[i])); options[i] = formatter.formatDistance(distance); } } @@ -354,10 +367,10 @@ public class PreferencesUtils { String[] entries = new String[entryValues.length]; final int recordingDistanceIntervalDefault = (int) getRecordingDistanceIntervalDefault().toM(); - boolean metricUnits = isMetricUnits(); + UnitSystem unitSystem = getUnitSystem(); DistanceFormatter formatter = DistanceFormatter.Builder() - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .setDecimalCount(0) .build(resources); for (int i = 0; i < entryValues.length; i++) { @@ -365,18 +378,23 @@ public class PreferencesUtils { Distance distance = Distance.of(1).multipliedBy(value); String displayValue = formatter.formatDistance(distance); - if (metricUnits) { - if (value == recordingDistanceIntervalDefault) { - entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); - } else { - entries[i] = displayValue; - } - } else { - if (value == recordingDistanceIntervalDefault) { - entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT()); - } else { - entries[i] = displayValue; - } + switch (unitSystem) { + case METRIC: + if (value == recordingDistanceIntervalDefault) { + entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); + } else { + entries[i] = displayValue; + } + break; + case IMPERIAL: + if (value == recordingDistanceIntervalDefault) { + entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT()); + } else { + entries[i] = displayValue; + } + break; + default: + throw new RuntimeException("Not implemented"); } } @@ -393,29 +411,34 @@ public class PreferencesUtils { String[] entries = new String[entryValues.length]; final int maxRecordingDistanceDefault = Integer.parseInt(resources.getString(R.string.max_recording_distance_default)); - boolean metricUnits = isMetricUnits(); + UnitSystem unitSystem = getUnitSystem(); DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(0) - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(resources); for (int i = 0; i < entryValues.length; i++) { int value = Integer.parseInt(entryValues[i]); Distance distance = Distance.of(1).multipliedBy(value); String displayValue = formatter.formatDistance(distance); - if (metricUnits) { - if (value == maxRecordingDistanceDefault) { - entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); - } else { - entries[i] = displayValue; - } - } else { - if (value == maxRecordingDistanceDefault) { - entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT()); - } else { - entries[i] = displayValue; - } + switch (unitSystem) { + case METRIC: + if (value == maxRecordingDistanceDefault) { + entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); + } else { + entries[i] = displayValue; + } + break; + case IMPERIAL: + if (value == maxRecordingDistanceDefault) { + entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT()); + } else { + entries[i] = displayValue; + } + break; + default: + throw new RuntimeException("Not implemented"); } } @@ -460,11 +483,11 @@ public class PreferencesUtils { final int recordingGPSAccuracyExcellent = Integer.parseInt(resources.getString(R.string.recording_gps_accuracy_excellent)); final int recordingGPSAccuracyPoor = Integer.parseInt(resources.getString(R.string.recording_gps_accuracy_poor)); - boolean metricUnits = isMetricUnits(); + UnitSystem unitSystem = getUnitSystem(); DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(0) - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(resources); for (int i = 0; i < entryValues.length; i++) { @@ -472,24 +495,29 @@ public class PreferencesUtils { Distance distance = Distance.of(1).multipliedBy(value); String displayValue = formatter.formatDistance(distance); - if (metricUnits) { - if (value == recordingGPSAccuracyDefault) { - entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); - } else if (value == recordingGPSAccuracyExcellent) { - entries[i] = resources.getString(R.string.value_integer_meter_excellent_gps, value); - } else if (value == recordingGPSAccuracyPoor) { - entries[i] = resources.getString(R.string.value_integer_meter_poor_gps, value); - } else { - entries[i] = displayValue; - } - } else { - if (value == recordingGPSAccuracyDefault) { - entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT()); - } else if (value == recordingGPSAccuracyExcellent) { - entries[i] = resources.getString(R.string.value_integer_feet_excellent_gps, (int) distance.toFT()); - } else { - entries[i] = displayValue; - } + switch (unitSystem) { + case METRIC: + if (value == recordingGPSAccuracyDefault) { + entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); + } else if (value == recordingGPSAccuracyExcellent) { + entries[i] = resources.getString(R.string.value_integer_meter_excellent_gps, value); + } else if (value == recordingGPSAccuracyPoor) { + entries[i] = resources.getString(R.string.value_integer_meter_poor_gps, value); + } else { + entries[i] = displayValue; + } + break; + case IMPERIAL: + if (value == recordingGPSAccuracyDefault) { + entries[i] = resources.getString(R.string.value_integer_feet_recommended, (int) distance.toFT()); + } else if (value == recordingGPSAccuracyExcellent) { + entries[i] = resources.getString(R.string.value_integer_feet_excellent_gps, (int) distance.toFT()); + } else { + entries[i] = displayValue; + } + break; + default: + throw new RuntimeException("Not implemented"); } } @@ -509,24 +537,30 @@ public class PreferencesUtils { final float idleSpeedDefault = Float.parseFloat(resources.getString(R.string.idle_speed_default)); - boolean metricUnits = isMetricUnits(); + UnitSystem unitSystem = getUnitSystem(); for (int i = 0; i < entryValues.length; i++) { float value = Float.parseFloat(entryValues[i]); - if (metricUnits) { - if (value == idleSpeedDefault) { - entries[i] = resources.getString(R.string.value_float_kilometer_hour_recommended, value); - } else { - entries[i] = resources.getString(R.string.value_float_kilometer_hour, value); - } - } else { - double valueMPH = Speed.ofKMH(value).toMPH(); - if (value == idleSpeedDefault) { - entries[i] = resources.getString(R.string.value_float_mile_hour_recommended, valueMPH); - } else { - entries[i] = resources.getString(R.string.value_float_mile_hour, valueMPH); - } + switch (unitSystem) { + case METRIC: + if (value == idleSpeedDefault) { + entries[i] = resources.getString(R.string.value_float_kilometer_hour_recommended, value); + } else { + entries[i] = resources.getString(R.string.value_float_kilometer_hour, value); + } + break; + case IMPERIAL: + double valueMPH = Speed.ofKMH(value).toMPH(); + + if (value == idleSpeedDefault) { + entries[i] = resources.getString(R.string.value_float_mile_hour_recommended, valueMPH); + } else { + entries[i] = resources.getString(R.string.value_float_mile_hour, valueMPH); + } + break; + default: + throw new RuntimeException("Not implemented"); } } diff --git a/src/main/java/de/dennisguse/opentracks/settings/UnitSystem.java b/src/main/java/de/dennisguse/opentracks/settings/UnitSystem.java new file mode 100644 index 000000000..1c73de145 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/settings/UnitSystem.java @@ -0,0 +1,23 @@ +package de.dennisguse.opentracks.settings; + +import de.dennisguse.opentracks.R; + +public enum UnitSystem { + METRIC(R.string.stats_units_metric), + IMPERIAL(R.string.stats_units_imperial); + + private final int preferenceIdentifier; + + UnitSystem(int preferenceIdentifier) { + this.preferenceIdentifier = preferenceIdentifier; + } + + public int getPreferenceId() { + return preferenceIdentifier; + } + + @Deprecated //TODO used to initialize before loading from preferences; should be loaded first + public static UnitSystem defaultUnitSystem() { + return METRIC; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/share/DescriptionGenerator.java b/src/main/java/de/dennisguse/opentracks/share/DescriptionGenerator.java index 56f1b316d..50efb9511 100644 --- a/src/main/java/de/dennisguse/opentracks/share/DescriptionGenerator.java +++ b/src/main/java/de/dennisguse/opentracks/share/DescriptionGenerator.java @@ -31,6 +31,7 @@ import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.UnitConversions; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.util.StringUtils; @@ -210,8 +211,8 @@ public class DescriptionGenerator { */ @VisibleForTesting void writePace(Speed speed, StringBuilder builder, int resId, String lineBreak) { - Pair paceInMetrics = SpeedFormatter.Builder().setMetricUnits(true).setReportSpeedOrPace(false).build(context).getSpeedParts(speed); - Pair paceInImperial = SpeedFormatter.Builder().setMetricUnits(false).setReportSpeedOrPace(false).build(context).getSpeedParts(speed); + Pair paceInMetrics = SpeedFormatter.Builder().setUnit(UnitSystem.METRIC).setReportSpeedOrPace(false).build(context).getSpeedParts(speed); + Pair paceInImperial = SpeedFormatter.Builder().setUnit(UnitSystem.IMPERIAL).setReportSpeedOrPace(false).build(context).getSpeedParts(speed); String formattedPaceMetrics = paceInMetrics.first != null ? paceInMetrics.first : context.getString(R.string.value_unknown); String formattedPaceImperial = paceInImperial.first != null ? paceInImperial.first : context.getString(R.string.value_unknown); diff --git a/src/main/java/de/dennisguse/opentracks/ui/aggregatedStatistics/AggregatedStatisticsAdapter.java b/src/main/java/de/dennisguse/opentracks/ui/aggregatedStatistics/AggregatedStatisticsAdapter.java index bc493f3cd..d7f1f7091 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/aggregatedStatistics/AggregatedStatisticsAdapter.java +++ b/src/main/java/de/dennisguse/opentracks/ui/aggregatedStatistics/AggregatedStatisticsAdapter.java @@ -16,6 +16,7 @@ import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.DistanceFormatter; import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.util.StringUtils; import de.dennisguse.opentracks.util.TrackIconUtils; @@ -99,7 +100,7 @@ public class AggregatedStatisticsAdapter extends BaseAdapter { private final TextView maxSpeedUnit; private final TextView maxSpeedLabel; - private boolean metricsUnits; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private boolean reportSpeed; public ViewHolder(View view) { @@ -121,7 +122,7 @@ public class AggregatedStatisticsAdapter extends BaseAdapter { public void setSpeed(AggregatedStatistics.AggregatedStatistic aggregatedStatistic) { setCommonValues(aggregatedStatistic); - SpeedFormatter formatter = SpeedFormatter.Builder().setMetricUnits(metricsUnits).setReportSpeedOrPace(reportSpeed).build(context); + SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(reportSpeed).build(context); { Pair parts = formatter.getSpeedParts(aggregatedStatistic.getTrackStatistics().getAverageMovingSpeed()); avgSpeed.setText(parts.first); @@ -138,7 +139,7 @@ public class AggregatedStatisticsAdapter extends BaseAdapter { } public void setPace(AggregatedStatistics.AggregatedStatistic aggregatedStatistic) { - SpeedFormatter formatter = SpeedFormatter.Builder().setMetricUnits(metricsUnits).setReportSpeedOrPace(reportSpeed).build(context); + SpeedFormatter formatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(reportSpeed).build(context); setCommonValues(aggregatedStatistic); { @@ -161,14 +162,14 @@ public class AggregatedStatisticsAdapter extends BaseAdapter { String category = aggregatedStatistic.getCategory(); reportSpeed = PreferencesUtils.isReportSpeed(category); - metricsUnits = PreferencesUtils.isMetricUnits(); + unitSystem = PreferencesUtils.getUnitSystem(); sportIcon.setImageResource(getIcon(aggregatedStatistic)); typeLabel.setText(category); numTracks.setText(StringUtils.valueInParentheses(String.valueOf(aggregatedStatistic.getCountTracks()))); Pair parts = DistanceFormatter.Builder() - .setMetricUnits(metricsUnits) + .setUnit(unitSystem) .build(context).getDistanceParts(aggregatedStatistic.getTrackStatistics().getTotalDistance()); distance.setText(parts.first); distanceUnit.setText(parts.second); diff --git a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsAdapter.java b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsAdapter.java index 615d9b52d..3c6227215 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsAdapter.java +++ b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsAdapter.java @@ -15,6 +15,7 @@ import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.DistanceFormatter; import de.dennisguse.opentracks.data.models.SpeedFormatter; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.util.StringUtils; public class IntervalStatisticsAdapter extends RecyclerView.Adapter { @@ -22,11 +23,11 @@ public class IntervalStatisticsAdapter extends RecyclerView.Adapter intervalList; private final Context context; private final StackMode stackMode; - private boolean metricUnits; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private boolean isReportSpeed; - public IntervalStatisticsAdapter(Context context, StackMode stackMode, boolean metricUnits, boolean isReportSpeed) { - this.metricUnits = metricUnits; + public IntervalStatisticsAdapter(Context context, StackMode stackMode, UnitSystem unitSystem, boolean isReportSpeed) { + this.unitSystem = unitSystem; this.context = context; this.stackMode = stackMode; this.isReportSpeed = isReportSpeed; @@ -57,14 +58,14 @@ public class IntervalStatisticsAdapter extends RecyclerView.Adapter swapData(List data, boolean metricUnits, boolean isReportSpeed) { - this.metricUnits = metricUnits; + public List swapData(List data, UnitSystem unitSystem, boolean isReportSpeed) { + this.unitSystem = unitSystem; this.isReportSpeed = isReportSpeed; intervalList = data; diff --git a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsModel.java b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsModel.java index 1f2e1b72c..8b309ac05 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsModel.java +++ b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalStatisticsModel.java @@ -22,6 +22,7 @@ import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.data.tables.TrackPointsColumns; +import de.dennisguse.opentracks.settings.UnitSystem; /** * This model is used to load intervals for a track. @@ -64,14 +65,14 @@ public class IntervalStatisticsModel extends AndroidViewModel { handler = null; } - public MutableLiveData> getIntervalStats(Track.Id trackId, boolean metricUnits, @Nullable IntervalOption interval) { + public MutableLiveData> getIntervalStats(Track.Id trackId, UnitSystem unitSystem, @Nullable IntervalOption interval) { if (intervalsLiveData == null) { if (interval == null) { interval = IntervalOption.OPTION_1; } intervalsLiveData = new MutableLiveData<>(); - distanceInterval = interval.getDistance(metricUnits); + distanceInterval = interval.getDistance(unitSystem); intervalStatistics = new IntervalStatistics(distanceInterval); loadIntervalStatistics(trackId); @@ -104,13 +105,13 @@ public class IntervalStatisticsModel extends AndroidViewModel { } } - public void update(Track.Id trackId, boolean metricUnits, @Nullable IntervalOption interval) { + public void update(Track.Id trackId, UnitSystem unitSystem, @Nullable IntervalOption interval) { if (interval == null) { interval = IntervalOption.DEFAULT; } lastTrackPointId = null; - distanceInterval = interval.getDistance(metricUnits); + distanceInterval = interval.getDistance(unitSystem); intervalStatistics = new IntervalStatistics(distanceInterval); loadIntervalStatistics(trackId); } @@ -138,9 +139,9 @@ public class IntervalStatisticsModel extends AndroidViewModel { this.multiplier = multiplier; } - public Distance getDistance(boolean metricUnits) { + public Distance getDistance(UnitSystem unitSystem) { return Distance - .one(metricUnits) + .one(unitSystem) .multipliedBy(multiplier); } diff --git a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalsFragment.java b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalsFragment.java index 547519db9..27aaf0bcc 100644 --- a/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalsFragment.java +++ b/src/main/java/de/dennisguse/opentracks/ui/intervals/IntervalsFragment.java @@ -24,6 +24,7 @@ import de.dennisguse.opentracks.data.models.DistanceFormatter; import de.dennisguse.opentracks.data.models.Track; import de.dennisguse.opentracks.databinding.IntervalListViewBinding; import de.dennisguse.opentracks.settings.PreferencesUtils; +import de.dennisguse.opentracks.settings.UnitSystem; /** * A fragment to display the intervals from recorded track. @@ -41,7 +42,7 @@ public class IntervalsFragment extends Fragment { private IntervalStatisticsModel.IntervalOption selectedInterval; private Track.Id trackId; - private boolean metricUnits; + private UnitSystem unitSystem = UnitSystem.defaultUnitSystem(); private IntervalStatisticsAdapter adapter; private ArrayAdapter intervalsAdapter; @@ -51,7 +52,7 @@ public class IntervalsFragment extends Fragment { protected final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> { if (PreferencesUtils.isKey(R.string.stats_units_key, key) || PreferencesUtils.isKey(R.string.stats_rate_key, key)) { - updateIntervals(PreferencesUtils.isMetricUnits(), selectedInterval); + updateIntervals(PreferencesUtils.getUnitSystem(), selectedInterval); if (intervalsAdapter != null) { intervalsAdapter.notifyDataSetChanged(); } @@ -101,14 +102,14 @@ public class IntervalsFragment extends Fragment { public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) { super.onViewCreated(view, savedInstanceState); - adapter = new IntervalStatisticsAdapter(getContext(), stackModeListView, metricUnits, isReportSpeed); + adapter = new IntervalStatisticsAdapter(getContext(), stackModeListView, unitSystem, isReportSpeed); viewBinding.intervalList.setLayoutManager(new LinearLayoutManager(getContext())); // TODO handle empty view: before we did viewBinding.intervalList.setEmptyView(viewBinding.intervalListEmptyView); viewBinding.intervalList.setAdapter(adapter); final DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(0) - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(getContext()); intervalsAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, IntervalStatisticsModel.IntervalOption.values()) { @@ -118,7 +119,7 @@ public class IntervalsFragment extends Fragment { TextView v = (TextView) super.getView(position, convertView, parent); IntervalStatisticsModel.IntervalOption option = getItem(position); - String stringValue = formatter.formatDistance(option.getDistance(metricUnits)); + String stringValue = formatter.formatDistance(option.getDistance(unitSystem)); v.setText(stringValue); return v; } @@ -131,7 +132,7 @@ public class IntervalsFragment extends Fragment { viewBinding.intervalsDropdown.setAdapter(intervalsAdapter); viewBinding.intervalsDropdown.setOnItemClickListener((parent, view1, position, id) -> { - updateIntervals(metricUnits, IntervalStatisticsModel.IntervalOption.values()[position]); + updateIntervals(unitSystem, IntervalStatisticsModel.IntervalOption.values()[position]); //TODO This duplicates the intervalAdapter code setIntervalsDropdownText(); @@ -191,8 +192,8 @@ public class IntervalsFragment extends Fragment { } viewBinding.intervalRate.setText(isReportSpeed ? getString(R.string.stats_speed) : getString(R.string.stats_pace)); - LiveData> liveData = viewModel.getIntervalStats(trackId, metricUnits, selectedInterval); - liveData.observe(getActivity(), intervalList -> adapter.swapData(intervalList, metricUnits, isReportSpeed)); + LiveData> liveData = viewModel.getIntervalStats(trackId, unitSystem, selectedInterval); + liveData.observe(getActivity(), intervalList -> adapter.swapData(intervalList, unitSystem, isReportSpeed)); setIntervalsDropdownText(); } @@ -200,23 +201,23 @@ public class IntervalsFragment extends Fragment { private void setIntervalsDropdownText() { DistanceFormatter formatter = DistanceFormatter.Builder() .setDecimalCount(0) - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(getContext()); IntervalStatisticsModel.IntervalOption option = selectedInterval != null ? selectedInterval : IntervalStatisticsModel.IntervalOption.DEFAULT; - String stringValue = formatter.formatDistance(option.getDistance(metricUnits)); + String stringValue = formatter.formatDistance(option.getDistance(unitSystem)); viewBinding.intervalsDropdown.setText(stringValue, false); } - private synchronized void updateIntervals(boolean metricUnits, IntervalStatisticsModel.IntervalOption selectedInterval) { - boolean update = metricUnits != this.metricUnits + private synchronized void updateIntervals(UnitSystem unitSystem, IntervalStatisticsModel.IntervalOption selectedInterval) { + boolean update = unitSystem != this.unitSystem || selectedInterval == null || !selectedInterval.sameMultiplier(this.selectedInterval); - this.metricUnits = metricUnits; + this.unitSystem = unitSystem; this.selectedInterval = selectedInterval; if (update && viewModel != null) { - viewModel.update(trackId, this.metricUnits, this.selectedInterval); + viewModel.update(trackId, this.unitSystem, this.selectedInterval); } } } diff --git a/src/main/java/de/dennisguse/opentracks/util/StringUtils.java b/src/main/java/de/dennisguse/opentracks/util/StringUtils.java index 94f7fa101..29e793d7d 100644 --- a/src/main/java/de/dennisguse/opentracks/util/StringUtils.java +++ b/src/main/java/de/dennisguse/opentracks/util/StringUtils.java @@ -43,8 +43,10 @@ import java.time.temporal.TemporalAccessor; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Cadence; import de.dennisguse.opentracks.data.models.Distance; +import de.dennisguse.opentracks.data.models.DistanceFormatter; import de.dennisguse.opentracks.data.models.HeartRate; import de.dennisguse.opentracks.data.models.Power; +import de.dennisguse.opentracks.settings.UnitSystem; /** * Various string manipulation methods. @@ -252,35 +254,18 @@ public class StringUtils { /** * @return the formatted altitude_m (or null) and it's unit as {@link Pair} */ - public static Pair getAltitudeParts(Context context, Float altitude_m, boolean metricUnits) { - String formattedValue = context.getString(R.string.value_unknown); - String unit = context.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet); + public static Pair getAltitudeParts(Context context, Float altitude_m, UnitSystem unitSystem) { + DistanceFormatter formatter = DistanceFormatter.Builder() + .setDecimalCount(1) + .setUnit(unitSystem) + .build(context); - if (altitude_m != null) { - double value = Distance.of(altitude_m).toM_FT(metricUnits); - formattedValue = StringUtils.formatDecimal(value, 1); - } - - return new Pair<>(formattedValue, unit); + Distance distance = altitude_m != null ? Distance.of(altitude_m) : Distance.of(Double.NaN); //TODO Refactor Double.NaN + return formatter.getDistanceParts(distance); } - public static String formatAltitude(Context context, Float altitude_m, boolean metricUnits) { - Pair altitudeParts = getAltitudeParts(context, altitude_m, metricUnits); - - return context.getString(R.string.altitude_with_unit, altitudeParts.first, altitudeParts.second); - } - - /** - * @return the formatted altitudeDifference_m (or null) and it's unit as {@link Pair} - */ - public static Pair getAltitudeChangeParts(Context context, Float altitudeDifference_m, boolean metricUnits) { - String formattedValue = altitudeDifference_m != null ? String.valueOf((int) Distance.of(altitudeDifference_m).toM_FT(metricUnits)) : context.getString(R.string.value_unknown); - String unit = context.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet); - return new Pair<>(formattedValue, unit); - } - - public static String formatAltitudeChange(Context context, Float altitude_m, boolean metricUnits) { - Pair altitudeParts = getAltitudeChangeParts(context, altitude_m, metricUnits); + public static String formatAltitude(Context context, Float altitude_m, UnitSystem unitSystem) { + Pair altitudeParts = getAltitudeParts(context, altitude_m, unitSystem); return context.getString(R.string.altitude_with_unit, altitudeParts.first, altitudeParts.second); } diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilder.java b/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilder.java index 07455614a..1963b3d14 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilder.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticDataBuilder.java @@ -18,6 +18,7 @@ import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.services.RecordingData; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.stats.SensorStatistics; import de.dennisguse.opentracks.stats.TrackStatistics; import de.dennisguse.opentracks.ui.customRecordingLayout.DataField; @@ -26,17 +27,17 @@ import de.dennisguse.opentracks.util.StringUtils; public class StatisticDataBuilder { - public static List fromRecordingData(@NonNull Context context, @NonNull RecordingData recordingData, @NonNull Layout layout, boolean metricUnits) { + public static List fromRecordingData(@NonNull Context context, @NonNull RecordingData recordingData, @NonNull Layout layout, UnitSystem unitSystem) { List statisticDataList = layout.getFields().stream() .filter(DataField::isVisible) - .map(field -> build(context, recordingData, field.getKey(), field.isPrimary(), metricUnits)) + .map(field -> build(context, recordingData, field.getKey(), field.isPrimary(), unitSystem)) .filter(Objects::nonNull) .collect(Collectors.toList()); - statisticDataList.addAll(getSensorStatsDataIfNeeded(context, recordingData, statisticDataList, metricUnits)); + statisticDataList.addAll(getSensorStatsDataIfNeeded(context, recordingData, statisticDataList, unitSystem)); return statisticDataList; } - private static StatisticData build(@NonNull Context context, @NonNull RecordingData recordingData, @NonNull String fieldKey, boolean isPrimary, boolean metricUnits) { + private static StatisticData build(@NonNull Context context, @NonNull RecordingData recordingData, @NonNull String fieldKey, boolean isPrimary, UnitSystem unitSystem) { final TrackPoint latestTrackPoint = recordingData.getLatestTrackPoint(); final SensorDataSet sensorDataSet = recordingData.getSensorDataSet(); final TrackStatistics trackStatistics = recordingData.getTrackStatistics(); @@ -48,8 +49,8 @@ public class StatisticDataBuilder { final String sensorUnknown = context.getString(R.string.value_unknown); - SpeedFormatter speedFormatterPace = SpeedFormatter.Builder().setMetricUnits(metricUnits).setReportSpeedOrPace(false).build(context); - SpeedFormatter speedFormatterSpeed = SpeedFormatter.Builder().setMetricUnits(metricUnits).setReportSpeedOrPace(true).build(context); + SpeedFormatter speedFormatterPace = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(false).build(context); + SpeedFormatter speedFormatterSpeed = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(true).build(context); if (fieldKey.equals(context.getString(R.string.stats_custom_layout_total_time_key))) { @@ -60,14 +61,14 @@ public class StatisticDataBuilder { title = context.getString(R.string.stats_moving_time); } else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_distance_key))) { valueAndUnit = DistanceFormatter.Builder() - .setMetricUnits(metricUnits) + .setUnit(unitSystem) .build(context).getDistanceParts(trackStatistics.getTotalDistance()); title = context.getString(R.string.stats_distance); } else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_speed_key)) || fieldKey.equals(context.getString(R.string.stats_custom_layout_pace_key))) { boolean reportSpeed = fieldKey.equals("speed"); title = reportSpeed ? context.getString(R.string.stats_speed) : context.getString(R.string.stats_pace); - SpeedFormatter localSpeedFormatter = SpeedFormatter.Builder().setMetricUnits(metricUnits).setReportSpeedOrPace(reportSpeed).build(context); + SpeedFormatter localSpeedFormatter = SpeedFormatter.Builder().setUnit(unitSystem).setReportSpeedOrPace(reportSpeed).build(context); if (sensorDataSet != null && sensorDataSet.getSpeed() != null) { valueAndUnit = localSpeedFormatter.getSpeedParts(sensorDataSet.getSpeed().first); description = sensorDataSet.getSpeed().second; @@ -98,12 +99,12 @@ public class StatisticDataBuilder { Float altitude = latestTrackPoint != null && latestTrackPoint.hasAltitude() ? (float) latestTrackPoint.getAltitude().toM() : null; title = context.getString(R.string.stats_altitude); description = latestTrackPoint != null && latestTrackPoint.hasAltitude() ? context.getString(latestTrackPoint.getAltitude().getLabelId()) : null; - valueAndUnit = StringUtils.getAltitudeParts(context, altitude, metricUnits); + valueAndUnit = StringUtils.getAltitudeParts(context, altitude, unitSystem); } else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_gain_key))) { - valueAndUnit = StringUtils.getAltitudeChangeParts(context, trackStatistics.getTotalAltitudeGain(), metricUnits); + valueAndUnit = StringUtils.getAltitudeParts(context, trackStatistics.getTotalAltitudeGain(), unitSystem); title = context.getString(R.string.stats_gain); } else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_loss_key))) { - valueAndUnit = StringUtils.getAltitudeChangeParts(context, trackStatistics.getTotalAltitudeLoss(), metricUnits); + valueAndUnit = StringUtils.getAltitudeParts(context, trackStatistics.getTotalAltitudeLoss(), unitSystem); title = context.getString(R.string.stats_loss); } else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_coordinates_key))) { title = context.getString(R.string.stats_coordinates); @@ -162,20 +163,20 @@ public class StatisticDataBuilder { /** * Builds a list of StatisticData with sensors configured but not in statisticDataList. */ - private static List getSensorStatsDataIfNeeded(Context context, RecordingData recordingData, List statisticDataList, boolean metricUnits) { + private static List getSensorStatsDataIfNeeded(Context context, RecordingData recordingData, List statisticDataList, UnitSystem unitSystem) { List sensorDataList = new ArrayList<>(); SensorDataSet sensorDataSet = recordingData.getSensorDataSet(); if (sensorDataSet == null) { return sensorDataList; } if (statisticDataList.stream().noneMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_heart_rate))) && sensorDataSet.getHeartRate() != null) { - sensorDataList.add(build(context, recordingData, "heart_rate", true, metricUnits)); + sensorDataList.add(build(context, recordingData, "heart_rate", true, unitSystem)); } if (statisticDataList.stream().noneMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_cadence))) && sensorDataSet.getCadence() != null) { - sensorDataList.add(build(context, recordingData, "cadence", true, metricUnits)); + sensorDataList.add(build(context, recordingData, "cadence", true, unitSystem)); } if (statisticDataList.stream().noneMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_power))) && sensorDataSet.getCyclingPower() != null && sensorDataSet.getCyclingPower().hasValue()) { - sensorDataList.add(build(context, recordingData, "power", true, metricUnits)); + sensorDataList.add(build(context, recordingData, "power", true, unitSystem)); } return sensorDataList; diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticsDataModel.java b/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticsDataModel.java index f58b8fd72..58efab998 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticsDataModel.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/StatisticsDataModel.java @@ -9,6 +9,7 @@ import androidx.lifecycle.MutableLiveData; import java.util.List; import de.dennisguse.opentracks.services.RecordingData; +import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.ui.customRecordingLayout.Layout; public class StatisticsDataModel extends AndroidViewModel { @@ -26,9 +27,9 @@ public class StatisticsDataModel extends AndroidViewModel { return statsData; } - public void update(RecordingData recordingData, Layout layout, boolean metricUnit) { + public void update(RecordingData recordingData, Layout layout, UnitSystem unitSystem) { new Thread(() -> { - List statisticDataList = StatisticDataBuilder.fromRecordingData(getApplication(), recordingData, layout, metricUnit); + List statisticDataList = StatisticDataBuilder.fromRecordingData(getApplication(), recordingData, layout, unitSystem); statsData.postValue(statisticDataList); }).start(); }