Refactoring: DistanceFormatter handles metricUnits.

This commit is contained in:
Dennis Guse
2022-04-23 20:26:08 +02:00
parent a57b5cd6ee
commit 16f238f34b
11 changed files with 70 additions and 31 deletions
@@ -16,18 +16,28 @@ public class DistanceFormatterTest {
private final Context context = ApplicationProvider.getApplicationContext(); private final Context context = ApplicationProvider.getApplicationContext();
@Test @Test
public void testFormatDistance() { public void testFormatDistance_metric() {
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(2) .setDecimalCount(2)
.setMetricUnits(true)
.build(context); .build(context);
// A large number in metric // A large number in metric
assertEquals("5.00 km", formatter.formatDistance(Distance.of(5000), true)); assertEquals("5.00 km", formatter.formatDistance(Distance.of(5000)));
// A large number in imperial
assertEquals("3.11 mi", formatter.formatDistance(Distance.of(5000), false));
// A small number in metric // A small number in metric
assertEquals("100.00 m", formatter.formatDistance(Distance.of(100), true)); assertEquals("100.00 m", formatter.formatDistance(Distance.of(100)));
}
@Test
public void testFormatDistance_imperial() {
DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(2)
.setMetricUnits(false)
.build(context);
// A large number in imperial
assertEquals("3.11 mi", formatter.formatDistance(Distance.of(5000)));
// A small number in imperial // A small number in imperial
assertEquals("328.08 ft", formatter.formatDistance(Distance.of(100), false)); assertEquals("328.08 ft", formatter.formatDistance(Distance.of(100)));
} }
} }
@@ -191,7 +191,9 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
int iconId = TrackIconUtils.getIconDrawable(icon); int iconId = TrackIconUtils.getIconDrawable(icon);
String name = cursor.getString(nameIndex); String name = cursor.getString(nameIndex);
String totalTime = StringUtils.formatElapsedTime(Duration.ofMillis(cursor.getLong(totalTimeIndex))); String totalTime = StringUtils.formatElapsedTime(Duration.ofMillis(cursor.getLong(totalTimeIndex)));
String totalDistance = DistanceFormatter.Builder().build(TrackListActivity.this).formatDistance(Distance.of(cursor.getDouble(totalDistanceIndex)), metricUnits); String totalDistance = DistanceFormatter.Builder()
.setMetricUnits(metricUnits)
.build(TrackListActivity.this).formatDistance(Distance.of(cursor.getDouble(totalDistanceIndex)));
int markerCount = cursor.getInt(markerCountIndex); int markerCount = cursor.getInt(markerCountIndex);
long startTime = cursor.getLong(startTimeIndex); long startTime = cursor.getLong(startTimeIndex);
int startTimeOffset = cursor.getInt(startTimeOffsetIndex); int startTimeOffset = cursor.getInt(startTimeOffsetIndex);
@@ -13,17 +13,20 @@ public class DistanceFormatter {
private final int decimalCount; private final int decimalCount;
private DistanceFormatter(Resources resources, int decimalCount) { private final boolean metricUnits;
private DistanceFormatter(Resources resources, int decimalCount, boolean metricUnits) {
this.resources = resources; this.resources = resources;
this.decimalCount = decimalCount; this.decimalCount = decimalCount;
this.metricUnits = metricUnits;
} }
public String formatDistance(Distance distance, boolean metricUnits) { public String formatDistance(Distance distance) {
if (distance.isInvalid()) { if (distance.isInvalid()) {
return resources.getString(R.string.value_unknown); return resources.getString(R.string.value_unknown);
} }
Pair<String, String> distanceParts = getDistanceParts(distance, metricUnits); Pair<String, String> distanceParts = getDistanceParts(distance);
return resources.getString(R.string.distance_with_unit, distanceParts.first, distanceParts.second); return resources.getString(R.string.distance_with_unit, distanceParts.first, distanceParts.second);
} }
@@ -34,7 +37,7 @@ public class DistanceFormatter {
* @param metricUnits true to use metric unit * @param metricUnits true to use metric unit
* @return the formatted distance (or null) and it's unit as {@link Pair} * @return the formatted distance (or null) and it's unit as {@link Pair}
*/ */
public Pair<String, String> getDistanceParts(Distance distance, boolean metricUnits) { public Pair<String, String> getDistanceParts(Distance distance) {
if (distance.isInvalid()) { if (distance.isInvalid()) {
return new Pair<>(null, resources.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet)); return new Pair<>(null, resources.getString(metricUnits ? R.string.unit_meter : R.string.unit_feet));
} }
@@ -62,8 +65,11 @@ public class DistanceFormatter {
private int decimalCount; private int decimalCount;
private boolean metricUnits;
public Builder() { public Builder() {
decimalCount = 2; decimalCount = 2;
metricUnits = true;
} }
public Builder setDecimalCount(int decimalCount) { public Builder setDecimalCount(int decimalCount) {
@@ -71,8 +77,13 @@ public class DistanceFormatter {
return this; return this;
} }
public Builder setMetricUnits(boolean metricUnits) {
this.metricUnits = metricUnits;
return this;
}
public DistanceFormatter build(Resources resource) { public DistanceFormatter build(Resources resource) {
return new DistanceFormatter(resource, decimalCount); return new DistanceFormatter(resource, decimalCount, metricUnits);
} }
public DistanceFormatter build(Context context) { public DistanceFormatter build(Context context) {
@@ -187,7 +187,9 @@ public class StatisticsRecordedFragment extends Fragment {
TrackStatistics trackStatistics = track.getTrackStatistics(); TrackStatistics trackStatistics = track.getTrackStatistics();
// Set total distance // Set total distance
{ {
Pair<String, String> parts = DistanceFormatter.Builder().build(getContext()).getDistanceParts(trackStatistics.getTotalDistance(), preferenceMetricUnits); Pair<String, String> parts = DistanceFormatter.Builder()
.setMetricUnits(preferenceMetricUnits)
.build(getContext()).getDistanceParts(trackStatistics.getTotalDistance());
viewBinding.statsDistanceValue.setText(parts.first); viewBinding.statsDistanceValue.setText(parts.first);
viewBinding.statsDistanceUnit.setText(parts.second); viewBinding.statsDistanceUnit.setText(parts.second);
@@ -84,9 +84,11 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh
void updateTrackPoint(Context context, TrackStatistics trackStatistics, TrackPoint trackPoint, Distance recordingGpsAccuracy) { void updateTrackPoint(Context context, TrackStatistics trackStatistics, TrackPoint trackPoint, Distance recordingGpsAccuracy) {
String formattedAccuracy = context.getString(R.string.value_none); String formattedAccuracy = context.getString(R.string.value_none);
DistanceFormatter formatter = DistanceFormatter.Builder().build(context); DistanceFormatter formatter = DistanceFormatter.Builder()
.setMetricUnits(metricUnits)
.build(context);
if (trackPoint.hasHorizontalAccuracy()) { if (trackPoint.hasHorizontalAccuracy()) {
formattedAccuracy = formatter.formatDistance(trackPoint.getHorizontalAccuracy(), metricUnits); formattedAccuracy = formatter.formatDistance(trackPoint.getHorizontalAccuracy());
boolean currentLocationWasAccurate = trackPoint.getHorizontalAccuracy().lessThan(recordingGpsAccuracy); boolean currentLocationWasAccurate = trackPoint.getHorizontalAccuracy().lessThan(recordingGpsAccuracy);
boolean shouldAlert = !currentLocationWasAccurate && previousLocationWasAccurate; boolean shouldAlert = !currentLocationWasAccurate && previousLocationWasAccurate;
@@ -94,7 +96,7 @@ class TrackRecordingServiceNotificationManager implements SharedPreferences.OnSh
previousLocationWasAccurate = currentLocationWasAccurate; previousLocationWasAccurate = currentLocationWasAccurate;
} }
notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, formatter.formatDistance(trackStatistics.getTotalDistance(), metricUnits))); notificationBuilder.setContentTitle(context.getString(R.string.track_distance_notification, formatter.formatDistance(trackStatistics.getTotalDistance())));
notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, StringUtils.formatSpeed(context, trackPoint.getSpeed(), metricUnits, true))); notificationBuilder.setContentText(context.getString(R.string.track_speed_notification, StringUtils.formatSpeed(context, trackPoint.getSpeed(), metricUnits, true)));
notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy)); notificationBuilder.setSubText(context.getString(R.string.track_recording_notification_accuracy, formattedAccuracy));
updateNotification(); updateNotification();
@@ -17,34 +17,34 @@ public class GpsSettingsFragment extends PreferenceFragmentCompat {
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.settings_gps); addPreferencesFromResource(R.xml.settings_gps);
boolean metricUnits = PreferencesUtils.isMetricUnits();
final DistanceFormatter formatter = DistanceFormatter.Builder() final DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(0) .setDecimalCount(0)
.setMetricUnits(metricUnits)
.build(getContext()); .build(getContext());
findPreference(getString(R.string.recording_distance_interval_key)) findPreference(getString(R.string.recording_distance_interval_key))
.setSummaryProvider( .setSummaryProvider(
preference -> { preference -> {
boolean metricUnits = PreferencesUtils.isMetricUnits();
Distance distance = PreferencesUtils.getRecordingDistanceInterval(); Distance distance = PreferencesUtils.getRecordingDistanceInterval();
return getString(R.string.settings_recording_location_frequency_summary, formatter.formatDistance(distance, metricUnits)); return getString(R.string.settings_recording_location_frequency_summary, formatter.formatDistance(distance));
} }
); );
findPreference(getString(R.string.max_recording_distance_key)) findPreference(getString(R.string.max_recording_distance_key))
.setSummaryProvider( .setSummaryProvider(
preference -> { preference -> {
boolean metricUnits = PreferencesUtils.isMetricUnits();
Distance distance = PreferencesUtils.getMaxRecordingDistance(); Distance distance = PreferencesUtils.getMaxRecordingDistance();
return getString(R.string.settings_recording_max_recording_distance_summary, formatter.formatDistance(distance, metricUnits)); return getString(R.string.settings_recording_max_recording_distance_summary, formatter.formatDistance(distance));
} }
); );
findPreference(getString(R.string.recording_gps_accuracy_key)) findPreference(getString(R.string.recording_gps_accuracy_key))
.setSummaryProvider( .setSummaryProvider(
preference -> { preference -> {
boolean metricUnits = PreferencesUtils.isMetricUnits();
Distance distance = PreferencesUtils.getThresholdHorizontalAccuracy(); Distance distance = PreferencesUtils.getThresholdHorizontalAccuracy();
return getString(R.string.settings_recording_min_required_accuracy_summary, formatter.formatDistance(distance, metricUnits)); return getString(R.string.settings_recording_min_required_accuracy_summary, formatter.formatDistance(distance));
} }
); );
@@ -310,13 +310,14 @@ public class PreferencesUtils {
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(0) .setDecimalCount(0)
.setMetricUnits(metricUnits)
.build(resources); .build(resources);
for (int i = 0; i < values.length; i++) { for (int i = 0; i < values.length; i++) {
if (resources.getString(R.string.announcement_off).equals(values[i])) { if (resources.getString(R.string.announcement_off).equals(values[i])) {
options[i] = resources.getString(R.string.value_off); options[i] = resources.getString(R.string.value_off);
} else { } else {
Distance distance = Distance.one(metricUnits).multipliedBy(Double.parseDouble(values[i])); Distance distance = Distance.one(metricUnits).multipliedBy(Double.parseDouble(values[i]));
options[i] = formatter.formatDistance(distance, metricUnits); options[i] = formatter.formatDistance(distance);
} }
} }
return options; return options;
@@ -356,13 +357,14 @@ public class PreferencesUtils {
boolean metricUnits = isMetricUnits(); boolean metricUnits = isMetricUnits();
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setMetricUnits(metricUnits)
.setDecimalCount(0) .setDecimalCount(0)
.build(resources); .build(resources);
for (int i = 0; i < entryValues.length; i++) { for (int i = 0; i < entryValues.length; i++) {
int value = Integer.parseInt(entryValues[i]); int value = Integer.parseInt(entryValues[i]);
Distance distance = Distance.of(1).multipliedBy(value); Distance distance = Distance.of(1).multipliedBy(value);
String displayValue = formatter.formatDistance(distance, metricUnits); String displayValue = formatter.formatDistance(distance);
if (metricUnits) { if (metricUnits) {
if (value == recordingDistanceIntervalDefault) { if (value == recordingDistanceIntervalDefault) {
entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); entries[i] = resources.getString(R.string.value_integer_meter_recommended, value);
@@ -395,12 +397,13 @@ public class PreferencesUtils {
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(0) .setDecimalCount(0)
.setMetricUnits(metricUnits)
.build(resources); .build(resources);
for (int i = 0; i < entryValues.length; i++) { for (int i = 0; i < entryValues.length; i++) {
int value = Integer.parseInt(entryValues[i]); int value = Integer.parseInt(entryValues[i]);
Distance distance = Distance.of(1).multipliedBy(value); Distance distance = Distance.of(1).multipliedBy(value);
String displayValue = formatter.formatDistance(distance, metricUnits); String displayValue = formatter.formatDistance(distance);
if (metricUnits) { if (metricUnits) {
if (value == maxRecordingDistanceDefault) { if (value == maxRecordingDistanceDefault) {
entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); entries[i] = resources.getString(R.string.value_integer_meter_recommended, value);
@@ -461,13 +464,14 @@ public class PreferencesUtils {
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(0) .setDecimalCount(0)
.setMetricUnits(metricUnits)
.build(resources); .build(resources);
for (int i = 0; i < entryValues.length; i++) { for (int i = 0; i < entryValues.length; i++) {
int value = Integer.parseInt(entryValues[i]); int value = Integer.parseInt(entryValues[i]);
Distance distance = Distance.of(1).multipliedBy(value); Distance distance = Distance.of(1).multipliedBy(value);
String displayValue = formatter.formatDistance(distance, metricUnits); String displayValue = formatter.formatDistance(distance);
if (metricUnits) { if (metricUnits) {
if (value == recordingGPSAccuracyDefault) { if (value == recordingGPSAccuracyDefault) {
entries[i] = resources.getString(R.string.value_integer_meter_recommended, value); entries[i] = resources.getString(R.string.value_integer_meter_recommended, value);
@@ -162,7 +162,9 @@ public class AggregatedStatisticsAdapter extends BaseAdapter {
typeLabel.setText(category); typeLabel.setText(category);
numTracks.setText(StringUtils.valueInParentheses(String.valueOf(aggregatedStatistic.getCountTracks()))); numTracks.setText(StringUtils.valueInParentheses(String.valueOf(aggregatedStatistic.getCountTracks())));
Pair<String, String> parts = DistanceFormatter.Builder().build(context).getDistanceParts(aggregatedStatistic.getTrackStatistics().getTotalDistance(), metricsUnits); Pair<String, String> parts = DistanceFormatter.Builder()
.setMetricUnits(metricsUnits)
.build(context).getDistanceParts(aggregatedStatistic.getTrackStatistics().getTotalDistance());
distance.setText(parts.first); distance.setText(parts.first);
distanceUnit.setText(parts.second); distanceUnit.setText(parts.second);
@@ -55,7 +55,9 @@ public class IntervalStatisticsAdapter extends RecyclerView.Adapter<RecyclerView
} else { } else {
sumDistance = interval.getDistance().multipliedBy(nextPosition); sumDistance = interval.getDistance().multipliedBy(nextPosition);
} }
viewHolder.distance.setText(DistanceFormatter.Builder().build(context).formatDistance(sumDistance, metricUnits)); viewHolder.distance.setText(DistanceFormatter.Builder()
.setMetricUnits(metricUnits)
.build(context).formatDistance(sumDistance));
viewHolder.rate.setText(StringUtils.formatSpeed(context, interval.getSpeed(), metricUnits, isReportSpeed)); viewHolder.rate.setText(StringUtils.formatSpeed(context, interval.getSpeed(), metricUnits, isReportSpeed));
@@ -108,6 +108,7 @@ public class IntervalsFragment extends Fragment {
final DistanceFormatter formatter = DistanceFormatter.Builder() final DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(0) .setDecimalCount(0)
.setMetricUnits(metricUnits)
.build(getContext()); .build(getContext());
intervalsAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, IntervalStatisticsModel.IntervalOption.values()) { intervalsAdapter = new ArrayAdapter<>(getContext(), android.R.layout.simple_spinner_dropdown_item, IntervalStatisticsModel.IntervalOption.values()) {
@@ -117,7 +118,7 @@ public class IntervalsFragment extends Fragment {
TextView v = (TextView) super.getView(position, convertView, parent); TextView v = (TextView) super.getView(position, convertView, parent);
IntervalStatisticsModel.IntervalOption option = getItem(position); IntervalStatisticsModel.IntervalOption option = getItem(position);
String stringValue = formatter.formatDistance(option.getDistance(metricUnits), metricUnits); String stringValue = formatter.formatDistance(option.getDistance(metricUnits));
v.setText(stringValue); v.setText(stringValue);
return v; return v;
} }
@@ -199,10 +200,11 @@ public class IntervalsFragment extends Fragment {
private void setIntervalsDropdownText() { private void setIntervalsDropdownText() {
DistanceFormatter formatter = DistanceFormatter.Builder() DistanceFormatter formatter = DistanceFormatter.Builder()
.setDecimalCount(0) .setDecimalCount(0)
.setMetricUnits(metricUnits)
.build(getContext()); .build(getContext());
IntervalStatisticsModel.IntervalOption option = selectedInterval != null ? selectedInterval : IntervalStatisticsModel.IntervalOption.DEFAULT; IntervalStatisticsModel.IntervalOption option = selectedInterval != null ? selectedInterval : IntervalStatisticsModel.IntervalOption.DEFAULT;
String stringValue = formatter.formatDistance(option.getDistance(metricUnits), metricUnits); String stringValue = formatter.formatDistance(option.getDistance(metricUnits));
viewBinding.intervalsDropdown.setText(stringValue, false); viewBinding.intervalsDropdown.setText(stringValue, false);
} }
@@ -54,7 +54,9 @@ public class StatisticDataBuilder {
valueAndUnit = new Pair<>(StringUtils.formatElapsedTime(trackStatistics.getMovingTime()), null); valueAndUnit = new Pair<>(StringUtils.formatElapsedTime(trackStatistics.getMovingTime()), null);
title = context.getString(R.string.stats_moving_time); title = context.getString(R.string.stats_moving_time);
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_distance_key))) { } else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_distance_key))) {
valueAndUnit = DistanceFormatter.Builder().build(context).getDistanceParts(trackStatistics.getTotalDistance(), metricUnits); valueAndUnit = DistanceFormatter.Builder()
.setMetricUnits(metricUnits)
.build(context).getDistanceParts(trackStatistics.getTotalDistance());
title = context.getString(R.string.stats_distance); 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))) { } 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"); boolean reportSpeed = fieldKey.equals("speed");