Compare commits

...

24 Commits

Author SHA1 Message Date
Dennis Guse 397e056f6f Release: v3.14.0 2020-12-10 22:52:02 +01:00
Dennis Guse eb79f2277a ChartView let's parent handle TouchEvents if not zoomed. 2020-12-06 22:35:44 +01:00
Román Martínez ae8833d21b ViewPager migrate to ViewPager2. Fixes #522.
Swiping between tabs work. Fixes #105.
2020-12-06 22:35:44 +01:00
Dennis Guse e8017a4e9d Bugfix: In preferences, the Bluetooth search icon was only animated after opening the dialog a 2nd time. 2020-12-06 00:09:24 +01:00
Dennis Guse cea180f871 Code cleanup using AndroidStudio's Analyze feature. 2020-12-05 23:22:15 +01:00
Dennis Guse be1b6ece9d IntervalsFragment: generate UI values from strings.xml (i18n). 2020-12-05 23:11:29 +01:00
Vanous 0592863d3c add Huami devices into Readme Tested Sensors 2020-12-05 15:42:09 +01:00
Dennis Guse 18bc100d5a BLE sensors: Miband3's is now considered a heart rate sensor during discovery.
Some BLE devices do not announce all there supported services in the BLE advertisement packages.
Android's ScanFilter decides based upon this information only.
When connecting to such a device (and trigger service discovery), the service can still be used.

Fixes #447.
2020-12-05 12:36:57 +01:00
Peter Storch 4476a15558 throw Exception when no doc.kml file found in kmz 2020-11-29 13:56:22 +01:00
Peter Storch 215c28be85 fix #537 ignore waypoint markers with invalid
coordinates on import.

I've also added a unit test with such an export file.
2020-11-29 13:56:22 +01:00
Dennis Guse a429fbe4df Interval list: RTL and localized formatting (only default strings.xml). 2020-11-28 15:05:49 +01:00
Dennis Guse 6b470c7fdc Intervals: change label from elevation to gain. 2020-11-28 15:05:49 +01:00
Dennis Guse 6b690f38ad Charts: text size is resolved from styles.
Fixes #524.
2020-11-28 15:05:49 +01:00
Dennis Guse f138826d60 Text in charts now scales using Android's global settings.
Fixes #524.
2020-11-28 15:05:49 +01:00
Dennis Guse 14ac29095d Removed unused theme. 2020-11-28 15:05:49 +01:00
Dennis Guse a3f4de7d18 Interval list: table header in accent color. 2020-11-28 15:05:49 +01:00
Dennis Guse 6392e88dc7 Enable RTL. 2020-11-28 15:05:49 +01:00
FTno 1e913d6bb5 Update strings.xml
Typos in source strings - Issue #530
2020-11-26 07:35:34 +01:00
dependabot[bot] ced8454f59 Bump mockito-android from 3.6.0 to 3.6.28
Bumps [mockito-android](https://github.com/mockito/mockito) from 3.6.0 to 3.6.28.
- [Release notes](https://github.com/mockito/mockito/releases)
- [Commits](https://github.com/mockito/mockito/compare/v3.6.0...v3.6.28)

Signed-off-by: dependabot[bot] <support@github.com>
2020-11-25 12:15:57 +01:00
Román Martínez 974a5afeb1 Only clean if parse error is out of <trk> 2020-11-25 06:39:07 +01:00
Román Martínez 9c9bdde6b9 Import files by track in memory (avoid clean track when error). Fixes #473. 2020-11-25 06:39:07 +01:00
Dennis Guse ca2bc6426c Release: v3.13.2 2020-11-22 20:21:50 +01:00
Dennis Guse 81097aac40 Bugfix: crash in landscape mode in TrackController due to wrong background. 2020-11-22 20:21:11 +01:00
Dennis Guse a74b5fc743 Cleanup. 2020-11-21 18:42:32 +01:00
63 changed files with 862 additions and 459 deletions
+3 -1
View File
@@ -9,6 +9,7 @@
* Polar OH1
Has updatable firmware that requires a user account at polar.com
* Wahoo Tickr (Model: WFBTHR02)
* Mi Band 3, Amazfit Band 5, Amazfit Bip. These devices are manufactured by Huami, and other Huami devices will very likely work. Theoretically, this sensor must be enabled, but testing reveals that it works even without enabling. For details on how to enable see [Gadgetbridge wiki](https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Huami-Heartrate-measurement#bluetooth-heart-rate-sensor)
## CSCP: Cycling Cadence and Speed Service
@@ -39,4 +40,5 @@ Also the distance is not computed.
* Elite drivo II
* QUARQ Red DZero Powermeter
* Tacx Satori Smart
* Wahoo Kickr v4.0
* Wahoo Kickr v4.0
+1 -1
View File
@@ -27,7 +27,7 @@ cp "$CHANGELOG_DIR/next_release.txt" "$CHANGELOG_FILE"
sed -i "s/(versionName)/$VERSIONNAME/" "$CHANGELOG_FILE"
echo -e "\nGit commit since last release\n------------"
git log $(git describe --tags --abbrev=0)..HEAD --no-merges --oneline
git log "$(git describe --tags --abbrev=0)..HEAD" --no-merges --oneline
echo -e "\nPlease edit the changelog for the new release"
gedit -w "$CHANGELOG_FILE"
+3 -3
View File
@@ -51,8 +51,8 @@ android {
defaultConfig {
applicationId "de.dennisguse.opentracks"
versionCode 3737
versionName "v3.13.1"
versionCode 3761
versionName "v3.14.0"
buildConfigField "String", "VERSION_NAME_FULL", "\"${getVersionName()}\""
@@ -98,5 +98,5 @@ dependencies {
androidTestImplementation 'androidx.test.ext:junit:1.1.2'
androidTestImplementation 'androidx.test:rules:1.3.0'
androidTestImplementation 'androidx.test:runner:1.3.0'
androidTestImplementation 'org.mockito:mockito-android:3.6.0'
androidTestImplementation 'org.mockito:mockito-android:3.6.28'
}
@@ -0,0 +1,5 @@
v3.13.2: OpenTracks
Bugfix:
- Crash in landscape mode
@@ -0,0 +1,10 @@
v3.14.0: OpenTracks
Changes:
- Properly support for right-to-left
- Import: faster cleanup after import failure
- Text in charts scales according to Android settings
- Heart rate: support for Huami devices (requires Gadgetbridge)
Developer:
- Import is now handled in-memory
@@ -48,7 +48,9 @@ public class ChartValueSeriesTest {
R.string.description_elevation_metric,
R.string.description_elevation_imperial,
R.color.chart_elevation_fill,
R.color.chart_elevation_border) {
R.color.chart_elevation_border,
15,
18) {
@Override
double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getElevation();
@@ -9,6 +9,7 @@ import androidx.test.filters.LargeTest;
import org.junit.After;
import org.junit.Before;
import org.junit.Ignore;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
@@ -196,6 +197,7 @@ public class ExportImportTest {
assertNull(importedTrack);
}
@Ignore
@LargeTest
@Test
public void kmz_only_track() {
@@ -203,6 +205,7 @@ public class ExportImportTest {
Log.e(TAG, "Test not implemented.");
}
@Ignore
@LargeTest
@Test
public void kmz_with_trackdetail() {
@@ -210,6 +213,7 @@ public class ExportImportTest {
Log.e(TAG, "Test not implemented.");
}
@Ignore
@LargeTest
@Test
public void kmz_with_trackdetail_and_sensordata() {
@@ -217,6 +221,7 @@ public class ExportImportTest {
Log.e(TAG, "Test not implemented.");
}
@Ignore
@LargeTest
@Test
public void kmz_with_trackdetail_and_sensordata_and_pictures() {
@@ -0,0 +1,93 @@
package de.dennisguse.opentracks.io.file.importer;
import android.content.Context;
import androidx.test.core.app.ApplicationProvider;
import androidx.test.filters.LargeTest;
import androidx.test.platform.app.InstrumentationRegistry;
import org.junit.After;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;
import java.io.InputStream;
import java.util.List;
import de.dennisguse.opentracks.content.data.Track;
import de.dennisguse.opentracks.content.data.TrackPoint;
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
import de.dennisguse.opentracks.util.StringUtils;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
/**
* Imports a legacy kml file with a statistics marker at the beginning
*/
@RunWith(JUnit4.class)
public class LegacyKmlImportTest {
private final Context context = ApplicationProvider.getApplicationContext();
private final ContentProviderUtils contentProviderUtils = new ContentProviderUtils(context);
private Track.Id importTrackId;
@After
public void tearDown() {
if (importTrackId != null) {
contentProviderUtils.deleteTrack(context, importTrackId);
}
}
@LargeTest
@Test
public void kml_legacy_track_import() {
// given
KmlFileTrackImporter trackImporter = new KmlFileTrackImporter(context);
InputStream inputStream = InstrumentationRegistry.getInstrumentation().getContext().getResources().openRawResource(de.dennisguse.opentracks.debug.test.R.raw.legacy_track);
// when
// 1. import
importTrackId = trackImporter.importFile(inputStream);
// then
// 1. track
Track importedTrack = contentProviderUtils.getTrack(importTrackId);
assertNotNull(importedTrack);
assertEquals("unknown", importedTrack.getCategory());
assertEquals("Test Track", importedTrack.getDescription());
assertEquals("2020-11-28 18:06", importedTrack.getName());
assertEquals("UNKNOWN", importedTrack.getIcon());
// 2. markers
assertEquals(0, contentProviderUtils.getMarkerCount(importTrackId));
// 3. trackpoints
List<TrackPoint> importedTrackPoints = contentProviderUtils.getTrackPoints(importTrackId);
assertEquals(8, importedTrackPoints.size()); // 6 trackpoints + pause and resume
// first 3 trackpoints
assertTrackpoint(importedTrackPoints.get(0), "2020-11-28T17:06:22.401Z", 1.234156, 12.340097, 469.286376953125);
assertTrackpoint(importedTrackPoints.get(1), "2020-11-28T17:06:25.448Z", 1.23415, 12.340036, 439.1626281738281);
assertTrackpoint(importedTrackPoints.get(2), "2020-11-28T17:06:47.888Z", 1.23405, 12.340057, 421.8070983886719);
// created pause trackpoint with time of previous valid trackpoint
assertTrackpoint(importedTrackPoints.get(3), "2020-11-28T17:06:47.888Z", 0.0, 100, 0.0);
// created resume trackpoint with time of next valid trackpoint
assertTrackpoint(importedTrackPoints.get(4), "2020-11-28T17:06:55.861Z", 0.0, 200, 0.0);
// last 3 trackpoints
assertTrackpoint(importedTrackPoints.get(5), "2020-11-28T17:06:55.861Z", 1.23405, 12.340057, 419.93902587890625);
assertTrackpoint(importedTrackPoints.get(6), "2020-11-28T17:06:56.905Z", 1.23405, 12.340057, 419.9036560058594);
assertTrackpoint(importedTrackPoints.get(7), "2020-11-28T17:07:20.870Z", 1.234046, 12.340082, 417.99432373046875);
}
private void assertTrackpoint(final TrackPoint trackPoint, final String when, final double longitude, final double latitude, final double altitude) {
assertEquals(StringUtils.parseTime(when), trackPoint.getTime());
assertEquals(latitude, trackPoint.getLatitude(), 0.001d);
assertEquals(longitude, trackPoint.getLongitude(), 0.001d);
assertEquals(altitude, trackPoint.getAltitude(), 0.001d);
}
}
@@ -9,7 +9,7 @@ import org.junit.Test;
*/
public class ElevationSumManagerTest {
private ElevationSumManager elevationSumManager = new ElevationSumManager();
private final ElevationSumManager elevationSumManager = new ElevationSumManager();
private static void addSensorValue(ElevationSumManager elevationSumManager, float[] values) {
for (float f : values) {
@@ -226,4 +226,13 @@ public class StringUtilsTest {
assertEquals("min/km", StringUtils.getSpeedParts(context, 0, true, false).second);
assertEquals("min/mi", StringUtils.getSpeedParts(context, 0, false, false).second);
}
@Test
public void testFormatSpeed() {
assertEquals("4:59 min/km", StringUtils.formatSpeed(context, 3.34, true, false));
assertEquals("8:02 min/mi", StringUtils.formatSpeed(context, 3.34, false, false));
assertEquals("12.02 km/h", StringUtils.formatSpeed(context, 3.34, true, true));
assertEquals("7.47 mph", StringUtils.formatSpeed(context, 3.34, false, true));
}
}
+173
View File
@@ -0,0 +1,173 @@
<?xml version="1.0" encoding="UTF-8"?>
<kml xmlns="http://www.opengis.net/kml/2.2"
xmlns:gx="http://www.google.com/kml/ext/2.2"
xmlns:atom="http://www.w3.org/2005/Atom"
xmlns:opentracks="http://opentracksapp.com/xmlschemas/v1">
<Document>
<open>1</open>
<visibility>1</visibility>
<name><![CDATA[2020-11-28 18:06]]></name>
<atom:generator><![CDATA[OpenTracks (Debug)]]></atom:generator>
<Style id="track">
<LineStyle><color>7f0000ff</color><width>4</width></LineStyle>
<IconStyle>
<scale>1.3</scale>
<Icon><href>http://earth.google.com/images/kml-icons/track-directional/track-0.png</href></Icon>
</IconStyle>
</Style>
<Style id="start"><IconStyle>
<scale>1.3</scale>
<Icon><href>http://maps.google.com/mapfiles/kml/paddle/grn-circle.png</href></Icon>
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels"/>
</IconStyle></Style>
<Style id="end"><IconStyle>
<scale>1.3</scale>
<Icon><href>http://maps.google.com/mapfiles/kml/paddle/red-circle.png</href></Icon>
<hotSpot x="32" y="1" xunits="pixels" yunits="pixels"/>
</IconStyle></Style>
<Style id="waypoint"><IconStyle>
<scale>1.3</scale>
<Icon><href>http://maps.google.com/mapfiles/kml/pushpin/blue-pushpin.png</href></Icon>
<hotSpot x="20" y="2" xunits="pixels" yunits="pixels"/>
</IconStyle></Style>
<Schema id="schema">
<gx:SimpleArrayField name="speed" type="float">
<displayName><![CDATA[Speed (m/s)]]></displayName>
</gx:SimpleArrayField>
<gx:SimpleArrayField name="power" type="float">
<displayName><![CDATA[Power (W)]]></displayName>
</gx:SimpleArrayField>
<gx:SimpleArrayField name="cadence" type="float">
<displayName><![CDATA[Cadence (rpm)]]></displayName>
</gx:SimpleArrayField>
<gx:SimpleArrayField name="heart_rate" type="float">
<displayName><![CDATA[Heart rate (bpm)]]></displayName>
</gx:SimpleArrayField>
</Schema>
<Folder>
<name><![CDATA[Sun, 28 Nov 2020 18:06 Markers]]></name>
<open>1</open>
<Placemark>
<name><![CDATA[Split 0]]></name>
<description><![CDATA[Total distance: 0.00 km (0.0 mi)
Total time: 00:00
Moving time: 00:00
Average speed: 0.00 km/h (0.0 mi/h)
Average moving speed: 0.00 km/h (0.0 mi/h)
Max speed: 0.00 km/h (0.0 mi/h)
Average pace: 0:00 min/km (0:00 min/mi)
Average moving pace: 0:00 min/km (0:00 min/mi)
Fastest pace: 0:00 min/km (0:00 min/mi)
Max elevation: -9223372036854775808 m (-9223372036854775808 ft)
Min elevation: 9223372036854775807 m (9223372036854775807 ft)
Elevation gain: 0 m (0 ft)
Max grade: 0 %
Min grade: 0 %
Recorded: 6/23 11:29
]]></description>
<TimeStamp><when>1970-01-01T00:00:00Z</when></TimeStamp>
<styleUrl>#waypoint</styleUrl>
<Point>
<coordinates>180.0,100.0</coordinates>
</Point>
</Placemark>
</Folder>
<Placemark>
<name><![CDATA[2020-11-28 18:06 (Start)]]></name>
<description><![CDATA[]]></description>
<TimeStamp><when>2020-11-28T17:06:22.401Z</when></TimeStamp>
<styleUrl>#start</styleUrl>
<Point>
<coordinates>1.234156,12.340097,469.286376953125</coordinates>
</Point>
</Placemark>
<Placemark>
<name><![CDATA[2020-11-28 18:06]]></name>
<description><![CDATA[Test Track]]></description>
<icon><![CDATA[UNKNOWN]]></icon>
<opentracks:trackid>2f170875-55d7-445d-b2b8-22a573c81dbc</opentracks:trackid>
<styleUrl>#track</styleUrl>
<ExtendedData>
<Data name="type"><value><![CDATA[unknown]]></value></Data>
</ExtendedData>
<gx:MultiTrack>
<altitudeMode>absolute</altitudeMode>
<gx:interpolate>1</gx:interpolate>
<gx:Track>
<when>2020-11-28T17:06:22.401Z</when>
<gx:coord>1.234156 12.340097 469.286376953125</gx:coord>
<when>2020-11-28T17:06:25.448Z</when>
<gx:coord>1.23415 12.340036 439.1626281738281</gx:coord>
<when>2020-11-28T17:06:47.888Z</when>
<gx:coord>1.23405 12.340057 421.8070983886719</gx:coord>
<ExtendedData>
<SchemaData schemaUrl="#schema">
<gx:SimpleArrayData name="speed">
<gx:value>0.5391469</gx:value>
<gx:value>0.15777911</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
<gx:SimpleArrayData name="elevation_gain">
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
</SchemaData>
</ExtendedData>
</gx:Track>
<gx:Track>
<when>2020-11-28T17:06:55.861Z</when>
<gx:coord>1.23405 12.340057 419.93902587890625</gx:coord>
<when>2020-11-28T17:06:56.905Z</when>
<gx:coord>1.23405 12.340057 419.9036560058594</gx:coord>
<when>2020-11-28T17:07:20.870Z</when>
<gx:coord>1.234046 12.340082 417.99432373046875</gx:coord>
<ExtendedData>
<SchemaData schemaUrl="#schema">
<gx:SimpleArrayData name="speed">
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
<gx:SimpleArrayData name="elevation_gain">
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
<gx:value>0.0</gx:value>
</gx:SimpleArrayData>
</SchemaData>
</ExtendedData>
</gx:Track>
</gx:MultiTrack>
</Placemark>
<Placemark>
<name><![CDATA[2020-11-28 18:06 (End)]]></name>
<description><![CDATA[OpenTracks (Debug)
Name: 2020-11-28 18:06
Activity type: unknown
Description: -
Total distance: 0.01 km (0.0 mi)
Total time: 01:04
Moving time: 00:00
Average speed: 0.49 km/h (0.3 mi/h)
Average moving speed: 0.00 km/h (0.0 mi/h)
Max speed: 0.00 km/h (0.0 mi/h)
Average pace: 122:30 min/km (197:08 min/mi)
Average moving pace: 0:00 min/km (0:00 min/mi)
Fastest pace: 0:00 min/km (0:00 min/mi)
Max elevation: 469 m (1540 ft)
Min elevation: 419 m (1376 ft)
Elevation gain: 0 m (0 ft)
Recorded: 11/28 18:06
]]></description>
<TimeStamp><when>2020-11-28T17:07:20.870Z</when></TimeStamp>
<styleUrl>#end</styleUrl>
<Point>
<coordinates>1.234046,12.340082,417.99432373046875</coordinates>
</Point>
</Placemark>
</Document>
</kml>
+56 -43
View File
@@ -50,10 +50,11 @@ limitations under the License.
<application
android:name=".Startup"
android:allowBackup="false"
android:hasFragileUserData="true"
android:hardwareAccelerated="true"
android:hasFragileUserData="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:supportsRtl="true"
android:theme="@style/ThemeCustom">
<activity android:name=".AboutActivity" />
@@ -71,14 +72,14 @@ limitations under the License.
<activity android:name=".io.file.importer.ImportActivity">
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/gpx+xml"/>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/gpx+xml" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/gpx"/>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/gpx" />
</intent-filter>
<intent-filter
@@ -86,13 +87,15 @@ limitations under the License.
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="data"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
<data android:scheme="file" />
<data android:scheme="content" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.gpx" />
<data android:pathPattern=".*\\..*\\.gpx" />
<data android:pathPattern=".*\\..*\\..*\\.gpx" />
@@ -110,12 +113,14 @@ limitations under the License.
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="data"/>
<data android:host="*"/>
<data android:scheme="file" />
<data android:scheme="content" />
<data android:scheme="data" />
<data android:host="*" />
<data android:pathPattern=".*\\.gpx" />
<data android:pathPattern=".*\\..*\\.gpx" />
<data android:pathPattern=".*\\..*\\..*\\.gpx" />
@@ -129,9 +134,9 @@ limitations under the License.
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google-earth.kmz"/>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/vnd.google-earth.kmz" />
</intent-filter>
<intent-filter
@@ -139,13 +144,15 @@ limitations under the License.
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="data"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
<data android:scheme="file" />
<data android:scheme="content" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.kmz" />
<data android:pathPattern=".*\\..*\\.kmz" />
<data android:pathPattern=".*\\..*\\..*\\.kmz" />
@@ -163,12 +170,14 @@ limitations under the License.
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="data"/>
<data android:host="*"/>
<data android:scheme="file" />
<data android:scheme="content" />
<data android:scheme="data" />
<data android:host="*" />
<data android:pathPattern=".*\\.kmz" />
<data android:pathPattern=".*\\..*\\.kmz" />
<data android:pathPattern=".*\\..*\\..*\\.kmz" />
@@ -182,9 +191,9 @@ limitations under the License.
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SEND"/>
<category android:name="android.intent.category.DEFAULT"/>
<data android:mimeType="application/vnd.google-earth.kml+xml"/>
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<data android:mimeType="application/vnd.google-earth.kml+xml" />
</intent-filter>
<intent-filter
@@ -192,13 +201,15 @@ limitations under the License.
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="data"/>
<data android:host="*"/>
<data android:mimeType="*/*"/>
<data android:scheme="file" />
<data android:scheme="content" />
<data android:scheme="data" />
<data android:host="*" />
<data android:mimeType="*/*" />
<data android:pathPattern=".*\\.kml" />
<data android:pathPattern=".*\\..*\\.kml" />
<data android:pathPattern=".*\\..*\\..*\\.kml" />
@@ -216,12 +227,14 @@ limitations under the License.
android:priority="50">
<action android:name="android.intent.action.VIEW" />
<action android:name="android.intent.action.SEND" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="file"/>
<data android:scheme="content"/>
<data android:scheme="data"/>
<data android:host="*"/>
<data android:scheme="file" />
<data android:scheme="content" />
<data android:scheme="data" />
<data android:host="*" />
<data android:pathPattern=".*\\.kml" />
<data android:pathPattern=".*\\..*\\.kml" />
<data android:pathPattern=".*\\..*\\..*\\.kml" />
@@ -237,7 +250,7 @@ limitations under the License.
<activity android:name=".MarkerDetailActivity">
<intent-filter>
<action android:name="de.dennisguse.opentracks.MarkerDetails"/>
<action android:name="de.dennisguse.opentracks.MarkerDetails" />
<category android:name="android.intent.category.DEFAULT" />
</intent-filter>
</activity>
@@ -258,8 +271,8 @@ limitations under the License.
<activity
android:name=".TrackListActivity"
android:theme="@style/SplashTheme"
android:launchMode="singleTop">
android:launchMode="singleTop"
android:theme="@style/SplashTheme">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
@@ -73,7 +73,7 @@ public class MarkerEditActivity extends AbstractActivity {
private Uri photoUri;
private Uri photoUriOriginal;
private List<Uri> photoUriDeleteList = new ArrayList<>();
private final List<Uri> photoUriDeleteList = new ArrayList<>();
private boolean hasCamera;
private boolean isNewMarker;
@@ -95,9 +95,7 @@ public class TrackEditActivity extends AbstractActivity implements ChooseActivit
}
setActivityTypeIcon(iconValue);
viewBinding.trackEditActivityTypeIcon.setOnClickListener(v -> {
ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), viewBinding.trackEditActivityType.getText().toString());
});
viewBinding.trackEditActivityTypeIcon.setOnClickListener(v -> ChooseActivityTypeDialogFragment.showDialog(getSupportFragmentManager(), viewBinding.trackEditActivityType.getText().toString()));
viewBinding.trackEditDescription.setText(track.getDescription());
@@ -22,11 +22,14 @@ import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewParent;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.tabs.TabLayoutMediator;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.data.Marker;
@@ -75,8 +78,10 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
trackDataHub = new TrackDataHub(this);
viewBinding.trackDetailActivityViewPager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT));
viewBinding.trackDetailActivityTablayout.setupWithViewPager(viewBinding.trackDetailActivityViewPager);
CustomFragmentPagerAdapter pagerAdapter = new CustomFragmentPagerAdapter(this);
viewBinding.trackDetailActivityViewPager.setAdapter(pagerAdapter);
new TabLayoutMediator(viewBinding.trackDetailActivityTablayout, viewBinding.trackDetailActivityViewPager,
(tab, position) -> tab.setText(pagerAdapter.getPageTitle(position))).attach();
if (savedInstanceState != null) {
viewBinding.trackDetailActivityViewPager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY));
}
@@ -220,20 +225,15 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
}
}
private class CustomFragmentPagerAdapter extends FragmentPagerAdapter {
private class CustomFragmentPagerAdapter extends FragmentStateAdapter {
public CustomFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
@Override
public int getCount() {
return 4;
public CustomFragmentPagerAdapter(@NonNull FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment getItem(int position) {
public Fragment createFragment(int position) {
switch (position) {
case 0:
return StatisticsRecordedFragment.newInstance(trackId);
@@ -249,6 +249,10 @@ public class TrackRecordedActivity extends AbstractListActivity implements Confi
}
@Override
public int getItemCount() {
return 4;
}
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
@@ -13,8 +13,10 @@ import android.view.WindowManager;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.fragment.app.FragmentActivity;
import androidx.viewpager2.adapter.FragmentStateAdapter;
import com.google.android.material.tabs.TabLayoutMediator;
import de.dennisguse.opentracks.content.TrackDataHub;
import de.dennisguse.opentracks.content.data.Track;
@@ -148,8 +150,10 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback);
trackDataHub = new TrackDataHub(this);
viewBinding.trackDetailActivityViewPager.setAdapter(new CustomFragmentPagerAdapter(getSupportFragmentManager(), FragmentPagerAdapter.BEHAVIOR_RESUME_ONLY_CURRENT_FRAGMENT));
viewBinding.trackDetailActivityTablayout.setupWithViewPager(viewBinding.trackDetailActivityViewPager);
CustomFragmentPagerAdapter pagerAdapter = new CustomFragmentPagerAdapter(this);
viewBinding.trackDetailActivityViewPager.setAdapter(pagerAdapter);
new TabLayoutMediator(viewBinding.trackDetailActivityTablayout, viewBinding.trackDetailActivityViewPager,
(tab, position) -> tab.setText(pagerAdapter.getPageTitle(position))).attach();
if (savedInstanceState != null) {
viewBinding.trackDetailActivityViewPager.setCurrentItem(savedInstanceState.getInt(CURRENT_TAB_TAG_KEY));
}
@@ -358,20 +362,15 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
finish();
}
private class CustomFragmentPagerAdapter extends FragmentPagerAdapter {
private class CustomFragmentPagerAdapter extends FragmentStateAdapter {
public CustomFragmentPagerAdapter(@NonNull FragmentManager fm, int behavior) {
super(fm, behavior);
}
@Override
public int getCount() {
return 4;
public CustomFragmentPagerAdapter(@NonNull FragmentActivity fa) {
super(fa);
}
@NonNull
@Override
public Fragment getItem(int position) {
public Fragment createFragment(int position) {
switch (position) {
case 0:
return StatisticsRecordingFragment.newInstance();
@@ -387,6 +386,10 @@ public class TrackRecordingActivity extends AbstractActivity implements ChooseAc
}
@Override
public int getItemCount() {
return 4;
}
public CharSequence getPageTitle(int position) {
switch (position) {
case 0:
@@ -1,7 +1,6 @@
package de.dennisguse.opentracks.adapters;
import android.content.Context;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@@ -20,10 +19,10 @@ import de.dennisguse.opentracks.viewmodels.IntervalStatistics;
public class IntervalStatisticsAdapter extends ArrayAdapter<IntervalStatistics.Interval> {
private StackMode stackMode;
private boolean metricUnits;
private final StackMode stackMode;
private final boolean metricUnits;
private float sumDistance_m;
private String category;
private final String category;
public IntervalStatisticsAdapter(Context context, List<IntervalStatistics.Interval> intervalList, String category, StackMode stackMode) {
super(context, R.layout.interval_stats_list_item, intervalList);
@@ -61,15 +60,12 @@ public class IntervalStatisticsAdapter extends ArrayAdapter<IntervalStatistics.I
viewHolder.distance.setText(StringUtils.formatDistance(getContext(), sumDistance_m, metricUnits));
if (PreferencesUtils.isReportSpeed(getContext(), category)) {
Pair<String, String> speedParts = StringUtils.getSpeedParts(getContext(), interval.getSpeed_ms(), metricUnits, true);
viewHolder.rate.setText(speedParts.first + " " + speedParts.second);
viewHolder.rate.setText(StringUtils.formatSpeed(getContext(), interval.getSpeed_ms(), metricUnits, true));
} else {
Pair<String, String> paceParts = StringUtils.getSpeedParts(getContext(), interval.getSpeed_ms(), metricUnits, false);
viewHolder.rate.setText(paceParts.first + " " + paceParts.second);
viewHolder.rate.setText(StringUtils.formatSpeed(getContext(), interval.getSpeed_ms(), metricUnits, false));
}
Pair<String, String> gainParts = StringUtils.formatElevation(getContext(), interval.getGain_m(), metricUnits);
viewHolder.gain.setText(gainParts.first + " " + gainParts.second);
viewHolder.gain.setText(StringUtils.formatDistance(getContext(), interval.getGain_m(), metricUnits));
return intervalView;
}
@@ -68,7 +68,7 @@ abstract class ChartValueSeries {
* @param fillColor the fill color
* @param strokeColor the stroke color
*/
ChartValueSeries(Context context, int absoluteMin, int absoluteMax, int[] intervalValues, int metricTitleId, int imperialTitleId, int fillColor, int strokeColor) {
ChartValueSeries(Context context, int absoluteMin, int absoluteMax, int[] intervalValues, int metricTitleId, int imperialTitleId, int fillColor, int strokeColor, int fontSizeSmall, int fontSizeMedium) {
this.absoluteMin = absoluteMin;
this.absoluteMax = absoluteMax;
this.intervalValues = intervalValues;
@@ -85,16 +85,14 @@ abstract class ChartValueSeries {
strokePaint.setColor(context.getResources().getColor(strokeColor));
strokePaint.setAntiAlias(true);
float scale = context.getResources().getDisplayMetrics().density;
// Make copies of the stroke paint with the default thickness
titlePaint = new Paint(strokePaint);
titlePaint.setTextSize(ChartView.MEDIUM_TEXT_SIZE * scale);
titlePaint.setTextSize(fontSizeMedium);
titlePaint.setTextAlign(Align.CENTER);
titlePaint.setStyle(Style.FILL_AND_STROKE);
markerPaint = new Paint(strokePaint);
markerPaint.setTextSize(ChartView.SMALL_TEXT_SIZE * scale);
markerPaint.setTextSize(fontSizeSmall);
markerPaint.setTextAlign(Align.RIGHT);
markerPaint.setStyle(Style.FILL_AND_STROKE);
@@ -30,9 +30,11 @@ import android.view.GestureDetector;
import android.view.MotionEvent;
import android.view.ScaleGestureDetector;
import android.view.View;
import android.view.ViewParent;
import android.widget.Scroller;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import androidx.core.view.GestureDetectorCompat;
import java.text.NumberFormat;
@@ -58,9 +60,6 @@ import de.dennisguse.opentracks.util.UnitConversions;
*/
public class ChartView extends View {
static final float MEDIUM_TEXT_SIZE = 18f;
static final float SMALL_TEXT_SIZE = 12f;
static final int Y_AXIS_INTERVALS = 5;
private static final int TARGET_X_AXIS_INTERVALS = 4;
@@ -114,7 +113,7 @@ public class ChartView extends View {
private int effectiveWidth = 0;
private int effectiveHeight = 0;
private boolean chartByDistance;
private final boolean chartByDistance;
private boolean metricUnits = true;
private boolean reportSpeed = true;
private boolean showPointer = false;
@@ -192,6 +191,9 @@ public class ChartView extends View {
public ChartView(Context context, final boolean chartByDistance) {
super(context);
this.chartByDistance = chartByDistance;
int fontSizeSmall = ThemeUtils.getFontSizeSmallInPx(context);
int fontSizeMedium = ThemeUtils.getFontSizeMediumInPx(context);
seriesList.add(new ChartValueSeries(context,
Integer.MIN_VALUE,
Integer.MAX_VALUE,
@@ -199,7 +201,9 @@ public class ChartView extends View {
R.string.description_elevation_metric,
R.string.description_elevation_imperial,
R.color.chart_elevation_fill,
R.color.chart_elevation_border) {
R.color.chart_elevation_border,
fontSizeSmall,
fontSizeMedium) {
@Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getElevation();
@@ -218,7 +222,9 @@ public class ChartView extends View {
R.string.description_speed_metric,
R.string.description_speed_imperial,
R.color.chart_speed_fill,
R.color.chart_speed_border) {
R.color.chart_speed_border,
fontSizeSmall,
fontSizeMedium) {
@Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getSpeed();
@@ -238,7 +244,9 @@ public class ChartView extends View {
R.string.description_pace_metric,
R.string.description_pace_imperial,
R.color.chart_pace_fill,
R.color.chart_pace_border) {
R.color.chart_pace_border,
fontSizeSmall,
fontSizeMedium) {
@Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getPace();
@@ -258,7 +266,9 @@ public class ChartView extends View {
R.string.description_sensor_heart_rate,
R.string.description_sensor_heart_rate,
R.color.chart_heart_rate_fill,
R.color.chart_heart_rate_border) {
R.color.chart_heart_rate_border,
fontSizeSmall,
fontSizeMedium) {
@Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getHeartRate();
@@ -277,7 +287,9 @@ public class ChartView extends View {
R.string.description_sensor_cadence,
R.string.description_sensor_cadence,
R.color.chart_cadence_fill,
R.color.chart_cadence_border) {
R.color.chart_cadence_border,
fontSizeSmall,
fontSizeMedium) {
@Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getCadence();
@@ -295,7 +307,9 @@ public class ChartView extends View {
R.string.description_sensor_power,
R.string.description_sensor_power,
R.color.chart_power_fill,
R.color.chart_power_border) {
R.color.chart_power_border,
fontSizeSmall,
fontSizeMedium) {
@Override
protected double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
return chartPoint.getPower();
@@ -309,13 +323,11 @@ public class ChartView extends View {
backgroundColor = ThemeUtils.getBackgroundColor(context);
float scale = context.getResources().getDisplayMetrics().density;
axisPaint = new Paint();
axisPaint.setStyle(Style.FILL_AND_STROKE);
axisPaint.setColor(ThemeUtils.getTextColorPrimary(context));
axisPaint.setAntiAlias(true);
axisPaint.setTextSize(SMALL_TEXT_SIZE * scale);
axisPaint.setTextSize(fontSizeSmall);
xAxisMarkerPaint = new Paint(axisPaint);
xAxisMarkerPaint.setTextAlign(Align.CENTER);
@@ -330,7 +342,7 @@ public class ChartView extends View {
markerPaint.setStyle(Style.STROKE);
markerPaint.setAntiAlias(false);
pointer = context.getResources().getDrawable(R.drawable.ic_logo_color_24dp);
pointer = ContextCompat.getDrawable(context, R.drawable.ic_logo_color_24dp);
pointer.setBounds(0, 0, pointer.getIntrinsicWidth(), pointer.getIntrinsicHeight());
markerPin = MarkerUtils.getDefaultPhoto(context);
@@ -489,6 +501,18 @@ public class ChartView extends View {
invalidate();
}
/**
* Handle parent's view disallow touch event.
*
* @param disallow Does disallow parent touch event?
*/
private void requestDisallowInterceptTouchEventInParent(boolean disallow) {
ViewParent parent = getParent();
if (parent != null) {
parent.requestDisallowInterceptTouchEvent(disallow);
}
}
/**
* Scrolls the view horizontally by a given amount.
*
@@ -496,13 +520,15 @@ public class ChartView extends View {
*/
private void scrollBy(int deltaX) {
int scrollX = getScrollX() + deltaX;
if (scrollX < 0) {
if (scrollX <= 0) {
scrollX = 0;
}
int maxWidth = effectiveWidth * (zoomLevel - 1);
if (scrollX > maxWidth) {
if (scrollX >= maxWidth) {
scrollX = maxWidth;
}
scrollTo(scrollX, 0);
}
@@ -527,6 +553,10 @@ public class ChartView extends View {
public boolean onTouchEvent(MotionEvent event) {
boolean isZoom = detectorZoom.onTouchEvent(event);
boolean isScrollTab = detectorScrollFlingTab.onTouchEvent(event);
// ChartView handles zoom gestures (more than one pointer) and all gestures when zoomed itself
requestDisallowInterceptTouchEventInParent(event.getPointerCount() != 1 || zoomLevel != MIN_ZOOM_LEVEL);
return isZoom || isScrollTab;
}
@@ -881,6 +911,7 @@ public class ChartView extends View {
/**
* Finds the index of the first data point containing data for a series.
*
* @return -1 if no data point contains data for the series.
*/
private int getFirstPopulatedChartDataIndex(ChartValueSeries chartValueSeries) {
@@ -488,7 +488,7 @@ public class ContentProviderUtils {
private void deleteMarkerPhoto(Context context, Marker marker) {
if (marker != null && marker.hasPhoto()) {
Uri uri = marker.getPhotoURI();
File file = FileUtils.getPhotoFileIfExists(context, marker.getTrackId(), uri);
File file = FileUtils.buildInternalPhotoFile(context, marker.getTrackId(), uri);
if (file.exists()) {
File parent = file.getParentFile();
file.delete();
@@ -616,7 +616,7 @@ public class ContentProviderUtils {
* @param trackId the trackPoints id
* @return the number of trackPoints inserted
*/
//TODO Only used for testing and file import; might be better to replace it.
//TODO Only used for testing; might be better to replace it.
public int bulkInsertTrackPoint(TrackPoint[] trackPoints, Track.Id trackId) {
ContentValues[] values = new ContentValues[trackPoints.length];
for (int i = 0; i < values.length; i++) {
@@ -625,6 +625,15 @@ public class ContentProviderUtils {
return contentResolver.bulkInsert(TrackPointsColumns.CONTENT_URI_BY_ID, values);
}
//TODO Only used for file import; might be better to replace it.
public int bulkInsertTrackPoint(List<TrackPoint> trackPoints, Track.Id trackId) {
ContentValues[] values = new ContentValues[trackPoints.size()];
for (int i = 0; i < trackPoints.size(); i++) {
values[i] = createContentValues(trackPoints.get(i), trackId);
}
return contentResolver.bulkInsert(TrackPointsColumns.CONTENT_URI_BY_ID, values);
}
/**
* Gets the first location id for a track.
* Returns null if it doesn't exist.
@@ -76,7 +76,8 @@ public class ChartFragment extends Fragment implements TrackDataListener {
private ChartBinding viewBinding;
//TODO Why is this needed?
//TODO REMOVE: Used to restore the TrackStatistics via TrackStatisticsUpdater; for the diagrams we should consider not this setting and just use all data that is in the database
@Deprecated
private int recordingDistanceInterval;
private String category = "";
@@ -40,7 +40,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
protected IntervalStatisticsAdapter.StackMode stackModeListView;
private IntervalStatisticsModel.IntervalOption selectedInterval;
private String intervalUnit;
private boolean metricUnits;
private IntervalStatisticsAdapter adapter;
private ArrayAdapter<IntervalStatisticsModel.IntervalOption> spinnerAdapter;
@@ -51,7 +51,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
protected final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (preferences, key) -> {
if (PreferencesUtils.isKey(getContext(), R.string.stats_units_key, key) || PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key)) {
intervalUnit = PreferencesUtils.isMetricUnits(getContext()) ? getContext().getString(R.string.unit_kilometer) : getContext().getString(R.string.unit_mile);
metricUnits = PreferencesUtils.isMetricUnits(getContext());
if (adapter != null) {
adapter.notifyDataSetChanged();
spinnerAdapter.notifyDataSetChanged();
@@ -74,7 +74,7 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
super.onViewCreated(view, savedInstanceState);
PreferencesUtils.register(getContext(), sharedPreferenceChangeListener);
intervalUnit = PreferencesUtils.isMetricUnits(getContext()) ? getContext().getString(R.string.unit_kilometer) : getContext().getString(R.string.unit_mile);
metricUnits = PreferencesUtils.isMetricUnits(getContext());
viewBinding.intervalList.setEmptyView(viewBinding.intervalListEmptyView);
@@ -87,15 +87,17 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
@Override
public View getView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
TextView v = (TextView) super.getView(position, convertView, parent);
v.setText(v.getText() + " " + intervalUnit);
if (metricUnits) {
v.setText(getContext().getString(R.string.value_integer_kilometer, Integer.parseInt(v.getText().toString())));
} else {
v.setText(getContext().getString(R.string.value_integer_mile, Integer.parseInt(v.getText().toString())));
}
return v;
}
@Override
public View getDropDownView(int position, @Nullable View convertView, @NonNull ViewGroup parent) {
TextView v = (TextView) super.getDropDownView(position, convertView, parent);
v.setText(v.getText() + " " + intervalUnit);
return v;
return getView(position, convertView, parent);
}
};
@@ -149,7 +151,6 @@ public class IntervalsFragment extends Fragment implements TrackDataListener {
return;
}
boolean metricUnits = PreferencesUtils.isMetricUnits(getContext());
IntervalStatistics intervalStatistics = viewModel.getIntervalStats(metricUnits, selectedInterval);
adapter = new IntervalStatisticsAdapter(getContext(), intervalStatistics.getIntervalList(), category, stackModeListView);
viewBinding.intervalList.setAdapter(adapter);
@@ -109,9 +109,7 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi
handlerUpdateUI = new Handler();
viewBinding.statsActivityTypeIcon.setOnClickListener(v -> {
((TrackRecordingActivity) getActivity()).chooseActivityType(category);
});
viewBinding.statsActivityTypeIcon.setOnClickListener(v -> ((TrackRecordingActivity) getActivity()).chooseActivityType(category));
sensorsAdapter = new SensorsAdapter(getContext());
sensorsRecyclerView = viewBinding.statsSensorsRecyclerView;
@@ -360,7 +360,7 @@ public class ExportActivity extends FragmentActivity implements ExportServiceRes
public boolean resolve() {
if (autoConflict == CONFLICT_NONE) {
Track track = contentProviderUtils.getTrack(trackId);
viewBinding.exportProgressAlertIcon.setImageDrawable(getDrawable(R.drawable.ic_report_problem_24));
viewBinding.exportProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(ExportActivity.this, R.drawable.ic_report_problem_24));
viewBinding.exportProgressAlertMsg.setText(getString(R.string.export_track_already_exists_msg, track.getName()));
setConflictVisibility(View.VISIBLE);
return false;
@@ -167,7 +167,7 @@ public class KmlTrackWriter implements TrackWriter {
@Override
public void writeMarker(Marker marker) {
if (printWriter != null && exportTrackDetail) {
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, marker.getTrackId(), marker.getPhotoURI()) != null;
boolean existsPhoto = FileUtils.buildInternalPhotoFile(context, marker.getTrackId(), marker.getPhotoURI()) != null;
if (marker.hasPhoto() && exportPhotos && existsPhoto) {
float heading = getHeading(marker.getTrackId(), marker.getLocation());
writePhotoOverlay(marker, heading);
@@ -53,7 +53,7 @@ public class KmzTrackExporter implements TrackExporter {
private final FileTrackExporter fileTrackExporter;
private final boolean exportPhotos;
private Context context;
private final Context context;
/**
* Constructor.
@@ -108,7 +108,7 @@ public class KmzTrackExporter implements TrackExporter {
Marker marker = contentProviderUtils.createMarker(cursor);
if (marker.hasPhoto()) {
Uri uriPhoto = marker.getPhotoURI();
boolean existsPhoto = FileUtils.getPhotoFileIfExists(context, track.getId(), uriPhoto) != null;
boolean existsPhoto = FileUtils.buildInternalPhotoFile(context, track.getId(), uriPhoto) != null;
if (existsPhoto) {
addImage(context, zipOutputStream, uriPhoto, marker);
}
@@ -29,7 +29,6 @@ import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Locale;
import java.util.UUID;
@@ -61,9 +60,6 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
private static final String TAG = AbstractFileTrackImporter.class.getSimpleName();
// The maximum number of buffered locations for bulk-insertion
private static final int MAX_BUFFERED_LOCATIONS = 512;
private final Context context;
private final ContentProviderUtils contentProviderUtils;
private final int recordingDistanceInterval;
@@ -127,18 +123,15 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
saxParser.parse(inputStream, this);
Log.d(TAG, "Total import time: " + (System.currentTimeMillis() - start) + "ms");
if (trackIds.size() != 1) {
// TODO Multi track is not supported yet.
throw new ImportParserException("Multi track not supported");
}
return trackIds.get(0);
} catch (IOException | SAXException | ParserConfigurationException e) {
Log.e(TAG, "Unable to import file", e);
cleanImport();
if (trackIds.size() > 0) {
cleanImport();
}
throw new ImportParserException(e);
} catch (SQLiteConstraintException e) {
Log.e(TAG, "Unable to import file", e);
cleanImport();
throw new ImportAlreadyExistsException(e);
}
}
@@ -228,17 +221,12 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
*/
protected void onTrackStart() throws SAXException {
trackData = new TrackData();
Uri uri = contentProviderUtils.insertTrack(trackData.track);
Track.Id trackId = new Track.Id(Long.parseLong(uri.getLastPathSegment()));
trackIds.add(trackId);
trackData.track.setId(trackId);
}
/**
* On track end.
*/
protected void onTrackEnd() {
flushLocations(trackData);
if (name != null) {
trackData.track.setName(name);
}
@@ -268,17 +256,27 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
}
trackData.track.setTrackStatistics(trackData.trackStatisticsUpdater.getTrackStatistics());
try {
contentProviderUtils.updateTrack(trackData.track);
} catch (SQLiteConstraintException e) {
Track track = contentProviderUtils.getTrack(trackData.track.getUuid());
if (track != null) {
if (PreferencesUtils.getPreventReimportTracks(context)) {
throw e;
throw new ImportAlreadyExistsException(context.getString(R.string.import_prevent_reimport));
}
//TODO This is a workaround until we have proper UI.
trackData.track.setUuid(UUID.randomUUID());
contentProviderUtils.updateTrack(trackData.track);
}
if (trackIds.size() > 0) {
// TODO Multi track is not supported yet.
cleanImport();
throw new ImportParserException("Multi track not supported");
}
Uri uri = contentProviderUtils.insertTrack(trackData.track);
Track.Id trackId = new Track.Id(Long.parseLong(uri.getLastPathSegment()));
trackIds.add(trackId);
trackData.track.setId(trackId);
flushLocations(trackData);
}
/**
@@ -303,7 +301,8 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
TrackPoint trackPoint = createTrackPoint();
if (!LocationUtils.isValidLocation(trackPoint.getLocation())) {
throw new SAXException(createErrorMessage("Invalid location detected: " + trackPoint));
Log.w(TAG, "Marker with invalid coordinates ignored: " + trackPoint.getLocation());
return;
}
Marker marker = new Marker(trackPoint.getLocation());
@@ -482,13 +481,9 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
}
trackData.trackStatisticsUpdater.addTrackPoint(trackPoint, recordingDistanceInterval);
trackData.bufferedTrackPoints[trackData.numBufferedTrackPoints] = trackPoint;
trackData.bufferedTrackPoints.add(trackPoint);
trackData.numBufferedTrackPoints++;
trackData.numberOfLocations++;
if (trackData.numBufferedTrackPoints >= MAX_BUFFERED_LOCATIONS) {
flushLocations(trackData);
}
}
/**
@@ -500,7 +495,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
if (data.numBufferedTrackPoints <= 0) {
return;
}
contentProviderUtils.bulkInsertTrackPoint(Arrays.copyOfRange(data.bufferedTrackPoints, 0, data.numBufferedTrackPoints), data.track.getId());
contentProviderUtils.bulkInsertTrackPoint(data.bufferedTrackPoints, data.track.getId());
data.numBufferedTrackPoints = 0;
}
@@ -537,7 +532,7 @@ abstract class AbstractFileTrackImporter extends DefaultHandler implements Track
final long importTime = System.currentTimeMillis();
// The buffered locations
final TrackPoint[] bufferedTrackPoints = new TrackPoint[MAX_BUFFERED_LOCATIONS];
final List<TrackPoint> bufferedTrackPoints = new ArrayList<>();
// The number of buffered locations
int numBufferedTrackPoints = 0;
@@ -24,6 +24,7 @@ import android.widget.Toast;
import androidx.annotation.NonNull;
import androidx.appcompat.widget.Toolbar;
import androidx.core.content.ContextCompat;
import androidx.documentfile.provider.DocumentFile;
import androidx.fragment.app.FragmentActivity;
import androidx.lifecycle.ViewModelProvider;
@@ -161,12 +162,12 @@ public class ImportActivity extends FragmentActivity {
viewBinding.importProgressLeftButton.setVisibility(View.VISIBLE);
viewBinding.importProgressLeftButton.setText(getString(R.string.generic_show_errors));
viewBinding.importProgressLeftButton.setOnClickListener((view) -> ErrorListDialog.showDialog(getSupportFragmentManager(), getString(R.string.import_error_list_dialog_title), summary.getFileErrors()));
viewBinding.importProgressAlertIcon.setImageDrawable(getDrawable(R.drawable.ic_report_problem_24));
viewBinding.importProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_report_problem_24));
String msg = getResources().getQuantityString(R.plurals.generic_completed_with_errors, summary.getErrorCount(), summary.getErrorCount());
viewBinding.importProgressAlertMsg.setText(msg);
} else {
viewBinding.importProgressLeftButton.setVisibility(View.GONE);
viewBinding.importProgressAlertIcon.setImageDrawable(getDrawable(R.drawable.ic_dialog_success_24dp));
viewBinding.importProgressAlertIcon.setImageDrawable(ContextCompat.getDrawable(this, R.drawable.ic_dialog_success_24dp));
viewBinding.importProgressAlertMsg.setText(getString(R.string.generic_completed));
}
}
@@ -4,4 +4,8 @@ class ImportAlreadyExistsException extends RuntimeException {
public ImportAlreadyExistsException(Exception e) {
super(e);
}
public ImportAlreadyExistsException(String msg) {
super(msg);
}
}
@@ -63,12 +63,12 @@ public class KmlFileTrackImporter extends AbstractFileTrackImporter {
private boolean trackStarted = false;
private String extendedDataType;
private ArrayList<TrackPoint> trackPoints = new ArrayList<>();
private ArrayList<Float> speedList = new ArrayList<>();
private ArrayList<Float> cadenceList = new ArrayList<>();
private ArrayList<Float> heartRateList = new ArrayList<>();
private ArrayList<Float> powerList = new ArrayList<>();
private ArrayList<Float> elevationGainList = new ArrayList<>();
private final ArrayList<TrackPoint> trackPoints = new ArrayList<>();
private final ArrayList<Float> speedList = new ArrayList<>();
private final ArrayList<Float> cadenceList = new ArrayList<>();
private final ArrayList<Float> heartRateList = new ArrayList<>();
private final ArrayList<Float> powerList = new ArrayList<>();
private final ArrayList<Float> elevationGainList = new ArrayList<>();
public KmlFileTrackImporter(Context context) {
this(context, new ContentProviderUtils(context));
@@ -177,6 +177,10 @@ public class KmzTrackImporter implements TrackImporter {
zipInputStream.closeEntry();
}
if (trackId == null) {
Log.d(TAG, "Unable to find doc.kml in kmz");
throw new RuntimeException(context.getString(R.string.import_no_kml_file_found));
}
return trackId;
} catch (ImportParserException | ImportAlreadyExistsException e) {
Log.e(TAG, "Unable to import file", e);
@@ -271,6 +275,7 @@ public class KmzTrackImporter implements TrackImporter {
* Reads an image file (zipInputStream) and save it in a file called fileName inside photo folder.
*
* @param zipInputStream the zip input stream
* @param trackId the track's id which image belongs to.
* @param fileName the file name
*/
private void readAndSaveImageFile(ZipInputStream zipInputStream, Track.Id trackId, String fileName) throws IOException {
@@ -25,7 +25,7 @@ class GpsStatus {
private GpsStatusValue gpsStatus = GpsStatusValue.GPS_NONE;
private GpsStatusListener client;
private Context context;
private final Context context;
// Last location. It can be null.
private Location lastLocation = null;
@@ -51,7 +51,7 @@ class GpsStatus {
}
}
private Handler gpsStatusHandler;
private final Handler gpsStatusHandler;
private GpsStatusRunner gpsStatusRunner = null;
/**
@@ -12,7 +12,7 @@ import de.dennisguse.opentracks.content.data.TrackPoint;
public class HandlerServer {
private static String TAG = HandlerServer.class.getSimpleName();
private static final String TAG = HandlerServer.class.getSimpleName();
private final LocationHandler locationHandler;
private final HandlerServerInterface service;
@@ -95,9 +95,7 @@ public class ActivityTypePreference extends DialogPreference {
});
iconView = view.findViewById(R.id.activity_type_preference_spinner);
iconView.setOnClickListener((it) -> {
showIconSelectDialog();
});
iconView.setOnClickListener((it) -> showIconSelectDialog());
updateIcon(TrackIconUtils.getIconValue(context, category));
}
@@ -154,7 +154,7 @@ public class SettingsActivity extends AppCompatActivity implements ChooseActivit
activityPreferenceDialog = ActivityTypePreference.ActivityPreferenceDialog.newInstance(preference.getKey());
dialogFragment = activityPreferenceDialog;
} else if (preference instanceof BluetoothLeHeartRatePreference) {
dialogFragment = BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(preference.getKey(), BluetoothUtils.HEART_RATE_SERVICE_UUID);
dialogFragment = BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(preference.getKey(), BluetoothUtils.HEART_RATE_SUPPORTING_DEVICES);
} else if (preference instanceof BluetoothLeCyclingCadenceAndSpeedPreference) {
dialogFragment = BluetoothLeSensorPreference.BluetoothLeSensorPreferenceDialog.newInstance(preference.getKey(), BluetoothUtils.CYCLING_SPEED_CADENCE_SERVICE_UUID);
} else if (preference instanceof BluetoothLeCyclingPowerPreference) {
@@ -8,8 +8,6 @@ import android.bluetooth.le.ScanResult;
import android.bluetooth.le.ScanSettings;
import android.content.Context;
import android.content.DialogInterface;
import android.graphics.drawable.Animatable;
import android.graphics.drawable.Drawable;
import android.os.Bundle;
import android.os.ParcelUuid;
import android.text.TextUtils;
@@ -18,13 +16,15 @@ import android.util.Log;
import android.widget.Toast;
import androidx.appcompat.app.AlertDialog;
import androidx.core.content.ContextCompat;
import androidx.preference.DialogPreference;
import androidx.preference.PreferenceDialogFragmentCompat;
import androidx.vectordrawable.graphics.drawable.AnimatedVectorDrawableCompat;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;
import de.dennisguse.opentracks.R;
import de.dennisguse.opentracks.settings.BluetoothLeAdapter;
@@ -39,7 +39,7 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
private static final String TAG = BluetoothLeSensorPreference.class.getSimpleName();
private static final String ARG_BLUETOOTH_UUID = "bluetoothUUID";
private static final String ARG_BLE_SERVICE_UUIDS = "bluetoothUUID";
private static final int DEVICE_NONE_RESOURCEID = R.string.value_none;
@@ -94,6 +94,8 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
public static class BluetoothLeSensorPreferenceDialog extends PreferenceDialogFragmentCompat {
private AnimatedVectorDrawableCompat bluetoothIcon;
private int selectedEntryIndex;
private final BluetoothLeAdapter listAdapter = new BluetoothLeAdapter();
@@ -109,8 +111,9 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
@Override
public void onBatchScanResults(List<ScanResult> results) {
for (ScanResult scanResult : results) {
listAdapter.add(scanResult.getDevice());
for (ScanResult result : results) {
Log.d(TAG, "Found device " + result.getDevice().getName() + " " + result);
listAdapter.add(result.getDevice());
}
}
@@ -124,10 +127,14 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
};
public static BluetoothLeSensorPreferenceDialog newInstance(String preferenceKey, UUID sensorUUID) {
return newInstance(preferenceKey, Collections.singletonList(sensorUUID));
}
public static BluetoothLeSensorPreferenceDialog newInstance(String preferenceKey, List<UUID> sensorUUIDs) {
final BluetoothLeSensorPreferenceDialog fragment = new BluetoothLeSensorPreferenceDialog();
final Bundle b = new Bundle(1);
b.putString(ARG_KEY, preferenceKey);
b.putSerializable(ARG_BLUETOOTH_UUID, sensorUUID);
b.putParcelableArrayList(ARG_BLE_SERVICE_UUIDS, new ArrayList<>(sensorUUIDs.stream().map(ParcelUuid::new).collect(Collectors.toList())));
fragment.setArguments(b);
return fragment;
}
@@ -136,8 +143,12 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
UUID sensorUUID = (UUID) getArguments().getSerializable(ARG_BLUETOOTH_UUID);
Log.i(TAG, "UUID: " + sensorUUID);
List<ParcelUuid> serviceUUIDs = getArguments().getParcelableArrayList(ARG_BLE_SERVICE_UUIDS);
// Don't know why: need to load the drawable _twice_, so that animation is actually started.
bluetoothIcon = AnimatedVectorDrawableCompat.create(getContext(), R.drawable.ic_bluetooth_searching_animated_24dp);
bluetoothIcon = AnimatedVectorDrawableCompat.create(getContext(), R.drawable.ic_bluetooth_searching_animated_24dp);
bluetoothIcon.start();
BluetoothAdapter bluetoothAdapter = BluetoothUtils.getAdapter(getContext());
if (bluetoothAdapter == null || !bluetoothAdapter.isEnabled()) {
@@ -148,7 +159,7 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
}
if (bluetoothAdapter.isDiscovering()) {
Log.i(TAG, "Cancelling ongoing B<aluetooth discovery.");
Log.i(TAG, "Cancelling ongoing Bluetooth discovery.");
bluetoothAdapter.cancelDiscovery();
}
@@ -170,9 +181,7 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
selectedEntryIndex = 1;
}
ScanFilter.Builder scanFilterBuilder = new ScanFilter.Builder().setServiceUuid(new ParcelUuid(sensorUUID));
List<ScanFilter> scanFilter = new ArrayList<>();
scanFilter.add(scanFilterBuilder.build());
List<ScanFilter> scanFilter = serviceUUIDs.stream().map(it -> new ScanFilter.Builder().setServiceUuid(it).build()).collect(Collectors.toList());
ScanSettings.Builder scanSettingsBuilder = new ScanSettings.Builder();
scanSettingsBuilder.setScanMode(ScanSettings.SCAN_MODE_LOW_LATENCY);
@@ -193,9 +202,7 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
dialog.dismiss();
});
Drawable icon = ContextCompat.getDrawable(getContext(), R.drawable.ic_bluetooth_searching_animated_24dp);
((Animatable) icon).start();
builder.setIcon(icon);
builder.setIcon(bluetoothIcon);
builder.setPositiveButton(null, null);
}
@@ -214,5 +221,12 @@ public abstract class BluetoothLeSensorPreference extends DialogPreference {
}
}
}
@Override
public void onDestroy() {
super.onDestroy();
bluetoothIcon = null;
scanner = null;
}
}
}
@@ -23,6 +23,9 @@ import android.util.Log;
import androidx.annotation.NonNull;
import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.UUID;
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
@@ -39,6 +42,12 @@ public class BluetoothUtils {
public static final UUID HEART_RATE_SERVICE_UUID = new UUID(0x180D00001000L, 0x800000805f9b34fbL);
public static final UUID HEART_RATE_MEASUREMENT_CHAR_UUID = new UUID(0x2A3700001000L, 0x800000805f9b34fbL);
public static final List<UUID> HEART_RATE_SUPPORTING_DEVICES = Collections.unmodifiableList(Arrays.asList(
BluetoothUtils.HEART_RATE_SERVICE_UUID,
//Devices that support HEART_RATE_SERVICE_UUID, but do not announce HEART_RATE_SERVICE_UUID in there BLE announcement messages (during device discovery).
UUID.fromString("0000fee0-0000-1000-8000-00805f9b34fb") //Miband3
));
public static final UUID CYCLING_POWER_UUID = new UUID(0x181800001000L, 0x800000805f9b34fbL);
public static final UUID CYCLING_POWER_MEASUREMENT_CHAR_UUID = new UUID(0x2A6300001000L, 0x800000805f9b34fbL);
@@ -4,6 +4,7 @@ import android.content.Context;
import android.graphics.drawable.Drawable;
import androidx.annotation.NonNull;
import androidx.core.content.ContextCompat;
import de.dennisguse.opentracks.R;
@@ -15,6 +16,6 @@ public class MarkerUtils {
}
public static Drawable getDefaultPhoto(@NonNull Context context) {
return context.getResources().getDrawable(ICON_ID);
return ContextCompat.getDrawable(context, ICON_ID);
}
}
@@ -5,18 +5,18 @@ import android.hardware.SensorManager;
public class PressureSensorUtils {
//Everything above is considered a meaningful change in elevation.
private static float ELEVATION_CHANGE_DIFF_M = 3.0f;
private static final float ELEVATION_CHANGE_DIFF_M = 3.0f;
private static float EXPONENTIAL_SMOOTHING = 0.3f;
private static final float EXPONENTIAL_SMOOTHING = 0.3f;
private PressureSensorUtils() {
}
public static class ElevationChange {
private float currentSensorValue_hPa;
private final float currentSensorValue_hPa;
private float elevationChange_m;
private final float elevationChange_m;
public ElevationChange(float currentSensorValue_hPa, float elevationChange_m) {
this.currentSensorValue_hPa = currentSensorValue_hPa;
@@ -118,6 +118,34 @@ public class StringUtils {
}
}
public static String formatSpeed(Context context, double speed_mps, boolean metricUnits, boolean reportSpeed) {
if (Double.isNaN(speed_mps) || Double.isInfinite(speed_mps)) {
speed_mps = 0;
}
double speed = speed_mps * UnitConversions.M_TO_KM; //KM p sec
if (!metricUnits) {
speed *= UnitConversions.KM_TO_MI;
}
if (reportSpeed) {
if (metricUnits) {
return context.getString(R.string.value_float_kilometer_hour, speed * UnitConversions.S_TO_HR);
} else {
return context.getString(R.string.value_float_mile_hour, speed * UnitConversions.S_TO_HR);
}
} else {
int pace = speed == 0 ? 0 : (int) Math.round(1 / speed); //sec / [KM | MI]
int minutes = pace / 60;
int seconds = pace % 60;
if (metricUnits) {
return context.getString(R.string.value_pace_kilometer, minutes, seconds);
} else {
return context.getString(R.string.value_pace_mile, minutes, seconds);
}
}
}
private static String formatDecimal(double value) {
return StringUtils.formatDecimal(value, 2);
}
@@ -2,10 +2,13 @@ package de.dennisguse.opentracks.util;
import android.content.Context;
import android.content.res.Resources;
import android.content.res.TypedArray;
import android.util.TypedValue;
import androidx.core.content.ContextCompat;
import de.dennisguse.opentracks.R;
public class ThemeUtils {
private ThemeUtils() {
@@ -37,4 +40,18 @@ public class ThemeUtils {
return ContextCompat.getColor(context, typedValue.resourceId);
}
public static int getFontSizeSmallInPx(Context context) {
TypedArray typedArray = context.obtainStyledAttributes(R.style.TextSmall, new int[]{android.R.attr.textSize});
int fontSize = typedArray.getDimensionPixelSize(0, 12);
typedArray.recycle();
return fontSize;
}
public static int getFontSizeMediumInPx(Context context) {
TypedArray typedArray = context.obtainStyledAttributes(R.style.TextMedium, new int[]{android.R.attr.textSize});
int fontSize = typedArray.getDimensionPixelSize(0, 15);
typedArray.recycle();
return fontSize;
}
}
@@ -8,7 +8,7 @@ import de.dennisguse.opentracks.util.LocationUtils;
import de.dennisguse.opentracks.util.UnitConversions;
public class IntervalStatistics {
private List<Interval> intervalList = new ArrayList<>();
private final List<Interval> intervalList = new ArrayList<>();
private float distanceInterval_m;
/**
@@ -19,10 +19,10 @@ limitations under the License.
android:id="@+id/track_controller_container"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:background="@color/track_controller_background_normal"
android:background="@drawable/track_controller_background"
android:orientation="vertical"
android:paddingLeft="8dp"
android:paddingRight="8dp">
android:paddingStart="8dp"
android:paddingEnd="8dp">
<ImageButton
android:id="@+id/track_controller_record"
+4 -4
View File
@@ -47,10 +47,10 @@ limitations under the License.
android:id="@+id/track_list_arrow_long"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentStart="true"
android:orientation="vertical"
android:paddingLeft="12dp"
android:paddingRight="16dp">
android:paddingStart="12dp"
android:paddingEnd="16dp">
<View
android:layout_width="match_parent"
@@ -73,7 +73,7 @@ limitations under the License.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_toRightOf="@id/track_list_arrow_long"
android:layout_toEndOf="@id/track_list_arrow_long"
android:orientation="vertical">
<View
+1 -1
View File
@@ -25,7 +25,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/track_detail_activity_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
+4 -7
View File
@@ -20,21 +20,18 @@
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
android:layout_height="match_parent" />
<TextView
style="@style/TextLarge"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_weight="4"
android:gravity="center_horizontal|center_vertical"
android:text="@string/aggregated_stats_empty_message" />
<View
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1" />
<View
android:layout_width="0dp"
android:layout_height="match_parent" />
</RelativeLayout>
@@ -33,9 +33,9 @@
android:id="@+id/aggregated_stats_sport_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
app:layout_constraintLeft_toLeftOf="@id/guideline1"
app:layout_constraintStart_toStartOf="@id/guideline1"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_activity_bike_24dp" />
@@ -45,10 +45,10 @@
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_sport_icon"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_sport_icon"
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_sport_icon"
app:layout_constraintTop_toTopOf="@+id/aggregated_stats_sport_icon"
tools:text="@string/activity_type_cycling"
android:layout_marginLeft="16dp" />
android:layout_marginStart="16dp" />
<TextView
android:id="@+id/aggregated_stats_num_tracks"
@@ -56,36 +56,36 @@
android:layout_marginTop="0dp"
android:layout_marginBottom="0dp"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_type_label"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_type_label"
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_type_label"
app:layout_constraintTop_toTopOf="@+id/aggregated_stats_type_label"
tools:text="(1)"
android:layout_marginLeft="4dp" />
android:layout_marginStart="4dp" />
<!-- Distance -->
<TextView
android:id="@+id/aggregated_stats_distance"
style="@style/StatsLargeValue"
app:layout_constraintLeft_toLeftOf="@id/guideline1"
app:layout_constraintStart_toStartOf="@id/guideline1"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_sport_icon"
tools:text="100000"
android:layout_marginLeft="16dp"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp" />
<TextView
android:id="@+id/aggregated_stats_distance_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_distance"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_distance"
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_distance"
tools:text="km" />
<!-- Time -->
<TextView
android:id="@+id/aggregated_stats_time"
style="@style/StatsLargeValue"
app:layout_constraintRight_toRightOf="@id/guideline3"
app:layout_constraintEnd_toEndOf="@id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_sport_icon"
tools:text="00:00:00"
android:layout_marginRight="16dp"
android:layout_marginEnd="16dp"
android:layout_marginTop="16dp" />
<!-- Avg. rate -->
@@ -94,8 +94,8 @@
style="@style/StatsSmallValue"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@id/aggregated_stats_distance"
app:layout_constraintLeft_toRightOf="@id/guideline1"
app:layout_constraintRight_toLeftOf="@+id/aggregated_stats_avg_rate_unit"
app:layout_constraintStart_toEndOf="@id/guideline1"
app:layout_constraintEnd_toStartOf="@+id/aggregated_stats_avg_rate_unit"
android:layout_marginTop="24dp"
tools:text="30" />
@@ -103,8 +103,8 @@
android:id="@+id/aggregated_stats_avg_rate_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintRight_toRightOf="@id/guideline2"
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintEnd_toEndOf="@id/guideline2"
tools:text="km/h" />
<TextView
@@ -112,8 +112,8 @@
style="@style/StatsTinyLabel"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_avg_rate"
app:layout_constraintLeft_toRightOf="@id/guideline1"
app:layout_constraintRight_toRightOf="@id/guideline2"
app:layout_constraintStart_toEndOf="@id/guideline1"
app:layout_constraintEnd_toEndOf="@id/guideline2"
tools:text="@string/stats_average_moving_speed" />
<!-- Max. rate -->
@@ -122,8 +122,8 @@
style="@style/StatsSmallValue"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintTop_toBottomOf="@id/aggregated_stats_time"
app:layout_constraintLeft_toRightOf="@id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/aggregated_stats_max_rate_unit"
app:layout_constraintStart_toEndOf="@id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/aggregated_stats_max_rate_unit"
android:layout_marginTop="24dp"
tools:text="70" />
@@ -131,8 +131,8 @@
android:id="@+id/aggregated_stats_max_rate_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/aggregated_stats_max_rate"
app:layout_constraintLeft_toRightOf="@+id/aggregated_stats_max_rate"
app:layout_constraintRight_toLeftOf="@id/guideline3"
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_max_rate"
app:layout_constraintEnd_toStartOf="@id/guideline3"
tools:text="km/h" />
<TextView
@@ -140,8 +140,8 @@
style="@style/StatsTinyLabel"
app:layout_constrainedWidth="true"
app:layout_constraintTop_toBottomOf="@+id/aggregated_stats_max_rate"
app:layout_constraintLeft_toRightOf="@id/guideline2"
app:layout_constraintRight_toLeftOf="@id/guideline3"
app:layout_constraintStart_toEndOf="@id/guideline2"
app:layout_constraintEnd_toStartOf="@id/guideline3"
tools:text="@string/stats_max_speed" />
</androidx.constraintlayout.widget.ConstraintLayout>
+6 -6
View File
@@ -14,7 +14,7 @@
<androidx.core.widget.NestedScrollView
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_weight="1"
@@ -62,9 +62,9 @@
style="@style/ProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginRight="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/export_progress_done"
@@ -113,8 +113,8 @@
android:id="@+id/export_progress_apply_to_all"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginRight="24dp"
android:layout_marginStart="24dp"
android:layout_marginEnd="24dp"
android:layout_marginBottom="24dp"
android:checked="false"
android:text="@string/export_all_do_it_for_all"
@@ -144,7 +144,7 @@
<Button
android:id="@+id/export_progress_right_button"
style="@style/BottomButton"
android:layout_gravity="right"
android:layout_gravity="end"
android:text="@string/generic_overwrite"
android:visibility="gone"
tools:visibility="visible"/>
+4 -4
View File
@@ -12,7 +12,7 @@
<androidx.core.widget.NestedScrollView
android:layout_weight="1"
android:layout_width="match_parent"
android:layout_height="match_parent">
android:layout_height="0dp">
<androidx.constraintlayout.widget.ConstraintLayout
android:layout_weight="1"
@@ -60,9 +60,9 @@
style="@style/ProgressBar"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginLeft="24dp"
android:layout_marginStart="24dp"
android:layout_marginTop="8dp"
android:layout_marginRight="24dp"
android:layout_marginEnd="24dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/import_progress_done"
@@ -126,7 +126,7 @@
<Button
android:id="@+id/import_progress_right_button"
style="@style/BottomButton"
android:layout_gravity="right"
android:layout_gravity="end"
android:text="@string/generic_ok"
android:visibility="gone"
tools:visibility="visible"/>
+18 -34
View File
@@ -1,21 +1,22 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
xmlns:tools="http://schemas.android.com/tools"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="8dp">
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="horizontal">
<TextView
style="@style/TextMediumPrimary"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_split_interval"
style="@style/TextMedium" />
android:text="@string/stats_split_interval" />
<Spinner
android:id="@+id/spinner_intervals"
@@ -28,56 +29,39 @@
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:layout_margin="8dp">
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:orientation="horizontal">
<TextView
android:id="@+id/interval_distance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextMedium"
android:layout_margin="1dp"
android:textAlignment="center"
android:layout_gravity="center"
style="@style/IntervalLabel"
android:text="@string/stats_distance" />
<TextView
android:id="@+id/interval_rate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextMedium"
android:layout_margin="1dp"
android:textAlignment="center"
android:layout_gravity="center"
tools:text="Speed"/>
style="@style/IntervalLabel"
tools:text="Speed" />
<TextView
android:id="@+id/interval_elevation"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextMedium"
android:layout_margin="1dp"
android:textAlignment="center"
android:layout_gravity="center"
android:text="@string/stats_elevation" />
style="@style/IntervalLabel"
android:text="@string/stats_gain" />
</LinearLayout>
<View
android:layout_width="match_parent"
android:layout_height="1dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:background="@color/stats_separator"/>
android:layout_marginStart="8dp"
android:layout_marginEnd="8dp"
android:background="@color/stats_separator" />
<ListView
android:id="@+id/interval_list"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="8dp"/>
android:layout_margin="8dp" />
<TextView
android:id="@+id/interval_list_empty_view"
@@ -1,47 +1,31 @@
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:orientation="horizontal">
<TextView
android:id="@+id/interval_item_distance"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
style="@style/TextMedium"
tools:text="1 km" />
<TextView
android:id="@+id/interval_item_distance"
style="@style/TextMedium"
android:layout_width="0dp"
android:layout_weight="1"
tools:text="1 km" />
<TextView
android:id="@+id/interval_item_rate"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center_vertical"
style="@style/TextMedium"
tools:text="15 km/h" />
<TextView
android:id="@+id/interval_item_rate"
style="@style/TextMedium"
android:layout_width="0dp"
android:layout_weight="1"
tools:text="15 km/h" />
<LinearLayout
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:orientation="horizontal">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:src="@drawable/ic_arrow_drop_up_24" />
<TextView
android:id="@+id/interval_item_gain"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
style="@style/TextMedium"
tools:text="100 m" />
</LinearLayout>
<TextView
android:id="@+id/interval_item_gain"
style="@style/TextMedium"
android:layout_width="0dp"
android:layout_weight="1"
app:drawableStartCompat="@drawable/ic_arrow_drop_up_24"
tools:text="100 m" />
</LinearLayout>
+6 -5
View File
@@ -44,7 +44,8 @@ limitations under the License.
android:layout_height="wrap_content"
android:minHeight="?android:attr/listPreferredItemHeight"
android:paddingTop="8dp"
android:paddingRight="12dp"
android:paddingStart="4dp"
android:paddingEnd="12dp"
android:paddingBottom="12dp"
android:shrinkColumns="1"
android:stretchColumns="1">
@@ -56,8 +57,8 @@ limitations under the License.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center_vertical"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="4dp"
android:layout_marginEnd="8dp"
android:contentDescription="@string/image_track"
app:tint="?android:textColorPrimary" />
<!-- Table 1: Row 1: Column 2: (Table 2) -->
@@ -105,8 +106,8 @@ limitations under the License.
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom"
android:layout_marginLeft="2dp"
android:layout_marginRight="2dp"
android:layout_marginStart="2dp"
android:layout_marginEnd="2dp"
android:layout_marginBottom="1dp"
android:contentDescription="@string/image_marker_count"
android:scaleType="centerInside"
+2 -2
View File
@@ -116,12 +116,12 @@ limitations under the License.
<Button
android:id="@+id/marker_edit_cancel"
style="@style/BottomButton"
android:layout_gravity="left"
android:layout_gravity="start"
android:text="@string/generic_cancel" />
<Button
android:id="@+id/marker_edit_done"
style="@style/BottomButton"
android:layout_gravity="right" />
android:layout_gravity="end" />
</LinearLayout>
</LinearLayout>
@@ -19,9 +19,9 @@ limitations under the License.
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingLeft="8dp"
android:paddingStart="8dp"
android:paddingTop="16dp"
android:paddingRight="8dp">
android:paddingEnd="8dp">
<AutoCompleteTextView
android:id="@+id/activity_type_preference_text_view"
+48 -48
View File
@@ -36,8 +36,8 @@
style="@style/StatsLargeLabel"
android:text="@string/stats_distance"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
@@ -45,8 +45,8 @@
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_distance_unit"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/stats_distance_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_label"
tools:text="100" />
@@ -54,8 +54,8 @@
android:id="@+id/stats_distance_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintLeft_toRightOf="@+id/stats_distance_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/stats_distance_value"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
tools:text="km" />
<!-- Activity Type -->
@@ -64,16 +64,16 @@
style="@style/StatsLargeLabel"
android:text="@string/track_edit_activity_type_hint"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
android:id="@+id/stats_activity_type_icon"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintTop_toTopOf="@+id/stats_distance_value"
app:tint="?android:attr/textColorPrimary"
@@ -85,15 +85,15 @@
style="@style/StatsLargeLabel"
android:text="@string/stats_total_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_value" />
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsLargeValue"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_total_time_label"
tools:text="00:00:00" />
@@ -103,8 +103,8 @@
style="@style/StatsLargeLabel"
android:text="@string/stats_moving_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/stats_total_time_label"
app:layout_constraintBottom_toBottomOf="@+id/stats_total_time_label" />
@@ -112,8 +112,8 @@
android:id="@+id/stats_moving_time_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_label"
tools:text="00:00:00" />
@@ -130,8 +130,8 @@
android:id="@+id/stats_speed_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_time_barrier" />
<!-- Average speed/pace -->
@@ -139,8 +139,8 @@
android:id="@+id/stats_average_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
tools:text="Avg. Speed" />
@@ -149,8 +149,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_average_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/stats_average_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_average_speed_label"
tools:text="30.00" />
@@ -158,8 +158,8 @@
android:id="@+id/stats_average_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_average_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_average_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/stats_average_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
tools:text="km/h" />
<!-- Speed max -->
@@ -167,8 +167,8 @@
android:id="@+id/stats_max_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Speed" />
@@ -177,8 +177,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_max_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/stats_max_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_max_speed_label"
tools:text="30.00" />
@@ -186,8 +186,8 @@
android:id="@+id/stats_max_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_max_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_max_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/stats_max_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
tools:text="km/h" />
<!-- Moving speed max -->
@@ -195,8 +195,8 @@
android:id="@+id/stats_moving_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Moving Speed" />
@@ -205,8 +205,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_moving_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/stats_moving_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_speed_label"
tools:text="30.00" />
@@ -214,8 +214,8 @@
android:id="@+id/stats_moving_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_moving_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_moving_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/stats_moving_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
tools:text="km/h" />
<!-- Barrier -->
@@ -231,8 +231,8 @@
android:id="@+id/stats_elevation_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_speed_barrier" />
<!-- Elevation gain -->
@@ -247,8 +247,8 @@
style="@style/StatsSmallLabel"
android:text="@string/stats_gain"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
<TextView
@@ -256,8 +256,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_elevation_gain_unit"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/stats_elevation_gain_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_gain_label"
tools:text="100" />
@@ -265,8 +265,8 @@
android:id="@+id/stats_elevation_gain_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_elevation_gain_value"
app:layout_constraintLeft_toRightOf="@+id/stats_elevation_gain_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/stats_elevation_gain_value"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
tools:text="m" />
<!-- Barrier -->
@@ -282,8 +282,8 @@
android:id="@+id/stats_end_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_barrier" />
</androidx.constraintlayout.widget.ConstraintLayout>
+72 -72
View File
@@ -36,8 +36,8 @@
style="@style/StatsLargeLabel"
android:text="@string/stats_distance"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toTopOf="parent" />
<TextView
@@ -45,8 +45,8 @@
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_distance_unit"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/stats_distance_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_label"
tools:text="100" />
@@ -54,8 +54,8 @@
android:id="@+id/stats_distance_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintLeft_toRightOf="@+id/stats_distance_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/stats_distance_value"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
tools:text="km" />
<!-- Activity Type -->
@@ -64,8 +64,8 @@
style="@style/StatsLargeLabel"
android:text="@string/track_edit_activity_type_hint"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="parent" />
<ImageView
@@ -73,8 +73,8 @@
style="@style/StatsLargeValue"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintBottom_toBottomOf="@+id/stats_distance_value"
app:layout_constraintTop_toTopOf="@+id/stats_distance_value" />
@@ -84,15 +84,15 @@
style="@style/StatsLargeLabel"
android:text="@string/stats_total_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_distance_value" />
<TextView
android:id="@+id/stats_total_time_value"
style="@style/StatsLargeValue"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_total_time_label"
tools:text="00:00:00" />
@@ -102,8 +102,8 @@
style="@style/StatsLargeLabel"
android:text="@string/stats_moving_time"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/stats_total_time_label"
app:layout_constraintBottom_toBottomOf="@+id/stats_total_time_label" />
@@ -111,8 +111,8 @@
android:id="@+id/stats_moving_time_value"
style="@style/StatsLargeValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_time_label"
tools:text="00:00:00" />
@@ -129,8 +129,8 @@
android:id="@+id/stats_speed_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_time_barrier" />
<!-- Speed/pace -->
@@ -138,8 +138,8 @@
android:id="@+id/stats_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
tools:text="Speed" />
@@ -148,8 +148,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/stats_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_speed_label"
tools:text="30.00" />
@@ -157,8 +157,8 @@
android:id="@+id/stats_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/stats_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
tools:text="km/h" />
<!-- Average speed/pace -->
@@ -166,8 +166,8 @@
android:id="@+id/stats_average_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
tools:text="Avg. Speed" />
@@ -176,8 +176,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_average_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/stats_average_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_average_speed_label"
tools:text="30.00" />
@@ -185,8 +185,8 @@
android:id="@+id/stats_average_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_average_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_average_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/stats_average_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
tools:text="km/h" />
<!-- Speed max -->
@@ -194,8 +194,8 @@
android:id="@+id/stats_max_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Speed" />
@@ -204,8 +204,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_max_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/stats_max_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_max_speed_label"
tools:text="30.00" />
@@ -213,8 +213,8 @@
android:id="@+id/stats_max_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_max_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_max_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/stats_max_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
tools:text="km/h" />
<!-- Moving speed max -->
@@ -222,8 +222,8 @@
android:id="@+id/stats_moving_speed_label"
style="@style/StatsSmallLabel"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
tools:text="Max. Moving Speed" />
@@ -232,8 +232,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_moving_speed_unit"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/stats_moving_speed_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_moving_speed_label"
tools:text="30.00" />
@@ -241,8 +241,8 @@
android:id="@+id/stats_moving_speed_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_moving_speed_value"
app:layout_constraintLeft_toRightOf="@+id/stats_moving_speed_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/stats_moving_speed_value"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
tools:text="km/h" />
<!-- Barrier -->
@@ -258,8 +258,8 @@
android:id="@+id/stats_elevation_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_speed_barrier" />
<!-- Elevation -->
@@ -275,8 +275,8 @@
style="@style/StatsSmallLabel"
android:text="@string/stats_elevation"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
<TextView
@@ -284,8 +284,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/stats_elevation_current_unit"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/stats_elevation_current_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_current_label"
tools:text="100" />
@@ -293,8 +293,8 @@
android:id="@+id/stats_elevation_current_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_elevation_current_value"
app:layout_constraintLeft_toRightOf="@+id/stats_elevation_current_value"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/stats_elevation_current_value"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
tools:text="m" />
<!-- Current elevation -->
@@ -303,8 +303,8 @@
style="@style/StatsSmallLabel"
android:text="@string/stats_gain"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_elevation_horizontal_line" />
<TextView
@@ -312,8 +312,8 @@
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/stats_elevation_gain_unit"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/stats_elevation_gain_unit"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_gain_label"
tools:text="100" />
@@ -321,8 +321,8 @@
android:id="@+id/stats_elevation_gain_unit"
style="@style/StatsUnit"
app:layout_constraintBottom_toBottomOf="@+id/stats_elevation_gain_value"
app:layout_constraintLeft_toRightOf="@+id/stats_elevation_gain_value"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/stats_elevation_gain_value"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
tools:text="m" />
<!-- Coordinate group -->
@@ -345,8 +345,8 @@
android:id="@+id/stats_coordinate_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_elevation_barrier" />
<!-- Latitude -->
@@ -355,15 +355,15 @@
style="@style/StatsSmallLabel"
android:text="@string/stats_latitude"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@id/stats_coordinate_horizontal_line" />
<TextView
android:id="@+id/stats_latitude_value"
style="@style/StatsSmallValue"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline2"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintTop_toBottomOf="@+id/stats_latitude_label"
tools:text="0.834937848" />
@@ -373,16 +373,16 @@
style="@style/StatsSmallLabel"
android:text="@string/stats_longitude"
app:layout_constrainedWidth="true"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_coordinate_horizontal_line" />
<TextView
android:id="@+id/stats_longitude_value"
style="@style/StatsSmallValue"
android:value="@string/value_unknown"
app:layout_constraintLeft_toRightOf="@+id/guideline2"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline2"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_longitude_label"
tools:text="0.834937848" />
@@ -399,8 +399,8 @@
android:id="@+id/stats_sensor_horizontal_line"
style="@style/StatsHorizontalLine"
android:layout_marginBottom="8dp"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/stats_location_barrier" />
<!-- Sensors data -->
@@ -408,8 +408,8 @@
android:id="@+id/stats_sensors_recycler_view"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/guideline"
app:layout_constraintRight_toLeftOf="@+id/guideline3"
app:layout_constraintStart_toEndOf="@+id/guideline"
app:layout_constraintEnd_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@id/stats_sensor_horizontal_line" />
</androidx.constraintlayout.widget.ConstraintLayout>
+2 -2
View File
@@ -95,13 +95,13 @@ limitations under the License.
<Button
android:id="@+id/track_edit_cancel"
style="@style/BottomButton"
android:layout_gravity="left"
android:layout_gravity="start"
android:text="@string/generic_cancel" />
<Button
android:id="@+id/track_edit_save"
style="@style/BottomButton"
android:layout_gravity="right"
android:layout_gravity="end"
android:text="@string/generic_save" />
</LinearLayout>
</LinearLayout>
+1 -1
View File
@@ -73,7 +73,7 @@ limitations under the License.
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="22"
android:gravity="left"
android:gravity="start"
android:text="@string/track_list_empty_message" />
<View
+1 -1
View File
@@ -25,7 +25,7 @@ limitations under the License.
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/track_detail_activity_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
+1 -1
View File
@@ -11,7 +11,7 @@
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<androidx.viewpager.widget.ViewPager
<androidx.viewpager2.widget.ViewPager2
android:id="@+id/track_detail_activity_view_pager"
android:layout_width="match_parent"
android:layout_height="0dp"
+10 -3
View File
@@ -38,12 +38,12 @@ limitations under the License.
a)
(live updates) Install <a href="https://github.com/OpenTracksApp/OSMDashboard">OSMDashboard</a>.
It provides online or offline maps via <a href="https://www.openstreetmap.org">OpenStreetMap</a>.\n
Actually, OSMDashboard is a separate app that only can access (temporarily) access the data of track(s) that are going to be shown.
Actually, OSMDashboard is a separate app that only can access (temporarily) the data of track(s) that are going to be shown.
\n
b)
Via a "normal" map application (e.g., <a href="http://osmand.net/">OsmAnd</a> and <a href="https://maps.me/">MAPS.ME</a>).
Those app need to support the KMZ file format (only locations and timestamps).
These apps need to support the KMZ file format (only locations and timestamps).
In fact, an app needs to support <i>ACTION_VIEW</i> with MIME <i>application/vnd.google-earth.kmz</i>.
</string>
@@ -77,7 +77,7 @@ limitations under the License.
What you can do:\n
a) check if GPS is enabled,\n
b) improve GPS reception (e.g., go outdoors),\n
c) check if with <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, and\n
c) check with <a href="https://f-droid.org/en/packages/com.android.gpstest.osmdroid/">GPSTest</a> app, and\n
d) disable power saving.\n
\n
If everything does not help please report a bug.
@@ -290,10 +290,12 @@ limitations under the License.
<string name="import_unsupported_format">Unsupported file format</string>
<string name="import_parser_error">Parser error: %1$s</string>
<string name="import_unable_to_import_file">Unable to import file: %1$s</string>
<string name="import_no_kml_file_found">No doc.kml file found in KMZ</string>
<string name="import_error_info">%1$s: %2$s</string>
<string name="import_error_list_dialog_title">Files not imported</string>
<string name="import_file_imported">File %1$s imported</string>
<string name="import_error">Imported %1$d of %2$s from %3$s</string>
<string name="import_prevent_reimport">You have set prevent re-import track</string>
<string name="import_no_directory">%1$s does not exist</string>
<string name="import_no_file">There were no files to import. Connect your device to your computer and place the files to import in %1$s.</string>
<string name="import_no_file_title">Import files</string>
@@ -507,8 +509,11 @@ limitations under the License.
<string name="value_always">Always</string>
<string name="value_float_feet">%1$.2f ft</string>
<string name="value_float_kilometer">%1$.2f km</string>
<string name="value_float_kilometer_hour">%1$.2f km/h</string>
<string name="value_float_meter">%1$.2f m</string>
<string name="value_float_mile">%1$.2f mi</string>
<string name="value_float_mile_hour">%1$.2f mph</string>
<string name="value_float_mile_poor_gps">%1$.1f mi (poor GPS)</string>
<string name="value_integer_feet">%1$d ft</string>
<string name="value_integer_feet_excellent_gps">%1$d ft (excellent GPS)</string>
@@ -524,6 +529,8 @@ limitations under the License.
<string name="value_integer_minute">%1$d min</string>
<string name="value_integer_percent">%1$d %%</string>
<string name="value_integer_second">%1$d s</string>
<string name="value_pace_mile">%1$d:%2$02d min/mi</string>
<string name="value_pace_kilometer">%1$d:%2$02d min/km</string>
<string name="value_none">None</string>
<string name="value_off">Off</string>
<string name="value_smallest">Smallest</string>
+17 -1
View File
@@ -117,7 +117,23 @@ limitations under the License.
<item name="android:paddingTop">6dp</item>
</style>
<style name="StatsLargeLabel" parent="@style/TextSmall">
<style name="LargeLabel" parent="@style/TextSmall">
<item name="android:textAllCaps">true</item>
<item name="android:textColor">?attr/colorAccent</item>
<item name="android:textStyle">bold</item>
</style>
<style name="IntervalLabel" parent="@style/LargeLabel">
<item name="android:singleLine">true</item>
<item name="android:layout_margin">1dp</item>
<item name="android:textAlignment">textStart</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:layout_weight">1</item>
<item name="android:layout_width">1dp</item>
<item name="android:layout_gravity">center</item>
</style>
<style name="StatsLargeLabel" parent="@style/LargeLabel">
<item name="android:gravity">center</item>
<item name="android:layout_gravity">center</item>
<item name="android:singleLine">false</item>
-9
View File
@@ -25,16 +25,7 @@ limitations under the License.
<item name="windowActionModeOverlay">true</item>
</style>
<style name="ThemeCustomNotTransparentDialog" parent="ThemeCustom">
<!-- TODO Remove when moving to settings to fragments. -->
<item name="android:windowContentOverlay">@null</item>
<item name="android:windowNoTitle">true</item>
<item name="android:windowIsFloating">true</item>
<item name="android:backgroundDimEnabled">true</item>
</style>
<style name="TrackDeleteActivity" parent="ThemeCustom">
<!-- TODO Remove when moving to TrackDeleteActivity to fragments. -->
<item name="android:windowIsTranslucent">true</item>
<item name="android:windowBackground">@android:color/transparent</item>
<item name="android:windowIsFloating">true</item>