forked from upstream-mirrors/OpenTracks
Proper handling of timezone data on UI. Fixes #301.
Details: - Date and time handled by OffsetDateTime Java class. - Track default name with offset (for date local and ISO 8601 options). - TrackListActivity: shows relative today's date (like Today, Yesterday, 22 Dec, 22 Dec 2021, etc). - StatisticsRecordedFragment: always shows the original date and time. For example, if you record an activity at 20h then it always will show 20h regardless the zone are where you are. - Added new tests.
This commit is contained in:
committed by
Román Martínez
parent
1631836327
commit
5cd6992c90
@@ -27,6 +27,8 @@ import org.junit.runner.RunWith;
|
|||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
@@ -91,7 +93,7 @@ public class DescriptionGeneratorTest {
|
|||||||
+ "Min elevation: -500 m (-1640 ft)<br>"
|
+ "Min elevation: -500 m (-1640 ft)<br>"
|
||||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
+ "Recorded: " + StringUtils.formatDateTime(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
|
||||||
|
|
||||||
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
@@ -127,7 +129,7 @@ public class DescriptionGeneratorTest {
|
|||||||
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
|
+ "Fastest pace: 0:10 min/km (0:16 min/mi)<br>"
|
||||||
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
+ "Elevation gain: 6000 m (19685 ft)<br>"
|
||||||
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
+ "Elevation loss: 6000 m (19685 ft)<br>"
|
||||||
+ "Recorded: " + StringUtils.formatDateTime(context, START_TIME) + "<br>";
|
+ "Recorded: " + StringUtils.formatDateTime(OffsetDateTime.ofInstant(START_TIME, ZoneId.systemDefault())) + "<br>";
|
||||||
|
|
||||||
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
assertEquals(expected, descriptionGenerator.generateTrackDescription(track, true));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,6 +20,8 @@ import static org.junit.Assert.assertEquals;
|
|||||||
import static org.junit.Assert.assertTrue;
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
import android.content.res.Configuration;
|
||||||
|
import android.content.res.Resources;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
@@ -27,9 +29,23 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import java.time.DayOfWeek;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.time.Month;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
import java.time.format.TextStyle;
|
||||||
|
import java.time.temporal.ChronoUnit;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
import java.util.GregorianCalendar;
|
import java.util.GregorianCalendar;
|
||||||
|
import java.util.Locale;
|
||||||
import java.util.TimeZone;
|
import java.util.TimeZone;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
import de.dennisguse.opentracks.content.data.Speed;
|
||||||
@@ -184,4 +200,82 @@ public class StringUtilsTest {
|
|||||||
assertEquals("12.0 km/h", StringUtils.formatSpeed(context, Speed.of(3.34), true, true));
|
assertEquals("12.0 km/h", StringUtils.formatSpeed(context, Speed.of(3.34), true, true));
|
||||||
assertEquals("7.5 mph", StringUtils.formatSpeed(context, Speed.of(3.34), false, true));
|
assertEquals("7.5 mph", StringUtils.formatSpeed(context, Speed.of(3.34), false, true));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormatDateTime() {
|
||||||
|
LocalDateTime localDateTime = LocalDateTime.parse("2022-01-02T10:15:30");
|
||||||
|
|
||||||
|
setLocale("en", "US");
|
||||||
|
testFormatDateTime(localDateTime, localDateTime.getMonth().getDisplayName(TextStyle.SHORT, Locale.getDefault()) + " " + localDateTime.getDayOfMonth() + ", " + localDateTime.getYear() + " 10:15:30");
|
||||||
|
|
||||||
|
setLocale("es", "ES");
|
||||||
|
testFormatDateTime(localDateTime, localDateTime.getDayOfMonth() + " " + localDateTime.getMonth().getDisplayName(TextStyle.SHORT, Locale.getDefault()) + " " + localDateTime.getYear() + " 10:15:30");
|
||||||
|
|
||||||
|
setLocale("de", "DE");
|
||||||
|
testFormatDateTime(localDateTime, String.format("%02d", localDateTime.getDayOfMonth()) + "." + String.format("%02d", localDateTime.getMonthValue()) + "." + String.format("%04d", localDateTime.getYear()) + " 10:15:30");
|
||||||
|
}
|
||||||
|
|
||||||
|
private void testFormatDateTime(LocalDateTime localDateTime, String expectedFormat) {
|
||||||
|
// given
|
||||||
|
int offsetFromLocale = OffsetDateTime.now().getOffset().getTotalSeconds() - 28800; // -08:00
|
||||||
|
OffsetDateTime localOffsetDateTime = OffsetDateTime.of(localDateTime, ZoneOffset.systemDefault().getRules().getOffset(Instant.now()));
|
||||||
|
OffsetDateTime outOffsetDateTime = OffsetDateTime.of(localDateTime, ZoneOffset.ofTotalSeconds(offsetFromLocale));
|
||||||
|
|
||||||
|
// when
|
||||||
|
String formatDate = StringUtils.formatDateTime(outOffsetDateTime);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(localOffsetDateTime.getOffset().getTotalSeconds(), outOffsetDateTime.getOffset().getTotalSeconds() + 28800);
|
||||||
|
assertEquals(formatDate, expectedFormat);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFormatDateTodayRelative() {
|
||||||
|
// given
|
||||||
|
ArrayList<String> shortDays = Arrays.stream(DayOfWeek.values()).map(d -> d.getDisplayName(TextStyle.FULL, Locale.getDefault())).collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
ArrayList<String> shortMonths = Arrays.stream(Month.values()).map(m -> m.getDisplayName(TextStyle.SHORT, Locale.getDefault())).collect(Collectors.toCollection(ArrayList::new));
|
||||||
|
|
||||||
|
LocalDate today = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()).toLocalDate();
|
||||||
|
LocalDate yesterday = today.minus(1, ChronoUnit.DAYS);
|
||||||
|
LocalDate dayName = today.minus(2, ChronoUnit.DAYS);
|
||||||
|
LocalDate thisYear = today.minus(15, ChronoUnit.DAYS);
|
||||||
|
LocalDate aYearAgo = today.minus(400, ChronoUnit.DAYS);
|
||||||
|
|
||||||
|
int offsetFromLocale = OffsetDateTime.now().getOffset().getTotalSeconds() - 28800; // -08:00
|
||||||
|
|
||||||
|
OffsetDateTime todayRecordedOdt = OffsetDateTime.of(LocalDateTime.of(today.getYear(), today.getMonth(), today.getDayOfMonth(), 20, 0, 0), ZoneOffset.ofTotalSeconds(offsetFromLocale));
|
||||||
|
OffsetDateTime yesterdayRecordedOdt = OffsetDateTime.of(LocalDateTime.of(yesterday.getYear(), yesterday.getMonth(), yesterday.getDayOfMonth(), 1, 0, 0), ZoneOffset.ofTotalSeconds(offsetFromLocale));
|
||||||
|
OffsetDateTime dayNameRecordedOdt = OffsetDateTime.of(LocalDateTime.of(dayName.getYear(), dayName.getMonth(), dayName.getDayOfMonth(), 7, 0, 0), ZoneOffset.ofTotalSeconds(offsetFromLocale));
|
||||||
|
OffsetDateTime thisYearRecordedOdt = OffsetDateTime.of(LocalDateTime.of(thisYear.getYear(), thisYear.getMonth(), thisYear.getDayOfMonth(), 12, 0, 0), ZoneOffset.ofTotalSeconds(offsetFromLocale));
|
||||||
|
OffsetDateTime aYearAgoRecordedOdt = OffsetDateTime.of(LocalDateTime.of(aYearAgo.getYear(), aYearAgo.getMonth(), aYearAgo.getDayOfMonth(), 17, 0, 0), ZoneOffset.ofTotalSeconds(offsetFromLocale));
|
||||||
|
|
||||||
|
// when
|
||||||
|
String formatToday = StringUtils.formatDateTodayRelative(context, todayRecordedOdt);
|
||||||
|
String formatYesterday = StringUtils.formatDateTodayRelative(context, yesterdayRecordedOdt);
|
||||||
|
String formatDayName = StringUtils.formatDateTodayRelative(context, dayNameRecordedOdt);
|
||||||
|
String formatThisYear = StringUtils.formatDateTodayRelative(context, thisYearRecordedOdt);
|
||||||
|
String formatAYearAgo = StringUtils.formatDateTodayRelative(context, aYearAgoRecordedOdt);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals("Today", formatToday);
|
||||||
|
assertEquals("Yesterday", formatYesterday);
|
||||||
|
assertTrue(shortDays.contains(formatDayName)); // Something like Friday
|
||||||
|
if (today.getYear() != thisYear.getYear()) {
|
||||||
|
assertTrue(shortMonths.stream().anyMatch(fty -> formatThisYear.matches("\\d+ " + fty + " \\d{4}"))); // Something like 14 Dec 2021
|
||||||
|
} else {
|
||||||
|
assertTrue(shortMonths.stream().anyMatch(fty -> formatThisYear.matches("\\d+ " + fty))); // Something like 14 Dec
|
||||||
|
}
|
||||||
|
assertTrue(shortMonths.stream().anyMatch(fty -> formatAYearAgo.matches("\\d+ " + fty + " \\d{4}"))); // Something like 14 Dec 2021
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setLocale(String language, String country) {
|
||||||
|
Locale locale = new Locale(language, country);
|
||||||
|
// here we update locale for date formatters
|
||||||
|
Locale.setDefault(locale);
|
||||||
|
// here we update locale for app resources
|
||||||
|
Resources res = context.getResources();
|
||||||
|
Configuration config = res.getConfiguration();
|
||||||
|
config.locale = locale;
|
||||||
|
res.updateConfiguration(config, res.getDisplayMetrics());
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,6 +16,8 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import static org.junit.Assert.assertEquals;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.test.core.app.ApplicationProvider;
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
@@ -24,16 +26,13 @@ import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|||||||
import org.junit.Test;
|
import org.junit.Test;
|
||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
import java.time.LocalDateTime;
|
||||||
import java.time.Instant;
|
import java.time.OffsetDateTime;
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
import de.dennisguse.opentracks.settings.PreferencesUtils;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Tests {@link TrackNameUtils}.
|
* Tests {@link TrackNameUtils}.
|
||||||
*
|
*
|
||||||
@@ -43,7 +42,7 @@ import static org.junit.Assert.assertEquals;
|
|||||||
public class TrackNameUtilsTest {
|
public class TrackNameUtilsTest {
|
||||||
|
|
||||||
private static final Track.Id TRACK_ID = new Track.Id(1L);
|
private static final Track.Id TRACK_ID = new Track.Id(1L);
|
||||||
private static final Instant START_TIME = Instant.ofEpochMilli(1288213406000L);
|
private static final OffsetDateTime START_TIME = OffsetDateTime.parse("2022-01-02T10:15:30+01:00");
|
||||||
|
|
||||||
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
|
private static final Context CONTEXT = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
@@ -53,7 +52,7 @@ public class TrackNameUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testTrackName_date_local() {
|
public void testTrackName_date_local() {
|
||||||
PreferencesUtils.setString(R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_local_value));
|
PreferencesUtils.setString(R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_local_value));
|
||||||
assertEquals(StringUtils.formatDateTime(CONTEXT, START_TIME), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
assertEquals(StringUtils.formatDateTimeWithOffset(START_TIME), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,8 +61,7 @@ public class TrackNameUtilsTest {
|
|||||||
@Test
|
@Test
|
||||||
public void testTrackName_date_iso_8601() {
|
public void testTrackName_date_iso_8601() {
|
||||||
PreferencesUtils.setString(R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value));
|
PreferencesUtils.setString(R.string.track_name_key, CONTEXT.getString(R.string.settings_recording_track_name_date_iso_8601_value));
|
||||||
SimpleDateFormat simpleDateFormat = new SimpleDateFormat(TrackNameUtils.ISO_8601_FORMAT, Locale.US);
|
assertEquals(StringUtils.formatDateTimeIso8601(START_TIME.toInstant(), START_TIME.getOffset()), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
||||||
assertEquals(simpleDateFormat.format(START_TIME.toEpochMilli()), TrackNameUtils.getTrackName(CONTEXT, TRACK_ID, START_TIME));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -326,7 +326,7 @@ public class MarkerListActivity extends AbstractActivity implements DeleteMarker
|
|||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
final String[] PROJECTION = new String[]{MarkerColumns._ID,
|
final String[] PROJECTION = new String[]{MarkerColumns._ID,
|
||||||
MarkerColumns.NAME, MarkerColumns.DESCRIPTION, MarkerColumns.CATEGORY,
|
MarkerColumns.NAME, MarkerColumns.DESCRIPTION, MarkerColumns.CATEGORY,
|
||||||
MarkerColumns.TIME, MarkerColumns.PHOTOURL};
|
MarkerColumns.TIME, MarkerColumns.PHOTOURL, MarkerColumns.TRACKID};
|
||||||
|
|
||||||
if (searchQuery == null) {
|
if (searchQuery == null) {
|
||||||
if (track != null) {
|
if (track != null) {
|
||||||
|
|||||||
@@ -49,6 +49,9 @@ import androidx.loader.content.CursorLoader;
|
|||||||
import androidx.loader.content.Loader;
|
import androidx.loader.content.Loader;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.Arrays;
|
import java.util.Arrays;
|
||||||
|
|
||||||
@@ -190,6 +193,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
|||||||
int totalTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME);
|
int totalTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALTIME);
|
||||||
int totalDistanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
|
int totalDistanceIndex = cursor.getColumnIndexOrThrow(TracksColumns.TOTALDISTANCE);
|
||||||
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
|
int startTimeIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME);
|
||||||
|
int startTimeOffsetIndex = cursor.getColumnIndexOrThrow(TracksColumns.STARTTIME_OFFSET);
|
||||||
int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY);
|
int categoryIndex = cursor.getColumnIndexOrThrow(TracksColumns.CATEGORY);
|
||||||
int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION);
|
int descriptionIndex = cursor.getColumnIndexOrThrow(TracksColumns.DESCRIPTION);
|
||||||
int markerCountIndex = cursor.getColumnIndexOrThrow(TracksColumns.MARKER_COUNT);
|
int markerCountIndex = cursor.getColumnIndexOrThrow(TracksColumns.MARKER_COUNT);
|
||||||
@@ -203,12 +207,14 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
|||||||
String totalDistance = StringUtils.formatDistance(TrackListActivity.this, Distance.of(cursor.getDouble(totalDistanceIndex)), metricUnits);
|
String totalDistance = StringUtils.formatDistance(TrackListActivity.this, Distance.of(cursor.getDouble(totalDistanceIndex)), metricUnits);
|
||||||
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);
|
||||||
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
|
String category = icon != null && !icon.equals("") ? null : cursor.getString(categoryIndex);
|
||||||
String description = cursor.getString(descriptionIndex);
|
String description = cursor.getString(descriptionIndex);
|
||||||
|
|
||||||
ListItemUtils.setListItem(TrackListActivity.this, view, isRecording, recordingStatus.isPaused(),
|
ListItemUtils.setListItem(TrackListActivity.this, view, isRecording, recordingStatus.isPaused(),
|
||||||
iconId, R.string.image_track, name, totalTime, totalDistance, markerCount,
|
iconId, R.string.image_track, name, totalTime, totalDistance, markerCount,
|
||||||
startTime, true, category, description, false);
|
OffsetDateTime.ofInstant(Instant.ofEpochMilli(startTime), ZoneOffset.ofTotalSeconds(startTimeOffset)),
|
||||||
|
category, description, false);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
viewBinding.trackList.setAdapter(resourceCursorAdapter);
|
viewBinding.trackList.setAdapter(resourceCursorAdapter);
|
||||||
@@ -515,7 +521,7 @@ public class TrackListActivity extends AbstractTrackDeleteActivity implements Co
|
|||||||
@Override
|
@Override
|
||||||
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
public Loader<Cursor> onCreateLoader(int arg0, Bundle arg1) {
|
||||||
final String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
final String[] PROJECTION = new String[]{TracksColumns._ID, TracksColumns.NAME,
|
||||||
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME,
|
TracksColumns.DESCRIPTION, TracksColumns.CATEGORY, TracksColumns.STARTTIME, TracksColumns.STARTTIME_OFFSET,
|
||||||
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON, TracksColumns.MARKER_COUNT};
|
TracksColumns.TOTALDISTANCE, TracksColumns.TOTALTIME, TracksColumns.ICON, TracksColumns.MARKER_COUNT};
|
||||||
|
|
||||||
final String sortOrder = TracksColumns.STARTTIME + " DESC";
|
final String sortOrder = TracksColumns.STARTTIME + " DESC";
|
||||||
|
|||||||
@@ -19,9 +19,15 @@ import androidx.cursoradapter.widget.ResourceCursorAdapter;
|
|||||||
|
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.io.InputStream;
|
import java.io.InputStream;
|
||||||
|
import java.time.Instant;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
import de.dennisguse.opentracks.content.data.MarkerColumns;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.util.ListItemUtils;
|
import de.dennisguse.opentracks.util.ListItemUtils;
|
||||||
import de.dennisguse.opentracks.util.MarkerUtils;
|
import de.dennisguse.opentracks.util.MarkerUtils;
|
||||||
|
|
||||||
@@ -66,6 +72,7 @@ public class MarkerResourceCursorAdapter extends ResourceCursorAdapter implement
|
|||||||
int categoryIndex = cursor.getColumnIndex(MarkerColumns.CATEGORY);
|
int categoryIndex = cursor.getColumnIndex(MarkerColumns.CATEGORY);
|
||||||
int descriptionIndex = cursor.getColumnIndex(MarkerColumns.DESCRIPTION);
|
int descriptionIndex = cursor.getColumnIndex(MarkerColumns.DESCRIPTION);
|
||||||
int photoUrlIndex = cursor.getColumnIndex(MarkerColumns.PHOTOURL);
|
int photoUrlIndex = cursor.getColumnIndex(MarkerColumns.PHOTOURL);
|
||||||
|
int trackIdIndex = cursor.getColumnIndex(MarkerColumns.TRACKID);
|
||||||
|
|
||||||
long id = cursor.getLong(idIndex);
|
long id = cursor.getLong(idIndex);
|
||||||
int iconId = MarkerUtils.ICON_ID;
|
int iconId = MarkerUtils.ICON_ID;
|
||||||
@@ -74,6 +81,7 @@ public class MarkerResourceCursorAdapter extends ResourceCursorAdapter implement
|
|||||||
String category = cursor.getString(categoryIndex);
|
String category = cursor.getString(categoryIndex);
|
||||||
String description = cursor.getString(descriptionIndex);
|
String description = cursor.getString(descriptionIndex);
|
||||||
String photoUrl = cursor.getString(photoUrlIndex);
|
String photoUrl = cursor.getString(photoUrlIndex);
|
||||||
|
long trackId = cursor.getLong(trackIdIndex);
|
||||||
|
|
||||||
view.setTag(String.valueOf(id));
|
view.setTag(String.valueOf(id));
|
||||||
|
|
||||||
@@ -96,7 +104,10 @@ public class MarkerResourceCursorAdapter extends ResourceCursorAdapter implement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ListItemUtils.setListItem(activity, view, false, true, iconId, R.string.image_marker, name, null, null, 0, time, false, category, description, hasPhoto);
|
ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
|
||||||
|
Track track = contentProviderUtils.getTrack(new Track.Id(trackId));
|
||||||
|
ListItemUtils.setListItem(activity, view, false, true, iconId, R.string.image_marker, name, null, null, 0,
|
||||||
|
OffsetDateTime.ofInstant(Instant.ofEpochMilli(time), track.getZoneOffset()), category, description, hasPhoto);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void clear() {
|
public void clear() {
|
||||||
|
|||||||
@@ -22,6 +22,8 @@ import android.util.Pair;
|
|||||||
import androidx.annotation.VisibleForTesting;
|
import androidx.annotation.VisibleForTesting;
|
||||||
|
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.ZoneId;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
@@ -150,7 +152,7 @@ public class DescriptionGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Recorded time
|
// Recorded time
|
||||||
builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTime(context, stats.getStartTime())));
|
builder.append(context.getString(R.string.description_recorded_time, StringUtils.formatDateTime(OffsetDateTime.ofInstant(stats.getStartTime(), ZoneId.systemDefault()))));
|
||||||
builder.append(lineBreak);
|
builder.append(lineBreak);
|
||||||
|
|
||||||
return builder.toString();
|
return builder.toString();
|
||||||
|
|||||||
@@ -82,10 +82,10 @@ public class FilterDialogFragment extends DialogFragment {
|
|||||||
TextInputEditText dateTo = layout.findViewById(R.id.filter_date_edit_text_to);
|
TextInputEditText dateTo = layout.findViewById(R.id.filter_date_edit_text_to);
|
||||||
|
|
||||||
LocalDateTime firstDayThisWeek = LocalDate.now().with(WeekFields.of(Locale.getDefault()).getFirstDayOfWeek()).atStartOfDay();
|
LocalDateTime firstDayThisWeek = LocalDate.now().with(WeekFields.of(Locale.getDefault()).getFirstDayOfWeek()).atStartOfDay();
|
||||||
dateFrom.setText(StringUtils.formatDate(getActivity(), firstDayThisWeek));
|
dateFrom.setText(StringUtils.formatLocalDateTime(firstDayThisWeek));
|
||||||
datePickerFrom.init(firstDayThisWeek.getYear(), firstDayThisWeek.getMonthValue() - 1, firstDayThisWeek.getDayOfMonth(), (view, year, monthOfYear, dayOfMonth) -> {
|
datePickerFrom.init(firstDayThisWeek.getYear(), firstDayThisWeek.getMonthValue() - 1, firstDayThisWeek.getDayOfMonth(), (view, year, monthOfYear, dayOfMonth) -> {
|
||||||
LocalDateTime localDateTime = LocalDateTime.of(year, monthOfYear + 1, dayOfMonth, 0, 0, 0);
|
LocalDateTime localDateTime = LocalDateTime.of(year, monthOfYear + 1, dayOfMonth, 0, 0, 0);
|
||||||
dateFrom.setText(StringUtils.formatDate(getActivity(), localDateTime));
|
dateFrom.setText(StringUtils.formatLocalDateTime(localDateTime));
|
||||||
datePickerFrom.setVisibility(View.GONE);
|
datePickerFrom.setVisibility(View.GONE);
|
||||||
datePickerTo.setMinDate(localDateTime.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());
|
datePickerTo.setMinDate(localDateTime.toInstant(ZoneOffset.ofTotalSeconds(0)).toEpochMilli());
|
||||||
if (localDateTime.isAfter(LocalDateTime.of(datePickerTo.getYear(), datePickerTo.getMonth() + 1, datePickerTo.getDayOfMonth(), 23, 59, 59))) {
|
if (localDateTime.isAfter(LocalDateTime.of(datePickerTo.getYear(), datePickerTo.getMonth() + 1, datePickerTo.getDayOfMonth(), 23, 59, 59))) {
|
||||||
@@ -94,10 +94,10 @@ public class FilterDialogFragment extends DialogFragment {
|
|||||||
});
|
});
|
||||||
|
|
||||||
LocalDateTime lastDayThisWeek = firstDayThisWeek.plusDays(6).withHour(23).withMinute(59).withSecond(59);
|
LocalDateTime lastDayThisWeek = firstDayThisWeek.plusDays(6).withHour(23).withMinute(59).withSecond(59);
|
||||||
dateTo.setText(StringUtils.formatDate(getActivity(), lastDayThisWeek));
|
dateTo.setText(StringUtils.formatLocalDateTime(lastDayThisWeek));
|
||||||
datePickerTo.init(lastDayThisWeek.getYear(), lastDayThisWeek.getMonthValue() - 1, lastDayThisWeek.getDayOfMonth(), (view, year, monthOfYear, dayOfMonth) -> {
|
datePickerTo.init(lastDayThisWeek.getYear(), lastDayThisWeek.getMonthValue() - 1, lastDayThisWeek.getDayOfMonth(), (view, year, monthOfYear, dayOfMonth) -> {
|
||||||
LocalDateTime localDateTime = LocalDateTime.of(year, monthOfYear + 1, dayOfMonth, 23, 59, 59);
|
LocalDateTime localDateTime = LocalDateTime.of(year, monthOfYear + 1, dayOfMonth, 23, 59, 59);
|
||||||
dateTo.setText(StringUtils.formatDate(getActivity(), localDateTime));
|
dateTo.setText(StringUtils.formatLocalDateTime(localDateTime));
|
||||||
datePickerTo.setVisibility(View.GONE);
|
datePickerTo.setVisibility(View.GONE);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@@ -179,7 +179,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
private void loadTrackDescription(@NonNull Track track) {
|
private void loadTrackDescription(@NonNull Track track) {
|
||||||
viewBinding.statsNameValue.setText(track.getName());
|
viewBinding.statsNameValue.setText(track.getName());
|
||||||
viewBinding.statsDescriptionValue.setText(track.getDescription());
|
viewBinding.statsDescriptionValue.setText(track.getDescription());
|
||||||
viewBinding.statsStartDatetimeValue.setText(StringUtils.formatDateTime(getContext(), track.getTrackStatistics().getStartTime()));
|
viewBinding.statsStartDatetimeValue.setText(StringUtils.formatDateTime(track.getStartTime()));
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
|
|||||||
@@ -9,6 +9,7 @@ import android.util.Pair;
|
|||||||
|
|
||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
@@ -59,13 +60,12 @@ class TrackRecordingManager {
|
|||||||
|
|
||||||
insertTrackPoint(trackId, segmentStartTrackPoint);
|
insertTrackPoint(trackId, segmentStartTrackPoint);
|
||||||
|
|
||||||
//TODO Pass TrackPoint
|
|
||||||
track.setName(TrackNameUtils.getTrackName(context, trackId, segmentStartTrackPoint.getTime()));
|
|
||||||
|
|
||||||
String category = PreferencesUtils.getDefaultActivity();
|
String category = PreferencesUtils.getDefaultActivity();
|
||||||
track.setCategory(category);
|
track.setCategory(category);
|
||||||
track.setIcon(TrackIconUtils.getIconValue(context, category));
|
track.setIcon(TrackIconUtils.getIconValue(context, category));
|
||||||
track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
|
track.setTrackStatistics(trackStatisticsUpdater.getTrackStatistics());
|
||||||
|
//TODO Pass TrackPoint
|
||||||
|
track.setName(TrackNameUtils.getTrackName(context, trackId, track.getStartTime()));
|
||||||
contentProviderUtils.updateTrack(track);
|
contentProviderUtils.updateTrack(track);
|
||||||
|
|
||||||
currentSegmentHasTrackPoint = false;
|
currentSegmentHasTrackPoint = false;
|
||||||
|
|||||||
@@ -17,8 +17,6 @@
|
|||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.graphics.BitmapFactory;
|
|
||||||
import android.text.format.DateUtils;
|
|
||||||
import android.view.Gravity;
|
import android.view.Gravity;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup.LayoutParams;
|
import android.view.ViewGroup.LayoutParams;
|
||||||
@@ -26,6 +24,9 @@ import android.widget.ImageView;
|
|||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import java.time.OffsetDateTime;
|
||||||
|
import java.time.format.DateTimeFormatter;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -51,13 +52,12 @@ public class ListItemUtils {
|
|||||||
* @param totalTime the total time value
|
* @param totalTime the total time value
|
||||||
* @param totalDistance the total distance value
|
* @param totalDistance the total distance value
|
||||||
* @param markerCount the marker count
|
* @param markerCount the marker count
|
||||||
* @param startTime the start time value
|
* @param offsetDateTime the start time with offset
|
||||||
* @param useRelativeTime true to display relative time if appropriate
|
|
||||||
* @param category the category value
|
* @param category the category value
|
||||||
* @param description the description value
|
* @param description the description value
|
||||||
* @param hasPhoto true if this list item has photo
|
* @param hasPhoto true if this list item has photo
|
||||||
*/
|
*/
|
||||||
public static void setListItem(Context context, View view, boolean isRecording, boolean isPaused, int iconId, int iconContentDescriptionId, String name, String totalTime, String totalDistance, int markerCount, long startTime, boolean useRelativeTime, String category, String description, boolean hasPhoto) {
|
public static void setListItem(Context context, View view, boolean isRecording, boolean isPaused, int iconId, int iconContentDescriptionId, String name, String totalTime, String totalDistance, int markerCount, OffsetDateTime offsetDateTime, String category, String description, boolean hasPhoto) {
|
||||||
// Set icon
|
// Set icon
|
||||||
if (isRecording) {
|
if (isRecording) {
|
||||||
iconId = isPaused ? R.drawable.ic_track_paused : R.drawable.ic_track_recording;
|
iconId = isPaused ? R.drawable.ic_track_paused : R.drawable.ic_track_recording;
|
||||||
@@ -104,12 +104,16 @@ public class ListItemUtils {
|
|||||||
setTextView(context, markerCountTextView, markerCountValue, hasPhoto);
|
setTextView(context, markerCountTextView, markerCountValue, hasPhoto);
|
||||||
|
|
||||||
// Set date/time
|
// Set date/time
|
||||||
String[] dateTime = getDateTime(isRecording, context, startTime, useRelativeTime);
|
|
||||||
TextView dateTextView = view.findViewById(R.id.list_item_date);
|
TextView dateTextView = view.findViewById(R.id.list_item_date);
|
||||||
setTextView(context, dateTextView, dateTime[0], hasPhoto);
|
|
||||||
|
|
||||||
TextView timeTextView = view.findViewById(R.id.list_item_time);
|
TextView timeTextView = view.findViewById(R.id.list_item_time);
|
||||||
setTextView(context, timeTextView, dateTime[1], hasPhoto);
|
String dateValue = null;
|
||||||
|
String timeValue = null;
|
||||||
|
if (!isRecording) {
|
||||||
|
dateValue = StringUtils.formatDateTodayRelative(context, offsetDateTime);
|
||||||
|
timeValue = offsetDateTime.format(DateTimeFormatter.ofPattern("hh:mm"));
|
||||||
|
}
|
||||||
|
setTextView(context, dateTextView, dateValue, hasPhoto);
|
||||||
|
setTextView(context, timeTextView, timeValue, hasPhoto);
|
||||||
|
|
||||||
// Set category and description
|
// Set category and description
|
||||||
TextView categoryDescriptionTextView = view.findViewById(R.id.list_item_category_description);
|
TextView categoryDescriptionTextView = view.findViewById(R.id.list_item_category_description);
|
||||||
@@ -133,27 +137,6 @@ public class ListItemUtils {
|
|||||||
params.gravity = timeDistanceTextView.getVisibility() == View.GONE && markerCountIcon.getVisibility() == View.GONE ? Gravity.TOP : Gravity.CENTER_VERTICAL;
|
params.gravity = timeDistanceTextView.getVisibility() == View.GONE && markerCountIcon.getVisibility() == View.GONE ? Gravity.TOP : Gravity.CENTER_VERTICAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int calculateInSampleSize(BitmapFactory.Options options, int reqWidth, int reqHeight) {
|
|
||||||
// Raw height and width of image
|
|
||||||
final int height = options.outHeight;
|
|
||||||
final int width = options.outWidth;
|
|
||||||
int inSampleSize = 1;
|
|
||||||
|
|
||||||
if (height > reqHeight || width > reqWidth) {
|
|
||||||
|
|
||||||
final int halfHeight = height / 2;
|
|
||||||
final int halfWidth = width / 2;
|
|
||||||
|
|
||||||
// Calculate the largest inSampleSize value that is a power of 2 and keeps both height and width larger than the requested height and width.
|
|
||||||
while ((halfHeight / inSampleSize) >= reqHeight
|
|
||||||
&& (halfWidth / inSampleSize) >= reqWidth) {
|
|
||||||
inSampleSize *= 2;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return inSampleSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string for share owner, total time, and total distance.
|
* Gets a string for share owner, total time, and total distance.
|
||||||
*
|
*
|
||||||
@@ -177,30 +160,6 @@ public class ListItemUtils {
|
|||||||
return builder.toString();
|
return builder.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Gets the date and time as an array of two strings.
|
|
||||||
*
|
|
||||||
* @param isRecording true if recording
|
|
||||||
* @param context the context
|
|
||||||
* @param time the start time
|
|
||||||
*/
|
|
||||||
private static String[] getDateTime(boolean isRecording, Context context, long time, boolean useRelativeTime) {
|
|
||||||
if (isRecording || time == 0L) {
|
|
||||||
return new String[]{null, null};
|
|
||||||
}
|
|
||||||
|
|
||||||
boolean isToday = DateUtils.isToday(time);
|
|
||||||
int timeFlags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_ABBREV_ALL;
|
|
||||||
|
|
||||||
if (isToday && useRelativeTime) {
|
|
||||||
return new String[]{DateUtils.getRelativeTimeSpanString(time, System.currentTimeMillis(), DateUtils.MINUTE_IN_MILLIS, DateUtils.FORMAT_ABBREV_RELATIVE).toString(), null};
|
|
||||||
} else if (isToday) {
|
|
||||||
return new String[]{DateUtils.formatDateTime(context, time, timeFlags), null};
|
|
||||||
}
|
|
||||||
|
|
||||||
return new String[]{DateUtils.formatDateTime(context, time, DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_ABBREV_ALL), DateUtils.formatDateTime(context, time, timeFlags)};
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Sets a text view.
|
* Sets a text view.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
*/
|
*/
|
||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import static java.time.temporal.ChronoUnit.DAYS;
|
||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.location.Location;
|
import android.location.Location;
|
||||||
import android.text.TextUtils;
|
import android.text.TextUtils;
|
||||||
@@ -28,12 +30,14 @@ import java.math.RoundingMode;
|
|||||||
import java.text.DecimalFormat;
|
import java.text.DecimalFormat;
|
||||||
import java.time.Duration;
|
import java.time.Duration;
|
||||||
import java.time.Instant;
|
import java.time.Instant;
|
||||||
|
import java.time.LocalDate;
|
||||||
import java.time.LocalDateTime;
|
import java.time.LocalDateTime;
|
||||||
import java.time.ZoneId;
|
import java.time.ZoneId;
|
||||||
import java.time.OffsetDateTime;
|
import java.time.OffsetDateTime;
|
||||||
import java.time.ZoneOffset;
|
import java.time.ZoneOffset;
|
||||||
import java.time.ZonedDateTime;
|
import java.time.ZonedDateTime;
|
||||||
import java.time.format.DateTimeFormatter;
|
import java.time.format.DateTimeFormatter;
|
||||||
|
import java.time.format.FormatStyle;
|
||||||
import java.time.temporal.TemporalAccessor;
|
import java.time.temporal.TemporalAccessor;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
@@ -54,18 +58,47 @@ public class StringUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the date and time based on user's phone date/time preferences.
|
* Formats the date and time of the OffsetDateTime (using default Locale format)
|
||||||
*/
|
*/
|
||||||
public static String formatDateTime(Context context, Instant time) {
|
public static String formatDateTime(OffsetDateTime odt) {
|
||||||
return DateUtils.formatDateTime(context, time.toEpochMilli(), DateUtils.FORMAT_SHOW_DATE | DateUtils.FORMAT_NUMERIC_DATE)
|
return odt.format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.MEDIUM));
|
||||||
+ " " + DateUtils.formatDateTime(context, time.toEpochMilli(), DateUtils.FORMAT_SHOW_TIME);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Formats the date and time based on user's phone date/time preferences.
|
* Formats the date and time with the offset (using default Locale format).
|
||||||
*/
|
*/
|
||||||
public static String formatDate(Context context, LocalDateTime localDateTime) {
|
public static String formatDateTimeWithOffset(OffsetDateTime odt) {
|
||||||
return DateUtils.formatDateTime(context, localDateTime.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli(), DateUtils.FORMAT_SHOW_DATE);
|
return odt.toZonedDateTime().format(DateTimeFormatter.ofLocalizedDateTime(FormatStyle.FULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String formatLocalDateTime(LocalDateTime localDateTime) {
|
||||||
|
return localDateTime.format(DateTimeFormatter.ofLocalizedDate(FormatStyle.FULL));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats the date relative to today date.
|
||||||
|
*/
|
||||||
|
public static String formatDateTodayRelative(Context context, OffsetDateTime odt) {
|
||||||
|
LocalDate today = LocalDateTime.ofInstant(Instant.now(), ZoneId.systemDefault()).toLocalDate();
|
||||||
|
LocalDate ld = odt.toLocalDate();
|
||||||
|
long daysBetween = DAYS.between(ld, today);
|
||||||
|
|
||||||
|
if (daysBetween == 0) {
|
||||||
|
// Today
|
||||||
|
return context.getString(R.string.generic_today);
|
||||||
|
} else if (daysBetween == 1) {
|
||||||
|
// Yesterday
|
||||||
|
return context.getString(R.string.generic_yesterday);
|
||||||
|
} else if (daysBetween < 7) {
|
||||||
|
// Name of the week day
|
||||||
|
return ld.format(DateTimeFormatter.ofPattern("EEEE"));
|
||||||
|
} else if (today.getYear() == ld.getYear()) {
|
||||||
|
// Short date without year
|
||||||
|
return ld.format(DateTimeFormatter.ofPattern("d MMM"));
|
||||||
|
} else {
|
||||||
|
// Short date with year
|
||||||
|
return ld.format(DateTimeFormatter.ofPattern("d MMM y"));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -18,11 +18,7 @@ package de.dennisguse.opentracks.util;
|
|||||||
|
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
|
|
||||||
import androidx.annotation.VisibleForTesting;
|
import java.time.OffsetDateTime;
|
||||||
|
|
||||||
import java.text.SimpleDateFormat;
|
|
||||||
import java.time.Instant;
|
|
||||||
import java.util.Locale;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
@@ -35,21 +31,17 @@ import de.dennisguse.opentracks.settings.PreferencesUtils;
|
|||||||
*/
|
*/
|
||||||
public class TrackNameUtils {
|
public class TrackNameUtils {
|
||||||
|
|
||||||
//TODO Could be available in java.time?
|
|
||||||
@VisibleForTesting
|
|
||||||
static final String ISO_8601_FORMAT = "yyyy-MM-dd HH:mm";
|
|
||||||
|
|
||||||
private TrackNameUtils() {
|
private TrackNameUtils() {
|
||||||
}
|
}
|
||||||
|
|
||||||
//TODO Should not access sharedPreferences; trackName should be an ENUM.
|
//TODO Should not access sharedPreferences; trackName should be an ENUM.
|
||||||
public static String getTrackName(Context context, Track.Id trackId, Instant startTime) {
|
public static String getTrackName(Context context, Track.Id trackId, OffsetDateTime startTime) {
|
||||||
String trackName = PreferencesUtils.getString(R.string.track_name_key, context.getString(R.string.track_name_default));
|
String trackName = PreferencesUtils.getString(R.string.track_name_key, context.getString(R.string.track_name_default));
|
||||||
|
|
||||||
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
|
if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_local_value))) {
|
||||||
return StringUtils.formatDateTime(context, startTime);
|
return StringUtils.formatDateTimeWithOffset(startTime);
|
||||||
} else if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_iso_8601_value))) {
|
} else if (trackName.equals(context.getString(R.string.settings_recording_track_name_date_iso_8601_value))) {
|
||||||
return new SimpleDateFormat(ISO_8601_FORMAT, Locale.US).format(startTime.toEpochMilli());
|
return StringUtils.formatDateTimeIso8601(startTime.toInstant(), startTime.getOffset());
|
||||||
} else {
|
} else {
|
||||||
return context.getString(R.string.track_name_format, trackId.getId());
|
return context.getString(R.string.track_name_format, trackId.getId());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -244,6 +244,8 @@ limitations under the License.
|
|||||||
<string name="generic_filter">Filter</string>
|
<string name="generic_filter">Filter</string>
|
||||||
<string name="generic_from">From</string>
|
<string name="generic_from">From</string>
|
||||||
<string name="generic_to">To</string>
|
<string name="generic_to">To</string>
|
||||||
|
<string name="generic_today">Today</string>
|
||||||
|
<string name="generic_yesterday">Yesterday</string>
|
||||||
<!-- Gps -->
|
<!-- Gps -->
|
||||||
<string name="gps_starting">Starting GPS</string>
|
<string name="gps_starting">Starting GPS</string>
|
||||||
<string name="gps_wait_for_better_signal">Waiting for a better GPS signal</string>
|
<string name="gps_wait_for_better_signal">Waiting for a better GPS signal</string>
|
||||||
|
|||||||
Reference in New Issue
Block a user