mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-09-30 16:52:21 +02:00
Recording stats layout customizable.
Users can select the order, visibility and importance (primary or secondary) of all stats for recording layout from the Settings. Also, users can select the number of columns per row in the recording layout: 1, 2 or 3. Finally, show altitude/coordinate from settings have been removed (not needed anymore). Fixes #659. Fixes #302. Fixes #820.
This commit is contained in:
+21
-2
@@ -43,7 +43,6 @@ class TrackPoint {
|
|||||||
- sensor_power
|
- sensor_power
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
class Marker {
|
class Marker {
|
||||||
- id
|
- id
|
||||||
- trackId
|
- trackId
|
||||||
@@ -58,6 +57,26 @@ class Marker {
|
|||||||
- photoUrl
|
- photoUrl
|
||||||
}
|
}
|
||||||
|
|
||||||
|
class DataField {
|
||||||
|
- key
|
||||||
|
- title
|
||||||
|
- isVisible
|
||||||
|
- isPrimary
|
||||||
|
- isWide
|
||||||
|
}
|
||||||
|
|
||||||
|
class StatisticData {
|
||||||
|
- value
|
||||||
|
- unit
|
||||||
|
- description
|
||||||
|
}
|
||||||
|
StatisticData o-- DataField
|
||||||
|
|
||||||
|
class Layout {
|
||||||
|
- profile
|
||||||
|
}
|
||||||
|
Layout "1" o-- "many" DataField
|
||||||
|
|
||||||
note left of TrackPoint
|
note left of TrackPoint
|
||||||
As of OpenTracks version 3.15.0, all times are using device time.
|
As of OpenTracks version 3.15.0, all times are using device time.
|
||||||
Before that TrackPoint.time contained GPS time (determined by GPS hardware).
|
Before that TrackPoint.time contained GPS time (determined by GPS hardware).
|
||||||
@@ -77,4 +96,4 @@ Trackpoints of Type.SEGMENT_START_MANUAL or Type.SEGMENT_END_MANUAL do not conta
|
|||||||
|
|
||||||
Tracks recorded prior to OpenTracks version 3.15.0, do neither begin with a Type.SEGMENT_START_MANUAL nor end with a Type.SEGMENT_END_MANUAL.
|
Tracks recorded prior to OpenTracks version 3.15.0, do neither begin with a Type.SEGMENT_START_MANUAL nor end with a Type.SEGMENT_END_MANUAL.
|
||||||
end note
|
end note
|
||||||
@enduml
|
@enduml
|
||||||
|
|||||||
@@ -1,191 +0,0 @@
|
|||||||
package de.dennisguse.opentracks;
|
|
||||||
|
|
||||||
|
|
||||||
import static androidx.test.espresso.Espresso.onData;
|
|
||||||
import static androidx.test.espresso.Espresso.onView;
|
|
||||||
import static androidx.test.espresso.action.ViewActions.click;
|
|
||||||
import static androidx.test.espresso.action.ViewActions.scrollTo;
|
|
||||||
import static androidx.test.espresso.assertion.ViewAssertions.matches;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.isDisplayed;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withClassName;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withContentDescription;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withId;
|
|
||||||
import static androidx.test.espresso.matcher.ViewMatchers.withText;
|
|
||||||
import static org.hamcrest.Matchers.allOf;
|
|
||||||
import static org.hamcrest.Matchers.anything;
|
|
||||||
import static org.hamcrest.Matchers.is;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.view.ViewParent;
|
|
||||||
|
|
||||||
import androidx.test.espresso.DataInteraction;
|
|
||||||
import androidx.test.espresso.UiController;
|
|
||||||
import androidx.test.espresso.ViewAction;
|
|
||||||
import androidx.test.espresso.ViewInteraction;
|
|
||||||
import androidx.test.ext.junit.rules.ActivityScenarioRule;
|
|
||||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
|
||||||
import androidx.test.filters.LargeTest;
|
|
||||||
import androidx.test.platform.app.InstrumentationRegistry;
|
|
||||||
import androidx.test.rule.GrantPermissionRule;
|
|
||||||
|
|
||||||
import org.hamcrest.Description;
|
|
||||||
import org.hamcrest.Matcher;
|
|
||||||
import org.hamcrest.TypeSafeMatcher;
|
|
||||||
import org.junit.Rule;
|
|
||||||
import org.junit.Test;
|
|
||||||
import org.junit.rules.TestRule;
|
|
||||||
import org.junit.runner.RunWith;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Espresso test that checks the unit for activity category selected.
|
|
||||||
* Also it checks that unit is properly when user change from a pace activity to an speed one.
|
|
||||||
*/
|
|
||||||
@LargeTest
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
|
||||||
public class EspressoCategoryUnitTest {
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public ActivityScenarioRule<TrackListActivity> mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class);
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public TestRule mRuntimePermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION);
|
|
||||||
|
|
||||||
private final Context context = InstrumentationRegistry.getInstrumentation().getTargetContext();
|
|
||||||
|
|
||||||
@Rule
|
|
||||||
public TestRule mLocaleRule = new PreferenceMetricUnitRule(context, true);
|
|
||||||
|
|
||||||
@Test
|
|
||||||
public void changeBetweenCategoryUpdateProperlyUnitTest() {
|
|
||||||
// Start record.
|
|
||||||
ViewInteraction appCompatImageButton = onView(
|
|
||||||
allOf(withId(R.id.controller_record), withContentDescription("Record"),
|
|
||||||
childAtPosition(
|
|
||||||
allOf(withId(R.id.controller_container),
|
|
||||||
childAtPosition(
|
|
||||||
withId(R.id.controller_fragment),
|
|
||||||
0)),
|
|
||||||
0),
|
|
||||||
isDisplayed()));
|
|
||||||
appCompatImageButton.perform(click());
|
|
||||||
|
|
||||||
{
|
|
||||||
// Change to running activity (pace activity).
|
|
||||||
ViewInteraction appCompatImageView = onView(
|
|
||||||
allOf(withId(R.id.stats_activity_type_icon),
|
|
||||||
childAtPosition(
|
|
||||||
childAtPosition(
|
|
||||||
withClassName(is("android.widget.ScrollView")),
|
|
||||||
0),
|
|
||||||
7)));
|
|
||||||
appCompatImageView.perform(scrollTo(), click());
|
|
||||||
|
|
||||||
DataInteraction imageView = onData(anything())
|
|
||||||
.inAdapterView(allOf(withId(R.id.choose_activity_type_grid_view),
|
|
||||||
childAtPosition(
|
|
||||||
withClassName(is("android.widget.LinearLayout")),
|
|
||||||
0)))
|
|
||||||
.atPosition(1);
|
|
||||||
imageView.perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Pace (min/km) in all fields.
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_speed_unit)));
|
|
||||||
textView.perform(waitFor(2000));
|
|
||||||
textView.check(matches(withText("min/km")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_average_speed_unit)));
|
|
||||||
textView.check(matches(withText("min/km")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_max_speed_unit)));
|
|
||||||
textView.check(matches(withText("min/km")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_moving_speed_unit)));
|
|
||||||
textView.check(matches(withText("min/km")));
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
// Change to biking activity (speed activity).
|
|
||||||
ViewInteraction appCompatImageView = onView(
|
|
||||||
allOf(withId(R.id.stats_activity_type_icon),
|
|
||||||
childAtPosition(
|
|
||||||
childAtPosition(
|
|
||||||
withClassName(is("android.widget.ScrollView")),
|
|
||||||
0),
|
|
||||||
7)));
|
|
||||||
appCompatImageView.perform(scrollTo(), click());
|
|
||||||
|
|
||||||
DataInteraction imageView = onData(anything())
|
|
||||||
.inAdapterView(allOf(withId(R.id.choose_activity_type_grid_view),
|
|
||||||
childAtPosition(
|
|
||||||
withClassName(is("android.widget.LinearLayout")),
|
|
||||||
0)))
|
|
||||||
.atPosition(9);
|
|
||||||
imageView.perform(click());
|
|
||||||
}
|
|
||||||
|
|
||||||
// Speed (km/h) in all fields.
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_speed_unit)));
|
|
||||||
textView.perform(waitFor(2000));
|
|
||||||
textView.check(matches(withText("km/h")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_average_speed_unit)));
|
|
||||||
textView.check(matches(withText("km/h")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_max_speed_unit)));
|
|
||||||
textView.check(matches(withText("km/h")));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
ViewInteraction textView = onView(allOf(withId(R.id.stats_moving_speed_unit)));
|
|
||||||
textView.check(matches(withText("km/h")));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private static Matcher<View> childAtPosition(
|
|
||||||
final Matcher<View> parentMatcher, final int position) {
|
|
||||||
|
|
||||||
return new TypeSafeMatcher<>() {
|
|
||||||
@Override
|
|
||||||
public void describeTo(Description description) {
|
|
||||||
description.appendText("Child at position " + position + " in parent ");
|
|
||||||
parentMatcher.describeTo(description);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public boolean matchesSafely(View view) {
|
|
||||||
ViewParent parent = view.getParent();
|
|
||||||
return parent instanceof ViewGroup && parentMatcher.matches(parent)
|
|
||||||
&& view.equals(((ViewGroup) parent).getChildAt(position));
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
private static ViewAction waitFor(final long duration_ms) {
|
|
||||||
return new ViewAction() {
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public String getDescription() {
|
|
||||||
return "Wait for milliseconds.";
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public Matcher<View> getConstraints() {
|
|
||||||
return isDisplayed();
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void perform(UiController uiController, final View view) {
|
|
||||||
uiController.loopMainThreadForAtLeast(duration_ms);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,108 @@
|
|||||||
|
package de.dennisguse.opentracks;
|
||||||
|
|
||||||
|
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.espresso.NoMatchingViewException;
|
||||||
|
import androidx.test.espresso.ViewAssertion;
|
||||||
|
import androidx.test.espresso.ViewInteraction;
|
||||||
|
import androidx.test.filters.LargeTest;
|
||||||
|
import androidx.test.rule.ActivityTestRule;
|
||||||
|
import androidx.test.rule.GrantPermissionRule;
|
||||||
|
import androidx.test.runner.AndroidJUnit4;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.view.ViewParent;
|
||||||
|
|
||||||
|
import static androidx.test.espresso.Espresso.onView;
|
||||||
|
import static androidx.test.espresso.action.ViewActions.*;
|
||||||
|
import static androidx.test.espresso.matcher.ViewMatchers.*;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
|
||||||
|
import org.hamcrest.Description;
|
||||||
|
import org.hamcrest.Matcher;
|
||||||
|
import org.hamcrest.TypeSafeMatcher;
|
||||||
|
import org.junit.Rule;
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import static org.hamcrest.CoreMatchers.is;
|
||||||
|
import static org.hamcrest.Matchers.allOf;
|
||||||
|
|
||||||
|
@LargeTest
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class EspressoCustomLayoutTest {
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public ActivityTestRule<TrackListActivity> mActivityTestRule = new ActivityTestRule<>(TrackListActivity.class);
|
||||||
|
|
||||||
|
@Rule
|
||||||
|
public GrantPermissionRule mGrantPermissionRule =
|
||||||
|
GrantPermissionRule.grant(
|
||||||
|
"android.permission.ACCESS_FINE_LOCATION");
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void customLayoutTest() {
|
||||||
|
ViewInteraction appCompatImageButton = onView(
|
||||||
|
allOf(withId(R.id.controller_record), withContentDescription("Record"),
|
||||||
|
childAtPosition(
|
||||||
|
allOf(withId(R.id.controller_container),
|
||||||
|
childAtPosition(
|
||||||
|
withId(R.id.controller_fragment),
|
||||||
|
0)),
|
||||||
|
0),
|
||||||
|
isDisplayed()));
|
||||||
|
appCompatImageButton.perform(click());
|
||||||
|
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
||||||
|
|
||||||
|
onView(withId(R.id.stats_recycler_view)).check(new RecyclerViewItemCountAssertion((int) layout.getFields().stream().filter(DataField::isVisible).count()));
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class RecyclerViewItemCountAssertion implements ViewAssertion {
|
||||||
|
private final int expectedCount;
|
||||||
|
|
||||||
|
public RecyclerViewItemCountAssertion(int expectedCount) {
|
||||||
|
this.expectedCount = expectedCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void check(View view, NoMatchingViewException noViewFoundException) {
|
||||||
|
if (noViewFoundException != null) {
|
||||||
|
throw noViewFoundException;
|
||||||
|
}
|
||||||
|
|
||||||
|
RecyclerView recyclerView = (RecyclerView) view;
|
||||||
|
RecyclerView.Adapter adapter = recyclerView.getAdapter();
|
||||||
|
assertThat(adapter.getItemCount(), is(expectedCount));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private static Matcher<View> childAtPosition(
|
||||||
|
final Matcher<View> parentMatcher, final int position) {
|
||||||
|
|
||||||
|
return new TypeSafeMatcher<View>() {
|
||||||
|
@Override
|
||||||
|
public void describeTo(Description description) {
|
||||||
|
description.appendText("Child at position " + position + " in parent ");
|
||||||
|
parentMatcher.describeTo(description);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean matchesSafely(View view) {
|
||||||
|
ViewParent parent = view.getParent();
|
||||||
|
return parent instanceof ViewGroup && parentMatcher.matches(parent)
|
||||||
|
&& view.equals(((ViewGroup) parent).getChildAt(position));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,9 +10,14 @@ import org.junit.Test;
|
|||||||
import org.junit.runner.RunWith;
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
import static org.junit.Assert.assertEquals;
|
import static org.junit.Assert.assertEquals;
|
||||||
|
import static org.junit.Assert.assertFalse;
|
||||||
|
import static org.junit.Assert.assertNotNull;
|
||||||
|
import static org.junit.Assert.assertTrue;
|
||||||
|
|
||||||
@RunWith(AndroidJUnit4.class)
|
@RunWith(AndroidJUnit4.class)
|
||||||
public class PreferencesUtilsTest {
|
public class PreferencesUtilsTest {
|
||||||
@@ -64,4 +69,131 @@ public class PreferencesUtilsTest {
|
|||||||
// then
|
// then
|
||||||
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
assertEquals(TrackFileFormat.KMZ_WITH_TRACKDETAIL_AND_SENSORDATA, trackFileFormat);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_default() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.clear();
|
||||||
|
editor.commit();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertTrue(layout.getFields().size() > 0);
|
||||||
|
assertEquals(layout.getProfile(), context.getString(R.string.default_activity_default));
|
||||||
|
assertTrue(layout.getFields().stream().anyMatch(DataField::isVisible));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_1() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(
|
||||||
|
context.getString(R.string.stats_custom_layout_fields_key),
|
||||||
|
"run;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(layout.getFields().size(), 4);
|
||||||
|
assertEquals(layout.getProfile(), "run");
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
|
||||||
|
assertTrue(layout.getFields().get(0).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(0).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
|
||||||
|
assertTrue(layout.getFields().get(1).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(1).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(2).getKey(), context.getString(R.string.stats_custom_layout_average_moving_speed_key));
|
||||||
|
assertFalse(layout.getFields().get(2).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(2).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(3).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
|
||||||
|
assertFalse(layout.getFields().get(3).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(3).isPrimary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testGetCustomLayout_coordinatesIsWide() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
SharedPreferences.Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putString(
|
||||||
|
context.getString(R.string.stats_custom_layout_fields_key),
|
||||||
|
"walking;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_coordinates_key) + ",0,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
||||||
|
editor.apply();
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout layout = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(layout.getFields().size(), 4);
|
||||||
|
assertEquals(layout.getProfile(), "walking");
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(0).getKey(), context.getString(R.string.stats_custom_layout_moving_time_key));
|
||||||
|
assertTrue(layout.getFields().get(0).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(0).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(1).getKey(), context.getString(R.string.stats_custom_layout_distance_key));
|
||||||
|
assertTrue(layout.getFields().get(1).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(1).isPrimary());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(2).getKey(), context.getString(R.string.stats_custom_layout_coordinates_key));
|
||||||
|
assertFalse(layout.getFields().get(2).isVisible());
|
||||||
|
assertTrue(layout.getFields().get(2).isPrimary());
|
||||||
|
assertTrue(layout.getFields().get(2).isWide());
|
||||||
|
|
||||||
|
assertEquals(layout.getFields().get(3).getKey(), context.getString(R.string.stats_custom_layout_speed_key));
|
||||||
|
assertFalse(layout.getFields().get(3).isVisible());
|
||||||
|
assertFalse(layout.getFields().get(3).isPrimary());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testSetCustomLayout() {
|
||||||
|
// given
|
||||||
|
SharedPreferences sharedPreferences = PreferencesUtils.getSharedPreferences(context);
|
||||||
|
Layout layoutSrc = new Layout("road cycling");
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_moving_time_key), context.getString(R.string.stats_moving_time), true, true, false));
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_distance_key), context.getString(R.string.stats_distance), true, false, false));
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_average_moving_speed_key), context.getString(R.string.stats_average_moving_speed), false, true, false));
|
||||||
|
layoutSrc.addField(new DataField(context.getString(R.string.stats_custom_layout_speed_key), context.getString(R.string.stats_speed), false, false, false));
|
||||||
|
|
||||||
|
// when
|
||||||
|
PreferencesUtils.setCustomLayout(sharedPreferences, context, layoutSrc);
|
||||||
|
|
||||||
|
// then
|
||||||
|
String csv = sharedPreferences.getString(context.getString(R.string.stats_custom_layout_fields_key), null);
|
||||||
|
assertNotNull(csv);
|
||||||
|
assertEquals(csv,
|
||||||
|
"road cycling;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_moving_time_key) + ",1,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_distance_key) + ",1,0;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_average_moving_speed_key) + ",0,1;"
|
||||||
|
+ context.getString(R.string.stats_custom_layout_speed_key) + ",0,0;");
|
||||||
|
|
||||||
|
Layout layoutDst = PreferencesUtils.getCustomLayout(sharedPreferences, context);
|
||||||
|
assertEquals(layoutSrc.getProfile(), layoutDst.getProfile());
|
||||||
|
assertEquals(layoutSrc.getFields().size(), layoutDst.getFields().size());
|
||||||
|
for (int i = 0; i < layoutSrc.getFields().size(); i++) {
|
||||||
|
assertEquals(layoutSrc.getFields().get(i).getKey(), layoutDst.getFields().get(i).getKey());
|
||||||
|
assertEquals(layoutSrc.getFields().get(i).isVisible(), layoutDst.getFields().get(i).isVisible());
|
||||||
|
assertEquals(layoutSrc.getFields().get(i).isPrimary(), layoutDst.getFields().get(i).isPrimary());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,68 @@
|
|||||||
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
|
||||||
|
@RunWith(AndroidJUnit4.class)
|
||||||
|
public class StatisticsUtilsTest extends TestCase {
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testEmptyValue() {
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_distance_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_total_time_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_speed_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_moving_time_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_speed_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_max_speed_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_float), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_moving_speed_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_altitude_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_gain_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_loss_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_pace_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_moving_pace_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_average_pace_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_time), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_fastest_pace_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_coordinates), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_coordinates_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_heart_rate_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_cadence_key)));
|
||||||
|
assertEquals(context.getString(R.string.stats_empty_value_integer), StatisticsUtils.emptyValue(context, context.getString(R.string.stats_custom_layout_power_key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFilterVisible() {
|
||||||
|
// given
|
||||||
|
Layout layout = new Layout("profile");
|
||||||
|
layout.addField(new DataField("key1", "title1", true, true, false));
|
||||||
|
layout.addField(new DataField("key2", "title2", false, true, false));
|
||||||
|
layout.addField(new DataField("key3", "title3", true, true, false));
|
||||||
|
layout.addField(new DataField("key4", "title4", false, true, false));
|
||||||
|
layout.addField(new DataField("key5", "title5", true, true, false));
|
||||||
|
|
||||||
|
// when
|
||||||
|
Layout resultTrue = StatisticsUtils.filterVisible(layout, true);
|
||||||
|
Layout resultFalse = StatisticsUtils.filterVisible(layout, false);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(resultTrue.getFields().size(), 3);
|
||||||
|
assertTrue(resultTrue.getFields().stream().anyMatch(f -> f.getKey().equals("key1")));
|
||||||
|
assertTrue(resultTrue.getFields().stream().anyMatch(f -> f.getKey().equals("key3")));
|
||||||
|
assertTrue(resultTrue.getFields().stream().anyMatch(f -> f.getKey().equals("key5")));
|
||||||
|
|
||||||
|
assertEquals(resultFalse.getFields().size(), 2);
|
||||||
|
assertTrue(resultFalse.getFields().stream().anyMatch(f -> f.getKey().equals("key2")));
|
||||||
|
assertTrue(resultFalse.getFields().stream().anyMatch(f -> f.getKey().equals("key4")));
|
||||||
|
}
|
||||||
|
}
|
||||||
+195
@@ -0,0 +1,195 @@
|
|||||||
|
package de.dennisguse.opentracks.viewmodels;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.test.core.app.ApplicationProvider;
|
||||||
|
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
|
||||||
|
import org.junit.Test;
|
||||||
|
import org.junit.runner.RunWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.MockitoJUnitRunner;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||||
|
import de.dennisguse.opentracks.stats.TrackStatistics;
|
||||||
|
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@RunWith(MockitoJUnitRunner.class)
|
||||||
|
public class StatisticDataBuilderTest extends TestCase {
|
||||||
|
|
||||||
|
private final Context context = ApplicationProvider.getApplicationContext();
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Track trackMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TrackStatistics trackStatisticsMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private TrackRecordingService.RecordingData recordingDataMock;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private SensorStatistics sensorStatisticsMock;
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromRecordingData() {
|
||||||
|
when(trackMock.getTrackStatistics()).thenReturn(trackStatisticsMock);
|
||||||
|
when(trackStatisticsMock.getTotalTime()).thenReturn(Duration.ofMillis(0));
|
||||||
|
when(trackStatisticsMock.getMovingTime()).thenReturn(Duration.ofMillis(0));
|
||||||
|
when(trackStatisticsMock.getTotalDistance()).thenReturn(Distance.of(0));
|
||||||
|
when(recordingDataMock.getTrackStatistics()).thenReturn(trackStatisticsMock);
|
||||||
|
|
||||||
|
// given
|
||||||
|
Layout layout = new Layout(context.getString(R.string.default_activity_default));
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_total_time_key), context.getString(R.string.stats_total_time), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_moving_time_key), context.getString(R.string.stats_moving_time), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_distance_key), context.getString(R.string.stats_distance), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_speed_key), context.getString(R.string.stats_speed), false, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_max_speed_key), context.getString(R.string.stats_max_speed), false, true, false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromRecordingData(context, recordingDataMock, layout, true);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(statisticDataList.size(), 3);
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_total_time))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_moving_time))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_distance))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromRecordingData_allFields() {
|
||||||
|
when(trackMock.getTrackStatistics()).thenReturn(trackStatisticsMock);
|
||||||
|
when(trackStatisticsMock.getTotalTime()).thenReturn(Duration.ofMillis(0));
|
||||||
|
when(trackStatisticsMock.getMovingTime()).thenReturn(Duration.ofMillis(0));
|
||||||
|
when(trackStatisticsMock.getTotalDistance()).thenReturn(Distance.of(0));
|
||||||
|
when(recordingDataMock.getTrackStatistics()).thenReturn(trackStatisticsMock);
|
||||||
|
|
||||||
|
// given
|
||||||
|
Layout layout = new Layout(context.getString(R.string.default_activity_default));
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_total_time_key), context.getString(R.string.stats_total_time), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_moving_time_key), context.getString(R.string.stats_moving_time), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_distance_key), context.getString(R.string.stats_distance), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_speed_key), context.getString(R.string.stats_speed), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_average_moving_speed_key), context.getString(R.string.stats_average_moving_speed), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_average_speed_key), context.getString(R.string.stats_average_speed), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_max_speed_key), context.getString(R.string.stats_max_speed), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_pace_key), context.getString(R.string.stats_pace), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_average_moving_pace_key), context.getString(R.string.stats_average_moving_pace), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_average_pace_key), context.getString(R.string.stats_average_pace), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_fastest_pace_key), context.getString(R.string.stats_fastest_pace), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_altitude_key), context.getString(R.string.stats_altitude), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_gain_key), context.getString(R.string.stats_gain), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_loss_key), context.getString(R.string.stats_loss), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_coordinates_key), context.getString(R.string.stats_coordinates), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_heart_rate_key), context.getString(R.string.stats_sensors_heart_rate), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_cadence_key), context.getString(R.string.stats_sensors_cadence), true, true, false);
|
||||||
|
layout.addField(context.getString(R.string.stats_custom_layout_power_key), context.getString(R.string.stats_sensors_power), true, true, false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromRecordingData(context, recordingDataMock, layout, true);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(statisticDataList.size(), 18);
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_total_time))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_moving_time))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_distance))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_speed))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_average_moving_speed))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_average_speed))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_max_speed))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_pace))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_average_moving_pace))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_average_pace))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_fastest_pace))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_altitude))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_gain))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_loss))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_coordinates))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_heart_rate))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_cadence))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_power))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromSensorStatistics_onlyHeartRate() {
|
||||||
|
when(sensorStatisticsMock.hasHeartRate()).thenReturn(true);
|
||||||
|
when(sensorStatisticsMock.getMaxHeartRate()).thenReturn(200f);
|
||||||
|
when(sensorStatisticsMock.getAvgHeartRate()).thenReturn(150f);
|
||||||
|
when(sensorStatisticsMock.hasCadence()).thenReturn(false);
|
||||||
|
when(sensorStatisticsMock.hasPower()).thenReturn(false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromSensorStatistics(context, sensorStatisticsMock);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(statisticDataList.size(), 2);
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_heart_rate_max))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_heart_rate_avg))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromSensorStatistics_onlyCadence() {
|
||||||
|
when(sensorStatisticsMock.hasHeartRate()).thenReturn(false);
|
||||||
|
when(sensorStatisticsMock.hasCadence()).thenReturn(true);
|
||||||
|
when(sensorStatisticsMock.getAvgCadence()).thenReturn(90f);
|
||||||
|
when(sensorStatisticsMock.getMaxCadence()).thenReturn(110f);
|
||||||
|
when(sensorStatisticsMock.hasPower()).thenReturn(false);
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromSensorStatistics(context, sensorStatisticsMock);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(statisticDataList.size(), 2);
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_cadence_max))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_cadence_avg))));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromSensorStatistics_onlyPower() {
|
||||||
|
when(sensorStatisticsMock.hasHeartRate()).thenReturn(false);
|
||||||
|
when(sensorStatisticsMock.hasCadence()).thenReturn(false);
|
||||||
|
when(sensorStatisticsMock.hasPower()).thenReturn(true);
|
||||||
|
when(sensorStatisticsMock.getAvgPower()).thenReturn(300f);
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromSensorStatistics(context, sensorStatisticsMock);
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_power_avg))));
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(statisticDataList.size(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
public void testFromSensorStatistics() {
|
||||||
|
when(sensorStatisticsMock.hasHeartRate()).thenReturn(true);
|
||||||
|
when(sensorStatisticsMock.getMaxHeartRate()).thenReturn(200f);
|
||||||
|
when(sensorStatisticsMock.getAvgHeartRate()).thenReturn(150f);
|
||||||
|
when(sensorStatisticsMock.hasCadence()).thenReturn(true);
|
||||||
|
when(sensorStatisticsMock.getAvgCadence()).thenReturn(90f);
|
||||||
|
when(sensorStatisticsMock.getMaxCadence()).thenReturn(110f);
|
||||||
|
when(sensorStatisticsMock.hasPower()).thenReturn(true);
|
||||||
|
when(sensorStatisticsMock.getAvgPower()).thenReturn(300f);
|
||||||
|
|
||||||
|
// when
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromSensorStatistics(context, sensorStatisticsMock);
|
||||||
|
|
||||||
|
// then
|
||||||
|
assertEquals(statisticDataList.size(), 5);
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_heart_rate_max))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_heart_rate_avg))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_cadence_max))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_cadence_avg))));
|
||||||
|
assertTrue(statisticDataList.stream().anyMatch(i -> i.getField().getTitle().equals(context.getString(R.string.sensor_state_power_avg))));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -316,6 +316,7 @@ limitations under the License.
|
|||||||
<activity android:name=".io.file.exporter.ExportActivity" />
|
<activity android:name=".io.file.exporter.ExportActivity" />
|
||||||
|
|
||||||
<activity android:name=".settings.SettingsActivity" />
|
<activity android:name=".settings.SettingsActivity" />
|
||||||
|
<activity android:name=".settings.SettingsCustomLayoutActivity" />
|
||||||
|
|
||||||
<activity
|
<activity
|
||||||
android:name=".ShowOnMapProxyActivity$KML"
|
android:name=".ShowOnMapProxyActivity$KML"
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package de.dennisguse.opentracks.adapters;
|
||||||
|
|
||||||
|
enum CustomLayoutFieldType {
|
||||||
|
SHORT(0),
|
||||||
|
WIDE(1);
|
||||||
|
|
||||||
|
private final int value;
|
||||||
|
|
||||||
|
CustomLayoutFieldType(int value) {
|
||||||
|
this.value = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public int value() {
|
||||||
|
return this.value;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
package de.dennisguse.opentracks.adapters;
|
|
||||||
|
|
||||||
import android.content.Context;
|
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
|
||||||
import android.view.ViewGroup;
|
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import androidx.annotation.NonNull;
|
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
|
||||||
|
|
||||||
import java.util.List;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
import de.dennisguse.opentracks.viewmodels.SensorDataModel;
|
|
||||||
|
|
||||||
public class SensorsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
|
||||||
|
|
||||||
private List<SensorDataModel> sensorDataList;
|
|
||||||
private final Context context;
|
|
||||||
|
|
||||||
public SensorsAdapter(Context context) {
|
|
||||||
this.context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
@NonNull
|
|
||||||
@Override
|
|
||||||
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
|
||||||
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.sensor_item, parent, false);
|
|
||||||
return new SensorsAdapter.ViewHolder(view);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
|
||||||
SensorsAdapter.ViewHolder viewHolder = (SensorsAdapter.ViewHolder) holder;
|
|
||||||
SensorDataModel sensorDataModel = sensorDataList.get(position);
|
|
||||||
viewHolder.setData(sensorDataModel);
|
|
||||||
}
|
|
||||||
|
|
||||||
@Override
|
|
||||||
public int getItemCount() {
|
|
||||||
if (sensorDataList == null) {
|
|
||||||
return 0;
|
|
||||||
} else {
|
|
||||||
return sensorDataList.size();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public List<SensorDataModel> swapData(List<SensorDataModel> data) {
|
|
||||||
if (sensorDataList == data) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
sensorDataList = data;
|
|
||||||
|
|
||||||
if (data != null) {
|
|
||||||
this.notifyDataSetChanged();
|
|
||||||
}
|
|
||||||
|
|
||||||
return data;
|
|
||||||
}
|
|
||||||
|
|
||||||
private class ViewHolder extends RecyclerView.ViewHolder {
|
|
||||||
private final TextView label;
|
|
||||||
private final TextView sensorValue;
|
|
||||||
private final TextView value;
|
|
||||||
private final TextView unit;
|
|
||||||
|
|
||||||
public ViewHolder(@NonNull View itemView) {
|
|
||||||
super(itemView);
|
|
||||||
label = itemView.findViewById(R.id.stats_sensor_label);
|
|
||||||
sensorValue = itemView.findViewById(R.id.stats_sensor_sensor_value);
|
|
||||||
value = itemView.findViewById(R.id.stats_sensor_value);
|
|
||||||
unit = itemView.findViewById(R.id.stats_sensor_unit);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void setData(SensorDataModel sensorDataModel) {
|
|
||||||
String sensorName = sensorDataModel.getSensorName();
|
|
||||||
String sensorValue = sensorDataModel.hasValue() ? sensorDataModel.getSensorValue() : context.getString(R.string.value_unknown);
|
|
||||||
|
|
||||||
this.label.setText(context.getString(sensorDataModel.getLabelId()));
|
|
||||||
if (sensorName == null) {
|
|
||||||
this.sensorValue.setVisibility(View.GONE);
|
|
||||||
} else {
|
|
||||||
this.sensorValue.setText(sensorName);
|
|
||||||
}
|
|
||||||
this.value.setText(sensorValue);
|
|
||||||
this.unit.setText(context.getString(sensorDataModel.getUnitId()));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,118 @@
|
|||||||
|
package de.dennisguse.opentracks.adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ImageView;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.content.res.AppCompatResources;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import java.util.Optional;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
import de.dennisguse.opentracks.util.StatisticsUtils;
|
||||||
|
|
||||||
|
public class SettingsCustomLayoutAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
private Layout layout;
|
||||||
|
private final Context context;
|
||||||
|
private final SettingsCustomLayoutItemClickListener itemClickListener;
|
||||||
|
|
||||||
|
public SettingsCustomLayoutAdapter(Context context, SettingsCustomLayoutItemClickListener itemClickListener, Layout layout) {
|
||||||
|
this.context = context;
|
||||||
|
this.itemClickListener = itemClickListener;
|
||||||
|
this.layout = layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(context).inflate(R.layout.custom_stats_item, parent, false);
|
||||||
|
return new SettingsCustomLayoutAdapter.ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||||
|
SettingsCustomLayoutAdapter.ViewHolder viewHolder = (SettingsCustomLayoutAdapter.ViewHolder) holder;
|
||||||
|
DataField field = layout.getFields().get(position);
|
||||||
|
viewHolder.itemView.setTag(field.getKey());
|
||||||
|
viewHolder.title.setText(field.getTitle());
|
||||||
|
viewHolder.value.setText(StatisticsUtils.emptyValue(context, field.getKey()));
|
||||||
|
|
||||||
|
viewHolder.title.setTextAppearance(context, field.isVisible() ? (field.isPrimary() ? R.style.StatsPrimaryLabel : R.style.StatsSecondaryLabel) : R.style.StatsLabelHidden);
|
||||||
|
viewHolder.value.setTextAppearance(context, field.isVisible() ? (field.isPrimary() ? R.style.StatsPrimaryValue : R.style.StatsSecondaryValue) : R.style.StatsValueHidden);
|
||||||
|
viewHolder.statusIcon.setVisibility(field.isVisible() ? View.GONE : View.VISIBLE);
|
||||||
|
viewHolder.statusIcon.setImageDrawable(AppCompatResources.getDrawable(context, R.drawable.ic_baseline_visibility_off_24));
|
||||||
|
viewHolder.moveIcon.setVisibility(field.isVisible() ? View.VISIBLE : View.GONE);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if (layout == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return layout.getFields().size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return layout.getFields().get(position).isWide() ? CustomLayoutFieldType.WIDE.value() : CustomLayoutFieldType.SHORT.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isItemWide(int position) {
|
||||||
|
return getItemViewType(position) == CustomLayoutFieldType.WIDE.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataField getItem(int position) {
|
||||||
|
return layout.getFields().get(position);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void swapValues(Layout data) {
|
||||||
|
this.layout = data;
|
||||||
|
if (this.layout != null) {
|
||||||
|
this.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public Layout move(int fromPosition, int toPosition) {
|
||||||
|
layout.moveField(fromPosition, toPosition);
|
||||||
|
notifyItemMoved(fromPosition, toPosition);
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
|
||||||
|
final TextView title;
|
||||||
|
final TextView value;
|
||||||
|
final TextView unit;
|
||||||
|
final ImageView statusIcon;
|
||||||
|
final ImageView moveIcon;
|
||||||
|
|
||||||
|
public ViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
title = itemView.findViewById(R.id.stats_description_main);
|
||||||
|
value = itemView.findViewById(R.id.stats_value);
|
||||||
|
unit = itemView.findViewById(R.id.stats_unit);
|
||||||
|
statusIcon = itemView.findViewById(R.id.stats_icon_show_status);
|
||||||
|
moveIcon = itemView.findViewById(R.id.stats_iv_drag_indicator);
|
||||||
|
itemView.setOnClickListener(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onClick(View view) {
|
||||||
|
String statTitle = (String) view.getTag();
|
||||||
|
Optional<DataField> optionalField = layout.getFields().stream().filter(f -> f.getKey().equals(statTitle)).findFirst();
|
||||||
|
optionalField.ifPresent(itemClickListener::onSettingsCustomLayoutItemClicked);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public interface SettingsCustomLayoutItemClickListener {
|
||||||
|
void onSettingsCustomLayoutItemClicked(@NonNull DataField field);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,140 @@
|
|||||||
|
package de.dennisguse.opentracks.adapters;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.view.LayoutInflater;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.StatisticData;
|
||||||
|
|
||||||
|
public class StatisticsAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {
|
||||||
|
|
||||||
|
private List<StatisticData> statisticDataList;
|
||||||
|
private final Context context;
|
||||||
|
|
||||||
|
public StatisticsAdapter(Context context) {
|
||||||
|
this.context = context;
|
||||||
|
this.statisticDataList = new ArrayList<>();
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.stats_item, parent, false);
|
||||||
|
return new StatisticsAdapter.ViewHolder(view);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
|
||||||
|
StatisticsAdapter.ViewHolder viewHolder = (StatisticsAdapter.ViewHolder) holder;
|
||||||
|
StatisticData statisticData = statisticDataList.get(position);
|
||||||
|
viewHolder.setData(statisticData);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemCount() {
|
||||||
|
if (statisticDataList == null) {
|
||||||
|
return 0;
|
||||||
|
} else {
|
||||||
|
return statisticDataList.size();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int getItemViewType(int position) {
|
||||||
|
return statisticDataList.get(position).getField().isWide() ? CustomLayoutFieldType.WIDE.value() : CustomLayoutFieldType.SHORT.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isItemWide(int position) {
|
||||||
|
return getItemViewType(position) == CustomLayoutFieldType.WIDE.value();
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<StatisticData> swapData(List<StatisticData> data) {
|
||||||
|
if (statisticDataList == data) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
statisticDataList = data;
|
||||||
|
|
||||||
|
if (data != null) {
|
||||||
|
this.notifyDataSetChanged();
|
||||||
|
}
|
||||||
|
|
||||||
|
return data;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static class WithRecordedLayout extends StatisticsAdapter {
|
||||||
|
public WithRecordedLayout(Context context) {
|
||||||
|
super(context);
|
||||||
|
}
|
||||||
|
|
||||||
|
@NonNull
|
||||||
|
@Override
|
||||||
|
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||||
|
View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.stats_recorded_item, parent, false);
|
||||||
|
return new StatisticsAdapter.ViewRecordedHolder(view);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewHolder extends RecyclerView.ViewHolder {
|
||||||
|
final TextView value;
|
||||||
|
final TextView unit;
|
||||||
|
final TextView descMain;
|
||||||
|
final TextView descSecondary;
|
||||||
|
|
||||||
|
public ViewHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
value = itemView.findViewById(R.id.stats_value);
|
||||||
|
unit = itemView.findViewById(R.id.stats_unit);
|
||||||
|
descMain = itemView.findViewById(R.id.stats_description_main);
|
||||||
|
descSecondary = itemView.findViewById(R.id.stats_description_secondary);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(StatisticData statisticData) {
|
||||||
|
if (statisticData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.value.setText(statisticData.hasValue() ? statisticData.getValue() : context.getString(R.string.value_unknown));
|
||||||
|
this.value.setTextAppearance(context, statisticData.getField().isPrimary() ? R.style.StatsPrimaryValue : R.style.StatsSecondaryValue);
|
||||||
|
this.unit.setText(statisticData.getUnit());
|
||||||
|
this.descMain.setText(statisticData.getField().getTitle());
|
||||||
|
this.descMain.setTextAppearance(context, statisticData.getField().isPrimary() ? R.style.StatsPrimaryLabel : R.style.StatsSecondaryLabel);
|
||||||
|
if (statisticData.hasDescription()) {
|
||||||
|
this.descSecondary.setVisibility(View.VISIBLE);
|
||||||
|
this.descSecondary.setText(statisticData.getDescription());
|
||||||
|
} else {
|
||||||
|
this.descSecondary.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ViewRecordedHolder extends ViewHolder {
|
||||||
|
|
||||||
|
public ViewRecordedHolder(@NonNull View itemView) {
|
||||||
|
super(itemView);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void setData(StatisticData statisticData) {
|
||||||
|
if (statisticData == null) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
this.value.setText(statisticData.hasValue() ? statisticData.getValue() : context.getString(R.string.value_unknown));
|
||||||
|
this.unit.setText(statisticData.getUnit());
|
||||||
|
this.descMain.setText(statisticData.getField().getTitle());
|
||||||
|
if (statisticData.hasDescription()) {
|
||||||
|
this.descSecondary.setVisibility(View.VISIBLE);
|
||||||
|
this.descSecondary.setText(statisticData.getDescription());
|
||||||
|
} else {
|
||||||
|
this.descSecondary.setVisibility(View.GONE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,101 @@
|
|||||||
|
package de.dennisguse.opentracks.content.data;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.util.CsvConstants;
|
||||||
|
|
||||||
|
public class DataField {
|
||||||
|
public static final String YES_VALUE = "1";
|
||||||
|
public static final String NOT_VALUE = "0";
|
||||||
|
|
||||||
|
private final String key;
|
||||||
|
private final String title;
|
||||||
|
private boolean isVisible;
|
||||||
|
private boolean isPrimary;
|
||||||
|
private final boolean isWide;
|
||||||
|
|
||||||
|
public DataField(String key, String title, boolean isVisible, boolean isPrimary, boolean isWide) {
|
||||||
|
this.key = key;
|
||||||
|
this.title = title;
|
||||||
|
this.isVisible = isVisible;
|
||||||
|
this.isPrimary = isPrimary;
|
||||||
|
this.isWide = isWide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getKey() {
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getTitle() {
|
||||||
|
return title;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isVisible() {
|
||||||
|
return isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void toggleVisibility() {
|
||||||
|
isVisible = !isVisible;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isPrimary() {
|
||||||
|
return isPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void togglePrimary() {
|
||||||
|
isPrimary = !isPrimary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isWide() {
|
||||||
|
return isWide;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String toCsv() {
|
||||||
|
String visible = this.isVisible ? YES_VALUE : NOT_VALUE;
|
||||||
|
String primary = this.isPrimary ? YES_VALUE : NOT_VALUE;
|
||||||
|
return key + CsvConstants.ITEM_SEPARATOR + visible + CsvConstants.ITEM_SEPARATOR + primary;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static String getTitleByKey(Context context, String key) {
|
||||||
|
if (key.equals(context.getString(R.string.stats_custom_layout_total_time_key))) {
|
||||||
|
return context.getString(R.string.stats_total_time);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_moving_time_key))) {
|
||||||
|
return context.getString(R.string.stats_moving_time);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_distance_key))) {
|
||||||
|
return context.getString(R.string.stats_distance);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_speed_key))) {
|
||||||
|
return context.getString(R.string.stats_speed);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_pace_key))) {
|
||||||
|
return context.getString(R.string.stats_pace);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_average_moving_speed_key))) {
|
||||||
|
return context.getString(R.string.stats_average_moving_speed);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_average_speed_key))) {
|
||||||
|
return context.getString(R.string.stats_average_speed);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_max_speed_key))) {
|
||||||
|
return context.getString(R.string.stats_max_speed);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_average_moving_pace_key))) {
|
||||||
|
return context.getString(R.string.stats_average_moving_pace);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_average_pace_key))) {
|
||||||
|
return context.getString(R.string.stats_average_pace);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_fastest_pace_key))) {
|
||||||
|
return context.getString(R.string.stats_fastest_pace);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_altitude_key))) {
|
||||||
|
return context.getString(R.string.stats_altitude);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_gain_key))) {
|
||||||
|
return context.getString(R.string.stats_gain);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_loss_key))) {
|
||||||
|
return context.getString(R.string.stats_loss);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_coordinates_key))) {
|
||||||
|
return context.getString(R.string.stats_coordinates);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_heart_rate_key))) {
|
||||||
|
return context.getString(R.string.stats_sensors_heart_rate);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_cadence_key))) {
|
||||||
|
return context.getString(R.string.stats_sensors_cadence);
|
||||||
|
} else if (key.equals(context.getString(R.string.stats_custom_layout_power_key))) {
|
||||||
|
return context.getString(R.string.stats_sensors_power);
|
||||||
|
} else {
|
||||||
|
throw new RuntimeException("It doesn't exists a field with key: " + key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,42 @@
|
|||||||
|
package de.dennisguse.opentracks.content.data;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
public class Layout {
|
||||||
|
private final String profile;
|
||||||
|
private final List<DataField> dataFields = new ArrayList<>();
|
||||||
|
|
||||||
|
public Layout(String profile) {
|
||||||
|
this.profile = profile;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addField(String key, String title, boolean visible, boolean primary, boolean isWide) {
|
||||||
|
dataFields.add(new DataField(key, title, visible, primary, isWide));
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addField(DataField dataField) {
|
||||||
|
dataFields.add(dataField);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void addFields(List<DataField> dataFields) {
|
||||||
|
this.dataFields.addAll(dataFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void removeField(DataField dataField) {
|
||||||
|
dataFields.remove(dataField);
|
||||||
|
}
|
||||||
|
|
||||||
|
public List<DataField> getFields() {
|
||||||
|
return new ArrayList<>(dataFields);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void moveField(int from, int to) {
|
||||||
|
DataField dataFieldToMove = dataFields.remove(from);
|
||||||
|
dataFields.add(to, dataFieldToMove);
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getProfile() {
|
||||||
|
return profile;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -254,9 +254,9 @@ public class MarkerDetailFragment extends Fragment {
|
|||||||
|
|
||||||
private void setLocation(boolean addShadow) {
|
private void setLocation(boolean addShadow) {
|
||||||
String value = "[" + getString(R.string.stats_latitude) + " "
|
String value = "[" + getString(R.string.stats_latitude) + " "
|
||||||
+ StringUtils.formatCoordinate(marker.getLatitude()) + ", "
|
+ StringUtils.formatCoordinate(getContext(), marker.getLatitude()) + ", "
|
||||||
+ getString(R.string.stats_longitude) + " "
|
+ getString(R.string.stats_longitude) + " "
|
||||||
+ StringUtils.formatCoordinate(marker.getLongitude()) + "]";
|
+ StringUtils.formatCoordinate(getContext(), marker.getLongitude()) + "]";
|
||||||
|
|
||||||
ListItemUtils.setTextView(getActivity(), viewBinding.markerDetailMarkerLocation, value, addShadow);
|
ListItemUtils.setTextView(getActivity(), viewBinding.markerDetailMarkerLocation, value, addShadow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,12 +31,11 @@ import androidx.fragment.app.Fragment;
|
|||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.TrackRecordedActivity;
|
import de.dennisguse.opentracks.TrackRecordedActivity;
|
||||||
import de.dennisguse.opentracks.adapters.SensorsAdapter;
|
import de.dennisguse.opentracks.adapters.StatisticsAdapter;
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
import de.dennisguse.opentracks.content.provider.ContentProviderUtils;
|
||||||
import de.dennisguse.opentracks.databinding.StatisticsRecordedBinding;
|
import de.dennisguse.opentracks.databinding.StatisticsRecordedBinding;
|
||||||
@@ -45,7 +44,8 @@ import de.dennisguse.opentracks.stats.TrackStatistics;
|
|||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
import de.dennisguse.opentracks.util.TrackIconUtils;
|
||||||
import de.dennisguse.opentracks.viewmodels.SensorDataModel;
|
import de.dennisguse.opentracks.viewmodels.StatisticData;
|
||||||
|
import de.dennisguse.opentracks.viewmodels.StatisticDataBuilder;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fragment to display track statistics to the user for a recorded {@link Track}.
|
* A fragment to display track statistics to the user for a recorded {@link Track}.
|
||||||
@@ -69,7 +69,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
}
|
}
|
||||||
|
|
||||||
private SensorStatistics sensorStatistics;
|
private SensorStatistics sensorStatistics;
|
||||||
private SensorsAdapter sensorsAdapter;
|
private StatisticsAdapter.WithRecordedLayout sensorsAdapter;
|
||||||
|
|
||||||
private Track.Id trackId;
|
private Track.Id trackId;
|
||||||
@Nullable // Lazily loaded.
|
@Nullable // Lazily loaded.
|
||||||
@@ -114,7 +114,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
|
|
||||||
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
||||||
|
|
||||||
sensorsAdapter = new SensorsAdapter(getContext());
|
sensorsAdapter = new StatisticsAdapter.WithRecordedLayout(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -238,10 +238,6 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
|
|
||||||
// Set altitude gain and loss
|
// Set altitude gain and loss
|
||||||
{
|
{
|
||||||
// Make altitude visible?
|
|
||||||
boolean show = PreferencesUtils.isShowStatsAltitude(sharedPreferences, getContext());
|
|
||||||
viewBinding.statsAltitudeGroup.setVisibility(show ? View.VISIBLE : View.GONE);
|
|
||||||
|
|
||||||
Float altitudeGain_m = trackStatistics.getTotalAltitudeGain();
|
Float altitudeGain_m = trackStatistics.getTotalAltitudeGain();
|
||||||
Float altitudeLoss_m = trackStatistics.getTotalAltitudeLoss();
|
Float altitudeLoss_m = trackStatistics.getTotalAltitudeLoss();
|
||||||
|
|
||||||
@@ -254,6 +250,9 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
parts = StringUtils.getAltitudeParts(getContext(), altitudeLoss_m, preferenceMetricUnits);
|
parts = StringUtils.getAltitudeParts(getContext(), altitudeLoss_m, preferenceMetricUnits);
|
||||||
viewBinding.statsAltitudeLossValue.setText(parts.first);
|
viewBinding.statsAltitudeLossValue.setText(parts.first);
|
||||||
viewBinding.statsAltitudeLossUnit.setText(parts.second);
|
viewBinding.statsAltitudeLossUnit.setText(parts.second);
|
||||||
|
|
||||||
|
boolean show = altitudeGain_m != null && altitudeLoss_m != null;
|
||||||
|
viewBinding.statsAltitudeGroup.setVisibility(show ? View.VISIBLE : View.GONE);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -262,18 +261,7 @@ public class StatisticsRecordedFragment extends Fragment {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
List<SensorDataModel> sensorDataList = new ArrayList<>();
|
List<StatisticData> sensorDataList = StatisticDataBuilder.fromSensorStatistics(getContext(), sensorStatistics);
|
||||||
if (sensorStatistics.hasHeartRate()) {
|
|
||||||
sensorDataList.add(new SensorDataModel(R.string.sensor_state_heart_rate_max, R.string.sensor_unit_beats_per_minute, sensorStatistics.getMaxHeartRate()));
|
|
||||||
sensorDataList.add(new SensorDataModel(R.string.sensor_state_heart_rate_avg, R.string.sensor_unit_beats_per_minute, sensorStatistics.getAvgHeartRate()));
|
|
||||||
}
|
|
||||||
if (sensorStatistics.hasCadence()) {
|
|
||||||
sensorDataList.add(new SensorDataModel(R.string.sensor_state_cadence_max, R.string.sensor_unit_rounds_per_minute, sensorStatistics.getMaxCadence()));
|
|
||||||
sensorDataList.add(new SensorDataModel(R.string.sensor_state_cadence_avg, R.string.sensor_unit_rounds_per_minute, sensorStatistics.getAvgCadence()));
|
|
||||||
}
|
|
||||||
if (sensorStatistics.hasPower()) {
|
|
||||||
sensorDataList.add(new SensorDataModel(R.string.sensor_state_power_avg, R.string.sensor_unit_power, sensorStatistics.getAvgPower()));
|
|
||||||
}
|
|
||||||
if (sensorDataList.size() > 0) {
|
if (sensorDataList.size() > 0) {
|
||||||
sensorsAdapter.swapData(sensorDataList);
|
sensorsAdapter.swapData(sensorDataList);
|
||||||
}
|
}
|
||||||
|
|||||||
+39
-178
@@ -3,7 +3,6 @@ package de.dennisguse.opentracks.fragments;
|
|||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
import android.util.Pair;
|
|
||||||
import android.view.LayoutInflater;
|
import android.view.LayoutInflater;
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
import android.view.ViewGroup;
|
import android.view.ViewGroup;
|
||||||
@@ -11,28 +10,25 @@ import android.view.ViewGroup;
|
|||||||
import androidx.annotation.NonNull;
|
import androidx.annotation.NonNull;
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.fragment.app.Fragment;
|
import androidx.fragment.app.Fragment;
|
||||||
|
import androidx.lifecycle.LiveData;
|
||||||
|
import androidx.lifecycle.ViewModelProvider;
|
||||||
|
import androidx.recyclerview.widget.DividerItemDecoration;
|
||||||
import androidx.recyclerview.widget.GridLayoutManager;
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
import androidx.recyclerview.widget.RecyclerView;
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
import java.time.Duration;
|
|
||||||
import java.util.ArrayList;
|
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
import de.dennisguse.opentracks.TrackRecordingActivity;
|
import de.dennisguse.opentracks.adapters.StatisticsAdapter;
|
||||||
import de.dennisguse.opentracks.adapters.SensorsAdapter;
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
import de.dennisguse.opentracks.content.data.Speed;
|
|
||||||
import de.dennisguse.opentracks.content.data.Track;
|
import de.dennisguse.opentracks.content.data.Track;
|
||||||
import de.dennisguse.opentracks.content.data.TrackPoint;
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
|
||||||
import de.dennisguse.opentracks.databinding.StatisticsRecordingBinding;
|
import de.dennisguse.opentracks.databinding.StatisticsRecordingBinding;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingService;
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
import de.dennisguse.opentracks.services.TrackRecordingServiceConnection;
|
||||||
import de.dennisguse.opentracks.util.PreferencesUtils;
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
import de.dennisguse.opentracks.viewmodels.StatisticData;
|
||||||
import de.dennisguse.opentracks.util.TrackIconUtils;
|
import de.dennisguse.opentracks.viewmodels.StatisticsDataModel;
|
||||||
import de.dennisguse.opentracks.viewmodels.SensorDataModel;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A fragment to display track statistics to the user for a currently recording {@link Track}.
|
* A fragment to display track statistics to the user for a currently recording {@link Track}.
|
||||||
@@ -51,15 +47,16 @@ public class StatisticsRecordingFragment extends Fragment {
|
|||||||
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
private TrackRecordingServiceConnection trackRecordingServiceConnection;
|
||||||
private TrackRecordingService.RecordingData recordingData = TrackRecordingService.NOT_RECORDING;
|
private TrackRecordingService.RecordingData recordingData = TrackRecordingService.NOT_RECORDING;
|
||||||
private TrackPoint latestTrackPoint;
|
private TrackPoint latestTrackPoint;
|
||||||
|
private Layout layout;
|
||||||
|
|
||||||
private StatisticsRecordingBinding viewBinding;
|
private StatisticsRecordingBinding viewBinding;
|
||||||
private SensorsAdapter sensorsAdapter;
|
private StatisticsAdapter statisticsAdapter;
|
||||||
|
private GridLayoutManager gridLayoutManager;
|
||||||
|
private StatisticsDataModel viewModel;
|
||||||
|
private LiveData<List<StatisticData>> statisticsLiveData;
|
||||||
|
|
||||||
private SharedPreferences sharedPreferences;
|
private SharedPreferences sharedPreferences;
|
||||||
private boolean preferenceMetricUnits;
|
private boolean preferenceMetricUnits;
|
||||||
private boolean preferenceReportSpeed;
|
|
||||||
private boolean preferenceShowAltitude;
|
|
||||||
private boolean preferenceShowCoordinate;
|
|
||||||
|
|
||||||
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
|
private final SharedPreferences.OnSharedPreferenceChangeListener sharedPreferenceChangeListener = (sharedPreferences, key) -> {
|
||||||
boolean updateUInecessary = false;
|
boolean updateUInecessary = false;
|
||||||
@@ -69,19 +66,13 @@ public class StatisticsRecordingFragment extends Fragment {
|
|||||||
preferenceMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getContext());
|
preferenceMetricUnits = PreferencesUtils.isMetricUnits(sharedPreferences, getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_rate_key, key) && recordingData != null) {
|
if (PreferencesUtils.isKey(getContext(), R.string.stats_custom_layout_fields_key, key)) {
|
||||||
updateUInecessary = true;
|
updateUInecessary = true;
|
||||||
preferenceReportSpeed = PreferencesUtils.isReportSpeed(sharedPreferences, getContext(), recordingData.getTrackCategory());
|
layout = PreferencesUtils.getCustomLayout(sharedPreferences, getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_show_grade_altitude_key, key)) {
|
if (PreferencesUtils.isKey(getContext(), R.string.stats_custom_layout_columns_key, key)) {
|
||||||
updateUInecessary = true;
|
gridLayoutManager.setSpanCount(PreferencesUtils.getLayoutColumns(sharedPreferences, getContext()));
|
||||||
preferenceShowAltitude = PreferencesUtils.isShowStatsAltitude(sharedPreferences, getContext());
|
|
||||||
}
|
|
||||||
|
|
||||||
if (PreferencesUtils.isKey(getContext(), R.string.stats_show_coordinate_key, key)) {
|
|
||||||
updateUInecessary = true;
|
|
||||||
preferenceShowCoordinate = PreferencesUtils.isStatsShowCoordinate(sharedPreferences, getContext());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (key != null && updateUInecessary && isResumed()) {
|
if (key != null && updateUInecessary && isResumed()) {
|
||||||
@@ -109,17 +100,28 @@ public class StatisticsRecordingFragment extends Fragment {
|
|||||||
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
sharedPreferences = PreferencesUtils.getSharedPreferences(getContext());
|
||||||
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback);
|
trackRecordingServiceConnection = new TrackRecordingServiceConnection(bindChangedCallback);
|
||||||
|
|
||||||
sensorsAdapter = new SensorsAdapter(getContext());
|
statisticsAdapter = new StatisticsAdapter(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||||
viewBinding = StatisticsRecordingBinding.inflate(inflater, container, false);
|
viewBinding = StatisticsRecordingBinding.inflate(inflater, container, false);
|
||||||
viewBinding.statsActivityTypeIcon.setOnClickListener(v -> ((TrackRecordingActivity) getActivity()).chooseActivityType(recordingData.getTrackCategory()));
|
|
||||||
|
|
||||||
RecyclerView sensorsRecyclerView = viewBinding.statsSensorsRecyclerView;
|
RecyclerView recyclerView = viewBinding.statsRecyclerView;
|
||||||
sensorsRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2));
|
recyclerView.addItemDecoration(new DividerItemDecoration(getContext(), RecyclerView.VERTICAL));
|
||||||
sensorsRecyclerView.setAdapter(sensorsAdapter);
|
final int numColumns = PreferencesUtils.getLayoutColumns(sharedPreferences, getContext());
|
||||||
|
gridLayoutManager = new GridLayoutManager(getContext(), numColumns);
|
||||||
|
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||||
|
@Override
|
||||||
|
public int getSpanSize(int position) {
|
||||||
|
if (statisticsAdapter.isItemWide(position)) {
|
||||||
|
return numColumns;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
recyclerView.setLayoutManager(gridLayoutManager);
|
||||||
|
recyclerView.setAdapter(statisticsAdapter);
|
||||||
|
|
||||||
return viewBinding.getRoot();
|
return viewBinding.getRoot();
|
||||||
}
|
}
|
||||||
@@ -131,13 +133,16 @@ public class StatisticsRecordingFragment extends Fragment {
|
|||||||
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
sharedPreferenceChangeListener.onSharedPreferenceChanged(sharedPreferences, null);
|
||||||
|
|
||||||
|
viewModel = new ViewModelProvider(getActivity()).get(StatisticsDataModel.class);
|
||||||
|
statisticsLiveData = viewModel.getStatsData();
|
||||||
|
statisticsLiveData.observe(getActivity(), statsDataList -> statisticsAdapter.swapData(statsDataList));
|
||||||
|
|
||||||
trackRecordingServiceConnection.startConnection(getContext());
|
trackRecordingServiceConnection.startConnection(getContext());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onPause() {
|
public void onPause() {
|
||||||
super.onPause();
|
super.onPause();
|
||||||
|
|
||||||
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
sharedPreferences.unregisterOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,160 +163,16 @@ public class StatisticsRecordingFragment extends Fragment {
|
|||||||
super.onDestroy();
|
super.onDestroy();
|
||||||
trackRecordingServiceConnection = null;
|
trackRecordingServiceConnection = null;
|
||||||
sharedPreferences = null;
|
sharedPreferences = null;
|
||||||
|
viewModel = null;
|
||||||
|
statisticsLiveData.removeObservers(getActivity());
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateUI() {
|
private void updateUI() {
|
||||||
if (isResumed()) {
|
if (isResumed()) {
|
||||||
updateStats();
|
viewModel.update(recordingData, layout, preferenceMetricUnits);
|
||||||
setLocationValues();
|
|
||||||
updateSensorDataUI();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to fetch most recent {@link SensorDataSet} from {@link de.dennisguse.opentracks.services.TrackRecordingService}.
|
|
||||||
* Also sets altitude gain and loss.
|
|
||||||
*/
|
|
||||||
private void updateSensorDataUI() {
|
|
||||||
SensorDataSet sensorDataSet = recordingData.getSensorDataSet();
|
|
||||||
if (sensorDataSet != null) {
|
|
||||||
List<SensorDataModel> sensorDataList = new ArrayList<>();
|
|
||||||
if (sensorDataSet.getHeartRate() != null) {
|
|
||||||
sensorDataList.add(new SensorDataModel(sensorDataSet.getHeartRate()));
|
|
||||||
}
|
|
||||||
if (sensorDataSet.getCyclingCadence() != null) {
|
|
||||||
sensorDataList.add(new SensorDataModel(sensorDataSet.getCyclingCadence()));
|
|
||||||
}
|
|
||||||
if (sensorDataSet.getCyclingPower() != null) {
|
|
||||||
sensorDataList.add(new SensorDataModel(sensorDataSet.getCyclingPower()));
|
|
||||||
}
|
|
||||||
sensorsAdapter.swapData(sensorDataList);
|
|
||||||
}
|
|
||||||
|
|
||||||
{
|
|
||||||
Pair<String, String> parts = StringUtils.getAltitudeParts(getContext(), recordingData.getTrackStatistics().getTotalAltitudeGain(), preferenceMetricUnits);
|
|
||||||
viewBinding.statsAltitudeGainValue.setText(parts.first);
|
|
||||||
viewBinding.statsAltitudeGainUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
{
|
|
||||||
Pair<String, String> parts = StringUtils.getAltitudeParts(getContext(), recordingData.getTrackStatistics().getTotalAltitudeLoss(), preferenceMetricUnits);
|
|
||||||
viewBinding.statsAltitudeLossValue.setText(parts.first);
|
|
||||||
viewBinding.statsAltitudeLossUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateStats() {
|
|
||||||
// Set activity type
|
|
||||||
String trackIconValue = TrackIconUtils.getIconValue(getContext(), recordingData.getTrackCategory());
|
|
||||||
viewBinding.statsActivityTypeIcon.setImageResource(TrackIconUtils.getIconDrawable(trackIconValue));
|
|
||||||
|
|
||||||
// Set time
|
|
||||||
viewBinding.statsMovingTimeValue.setText(StringUtils.formatElapsedTime(recordingData.getTrackStatistics().getMovingTime()));
|
|
||||||
updateTotalTime();
|
|
||||||
|
|
||||||
// Set average speed/pace
|
|
||||||
{
|
|
||||||
Speed speed = recordingData.getTrackStatistics().getAverageSpeed();
|
|
||||||
viewBinding.statsAverageSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_speed : R.string.stats_average_pace);
|
|
||||||
|
|
||||||
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, preferenceMetricUnits, preferenceReportSpeed);
|
|
||||||
viewBinding.statsAverageSpeedValue.setText(parts.first);
|
|
||||||
viewBinding.statsAverageSpeedUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set max speed/pace
|
|
||||||
{
|
|
||||||
Speed speed = recordingData.getTrackStatistics().getMaxSpeed();
|
|
||||||
|
|
||||||
viewBinding.statsMaxSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_max_speed : R.string.stats_fastest_pace);
|
|
||||||
|
|
||||||
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, preferenceMetricUnits, preferenceReportSpeed);
|
|
||||||
viewBinding.statsMaxSpeedValue.setText(parts.first);
|
|
||||||
viewBinding.statsMaxSpeedUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set moving speed/pace
|
|
||||||
{
|
|
||||||
Speed speed = recordingData.getTrackStatistics().getAverageMovingSpeed();
|
|
||||||
|
|
||||||
viewBinding.statsMovingSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_average_moving_speed : R.string.stats_average_moving_pace);
|
|
||||||
|
|
||||||
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, preferenceMetricUnits, preferenceReportSpeed);
|
|
||||||
viewBinding.statsMovingSpeedValue.setText(parts.first);
|
|
||||||
viewBinding.statsMovingSpeedUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set altitude gain and loss
|
|
||||||
viewBinding.statsAltitudeGroup.setVisibility(preferenceShowAltitude ? View.VISIBLE : View.GONE);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void updateTotalTime() {
|
|
||||||
Duration totalTime = recordingData.getTrackStatistics().getTotalTime();
|
|
||||||
viewBinding.statsTotalTimeValue.setText(StringUtils.formatElapsedTime(totalTime));
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setLocationValues() {
|
|
||||||
// Set speed/pace
|
|
||||||
Speed speed = latestTrackPoint != null && latestTrackPoint.hasSpeed() ? latestTrackPoint.getSpeed() : null;
|
|
||||||
|
|
||||||
SensorDataSet sensorDataSet = recordingData.getSensorDataSet();
|
|
||||||
if (sensorDataSet != null && sensorDataSet.getCyclingDistanceSpeed() != null) {
|
|
||||||
SensorDataCycling.DistanceSpeed data = sensorDataSet.getCyclingDistanceSpeed();
|
|
||||||
if (data.hasValue() && data.isRecent()) {
|
|
||||||
speed = data.getValue().getSpeed();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
setSpeed(speed);
|
|
||||||
|
|
||||||
// Set distance
|
|
||||||
{
|
|
||||||
Pair<String, String> parts = StringUtils.getDistanceParts(getContext(), recordingData.getTrackStatistics().getTotalDistance(), preferenceMetricUnits);
|
|
||||||
|
|
||||||
viewBinding.statsDistanceValue.setText(parts.first);
|
|
||||||
viewBinding.statsDistanceUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
// Set altitude
|
|
||||||
viewBinding.statsAltitudeGroup.setVisibility(preferenceShowAltitude ? View.VISIBLE : View.GONE);
|
|
||||||
|
|
||||||
if (preferenceShowAltitude) {
|
|
||||||
// Current altitude
|
|
||||||
Float altitude = null;
|
|
||||||
int labelId = R.string.value_unknown;
|
|
||||||
if (latestTrackPoint != null && latestTrackPoint.hasAltitude()) {
|
|
||||||
altitude = (float) latestTrackPoint.getAltitude().toM();
|
|
||||||
labelId = latestTrackPoint.getAltitude().getLabelId();
|
|
||||||
}
|
|
||||||
|
|
||||||
Pair<String, String> parts = StringUtils.getAltitudeParts(getContext(), altitude, preferenceMetricUnits);
|
|
||||||
viewBinding.statsAltitudeCurrentValue.setText(parts.first);
|
|
||||||
viewBinding.statsAltitudeCurrentUnit.setText(parts.second);
|
|
||||||
|
|
||||||
viewBinding.statsAltitudeCurrentLabelEgm.setText(labelId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Set coordinate
|
|
||||||
viewBinding.statsCoordinateGroup.setVisibility(preferenceShowCoordinate ? View.VISIBLE : View.GONE);
|
|
||||||
if (preferenceShowCoordinate) {
|
|
||||||
String latitudeText = getContext().getString(R.string.value_unknown);
|
|
||||||
String longitudeText = getContext().getString(R.string.value_unknown);
|
|
||||||
if (latestTrackPoint != null && latestTrackPoint.hasLocation()) {
|
|
||||||
latitudeText = StringUtils.formatCoordinate(latestTrackPoint.getLatitude());
|
|
||||||
longitudeText = StringUtils.formatCoordinate(latestTrackPoint.getLongitude());
|
|
||||||
}
|
|
||||||
viewBinding.statsLatitudeValue.setText(latitudeText);
|
|
||||||
viewBinding.statsLongitudeValue.setText(longitudeText);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void setSpeed(Speed speed) {
|
|
||||||
viewBinding.statsSpeedLabel.setText(preferenceReportSpeed ? R.string.stats_speed : R.string.stats_pace);
|
|
||||||
|
|
||||||
Pair<String, String> parts = StringUtils.getSpeedParts(getContext(), speed, preferenceMetricUnits, preferenceReportSpeed);
|
|
||||||
viewBinding.statsSpeedValue.setText(parts.first);
|
|
||||||
viewBinding.statsSpeedUnit.setText(parts.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void onRecordingDataChanged(TrackRecordingService.RecordingData recordingData) {
|
private void onRecordingDataChanged(TrackRecordingService.RecordingData recordingData) {
|
||||||
String oldCategory = this.recordingData.getTrackCategory();
|
String oldCategory = this.recordingData.getTrackCategory();
|
||||||
String newCategory = recordingData.getTrackCategory();
|
String newCategory = recordingData.getTrackCategory();
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package de.dennisguse.opentracks.settings;
|
|||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.os.Bundle;
|
import android.os.Bundle;
|
||||||
import android.util.AttributeSet;
|
import android.util.AttributeSet;
|
||||||
|
import android.util.Log;
|
||||||
import android.widget.Toast;
|
import android.widget.Toast;
|
||||||
|
|
||||||
import androidx.fragment.app.FragmentActivity;
|
import androidx.fragment.app.FragmentActivity;
|
||||||
@@ -35,15 +36,23 @@ public class ResetDialogPreference extends DialogPreference {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDialogClosed(boolean positiveResult) {
|
public void onDialogClosed(boolean positiveResult) {
|
||||||
if (positiveResult) {
|
if (!positiveResult) {
|
||||||
FragmentActivity activity = getActivity();
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
FragmentActivity activity = getActivity();
|
||||||
|
|
||||||
|
String preferenceKey = getArguments().getString(PreferenceDialogFragmentCompat.ARG_KEY);
|
||||||
|
if (preferenceKey.equals(getString(R.string.settings_reset_key))) {
|
||||||
PreferencesUtils.resetPreferences(activity, true);
|
PreferencesUtils.resetPreferences(activity, true);
|
||||||
Toast.makeText(activity, R.string.settings_reset_done, Toast.LENGTH_SHORT).show();
|
Toast.makeText(activity, R.string.settings_reset_done, Toast.LENGTH_SHORT).show();
|
||||||
|
} else if (preferenceKey.equals(getString(R.string.settings_layout_reset_key))) {
|
||||||
|
PreferencesUtils.resetCustomLayoutPreferences(activity);
|
||||||
|
Toast.makeText(activity, R.string.settings_layout_reset_done, Toast.LENGTH_SHORT).show();
|
||||||
|
}
|
||||||
|
|
||||||
if (activity instanceof ResetCallback) {
|
if (activity instanceof ResetCallback) {
|
||||||
((ResetCallback) activity).onReset();
|
((ResetCallback) activity).onReset();
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -208,6 +208,13 @@ public class SettingsActivity extends AbstractActivity implements ChooseActivity
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
Preference customLayoutPreference = findPreference(getString(R.string.stats_custom_layout_key));
|
||||||
|
customLayoutPreference.setOnPreferenceClickListener((preference) -> {
|
||||||
|
Intent intent = new Intent(getContext(), SettingsCustomLayoutActivity.class);
|
||||||
|
startActivity(intent);
|
||||||
|
return true;
|
||||||
|
});
|
||||||
|
|
||||||
announcementsFrequency = findPreference(getString(R.string.voice_frequency_key));
|
announcementsFrequency = findPreference(getString(R.string.voice_frequency_key));
|
||||||
announcementsSpeed = findPreference(getString(R.string.voice_speed_rate_key));
|
announcementsSpeed = findPreference(getString(R.string.voice_speed_rate_key));
|
||||||
updateVoiceAnnouncements();
|
updateVoiceAnnouncements();
|
||||||
|
|||||||
@@ -0,0 +1,170 @@
|
|||||||
|
package de.dennisguse.opentracks.settings;
|
||||||
|
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
import android.os.Bundle;
|
||||||
|
import android.view.View;
|
||||||
|
import android.widget.AdapterView;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.ScrollView;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.appcompat.app.AlertDialog;
|
||||||
|
import androidx.appcompat.widget.Toolbar;
|
||||||
|
import androidx.recyclerview.widget.GridLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.ItemTouchHelper;
|
||||||
|
import androidx.recyclerview.widget.LinearLayoutManager;
|
||||||
|
import androidx.recyclerview.widget.RecyclerView;
|
||||||
|
|
||||||
|
import java.util.stream.IntStream;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.AbstractActivity;
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.adapters.SettingsCustomLayoutAdapter;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
import de.dennisguse.opentracks.databinding.ActivitySettingsCustomLayoutBinding;
|
||||||
|
import de.dennisguse.opentracks.util.PreferencesUtils;
|
||||||
|
import de.dennisguse.opentracks.util.StatisticsUtils;
|
||||||
|
|
||||||
|
public class SettingsCustomLayoutActivity extends AbstractActivity implements SettingsCustomLayoutAdapter.SettingsCustomLayoutItemClickListener {
|
||||||
|
|
||||||
|
private ActivitySettingsCustomLayoutBinding viewBinding;
|
||||||
|
private GridLayoutManager gridLayoutManager;
|
||||||
|
private SettingsCustomLayoutAdapter adapterFieldsVisible;
|
||||||
|
private SettingsCustomLayoutAdapter adapterFieldsHidden;
|
||||||
|
private Layout layoutFieldsVisible;
|
||||||
|
private Layout layoutFieldsHidden;
|
||||||
|
private SharedPreferences sharedPreferences;
|
||||||
|
private int numColumns;
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onCreate(Bundle savedInstanceState) {
|
||||||
|
super.onCreate(savedInstanceState);
|
||||||
|
|
||||||
|
sharedPreferences = PreferencesUtils.getSharedPreferences(this);
|
||||||
|
|
||||||
|
// Recycler view with visible stats.
|
||||||
|
layoutFieldsVisible = StatisticsUtils.filterVisible(PreferencesUtils.getCustomLayout(sharedPreferences, this), true);
|
||||||
|
adapterFieldsVisible = new SettingsCustomLayoutAdapter(this, this, layoutFieldsVisible);
|
||||||
|
|
||||||
|
numColumns = PreferencesUtils.getLayoutColumns(sharedPreferences, this);
|
||||||
|
RecyclerView recyclerViewVisible = viewBinding.recyclerViewVisible;
|
||||||
|
gridLayoutManager = new GridLayoutManager(this, numColumns);
|
||||||
|
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
|
||||||
|
@Override
|
||||||
|
public int getSpanSize(int position) {
|
||||||
|
if (adapterFieldsVisible.isItemWide(position)) {
|
||||||
|
return numColumns;
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
recyclerViewVisible.setLayoutManager(gridLayoutManager);
|
||||||
|
recyclerViewVisible.setAdapter(adapterFieldsVisible);
|
||||||
|
|
||||||
|
ItemTouchHelper.SimpleCallback simpleCallback = new ItemTouchHelper.SimpleCallback(
|
||||||
|
ItemTouchHelper.UP | ItemTouchHelper.DOWN | ItemTouchHelper.START | ItemTouchHelper.END, 0) {
|
||||||
|
@Override
|
||||||
|
public boolean onMove(@NonNull RecyclerView recyclerView, @NonNull RecyclerView.ViewHolder viewHolder, @NonNull RecyclerView.ViewHolder target) {
|
||||||
|
int fromPosition = viewHolder.getAdapterPosition();
|
||||||
|
int toPosition = target.getAdapterPosition();
|
||||||
|
layoutFieldsVisible = adapterFieldsVisible.move(fromPosition, toPosition);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSwiped(@NonNull RecyclerView.ViewHolder viewHolder, int direction) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(simpleCallback);
|
||||||
|
itemTouchHelper.attachToRecyclerView(recyclerViewVisible);
|
||||||
|
|
||||||
|
// Spinner with items per row.
|
||||||
|
ArrayAdapter<Integer> spinnerAdapter = new ArrayAdapter<>(this,
|
||||||
|
android.R.layout.simple_spinner_dropdown_item,
|
||||||
|
IntStream.of(getResources().getIntArray(R.array.stats_custom_layout_fields_columns_per_row)).boxed().toArray(Integer[]::new));
|
||||||
|
viewBinding.spinnerOptions.setAdapter(spinnerAdapter);
|
||||||
|
viewBinding.spinnerOptions.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
numColumns = position + 1;
|
||||||
|
gridLayoutManager.setSpanCount(numColumns);
|
||||||
|
PreferencesUtils.setLayoutColumns(sharedPreferences, SettingsCustomLayoutActivity.this, position + 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> parent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
viewBinding.spinnerOptions.setSelection(PreferencesUtils.getLayoutColumns(sharedPreferences, SettingsCustomLayoutActivity.this) - 1);
|
||||||
|
|
||||||
|
// Recycler view with not visible stats.
|
||||||
|
layoutFieldsHidden = StatisticsUtils.filterVisible(PreferencesUtils.getCustomLayout(sharedPreferences, this), false);
|
||||||
|
adapterFieldsHidden = new SettingsCustomLayoutAdapter(this, this, layoutFieldsHidden);
|
||||||
|
RecyclerView recyclerViewNotVisible = viewBinding.recyclerViewNotVisible;
|
||||||
|
recyclerViewNotVisible.setLayoutManager(new LinearLayoutManager(this));
|
||||||
|
recyclerViewNotVisible.setAdapter(adapterFieldsHidden);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onPause() {
|
||||||
|
super.onPause();
|
||||||
|
if (!layoutFieldsVisible.getFields().isEmpty() || !layoutFieldsHidden.getFields().isEmpty()) {
|
||||||
|
Layout newLayout = new Layout(layoutFieldsVisible.getProfile());
|
||||||
|
newLayout.addFields(layoutFieldsVisible.getFields());
|
||||||
|
newLayout.addFields(layoutFieldsHidden.getFields());
|
||||||
|
PreferencesUtils.setCustomLayout(sharedPreferences, this, newLayout);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void onDestroy() {
|
||||||
|
super.onDestroy();
|
||||||
|
sharedPreferences = null;
|
||||||
|
layoutFieldsVisible = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected void setupActionBarBack(Toolbar toolbar) {
|
||||||
|
super.setupActionBarBack(toolbar);
|
||||||
|
toolbar.setTitle(R.string.menu_settings);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
protected View getRootView() {
|
||||||
|
viewBinding = ActivitySettingsCustomLayoutBinding.inflate(getLayoutInflater());
|
||||||
|
return viewBinding.getRoot();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onSettingsCustomLayoutItemClicked(@NonNull DataField field) {
|
||||||
|
if (field.isVisible()) {
|
||||||
|
new AlertDialog.Builder(this)
|
||||||
|
.setTitle(R.string.generic_choose_an_option)
|
||||||
|
.setItems(new String[]{getString(field.isPrimary() ? R.string.field_set_secondary : R.string.field_set_primary), getString(R.string.field_remove_from_layout)}, (dialog, which) -> {
|
||||||
|
if (which == 0) {
|
||||||
|
field.togglePrimary();
|
||||||
|
} else {
|
||||||
|
layoutFieldsVisible.removeField(field);
|
||||||
|
field.toggleVisibility();
|
||||||
|
layoutFieldsHidden.addField(field);
|
||||||
|
}
|
||||||
|
|
||||||
|
adapterFieldsVisible.swapValues(layoutFieldsVisible);
|
||||||
|
adapterFieldsHidden.swapValues(layoutFieldsHidden);
|
||||||
|
})
|
||||||
|
.create()
|
||||||
|
.show();
|
||||||
|
} else {
|
||||||
|
layoutFieldsHidden.removeField(field);
|
||||||
|
field.toggleVisibility();
|
||||||
|
layoutFieldsVisible.addField(field);
|
||||||
|
viewBinding.scrollView.fullScroll(ScrollView.FOCUS_UP);
|
||||||
|
|
||||||
|
adapterFieldsVisible.swapValues(layoutFieldsVisible);
|
||||||
|
adapterFieldsHidden.swapValues(layoutFieldsHidden);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
public final class CsvConstants {
|
||||||
|
private CsvConstants() {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
public static final String LINE_SEPARATOR = ";";
|
||||||
|
public static final String ITEM_SEPARATOR = ",";
|
||||||
|
}
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.content.SharedPreferences;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
|
||||||
|
public class PreferencesOpenHelper {
|
||||||
|
private final Context context;
|
||||||
|
private final SharedPreferences sharedPreferences;
|
||||||
|
|
||||||
|
private static final int PREFERENCES_VERSION = 1;
|
||||||
|
|
||||||
|
private PreferencesOpenHelper(Context context, SharedPreferences sharedPreferences) {
|
||||||
|
this.context = context;
|
||||||
|
this.sharedPreferences = sharedPreferences;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static PreferencesOpenHelper newInstance(Context context, SharedPreferences sharedPreferences) {
|
||||||
|
return new PreferencesOpenHelper(context, sharedPreferences);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void checkForUpgrade() {
|
||||||
|
int lastVersion = PreferencesUtils.getInt(sharedPreferences, context, R.string.prefs_last_version_key, 0);
|
||||||
|
if (PREFERENCES_VERSION > lastVersion) {
|
||||||
|
onUpgrade();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onUpgrade() {
|
||||||
|
PreferencesUtils.setInt(sharedPreferences, context, R.string.prefs_last_version_key, PREFERENCES_VERSION);
|
||||||
|
switch (PREFERENCES_VERSION) {
|
||||||
|
case 1:
|
||||||
|
upgradeFrom0to1();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void upgradeFrom0to1() {
|
||||||
|
PreferencesUtils.setString(sharedPreferences, context, R.string.stats_custom_layout_fields_key, PreferencesUtils.buildDefaultLayout(context));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -16,9 +16,11 @@
|
|||||||
|
|
||||||
package de.dennisguse.opentracks.util;
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import android.annotation.SuppressLint;
|
||||||
import android.content.Context;
|
import android.content.Context;
|
||||||
import android.content.SharedPreferences;
|
import android.content.SharedPreferences;
|
||||||
import android.content.SharedPreferences.Editor;
|
import android.content.SharedPreferences.Editor;
|
||||||
|
import android.content.res.TypedArray;
|
||||||
import android.net.Uri;
|
import android.net.Uri;
|
||||||
import android.util.Log;
|
import android.util.Log;
|
||||||
|
|
||||||
@@ -26,8 +28,16 @@ import androidx.annotation.VisibleForTesting;
|
|||||||
import androidx.documentfile.provider.DocumentFile;
|
import androidx.documentfile.provider.DocumentFile;
|
||||||
import androidx.preference.PreferenceManager;
|
import androidx.preference.PreferenceManager;
|
||||||
|
|
||||||
|
import java.lang.reflect.Field;
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.Arrays;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
import de.dennisguse.opentracks.content.data.Distance;
|
import de.dennisguse.opentracks.content.data.Distance;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
import de.dennisguse.opentracks.io.file.TrackFileFormat;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -44,7 +54,9 @@ public class PreferencesUtils {
|
|||||||
|
|
||||||
@Deprecated //Should only be used to get a sharedPreference for more than one interaction!
|
@Deprecated //Should only be used to get a sharedPreference for more than one interaction!
|
||||||
public static SharedPreferences getSharedPreferences(Context context) {
|
public static SharedPreferences getSharedPreferences(Context context) {
|
||||||
return PreferenceManager.getDefaultSharedPreferences(context);
|
SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(context);
|
||||||
|
PreferencesOpenHelper.newInstance(context, sharedPreferences).checkForUpgrade();
|
||||||
|
return sharedPreferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static String getDefaultActivity(SharedPreferences sharedPreferences, Context context) {
|
public static String getDefaultActivity(SharedPreferences sharedPreferences, Context context) {
|
||||||
@@ -80,7 +92,7 @@ public class PreferencesUtils {
|
|||||||
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
|
return sharedPreferences.getBoolean(getKey(context, keyId), defaultValue);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static int getInt(SharedPreferences sharedPreferences, Context context, int keyId, int defaultValue) {
|
static int getInt(SharedPreferences sharedPreferences, Context context, int keyId, int defaultValue) {
|
||||||
try {
|
try {
|
||||||
return sharedPreferences.getInt(getKey(context, keyId), defaultValue);
|
return sharedPreferences.getInt(getKey(context, keyId), defaultValue);
|
||||||
} catch (ClassCastException e) {
|
} catch (ClassCastException e) {
|
||||||
@@ -123,6 +135,12 @@ public class PreferencesUtils {
|
|||||||
editor.apply();
|
editor.apply();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void setInt(SharedPreferences sharedPreferences, Context context, int keyId, int value) {
|
||||||
|
Editor editor = sharedPreferences.edit();
|
||||||
|
editor.putInt(getKey(context, keyId), value);
|
||||||
|
editor.apply();
|
||||||
|
}
|
||||||
|
|
||||||
public static boolean isMetricUnits(SharedPreferences sharedPreferences, Context context) {
|
public static boolean isMetricUnits(SharedPreferences sharedPreferences, Context context) {
|
||||||
final String STATS_UNIT = context.getString(R.string.stats_units_default);
|
final String STATS_UNIT = context.getString(R.string.stats_units_default);
|
||||||
return STATS_UNIT.equals(getString(sharedPreferences, context, R.string.stats_units_key, STATS_UNIT));
|
return STATS_UNIT.equals(getString(sharedPreferences, context, R.string.stats_units_key, STATS_UNIT));
|
||||||
@@ -196,16 +214,6 @@ public class PreferencesUtils {
|
|||||||
return getBoolean(sharedPreferences, context, R.string.stats_fullscreen_while_recording_key, DEFAULT);
|
return getBoolean(sharedPreferences, context, R.string.stats_fullscreen_while_recording_key, DEFAULT);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static boolean isShowStatsAltitude(SharedPreferences sharedPreferences, Context context) {
|
|
||||||
final boolean STATS_SHOW_ALTITUDE = context.getResources().getBoolean(R.bool.stats_show_altitude_default);
|
|
||||||
return getBoolean(sharedPreferences, context, R.string.stats_show_grade_altitude_key, STATS_SHOW_ALTITUDE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static boolean isStatsShowCoordinate(SharedPreferences sharedPreferences, Context context) {
|
|
||||||
final boolean STATS_SHOW_COORDINATE = context.getResources().getBoolean(R.bool.stats_show_coordinate_default);
|
|
||||||
return getBoolean(sharedPreferences, context, R.string.stats_show_coordinate_key, STATS_SHOW_COORDINATE);
|
|
||||||
}
|
|
||||||
|
|
||||||
public static int getVoiceFrequency(SharedPreferences sharedPreferences, Context context) {
|
public static int getVoiceFrequency(SharedPreferences sharedPreferences, Context context) {
|
||||||
final int VOICE_FREQUENCY_DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default));
|
final int VOICE_FREQUENCY_DEFAULT = Integer.parseInt(context.getResources().getString(R.string.voice_frequency_default));
|
||||||
return getInt(sharedPreferences, context, R.string.voice_frequency_key, VOICE_FREQUENCY_DEFAULT);
|
return getInt(sharedPreferences, context, R.string.voice_frequency_key, VOICE_FREQUENCY_DEFAULT);
|
||||||
@@ -318,4 +326,78 @@ public class PreferencesUtils {
|
|||||||
public static boolean isDefaultExportDirectoryUri(SharedPreferences sharedPreferences, Context context) {
|
public static boolean isDefaultExportDirectoryUri(SharedPreferences sharedPreferences, Context context) {
|
||||||
return getDefaultExportDirectoryUri(sharedPreferences, context) != null;
|
return getDefaultExportDirectoryUri(sharedPreferences, context) != null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int getLayoutColumns(SharedPreferences sharedPreferences, Context context) {
|
||||||
|
return getInt(sharedPreferences, context, R.string.stats_custom_layout_columns_key, context.getResources().getInteger(R.integer.stats_custom_layout_columns_default));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setLayoutColumns(SharedPreferences sharedPreferences, Context context, int columns) {
|
||||||
|
setInt(sharedPreferences, context, R.string.stats_custom_layout_columns_key, columns);
|
||||||
|
}
|
||||||
|
|
||||||
|
private static List<TypedArray> getMultiTypedArray(Context context, String key) {
|
||||||
|
List<TypedArray> typedArrays = new ArrayList<>();
|
||||||
|
|
||||||
|
try {
|
||||||
|
Class<R.array> resource = R.array.class;
|
||||||
|
Field field;
|
||||||
|
int i = 0;
|
||||||
|
|
||||||
|
do {
|
||||||
|
field = resource.getField(key + context.getString(R.string.stats_custom_layout_fields_default_value_separator) + i);
|
||||||
|
typedArrays.add(context.getResources().obtainTypedArray(field.getInt(null)));
|
||||||
|
i++;
|
||||||
|
} while (field != null);
|
||||||
|
} catch (Exception e) {
|
||||||
|
e.printStackTrace();
|
||||||
|
Log.e(TAG, e.getMessage());
|
||||||
|
}
|
||||||
|
|
||||||
|
return typedArrays;
|
||||||
|
}
|
||||||
|
|
||||||
|
@SuppressLint("ResourceType")
|
||||||
|
static String buildDefaultLayout(Context context) {
|
||||||
|
List<TypedArray> fieldsArrays = getMultiTypedArray(context, "stats_custom_layout_fields_default_value");
|
||||||
|
return context.getString(R.string.default_activity_default) + CsvConstants.LINE_SEPARATOR
|
||||||
|
+ fieldsArrays.stream().map(i -> i.getString(0) + CsvConstants.ITEM_SEPARATOR + i.getString(1)).collect(Collectors.joining(CsvConstants.LINE_SEPARATOR))
|
||||||
|
+ CsvConstants.LINE_SEPARATOR;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Layout getCustomLayout(SharedPreferences sharedPreferences, Context context) {
|
||||||
|
String csvCustomLayout = getString(sharedPreferences, context, R.string.stats_custom_layout_fields_key, buildDefaultLayout(context));
|
||||||
|
List<String> csvParts = Arrays.asList(csvCustomLayout.split(CsvConstants.LINE_SEPARATOR));
|
||||||
|
Layout layout = new Layout(csvParts.get(0));
|
||||||
|
for (int i = 1; i < csvParts.size(); i++) {
|
||||||
|
String[] fieldParts = csvParts.get(i).split(CsvConstants.ITEM_SEPARATOR);
|
||||||
|
layout.addField(fieldParts[0], DataField.getTitleByKey(context, fieldParts[0]), fieldParts[1].equals(DataField.YES_VALUE), fieldParts[2].equals(DataField.YES_VALUE), fieldParts[0].equals(context.getString(R.string.stats_custom_layout_coordinates_key)));
|
||||||
|
}
|
||||||
|
|
||||||
|
return layout;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void setCustomLayout(SharedPreferences sharedPreferences, Context context, Layout layout) {
|
||||||
|
List<DataField> fields = layout.getFields();
|
||||||
|
if (fields.isEmpty()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
String csv = layout.getProfile() + CsvConstants.LINE_SEPARATOR
|
||||||
|
+ fields.stream().map(DataField::toCsv).collect(Collectors.joining(CsvConstants.LINE_SEPARATOR)) + CsvConstants.LINE_SEPARATOR;
|
||||||
|
setString(sharedPreferences, context, R.string.stats_custom_layout_fields_key, csv);
|
||||||
|
}
|
||||||
|
|
||||||
|
public static void resetCustomLayoutPreferences(Context context) {
|
||||||
|
SharedPreferences settings = getSharedPreferences(context);
|
||||||
|
if (settings.contains(context.getString(R.string.stats_custom_layout_fields_key))) {
|
||||||
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.remove(context.getString(R.string.stats_custom_layout_fields_key));
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
if (settings.contains(context.getString(R.string.stats_custom_layout_columns_key))) {
|
||||||
|
SharedPreferences.Editor editor = settings.edit();
|
||||||
|
editor.remove(context.getString(R.string.stats_custom_layout_columns_key));
|
||||||
|
editor.commit();
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,31 @@
|
|||||||
|
package de.dennisguse.opentracks.util;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
|
||||||
|
public class StatisticsUtils {
|
||||||
|
|
||||||
|
public static String emptyValue(@NonNull Context context, @NonNull String statTitle) {
|
||||||
|
if (PreferencesUtils.isKey(context, R.string.stats_custom_layout_total_time_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_moving_time_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_pace_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_average_moving_pace_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_average_pace_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_fastest_pace_key, statTitle)) {
|
||||||
|
return context.getString(R.string.stats_empty_value_time);
|
||||||
|
} else if (PreferencesUtils.isKey(context, R.string.stats_custom_layout_distance_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_speed_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_average_speed_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_max_speed_key, statTitle) || PreferencesUtils.isKey(context, R.string.stats_custom_layout_average_moving_speed_key, statTitle)) {
|
||||||
|
return context.getString(R.string.stats_empty_value_float);
|
||||||
|
} else if (PreferencesUtils.isKey(context, R.string.stats_custom_layout_coordinates_key, statTitle)) {
|
||||||
|
return context.getString(R.string.stats_empty_value_coordinates);
|
||||||
|
} else {
|
||||||
|
return context.getString(R.string.stats_empty_value_integer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Layout filterVisible(Layout layout, boolean visible) {
|
||||||
|
Layout result = new Layout(layout.getProfile());
|
||||||
|
result.addFields(layout.getFields().stream().filter(f -> f.isVisible() == visible).collect(Collectors.toList()));
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -124,10 +124,22 @@ public class StringUtils {
|
|||||||
/**
|
/**
|
||||||
* Formats a coordinate
|
* Formats a coordinate
|
||||||
*
|
*
|
||||||
|
* @param context the context's object.
|
||||||
* @param coordinate the coordinate
|
* @param coordinate the coordinate
|
||||||
*/
|
*/
|
||||||
public static String formatCoordinate(double coordinate) {
|
public static String formatCoordinate(Context context, double coordinate) {
|
||||||
return Location.convert(coordinate, Location.FORMAT_DEGREES) + COORDINATE_DEGREE;
|
return context.getString(R.string.location_coordinate, Location.convert(coordinate, Location.FORMAT_DEGREES));
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Formats a complete coordinate (latitude, longitude)
|
||||||
|
*
|
||||||
|
* @param context the context's object.
|
||||||
|
* @param latitude the coordinate's latitude.
|
||||||
|
* @param longitude the coordinate's longitude.
|
||||||
|
*/
|
||||||
|
public static String formatCoordinate(Context context, double latitude, double longitude) {
|
||||||
|
return context.getString(R.string.location_latitude_longitude, Location.convert(latitude, Location.FORMAT_DEGREES), Location.convert(longitude, Location.FORMAT_DEGREES));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -191,6 +203,33 @@ public class StringUtils {
|
|||||||
return new Pair<>(context.getString(R.string.time, minutes, seconds), unitString);
|
return new Pair<>(context.getString(R.string.time, minutes, seconds), unitString);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static Pair<String, String> getHeartRateParts(Context context, Float heartrate_bpm) {
|
||||||
|
String value = context.getString(R.string.value_none);
|
||||||
|
if (heartrate_bpm != null) {
|
||||||
|
value = StringUtils.formatDecimal(heartrate_bpm, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(value, context.getString(R.string.sensor_unit_beats_per_minute));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pair<String, String> getCadenceParts(Context context, Float cadence_rpm) {
|
||||||
|
String value = context.getString(R.string.value_none);
|
||||||
|
if (cadence_rpm != null) {
|
||||||
|
value = StringUtils.formatDecimal(cadence_rpm, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(value, context.getString(R.string.sensor_unit_rounds_per_minute));
|
||||||
|
}
|
||||||
|
|
||||||
|
public static Pair<String, String> getPowerParts(Context context, Float power_w) {
|
||||||
|
String value = context.getString(R.string.value_none);
|
||||||
|
if (power_w != null) {
|
||||||
|
value = StringUtils.formatDecimal(power_w, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
return new Pair<>(value, context.getString(R.string.sensor_unit_power));
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Gets a string for category.
|
* Gets a string for category.
|
||||||
*
|
*
|
||||||
|
|||||||
@@ -1,56 +0,0 @@
|
|||||||
package de.dennisguse.opentracks.viewmodels;
|
|
||||||
|
|
||||||
import de.dennisguse.opentracks.R;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorData;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCycling;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataCyclingPower;
|
|
||||||
import de.dennisguse.opentracks.content.sensor.SensorDataHeartRate;
|
|
||||||
import de.dennisguse.opentracks.util.StringUtils;
|
|
||||||
|
|
||||||
public class SensorDataModel {
|
|
||||||
private int labelId;
|
|
||||||
private final String sensorValue;
|
|
||||||
private String sensorName;
|
|
||||||
private int unitId;
|
|
||||||
|
|
||||||
public SensorDataModel(int labelId, int unitId, float sensorValue) {
|
|
||||||
this.labelId = labelId;
|
|
||||||
this.unitId = unitId;
|
|
||||||
this.sensorValue = StringUtils.formatDecimal(sensorValue, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public SensorDataModel(SensorData<Float> sensorData) {
|
|
||||||
this.sensorName = sensorData.getSensorNameOrAddress();
|
|
||||||
this.sensorValue = sensorData.hasValue() && sensorData.isRecent() ? StringUtils.formatDecimal(sensorData.getValue(), 0) : null;
|
|
||||||
if (sensorData instanceof SensorDataHeartRate) {
|
|
||||||
this.labelId = R.string.sensor_state_heart_rate;
|
|
||||||
this.unitId = R.string.sensor_unit_beats_per_minute;
|
|
||||||
} else if (sensorData instanceof SensorDataCycling.Cadence) {
|
|
||||||
this.labelId = R.string.sensor_state_cadence;
|
|
||||||
this.unitId = R.string.sensor_unit_rounds_per_minute;
|
|
||||||
} else if (sensorData instanceof SensorDataCyclingPower) {
|
|
||||||
this.labelId = R.string.sensor_state_power;
|
|
||||||
this.unitId = R.string.sensor_unit_power;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getLabelId() {
|
|
||||||
return labelId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public int getUnitId() {
|
|
||||||
return unitId;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSensorName() {
|
|
||||||
return sensorName;
|
|
||||||
}
|
|
||||||
|
|
||||||
public String getSensorValue() {
|
|
||||||
return sensorValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
public boolean hasValue() {
|
|
||||||
return sensorValue != null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
package de.dennisguse.opentracks.viewmodels;
|
||||||
|
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
|
||||||
|
public class StatisticData {
|
||||||
|
private final DataField dataField;
|
||||||
|
private final String value;
|
||||||
|
private final String unit;
|
||||||
|
private final String description;
|
||||||
|
|
||||||
|
public StatisticData(@NonNull DataField dataField, @NonNull Pair<String, String> valueAndUnit, String description) {
|
||||||
|
this.dataField = dataField;
|
||||||
|
this.value = valueAndUnit.first;
|
||||||
|
this.unit = valueAndUnit.second;
|
||||||
|
this.description = description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public DataField getField() {
|
||||||
|
return dataField;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getValue() {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasValue() {
|
||||||
|
return value != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getUnit() {
|
||||||
|
return unit;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDescription() {
|
||||||
|
return description;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean hasDescription() {
|
||||||
|
return description != null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,205 @@
|
|||||||
|
package de.dennisguse.opentracks.viewmodels;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
|
import android.util.Pair;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
|
||||||
|
import java.util.ArrayList;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Objects;
|
||||||
|
import java.util.stream.Collectors;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.R;
|
||||||
|
import de.dennisguse.opentracks.content.data.DataField;
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
import de.dennisguse.opentracks.content.data.Speed;
|
||||||
|
import de.dennisguse.opentracks.content.data.TrackPoint;
|
||||||
|
import de.dennisguse.opentracks.content.sensor.SensorDataSet;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
import de.dennisguse.opentracks.stats.SensorStatistics;
|
||||||
|
import de.dennisguse.opentracks.util.StringUtils;
|
||||||
|
|
||||||
|
public class StatisticDataBuilder {
|
||||||
|
|
||||||
|
public static List<StatisticData> fromRecordingData(@NonNull Context context, @NonNull TrackRecordingService.RecordingData recordingData, @NonNull Layout layout, boolean metricUnits) {
|
||||||
|
List<StatisticData> statisticDataList = layout.getFields().stream()
|
||||||
|
.filter(DataField::isVisible)
|
||||||
|
.map(field -> build(context, recordingData, field.getKey(), field.isPrimary(), metricUnits))
|
||||||
|
.filter(Objects::nonNull)
|
||||||
|
.collect(Collectors.toList());
|
||||||
|
statisticDataList.addAll(getSensorStatsDataIfNeeded(context, recordingData, statisticDataList, metricUnits));
|
||||||
|
return statisticDataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
private static StatisticData build(@NonNull Context context, @NonNull TrackRecordingService.RecordingData recordingData, @NonNull String fieldKey, boolean isPrimary, boolean metricUnits) {
|
||||||
|
final TrackPoint latestTrackPoint = recordingData.getLatestTrackPoint();
|
||||||
|
final SensorDataSet sensorDataSet = recordingData.getSensorDataSet();
|
||||||
|
|
||||||
|
String title = null;
|
||||||
|
String description = null;
|
||||||
|
Pair<String, String> valueAndUnit = null;
|
||||||
|
boolean isWide = false;
|
||||||
|
if (fieldKey.equals(context.getString(R.string.stats_custom_layout_total_time_key))) {
|
||||||
|
valueAndUnit = new Pair<>(StringUtils.formatElapsedTime(recordingData.getTrackStatistics().getTotalTime()), null);
|
||||||
|
title = context.getString(R.string.stats_total_time);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_moving_time_key))) {
|
||||||
|
valueAndUnit = new Pair<>(StringUtils.formatElapsedTime(recordingData.getTrackStatistics().getMovingTime()), null);
|
||||||
|
title = context.getString(R.string.stats_moving_time);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_distance_key))) {
|
||||||
|
valueAndUnit = StringUtils.getDistanceParts(context, recordingData.getTrackStatistics().getTotalDistance(), metricUnits);
|
||||||
|
title = context.getString(R.string.stats_distance);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_speed_key)) || fieldKey.equals(context.getString(R.string.stats_custom_layout_pace_key))) {
|
||||||
|
boolean reportSpeed = fieldKey.equals("speed");
|
||||||
|
title = fieldKey.equals("speed") ? context.getString(R.string.stats_speed) : context.getString(R.string.stats_pace);
|
||||||
|
Speed speed = latestTrackPoint != null && latestTrackPoint.hasSpeed() ? latestTrackPoint.getSpeed() : null;
|
||||||
|
if (sensorDataSet != null && sensorDataSet.getCyclingDistanceSpeed() != null && sensorDataSet.getCyclingDistanceSpeed().hasValue() && sensorDataSet.getCyclingDistanceSpeed().isRecent()) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, sensorDataSet.getCyclingDistanceSpeed().getValue().getSpeed(), metricUnits, reportSpeed);
|
||||||
|
description = context.getString(R.string.description_speed_source_sensor, sensorDataSet.getCyclingDistanceSpeed().getSensorNameOrAddress());
|
||||||
|
} else {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, speed, metricUnits, reportSpeed);
|
||||||
|
description = context.getString(R.string.description_speed_source_gps);
|
||||||
|
}
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_average_moving_speed_key))) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, recordingData.getTrackStatistics().getAverageMovingSpeed(), metricUnits, true);
|
||||||
|
title = context.getString(R.string.stats_average_moving_speed);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_average_speed_key))) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, recordingData.getTrackStatistics().getAverageSpeed(), metricUnits, true);
|
||||||
|
title = context.getString(R.string.stats_average_speed);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_max_speed_key))) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, recordingData.getTrackStatistics().getMaxSpeed(), metricUnits, true);
|
||||||
|
title = context.getString(R.string.stats_max_speed);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_average_moving_pace_key))) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, recordingData.getTrackStatistics().getAverageMovingSpeed(), metricUnits, false);
|
||||||
|
title = context.getString(R.string.stats_average_moving_pace);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_average_pace_key))) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, recordingData.getTrackStatistics().getAverageSpeed(), metricUnits, false);
|
||||||
|
title = context.getString(R.string.stats_average_pace);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_fastest_pace_key))) {
|
||||||
|
valueAndUnit = StringUtils.getSpeedParts(context, recordingData.getTrackStatistics().getMaxSpeed(), metricUnits, true);
|
||||||
|
title = context.getString(R.string.stats_fastest_pace);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_altitude_key))) {
|
||||||
|
Float altitude = latestTrackPoint != null && latestTrackPoint.hasAltitude() ? (float) latestTrackPoint.getAltitude().toM() : null;
|
||||||
|
title = context.getString(R.string.stats_altitude);
|
||||||
|
description = latestTrackPoint != null && latestTrackPoint.hasAltitude() ? context.getString(latestTrackPoint.getAltitude().getLabelId()) : null;
|
||||||
|
valueAndUnit = StringUtils.getAltitudeParts(context, altitude, metricUnits);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_gain_key))) {
|
||||||
|
valueAndUnit = StringUtils.getAltitudeParts(context, recordingData.getTrackStatistics().getTotalAltitudeGain(), metricUnits);
|
||||||
|
title = context.getString(R.string.stats_gain);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_loss_key))) {
|
||||||
|
valueAndUnit = StringUtils.getAltitudeParts(context, recordingData.getTrackStatistics().getTotalAltitudeLoss(), metricUnits);
|
||||||
|
title = context.getString(R.string.stats_loss);
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_coordinates_key))) {
|
||||||
|
title = context.getString(R.string.stats_coordinates);
|
||||||
|
isWide = true;
|
||||||
|
if (latestTrackPoint != null && latestTrackPoint.hasLocation()) {
|
||||||
|
valueAndUnit = new Pair<>(StringUtils.formatCoordinate(context, latestTrackPoint.getLatitude(), latestTrackPoint.getLongitude()), null);
|
||||||
|
} else {
|
||||||
|
valueAndUnit = new Pair<>(context.getString(R.string.value_none), null);
|
||||||
|
}
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_heart_rate_key))) {
|
||||||
|
title = context.getString(R.string.stats_sensors_heart_rate);
|
||||||
|
if (sensorDataSet != null && sensorDataSet.getHeartRate() != null && sensorDataSet.getHeartRate().hasValue() && sensorDataSet.getHeartRate().isRecent()) {
|
||||||
|
valueAndUnit = StringUtils.getHeartRateParts(context, sensorDataSet.getHeartRate().getValue());
|
||||||
|
description = sensorDataSet.getHeartRate().getSensorNameOrAddress();
|
||||||
|
} else {
|
||||||
|
valueAndUnit = StringUtils.getHeartRateParts(context, null);
|
||||||
|
description = context.getString(R.string.value_none);
|
||||||
|
}
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_cadence_key))) {
|
||||||
|
title = context.getString(R.string.stats_sensors_cadence);
|
||||||
|
if (sensorDataSet != null && sensorDataSet.getCyclingCadence() != null && sensorDataSet.getCyclingCadence().hasValue() && sensorDataSet.getCyclingCadence().isRecent()) {
|
||||||
|
valueAndUnit = StringUtils.getCadenceParts(context, sensorDataSet.getCyclingCadence().getValue());
|
||||||
|
description = sensorDataSet.getCyclingCadence().getSensorNameOrAddress();
|
||||||
|
} else {
|
||||||
|
valueAndUnit = StringUtils.getCadenceParts(context, null);
|
||||||
|
description = context.getString(R.string.value_none);
|
||||||
|
}
|
||||||
|
} else if (fieldKey.equals(context.getString(R.string.stats_custom_layout_power_key))) {
|
||||||
|
title = context.getString(R.string.stats_sensors_power);
|
||||||
|
if (sensorDataSet != null && sensorDataSet.getCyclingPower() != null && sensorDataSet.getCyclingPower().hasValue() && sensorDataSet.getCyclingPower().isRecent()) {
|
||||||
|
valueAndUnit = StringUtils.getPowerParts(context, sensorDataSet.getCyclingPower().getValue());
|
||||||
|
description = sensorDataSet.getCyclingPower().getSensorNameOrAddress();
|
||||||
|
} else {
|
||||||
|
valueAndUnit = StringUtils.getPowerParts(context, null);
|
||||||
|
description = context.getString(R.string.value_none);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (valueAndUnit == null) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
return new StatisticData(new DataField(fieldKey, title, true, isPrimary, isWide), valueAndUnit, description);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Builds a list of StatisticData with sensors connected but not in statisticDataList.
|
||||||
|
*/
|
||||||
|
private static List<StatisticData> getSensorStatsDataIfNeeded(Context context, TrackRecordingService.RecordingData recordingData, List<StatisticData> statisticDataList, boolean metricUnits) {
|
||||||
|
List<StatisticData> sensorDataList = new ArrayList<>();
|
||||||
|
SensorDataSet sensorDataSet = recordingData.getSensorDataSet();
|
||||||
|
if (sensorDataSet == null) {
|
||||||
|
return sensorDataList;
|
||||||
|
}
|
||||||
|
if (statisticDataList.stream().noneMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_heart_rate))) && sensorDataSet.getHeartRate() != null && sensorDataSet.getHeartRate().hasValue() && sensorDataSet.getHeartRate().isRecent()) {
|
||||||
|
sensorDataList.add(build(context, recordingData, "heart_rate", true, metricUnits));
|
||||||
|
}
|
||||||
|
if (statisticDataList.stream().noneMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_cadence))) && sensorDataSet.getCyclingCadence() != null && sensorDataSet.getCyclingCadence().hasValue() && sensorDataSet.getCyclingCadence().isRecent()) {
|
||||||
|
sensorDataList.add(build(context, recordingData, "cadence", true, metricUnits));
|
||||||
|
}
|
||||||
|
if (statisticDataList.stream().noneMatch(i -> i.getField().getTitle().equals(context.getString(R.string.stats_sensors_power))) && sensorDataSet.getCyclingPower() != null && sensorDataSet.getCyclingPower().hasValue() && sensorDataSet.getCyclingPower().isRecent()) {
|
||||||
|
sensorDataList.add(build(context, recordingData, "power", true, metricUnits));
|
||||||
|
}
|
||||||
|
|
||||||
|
return sensorDataList;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static List<StatisticData> fromSensorStatistics(@NonNull Context context, @NonNull SensorStatistics sensorStatistics) {
|
||||||
|
List<StatisticData> sensorDataList = new ArrayList<>();
|
||||||
|
|
||||||
|
if (sensorStatistics.hasHeartRate()) {
|
||||||
|
sensorDataList.add(
|
||||||
|
new StatisticData(
|
||||||
|
new DataField(context.getString(R.string.stats_custom_layout_heart_rate_key), context.getString(R.string.sensor_state_heart_rate_max), true, true, false),
|
||||||
|
StringUtils.getHeartRateParts(context, sensorStatistics.getMaxHeartRate()),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sensorDataList.add(
|
||||||
|
new StatisticData(
|
||||||
|
new DataField(context.getString(R.string.stats_custom_layout_average_heart_rate_key), context.getString(R.string.sensor_state_heart_rate_avg), true, true, false),
|
||||||
|
StringUtils.getHeartRateParts(context, sensorStatistics.getAvgHeartRate()),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (sensorStatistics.hasCadence()) {
|
||||||
|
sensorDataList.add(
|
||||||
|
new StatisticData(
|
||||||
|
new DataField(context.getString(R.string.stats_custom_layout_cadence_key), context.getString(R.string.sensor_state_cadence_max), true, true, false),
|
||||||
|
StringUtils.getCadenceParts(context, sensorStatistics.getMaxCadence()),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
sensorDataList.add(
|
||||||
|
new StatisticData(
|
||||||
|
new DataField(context.getString(R.string.stats_custom_layout_average_cadence_key), context.getString(R.string.sensor_state_cadence_avg), true, true, false),
|
||||||
|
StringUtils.getCadenceParts(context, sensorStatistics.getAvgCadence()),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (sensorStatistics.hasPower()) {
|
||||||
|
sensorDataList.add(
|
||||||
|
new StatisticData(
|
||||||
|
new DataField(context.getString(R.string.stats_custom_layout_power_key), context.getString(R.string.sensor_state_power_avg), true, true, false),
|
||||||
|
StringUtils.getPowerParts(context, sensorStatistics.getAvgPower()),
|
||||||
|
null
|
||||||
|
)
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
return sensorDataList;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
package de.dennisguse.opentracks.viewmodels;
|
||||||
|
|
||||||
|
import android.app.Application;
|
||||||
|
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import androidx.lifecycle.AndroidViewModel;
|
||||||
|
import androidx.lifecycle.MutableLiveData;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import de.dennisguse.opentracks.content.data.Layout;
|
||||||
|
import de.dennisguse.opentracks.services.TrackRecordingService;
|
||||||
|
|
||||||
|
public class StatisticsDataModel extends AndroidViewModel {
|
||||||
|
|
||||||
|
private MutableLiveData<List<StatisticData>> statsData;
|
||||||
|
|
||||||
|
public StatisticsDataModel(@NonNull Application application) {
|
||||||
|
super(application);
|
||||||
|
}
|
||||||
|
|
||||||
|
public MutableLiveData<List<StatisticData>> getStatsData() {
|
||||||
|
if (statsData == null) {
|
||||||
|
statsData = new MutableLiveData<>();
|
||||||
|
}
|
||||||
|
return statsData;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void update(TrackRecordingService.RecordingData recordingData, Layout layout, boolean metricUnit) {
|
||||||
|
new Thread(() -> {
|
||||||
|
List<StatisticData> statisticDataList = StatisticDataBuilder.fromRecordingData(getApplication(), recordingData, layout, metricUnit);
|
||||||
|
statsData.postValue(statisticDataList);
|
||||||
|
}).start();
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M11,18c0,1.1 -0.9,2 -2,2s-2,-0.9 -2,-2 0.9,-2 2,-2 2,0.9 2,2zM9,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM9,4c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,8c1.1,0 2,-0.9 2,-2s-0.9,-2 -2,-2 -2,0.9 -2,2 0.9,2 2,2zM15,10c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2zM15,16c-1.1,0 -2,0.9 -2,2s0.9,2 2,2 2,-0.9 2,-2 -0.9,-2 -2,-2z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,4.5C7,4.5 2.73,7.61 1,12c1.73,4.39 6,7.5 11,7.5s9.27,-3.11 11,-7.5c-1.73,-4.39 -6,-7.5 -11,-7.5zM12,17c-2.76,0 -5,-2.24 -5,-5s2.24,-5 5,-5 5,2.24 5,5 -2.24,5 -5,5zM12,9c-1.66,0 -3,1.34 -3,3s1.34,3 3,3 3,-1.34 3,-3 -1.34,-3 -3,-3z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:width="24dp"
|
||||||
|
android:height="24dp"
|
||||||
|
android:viewportWidth="24"
|
||||||
|
android:viewportHeight="24"
|
||||||
|
android:tint="?attr/colorControlNormal">
|
||||||
|
<path
|
||||||
|
android:fillColor="@android:color/white"
|
||||||
|
android:pathData="M12,7c2.76,0 5,2.24 5,5 0,0.65 -0.13,1.26 -0.36,1.83l2.92,2.92c1.51,-1.26 2.7,-2.89 3.43,-4.75 -1.73,-4.39 -6,-7.5 -11,-7.5 -1.4,0 -2.74,0.25 -3.98,0.7l2.16,2.16C10.74,7.13 11.35,7 12,7zM2,4.27l2.28,2.28 0.46,0.46C3.08,8.3 1.78,10.02 1,12c1.73,4.39 6,7.5 11,7.5 1.55,0 3.03,-0.3 4.38,-0.84l0.42,0.42L19.73,22 21,20.73 3.27,3 2,4.27zM7.53,9.8l1.55,1.55c-0.05,0.21 -0.08,0.43 -0.08,0.65 0,1.66 1.34,3 3,3 0.22,0 0.44,-0.03 0.65,-0.08l1.55,1.55c-0.67,0.33 -1.41,0.53 -2.2,0.53 -2.76,0 -5,-2.24 -5,-5 0,-0.79 0.2,-1.53 0.53,-2.2zM11.84,9.02l3.15,3.15 0.02,-0.16c0,-1.66 -1.34,-3 -3,-3l-0.17,0.01z"/>
|
||||||
|
</vector>
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="match_parent"
|
||||||
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
|
android:orientation="vertical">
|
||||||
|
|
||||||
|
<include layout="@layout/toolbar" />
|
||||||
|
|
||||||
|
<LinearLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
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:layout_marginEnd="16dp"
|
||||||
|
android:text="@string/settings_recording_customize_layout_select_columns" />
|
||||||
|
|
||||||
|
<Spinner
|
||||||
|
android:id="@+id/spinner_options"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:gravity="center" />
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
|
|
||||||
|
<androidx.core.widget.NestedScrollView
|
||||||
|
android:id="@+id/scroll_view"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view_visible"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toTopOf="@id/recycler_view_not_visible" />
|
||||||
|
|
||||||
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/recycler_view_not_visible"
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:layout_marginTop="24dp"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/recycler_view_visible"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.core.widget.NestedScrollView>
|
||||||
|
|
||||||
|
</LinearLayout>
|
||||||
@@ -42,7 +42,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/aggregated_stats_type_label"
|
android:id="@+id/aggregated_stats_type_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
android:layout_marginStart="16dp"
|
android:layout_marginStart="16dp"
|
||||||
android:layout_marginTop="0dp"
|
android:layout_marginTop="0dp"
|
||||||
android:layout_marginBottom="0dp"
|
android:layout_marginBottom="0dp"
|
||||||
@@ -53,7 +53,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/aggregated_stats_num_tracks"
|
android:id="@+id/aggregated_stats_num_tracks"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
android:layout_marginStart="4dp"
|
android:layout_marginStart="4dp"
|
||||||
android:layout_marginTop="0dp"
|
android:layout_marginTop="0dp"
|
||||||
android:layout_marginBottom="0dp"
|
android:layout_marginBottom="0dp"
|
||||||
@@ -63,12 +63,9 @@
|
|||||||
tools:text="(1)" />
|
tools:text="(1)" />
|
||||||
|
|
||||||
<!-- Distance -->
|
<!-- Distance -->
|
||||||
|
|
||||||
<!-- Time -->
|
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/aggregated_stats_distance"
|
android:id="@+id/aggregated_stats_distance"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
app:layout_constraintEnd_toStartOf="@id/aggregated_stats_distance_unit"
|
app:layout_constraintEnd_toStartOf="@id/aggregated_stats_distance_unit"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
@@ -86,9 +83,10 @@
|
|||||||
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_distance"
|
app:layout_constraintStart_toEndOf="@+id/aggregated_stats_distance"
|
||||||
tools:text="km" />
|
tools:text="km" />
|
||||||
|
|
||||||
|
<!-- Time -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/aggregated_stats_time"
|
android:id="@+id/aggregated_stats_time"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:layout_marginTop="16dp"
|
android:layout_marginTop="16dp"
|
||||||
android:layout_marginEnd="16dp"
|
android:layout_marginEnd="16dp"
|
||||||
app:layout_constraintEnd_toEndOf="@id/guideline3"
|
app:layout_constraintEnd_toEndOf="@id/guideline3"
|
||||||
|
|||||||
@@ -0,0 +1,49 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.cardview.widget.CardView
|
||||||
|
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"
|
||||||
|
style="@style/StatsCardView">
|
||||||
|
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:paddingTop="8dp"
|
||||||
|
android:paddingBottom="8dp">
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/stats_iv_drag_indicator"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
android:src="@drawable/ic_baseline_drag_indicator_24"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/stats_layout"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent" />
|
||||||
|
|
||||||
|
<include
|
||||||
|
android:id="@+id/stats_layout"
|
||||||
|
android:layout_width="0dp"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
layout="@layout/stats_item"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="spread_inside"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/stats_iv_drag_indicator"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/stats_icon_show_status"
|
||||||
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
|
<ImageView
|
||||||
|
android:id="@+id/stats_icon_show_status"
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content"
|
||||||
|
tools:src="@drawable/ic_baseline_visibility_24"
|
||||||
|
android:layout_marginEnd="8dp"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/stats_layout"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
|
|
||||||
|
</androidx.cardview.widget.CardView>
|
||||||
@@ -88,7 +88,7 @@
|
|||||||
<!-- Distance -->
|
<!-- Distance -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_distance_label"
|
android:id="@+id/stats_distance_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
android:text="@string/stats_distance"
|
android:text="@string/stats_distance"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
@@ -97,7 +97,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_distance_value"
|
android:id="@+id/stats_distance_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
@@ -116,7 +116,7 @@
|
|||||||
<!-- Moving time -->
|
<!-- Moving time -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_moving_time_label"
|
android:id="@+id/stats_moving_time_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
android:text="@string/stats_moving_time"
|
android:text="@string/stats_moving_time"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
@@ -125,7 +125,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_moving_time_value"
|
android:id="@+id/stats_moving_time_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
@@ -170,7 +170,7 @@
|
|||||||
<!-- Speed/Pace max -->
|
<!-- Speed/Pace max -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_max_speed_label"
|
android:id="@+id/stats_max_speed_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
||||||
@@ -179,7 +179,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_max_speed_value"
|
android:id="@+id/stats_max_speed_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
@@ -198,7 +198,7 @@
|
|||||||
<!-- Avg. moving speed/pace -->
|
<!-- Avg. moving speed/pace -->
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_moving_speed_label"
|
android:id="@+id/stats_moving_speed_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
||||||
@@ -207,7 +207,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_moving_speed_value"
|
android:id="@+id/stats_moving_speed_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
@@ -277,7 +277,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_altitude_gain_label"
|
android:id="@+id/stats_altitude_gain_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
android:text="@string/stats_gain"
|
android:text="@string/stats_gain"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
@@ -286,7 +286,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_altitude_gain_value"
|
android:id="@+id/stats_altitude_gain_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
app:layout_constraintStart_toEndOf="@id/guideline"
|
||||||
@@ -304,7 +304,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_altitude_loss_label"
|
android:id="@+id/stats_altitude_loss_label"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
android:text="@string/stats_loss"
|
android:text="@string/stats_loss"
|
||||||
app:layout_constrainedWidth="true"
|
app:layout_constrainedWidth="true"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
@@ -313,7 +313,7 @@
|
|||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_altitude_loss_value"
|
android:id="@+id/stats_altitude_loss_value"
|
||||||
style="@style/StatsLargeValue"
|
style="@style/StatsPrimaryValue"
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
app:layout_constraintStart_toEndOf="@id/guideline2"
|
||||||
|
|||||||
@@ -1,457 +1,17 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||||
xmlns:tools="http://schemas.android.com/tools"
|
style="@style/StatsScrollView"
|
||||||
style="@style/StatsScrollView">
|
android:layout_width="match_parent"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout
|
<androidx.recyclerview.widget.RecyclerView
|
||||||
|
android:id="@+id/stats_recycler_view"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content">
|
android:layout_height="match_parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="parent"
|
||||||
|
app:layout_constraintStart_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="parent" />
|
||||||
|
|
||||||
<!-- Guidelines -->
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
<androidx.constraintlayout.widget.Guideline
|
|
||||||
android:id="@+id/guideline"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintGuide_begin="8dp" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
|
||||||
android:id="@+id/guideline2"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintGuide_percent="0.5" />
|
|
||||||
|
|
||||||
<androidx.constraintlayout.widget.Guideline
|
|
||||||
android:id="@+id/guideline3"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="0dp"
|
|
||||||
android:orientation="vertical"
|
|
||||||
app:layout_constraintGuide_end="8dp" />
|
|
||||||
|
|
||||||
<!-- Distance -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_distance_label"
|
|
||||||
style="@style/StatsLargeLabel"
|
|
||||||
android:text="@string/stats_distance"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_distance_value"
|
|
||||||
style="@style/StatsLargeValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_distance_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_distance_label"
|
|
||||||
tools:text="100" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_distance_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_distance_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_distance_value"
|
|
||||||
tools:text="km" />
|
|
||||||
|
|
||||||
<!-- Activity Type -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_activity_type_label"
|
|
||||||
style="@style/StatsLargeLabel"
|
|
||||||
android:text="@string/track_edit_activity_type_hint"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
|
||||||
|
|
||||||
<ImageView
|
|
||||||
android:id="@+id/stats_activity_type_icon"
|
|
||||||
style="@style/StatsLargeValue"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_distance_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/stats_distance_value"
|
|
||||||
app:tint="?android:textColorPrimary" />
|
|
||||||
|
|
||||||
<!-- Total time -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_total_time_label"
|
|
||||||
style="@style/StatsLargeLabel"
|
|
||||||
android:text="@string/stats_total_time"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_distance_value" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_total_time_value"
|
|
||||||
style="@style/StatsLargeValue"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_total_time_label"
|
|
||||||
tools:text="00:00:00" />
|
|
||||||
|
|
||||||
<!-- Moving time -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_time_label"
|
|
||||||
style="@style/StatsLargeLabel"
|
|
||||||
android:text="@string/stats_moving_time"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_total_time_label"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toTopOf="@id/stats_total_time_label"
|
|
||||||
app:layout_constraintVertical_bias="1.0" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_time_value"
|
|
||||||
style="@style/StatsLargeValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_moving_time_label"
|
|
||||||
tools:text="00:00:00" />
|
|
||||||
|
|
||||||
<!-- Barrier -->
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/stats_time_barrier"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="bottom"
|
|
||||||
app:constraint_referenced_ids="stats_total_time_value,stats_moving_time_value" />
|
|
||||||
|
|
||||||
<!-- Horizontal line -->
|
|
||||||
<View
|
|
||||||
android:id="@+id/stats_speed_horizontal_line"
|
|
||||||
style="@style/StatsHorizontalLine"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_time_barrier" />
|
|
||||||
|
|
||||||
<!-- Speed/pace -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_speed_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
|
|
||||||
tools:text="Speed" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_speed_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_speed_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_speed_label"
|
|
||||||
tools:text="30.00" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_speed_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_speed_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_speed_value"
|
|
||||||
tools:text="km/h" />
|
|
||||||
|
|
||||||
<!-- Average speed/pace -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_average_speed_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_speed_horizontal_line"
|
|
||||||
tools:text="Avg. Speed" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_average_speed_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_average_speed_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_label"
|
|
||||||
tools:text="30.00" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_average_speed_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_average_speed_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_average_speed_value"
|
|
||||||
tools:text="km/h" />
|
|
||||||
|
|
||||||
<!-- Speed max -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_max_speed_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
|
|
||||||
tools:text="Max. Speed" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_max_speed_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_max_speed_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_max_speed_label"
|
|
||||||
tools:text="30.00" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_max_speed_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_max_speed_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_max_speed_value"
|
|
||||||
tools:text="km/h" />
|
|
||||||
|
|
||||||
<!-- Moving speed max -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_speed_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_average_speed_value"
|
|
||||||
tools:text="Max. Moving Speed" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_speed_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_moving_speed_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_moving_speed_label"
|
|
||||||
tools:text="30.00" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_moving_speed_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_moving_speed_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_moving_speed_value"
|
|
||||||
tools:text="km/h" />
|
|
||||||
|
|
||||||
<!-- Barrier -->
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/stats_speed_barrier"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="bottom"
|
|
||||||
app:constraint_referenced_ids="stats_max_speed_value,stats_moving_speed_value" />
|
|
||||||
|
|
||||||
<!-- Horizontal line -->
|
|
||||||
<View
|
|
||||||
android:id="@+id/stats_altitude_horizontal_line"
|
|
||||||
style="@style/StatsHorizontalLine"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_speed_barrier" />
|
|
||||||
|
|
||||||
<!-- altitude -->
|
|
||||||
<androidx.constraintlayout.widget.Group
|
|
||||||
android:id="@+id/stats_altitude_group"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:constraint_referenced_ids="stats_altitude_horizontal_line,stats_altitude_current_label,stats_altitude_current_value,stats_altitude_current_unit,stats_altitude_gain_label,stats_altitude_gain_value,stats_altitude_gain_unit,stats_altitude_loss_label,stats_altitude_loss_value,stats_altitude_loss_unit,stats_altitude_current_label_egm" />
|
|
||||||
|
|
||||||
<!-- altitude -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_current_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
android:text="@string/stats_altitude"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_horizontal_line" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_current_label_egm"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:layout_marginTop="0dp"
|
|
||||||
android:text="@string/egm2008"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_current_value" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_current_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_altitude_current_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_current_label"
|
|
||||||
tools:text="100" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_current_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_altitude_current_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_altitude_current_value"
|
|
||||||
tools:text="m" />
|
|
||||||
|
|
||||||
<!-- Altitude gain -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_gain_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
android:text="@string/stats_gain"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_horizontal_line" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_gain_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_altitude_gain_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_gain_label"
|
|
||||||
tools:text="100" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_gain_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_altitude_gain_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_altitude_gain_value"
|
|
||||||
tools:text="m" />
|
|
||||||
|
|
||||||
<!-- Altitude loss -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_loss_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
android:text="@string/stats_loss"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_gain_value" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_loss_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
android:value="@string/value_unknown"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_altitude_loss_unit"
|
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_loss_label"
|
|
||||||
tools:text="100" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_altitude_loss_unit"
|
|
||||||
style="@style/StatsUnit"
|
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_altitude_loss_value"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_altitude_loss_value"
|
|
||||||
tools:text="m" />
|
|
||||||
|
|
||||||
<!-- Coordinate group -->
|
|
||||||
<androidx.constraintlayout.widget.Group
|
|
||||||
android:id="@+id/stats_coordinate_group"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:constraint_referenced_ids="stats_latitude_label,stats_latitude_value,stats_longitude_label,stats_longitude_value,stats_coordinate_horizontal_line" />
|
|
||||||
|
|
||||||
<!-- Barrier -->
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/stats_altitude_barrier"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="bottom"
|
|
||||||
app:constraint_referenced_ids="stats_altitude_current_value,stats_altitude_gain_value,stats_altitude_loss_value" />
|
|
||||||
|
|
||||||
<!-- Horizontal line -->
|
|
||||||
<View
|
|
||||||
android:id="@+id/stats_coordinate_horizontal_line"
|
|
||||||
style="@style/StatsHorizontalLine"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_altitude_barrier" />
|
|
||||||
|
|
||||||
<!-- Latitude -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_latitude_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
android:text="@string/stats_latitude"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_coordinate_horizontal_line" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_latitude_value"
|
|
||||||
style="@style/StatsSmallValue"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline2"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_latitude_label"
|
|
||||||
tools:text="0.834937848" />
|
|
||||||
|
|
||||||
<!-- Longitude -->
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_longitude_label"
|
|
||||||
style="@style/StatsSmallLabel"
|
|
||||||
android:text="@string/stats_longitude"
|
|
||||||
app:layout_constrainedWidth="true"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
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_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline2"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_longitude_label"
|
|
||||||
tools:text="0.834937848" />
|
|
||||||
|
|
||||||
<!-- Barrier -->
|
|
||||||
<androidx.constraintlayout.widget.Barrier
|
|
||||||
android:id="@+id/stats_location_barrier"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:barrierDirection="bottom"
|
|
||||||
app:constraint_referenced_ids="stats_latitude_value,stats_longitude_value" />
|
|
||||||
|
|
||||||
<!-- Horizontal line -->
|
|
||||||
<View
|
|
||||||
android:id="@+id/stats_sensor_horizontal_line"
|
|
||||||
style="@style/StatsHorizontalLine"
|
|
||||||
android:layout_marginBottom="8dp"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_location_barrier" />
|
|
||||||
|
|
||||||
<!-- Sensors data -->
|
|
||||||
<androidx.recyclerview.widget.RecyclerView
|
|
||||||
android:id="@+id/stats_sensors_recycler_view"
|
|
||||||
android:layout_width="0dp"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:layout_constraintEnd_toStartOf="@id/guideline3"
|
|
||||||
app:layout_constraintStart_toEndOf="@id/guideline"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_sensor_horizontal_line" />
|
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
|
||||||
</ScrollView>
|
|
||||||
|
|||||||
@@ -0,0 +1,47 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
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:paddingBottom="16dp"
|
||||||
|
android:paddingTop="16dp">
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_value"
|
||||||
|
style="@style/StatsPrimaryValue"
|
||||||
|
android:value="@string/value_unknown"
|
||||||
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintTop_toTopOf="parent"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toStartOf="@id/stats_unit"
|
||||||
|
tools:text="90" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_unit"
|
||||||
|
style="@style/StatsUnit"
|
||||||
|
tools:text="@string/sensor_unit_beats_per_minute"
|
||||||
|
app:layout_constraintStart_toEndOf="@id/stats_value"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintBottom_toBottomOf="@id/stats_value" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_description_main"
|
||||||
|
style="@style/StatsPrimaryLabel"
|
||||||
|
tools:text="@string/sensor_state_heart_rate"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_value" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_description_secondary"
|
||||||
|
style="@style/StatsTinyValue"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_description_main"
|
||||||
|
tools:visibility="visible"
|
||||||
|
tools:text="90" />
|
||||||
|
|
||||||
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -1,42 +1,47 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<androidx.constraintlayout.widget.ConstraintLayout
|
||||||
|
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_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
android:paddingBottom="16dp"
|
||||||
xmlns:tools="http://schemas.android.com/tools">
|
android:paddingTop="16dp">
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_sensor_label"
|
android:id="@+id/stats_description_main"
|
||||||
style="@style/StatsLargeLabel"
|
style="@style/LargeLabel"
|
||||||
tools:text="@string/sensor_state_heart_rate"
|
tools:text="@string/sensor_state_heart_rate"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintTop_toTopOf="parent" />
|
app:layout_constraintTop_toTopOf="parent" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_sensor_sensor_value"
|
android:id="@+id/stats_value"
|
||||||
style="@style/StatsTinyValue"
|
style="@style/StatsPrimaryValue"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_sensor_label"
|
|
||||||
tools:text="90" />
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/stats_sensor_value"
|
|
||||||
style="@style/StatsLargeValue"
|
|
||||||
android:value="@string/value_unknown"
|
android:value="@string/value_unknown"
|
||||||
app:layout_constraintHorizontal_chainStyle="packed"
|
app:layout_constraintHorizontal_chainStyle="packed"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_description_main"
|
||||||
app:layout_constraintStart_toStartOf="parent"
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
app:layout_constraintEnd_toStartOf="@id/stats_sensor_unit"
|
app:layout_constraintEnd_toStartOf="@id/stats_unit"
|
||||||
app:layout_constraintTop_toBottomOf="@id/stats_sensor_sensor_value"
|
|
||||||
tools:text="90" />
|
tools:text="90" />
|
||||||
|
|
||||||
<TextView
|
<TextView
|
||||||
android:id="@+id/stats_sensor_unit"
|
android:id="@+id/stats_unit"
|
||||||
style="@style/StatsUnit"
|
style="@style/StatsUnit"
|
||||||
tools:text="@string/sensor_unit_beats_per_minute"
|
tools:text="@string/sensor_unit_beats_per_minute"
|
||||||
app:layout_constraintStart_toEndOf="@id/stats_sensor_value"
|
app:layout_constraintStart_toEndOf="@id/stats_value"
|
||||||
app:layout_constraintEnd_toEndOf="parent"
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
app:layout_constraintBottom_toBottomOf="@id/stats_sensor_value" />
|
app:layout_constraintBottom_toBottomOf="@id/stats_value" />
|
||||||
|
|
||||||
|
<TextView
|
||||||
|
android:id="@+id/stats_description_secondary"
|
||||||
|
style="@style/StatsTinyValue"
|
||||||
|
android:visibility="gone"
|
||||||
|
app:layout_constraintStart_toStartOf="parent"
|
||||||
|
app:layout_constraintEnd_toEndOf="parent"
|
||||||
|
app:layout_constraintTop_toBottomOf="@id/stats_value"
|
||||||
|
tools:visibility="visible"
|
||||||
|
tools:text="90" />
|
||||||
|
|
||||||
</androidx.constraintlayout.widget.ConstraintLayout>
|
</androidx.constraintlayout.widget.ConstraintLayout>
|
||||||
@@ -217,7 +217,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">البلوتوث</string>
|
<string name="settings_sensor_bluetooth">البلوتوث</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">خط العرض/خط الطول</string>
|
|
||||||
<string name="settings_stats_rate_title">المعدل المفضل</string>
|
<string name="settings_stats_rate_title">المعدل المفضل</string>
|
||||||
<string name="settings_stats_units_imperial">وحدات القياس البريطانية (ميل، قدم)</string>
|
<string name="settings_stats_units_imperial">وحدات القياس البريطانية (ميل، قدم)</string>
|
||||||
<string name="settings_stats_units_metric">وحدات القياس المترية (كم، م)</string>
|
<string name="settings_stats_units_metric">وحدات القياس المترية (كم، م)</string>
|
||||||
|
|||||||
@@ -176,7 +176,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Reset now?</string>
|
<string name="settings_reset_confirm_title">Reset now?</string>
|
||||||
<string name="settings_reset_done">All settings have been reverted to default values</string>
|
<string name="settings_reset_done">All settings have been reverted to default values</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitude/Longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Preferred rate</string>
|
<string name="settings_stats_rate_title">Preferred rate</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (miles, ft)</string>
|
<string name="settings_stats_units_imperial">Imperial (miles, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
||||||
|
|||||||
@@ -178,7 +178,6 @@
|
|||||||
<string name="settings_reset_confirm_title">¿Restablecer ahora?</string>
|
<string name="settings_reset_confirm_title">¿Restablecer ahora?</string>
|
||||||
<string name="settings_reset_done">Se restablecieron los valores predeterminados de todas las opciones de configuración</string>
|
<string name="settings_reset_done">Se restablecieron los valores predeterminados de todas las opciones de configuración</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitud/longitud</string>
|
|
||||||
<string name="settings_stats_rate_title">Tasa preferida</string>
|
<string name="settings_stats_rate_title">Tasa preferida</string>
|
||||||
<string name="settings_stats_units_imperial">Imperiales (millas, pies)</string>
|
<string name="settings_stats_units_imperial">Imperiales (millas, pies)</string>
|
||||||
<string name="settings_stats_units_metric">Métricas (km, m)</string>
|
<string name="settings_stats_units_metric">Métricas (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Ширина и дължина</string>
|
|
||||||
<string name="settings_stats_rate_title">Предпочитана мярка</string>
|
<string name="settings_stats_rate_title">Предпочитана мярка</string>
|
||||||
<string name="settings_stats_units_imperial">Имперски (мил, фт)</string>
|
<string name="settings_stats_units_imperial">Имперски (мил, фт)</string>
|
||||||
<string name="settings_stats_units_metric">Метрични (км, м)</string>
|
<string name="settings_stats_units_metric">Метрични (км, м)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitud/Longitud</string>
|
|
||||||
<string name="settings_stats_rate_title">Mesura preferida</string>
|
<string name="settings_stats_rate_title">Mesura preferida</string>
|
||||||
<string name="settings_stats_units_imperial">Sistema anglosaxó (milles, peus)</string>
|
<string name="settings_stats_units_imperial">Sistema anglosaxó (milles, peus)</string>
|
||||||
<string name="settings_stats_units_metric">Sistema mètric (km, m)</string>
|
<string name="settings_stats_units_metric">Sistema mètric (km, m)</string>
|
||||||
|
|||||||
@@ -280,7 +280,6 @@ Pokud zařízení GPS hlásí nepřesná data (např. Polohu, rychlost, nadmořs
|
|||||||
<string name="settings_sensor_connecting">Připojeno k senzoru %1$s</string>
|
<string name="settings_sensor_connecting">Připojeno k senzoru %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Odpojeno od %1$s</string>
|
<string name="settings_sensor_disconnected">Odpojeno od %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Zeměpisná šířka/délka</string>
|
|
||||||
<string name="settings_stats_rate_title">Preferovaná rychlost</string>
|
<string name="settings_stats_rate_title">Preferovaná rychlost</string>
|
||||||
<string name="settings_stats_units_imperial">Imperiální jednotky (míle, stopy)</string>
|
<string name="settings_stats_units_imperial">Imperiální jednotky (míle, stopy)</string>
|
||||||
<string name="settings_stats_units_metric">Metrické jednotky (km, m)</string>
|
<string name="settings_stats_units_metric">Metrické jednotky (km, m)</string>
|
||||||
|
|||||||
@@ -282,7 +282,6 @@ Hvis GPS-enheden rapporterer unøjagtige data (f.eks. Placering, hastighed, høj
|
|||||||
<string name="settings_sensor_connecting">Tilsluttet %1$s</string>
|
<string name="settings_sensor_connecting">Tilsluttet %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Frakoblet %1$s</string>
|
<string name="settings_sensor_disconnected">Frakoblet %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Breddegrad/længdegrad</string>
|
|
||||||
<string name="settings_stats_rate_title">Foretrukkenfartenhed</string>
|
<string name="settings_stats_rate_title">Foretrukkenfartenhed</string>
|
||||||
<string name="settings_stats_units_imperial">Britisk (mil, ft)</string>
|
<string name="settings_stats_units_imperial">Britisk (mil, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
|
||||||
|
|||||||
@@ -284,7 +284,6 @@ Meldet das GPS-Gerät ungenaue Daten (z.B. Standort, Geschwindigkeit, Höhe), ka
|
|||||||
<string name="settings_sensor_connecting">Verbunden mit %1$s</string>
|
<string name="settings_sensor_connecting">Verbunden mit %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Verbindung getrennt von %1$s</string>
|
<string name="settings_sensor_disconnected">Verbindung getrennt von %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Breiten-/Längengrad</string>
|
|
||||||
<string name="settings_stats_rate_title">Bevorzugtes Maß</string>
|
<string name="settings_stats_rate_title">Bevorzugtes Maß</string>
|
||||||
<string name="settings_stats_units_imperial">Englisch (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Englisch (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Πλάτος/Μήκος</string>
|
|
||||||
<string name="settings_stats_rate_title">Προτιμώμενος ρυθμός</string>
|
<string name="settings_stats_rate_title">Προτιμώμενος ρυθμός</string>
|
||||||
<string name="settings_stats_units_imperial">Αγγλοσαξονικό (μίλια, πόδια)</string>
|
<string name="settings_stats_units_imperial">Αγγλοσαξονικό (μίλια, πόδια)</string>
|
||||||
<string name="settings_stats_units_metric">Μετρικό (χλμ, μέτρα)</string>
|
<string name="settings_stats_units_metric">Μετρικό (χλμ, μέτρα)</string>
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ Si el dispositivo GPS reporta datos inexactos (por ejemplo, ubicación, velocida
|
|||||||
<string name="settings_sensor_connecting">Conectado a %1$s</string>
|
<string name="settings_sensor_connecting">Conectado a %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Desconectado de %1$s</string>
|
<string name="settings_sensor_disconnected">Desconectado de %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitud/Longitud</string>
|
|
||||||
<string name="settings_stats_rate_title">Ritmo preferido</string>
|
<string name="settings_stats_rate_title">Ritmo preferido</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (millas, pies)</string>
|
<string name="settings_stats_units_imperial">Imperial (millas, pies)</string>
|
||||||
<string name="settings_stats_units_metric">Métrica (km, m)</string>
|
<string name="settings_stats_units_metric">Métrica (km, m)</string>
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ Kui GPS-seade teatab ebatäpsetest andmetest (nt asukoht, kiirus, kõrgus), ei s
|
|||||||
<string name="settings_sensor_connecting">Ühendatud anduriga %1$s</string>
|
<string name="settings_sensor_connecting">Ühendatud anduriga %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Lahti ühendatud %1$s</string>
|
<string name="settings_sensor_disconnected">Lahti ühendatud %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Laiuskraad/pikkuskraad</string>
|
|
||||||
<string name="settings_stats_rate_title">Eelistatud määr</string>
|
<string name="settings_stats_rate_title">Eelistatud määr</string>
|
||||||
<string name="settings_stats_units_imperial">Inglise mõõtühikud (miili, jalga)</string>
|
<string name="settings_stats_units_imperial">Inglise mõõtühikud (miili, jalga)</string>
|
||||||
<string name="settings_stats_units_metric">Meetermõõdustik (km, m)</string>
|
<string name="settings_stats_units_metric">Meetermõõdustik (km, m)</string>
|
||||||
|
|||||||
@@ -280,7 +280,6 @@ GPS gailuak datu okerrak salatzen baditu (adibidez, kokapena, abiadura, kota), O
|
|||||||
<string name="settings_sensor_connecting">Honekin konektatuta: %1$s</string>
|
<string name="settings_sensor_connecting">Honekin konektatuta: %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Deskonektatuta %1$s</string>
|
<string name="settings_sensor_disconnected">Deskonektatuta %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitudea/Longitudea</string>
|
|
||||||
<string name="settings_stats_rate_title">Erritmo hobetsia</string>
|
<string name="settings_stats_rate_title">Erritmo hobetsia</string>
|
||||||
<string name="settings_stats_units_imperial">Inperiala (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Inperiala (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrikoa (km, m)</string>
|
<string name="settings_stats_units_metric">Metrikoa (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">بلوتوث</string>
|
<string name="settings_sensor_bluetooth">بلوتوث</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">عرض جغرافیایی/ طول جغرافیایی</string>
|
|
||||||
<string name="settings_stats_rate_title">اولویت سنجه سرعت</string>
|
<string name="settings_stats_rate_title">اولویت سنجه سرعت</string>
|
||||||
<string name="settings_stats_units_imperial">انگلیسی (مایل، فوت)</string>
|
<string name="settings_stats_units_imperial">انگلیسی (مایل، فوت)</string>
|
||||||
<string name="settings_stats_units_metric">متریک (کیلومتر، متر)</string>
|
<string name="settings_stats_units_metric">متریک (کیلومتر، متر)</string>
|
||||||
|
|||||||
@@ -284,7 +284,6 @@ limitations under the License.
|
|||||||
<string name="settings_sensor_connecting">Yhdistetty: %1$s</string>
|
<string name="settings_sensor_connecting">Yhdistetty: %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Yhteys katkaistu: %1$s</string>
|
<string name="settings_sensor_disconnected">Yhteys katkaistu: %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Leveys-/pituusaste</string>
|
|
||||||
<string name="settings_stats_rate_title">Haluttu nopeus</string>
|
<string name="settings_stats_rate_title">Haluttu nopeus</string>
|
||||||
<string name="settings_stats_units_imperial">Brittiläinen järj.
|
<string name="settings_stats_units_imperial">Brittiläinen järj.
|
||||||
(maili, jalka)</string>
|
(maili, jalka)</string>
|
||||||
|
|||||||
@@ -176,7 +176,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Réinitialiser maintenant?</string>
|
<string name="settings_reset_confirm_title">Réinitialiser maintenant?</string>
|
||||||
<string name="settings_reset_done">Les valeurs par défaut de tous les paramètres ont bien été rétablies</string>
|
<string name="settings_reset_done">Les valeurs par défaut de tous les paramètres ont bien été rétablies</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitude/longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Mode de calcul souhaité</string>
|
<string name="settings_stats_rate_title">Mode de calcul souhaité</string>
|
||||||
<string name="settings_stats_units_imperial">Unités impériales (mi, pi)</string>
|
<string name="settings_stats_units_imperial">Unités impériales (mi, pi)</string>
|
||||||
<string name="settings_stats_units_metric">Unités métriques (km, m)</string>
|
<string name="settings_stats_units_metric">Unités métriques (km, m)</string>
|
||||||
|
|||||||
@@ -176,7 +176,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Réinitialiser maintenant ?</string>
|
<string name="settings_reset_confirm_title">Réinitialiser maintenant ?</string>
|
||||||
<string name="settings_reset_done">Les valeurs par défaut de tous les paramètres ont bien été rétablies.</string>
|
<string name="settings_reset_done">Les valeurs par défaut de tous les paramètres ont bien été rétablies.</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitude/Longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Mode de calcul souhaité</string>
|
<string name="settings_stats_rate_title">Mode de calcul souhaité</string>
|
||||||
<string name="settings_stats_units_imperial">Unités impériales (mi, pi)</string>
|
<string name="settings_stats_units_imperial">Unités impériales (mi, pi)</string>
|
||||||
<string name="settings_stats_units_metric">Unités métriques (km, m)</string>
|
<string name="settings_stats_units_metric">Unités métriques (km, m)</string>
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ Si le dispositif GPS signale des données inexactes (par exemple, la localisatio
|
|||||||
<string name="settings_sensor_connecting">Connecté à %1$s</string>
|
<string name="settings_sensor_connecting">Connecté à %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Déconnecté de %1$s</string>
|
<string name="settings_sensor_disconnected">Déconnecté de %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitude/Longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Mode de calcul souhaité</string>
|
<string name="settings_stats_rate_title">Mode de calcul souhaité</string>
|
||||||
<string name="settings_stats_units_imperial">Unités impériales (mi, pi)</string>
|
<string name="settings_stats_units_imperial">Unités impériales (mi, pi)</string>
|
||||||
<string name="settings_stats_units_metric">Unités métriques (km, m)</string>
|
<string name="settings_stats_units_metric">Unités métriques (km, m)</string>
|
||||||
|
|||||||
@@ -294,7 +294,6 @@ Se te detés ou estás en interiores, non se gardarán datos do sensor (mais ser
|
|||||||
<string name="settings_sensor_disconnected">Desconectado de %1$s</string>
|
<string name="settings_sensor_disconnected">Desconectado de %1$s</string>
|
||||||
<string name="settings_sensor_wheel_circumference">Circunferencia da roda (mm)</string>
|
<string name="settings_sensor_wheel_circumference">Circunferencia da roda (mm)</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitude/lonxitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Indicador preferido</string>
|
<string name="settings_stats_rate_title">Indicador preferido</string>
|
||||||
<string name="settings_stats_units_imperial">Imperiais (millas, pés)</string>
|
<string name="settings_stats_units_imperial">Imperiais (millas, pés)</string>
|
||||||
<string name="settings_stats_units_metric">Métricas (km, m)</string>
|
<string name="settings_stats_units_metric">Métricas (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">अक्षांश/देशांतर</string>
|
|
||||||
<string name="settings_stats_rate_title">पसंदीदा दर</string>
|
<string name="settings_stats_rate_title">पसंदीदा दर</string>
|
||||||
<string name="settings_stats_units_imperial">इंपीरियल (मील, फुट)</string>
|
<string name="settings_stats_units_imperial">इंपीरियल (मील, फुट)</string>
|
||||||
<string name="settings_stats_units_metric">मेट्रिक (किमी, मी)</string>
|
<string name="settings_stats_units_metric">मेट्रिक (किमी, मी)</string>
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Geografska širina/duljina</string>
|
|
||||||
<string name="settings_stats_rate_title">Preferirana stopa</string>
|
<string name="settings_stats_rate_title">Preferirana stopa</string>
|
||||||
<string name="settings_stats_units_imperial">Imperijalne (milje, stope)</string>
|
<string name="settings_stats_units_imperial">Imperijalne (milje, stope)</string>
|
||||||
<string name="settings_stats_units_metric">Metričke (km, m)</string>
|
<string name="settings_stats_units_metric">Metričke (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Szélesség/hosszúság</string>
|
|
||||||
<string name="settings_stats_rate_title">Mérték választása</string>
|
<string name="settings_stats_rate_title">Mérték választása</string>
|
||||||
<string name="settings_stats_units_imperial">Angolszász (mérföld, láb)</string>
|
<string name="settings_stats_units_imperial">Angolszász (mérföld, láb)</string>
|
||||||
<string name="settings_stats_units_metric">Metrikus (km, m)</string>
|
<string name="settings_stats_units_metric">Metrikus (km, m)</string>
|
||||||
|
|||||||
@@ -175,7 +175,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Setel ulang sekarang?</string>
|
<string name="settings_reset_confirm_title">Setel ulang sekarang?</string>
|
||||||
<string name="settings_reset_done">Semua setelan telah dikembalikan ke nilai default</string>
|
<string name="settings_reset_done">Semua setelan telah dikembalikan ke nilai default</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Lintang/Bujur</string>
|
|
||||||
<string name="settings_stats_rate_title">Laju yang dipilih</string>
|
<string name="settings_stats_rate_title">Laju yang dipilih</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (mil, kaki)</string>
|
<string name="settings_stats_units_imperial">Imperial (mil, kaki)</string>
|
||||||
<string name="settings_stats_units_metric">Metrik (km, m)</string>
|
<string name="settings_stats_units_metric">Metrik (km, m)</string>
|
||||||
|
|||||||
@@ -255,7 +255,6 @@ Infatti, un\'applicazione deve supportare <i>ACTION_VIEW</i> con MIME <i>applica
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitudine/longitudine</string>
|
|
||||||
<string name="settings_stats_rate_title">Velocità preferita</string>
|
<string name="settings_stats_rate_title">Velocità preferita</string>
|
||||||
<string name="settings_stats_units_imperial">Imperiale (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperiale (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrico (km, m)</string>
|
<string name="settings_stats_units_metric">Metrico (km, m)</string>
|
||||||
|
|||||||
@@ -178,7 +178,6 @@
|
|||||||
<string name="settings_reset_confirm_title">לאפס כעת?</string>
|
<string name="settings_reset_confirm_title">לאפס כעת?</string>
|
||||||
<string name="settings_reset_done">כל ההגדרות הוחזרו לערכי ברירת המחדל</string>
|
<string name="settings_reset_done">כל ההגדרות הוחזרו לערכי ברירת המחדל</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">קו רוחב/קו אורך</string>
|
|
||||||
<string name="settings_stats_rate_title">קצב מועדף</string>
|
<string name="settings_stats_rate_title">קצב מועדף</string>
|
||||||
<string name="settings_stats_units_imperial">אימפריאלי (מייל, רגל)</string>
|
<string name="settings_stats_units_imperial">אימפריאלי (מייל, רגל)</string>
|
||||||
<string name="settings_stats_units_metric">מטרי (ק\"מ, מ\')</string>
|
<string name="settings_stats_units_metric">מטרי (ק\"מ, מ\')</string>
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">緯度/経度</string>
|
|
||||||
<string name="settings_stats_rate_title">計測方法</string>
|
<string name="settings_stats_rate_title">計測方法</string>
|
||||||
<string name="settings_stats_units_imperial">ヤード・ポンド法(マイル、フィート)</string>
|
<string name="settings_stats_units_imperial">ヤード・ポンド法(マイル、フィート)</string>
|
||||||
<string name="settings_stats_units_metric">メートル法(km、m)</string>
|
<string name="settings_stats_units_metric">メートル法(km、m)</string>
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">블루투스</string>
|
<string name="settings_sensor_bluetooth">블루투스</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">위도/경도</string>
|
|
||||||
<string name="settings_stats_rate_title">선호하는 속도</string>
|
<string name="settings_stats_rate_title">선호하는 속도</string>
|
||||||
<string name="settings_stats_units_imperial">야드파운드법(마일, 피트)</string>
|
<string name="settings_stats_units_imperial">야드파운드법(마일, 피트)</string>
|
||||||
<string name="settings_stats_units_metric">미터법(km,m)</string>
|
<string name="settings_stats_units_metric">미터법(km,m)</string>
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Platuma ir ilguma</string>
|
|
||||||
<string name="settings_stats_rate_title">Pageidaujamas greitis</string>
|
<string name="settings_stats_rate_title">Pageidaujamas greitis</string>
|
||||||
<string name="settings_stats_units_imperial">Imperinės (myl., pėdos)</string>
|
<string name="settings_stats_units_imperial">Imperinės (myl., pėdos)</string>
|
||||||
<string name="settings_stats_units_metric">Metrinės (km, m)</string>
|
<string name="settings_stats_units_metric">Metrinės (km, m)</string>
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Platums/garums</string>
|
|
||||||
<string name="settings_stats_rate_title">Vēlamais rādītājs</string>
|
<string name="settings_stats_rate_title">Vēlamais rādītājs</string>
|
||||||
<string name="settings_stats_units_imperial">Standarta (jūdzes, pēdas)</string>
|
<string name="settings_stats_units_imperial">Standarta (jūdzes, pēdas)</string>
|
||||||
<string name="settings_stats_units_metric">Metriskās (km, m)</string>
|
<string name="settings_stats_units_metric">Metriskās (km, m)</string>
|
||||||
|
|||||||
@@ -177,7 +177,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Resetați acum?</string>
|
<string name="settings_reset_confirm_title">Resetați acum?</string>
|
||||||
<string name="settings_reset_done">Toate setările au revenit la valorile prestabilite</string>
|
<string name="settings_reset_done">Toate setările au revenit la valorile prestabilite</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitudine/longitudine</string>
|
|
||||||
<string name="settings_stats_rate_title">Rata de preferat</string>
|
<string name="settings_stats_rate_title">Rata de preferat</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitud/Longitud</string>
|
|
||||||
<string name="settings_stats_rate_title">Kadar pilihan</string>
|
<string name="settings_stats_rate_title">Kadar pilihan</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (bt, kaki)</string>
|
<string name="settings_stats_units_imperial">Imperial (bt, kaki)</string>
|
||||||
<string name="settings_stats_units_metric">Metrik (km, m)</string>
|
<string name="settings_stats_units_metric">Metrik (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Bredde- og lengdegrad</string>
|
|
||||||
<string name="settings_stats_rate_title">Foretrukket måling</string>
|
<string name="settings_stats_rate_title">Foretrukket måling</string>
|
||||||
<string name="settings_stats_units_imperial">Britisk (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Britisk (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
|
||||||
|
|||||||
@@ -279,7 +279,6 @@ Als het GPS-apparaat onnauwkeurige gegevens rapporteert (bijv. locatie, snelheid
|
|||||||
<string name="settings_sensor_connecting">Verbonden met %1$s</string>
|
<string name="settings_sensor_connecting">Verbonden met %1$s</string>
|
||||||
<string name="settings_sensor_disconnected">Ontkoppeld van %1$s</string>
|
<string name="settings_sensor_disconnected">Ontkoppeld van %1$s</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Breedte-/lengtegraad</string>
|
|
||||||
<string name="settings_stats_rate_title">Voorkeursverhouding</string>
|
<string name="settings_stats_rate_title">Voorkeursverhouding</string>
|
||||||
<string name="settings_stats_units_imperial">Engels (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Engels (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisch (km, m)</string>
|
||||||
|
|||||||
@@ -242,7 +242,6 @@ limitations under the License.
|
|||||||
<string name="settings_sensor_disconnected">Rozłaczony z %1$s</string>
|
<string name="settings_sensor_disconnected">Rozłaczony z %1$s</string>
|
||||||
<string name="settings_sensor_wheel_circumference">Obwód koła (mm)</string>
|
<string name="settings_sensor_wheel_circumference">Obwód koła (mm)</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Długości i szerokości geograficznej</string>
|
|
||||||
<string name="settings_stats_rate_title">Wybór tempo/prędkość</string>
|
<string name="settings_stats_rate_title">Wybór tempo/prędkość</string>
|
||||||
<string name="settings_stats_units_imperial">Imperialne (mile, stopy)</string>
|
<string name="settings_stats_units_imperial">Imperialne (mile, stopy)</string>
|
||||||
<string name="settings_stats_units_metric">Metryczne (km, m)</string>
|
<string name="settings_stats_units_metric">Metryczne (km, m)</string>
|
||||||
|
|||||||
@@ -176,7 +176,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Redefinir agora?</string>
|
<string name="settings_reset_confirm_title">Redefinir agora?</string>
|
||||||
<string name="settings_reset_done">Todas as configurações foram revertidas para os valores padrão</string>
|
<string name="settings_reset_done">Todas as configurações foram revertidas para os valores padrão</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitude/longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Taxa preferencial</string>
|
<string name="settings_stats_rate_title">Taxa preferencial</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (milhas, pés)</string>
|
<string name="settings_stats_units_imperial">Imperial (milhas, pés)</string>
|
||||||
<string name="settings_stats_units_metric">Métrica (km, m)</string>
|
<string name="settings_stats_units_metric">Métrica (km, m)</string>
|
||||||
|
|||||||
@@ -176,7 +176,6 @@
|
|||||||
<string name="settings_reset_confirm_title">Repor agora?</string>
|
<string name="settings_reset_confirm_title">Repor agora?</string>
|
||||||
<string name="settings_reset_done">Todas as definições foram revertidas para os valores predefinidos</string>
|
<string name="settings_reset_done">Todas as definições foram revertidas para os valores predefinidos</string>
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<string name="settings_stats_coordinate">Latitude/Longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Avaliação preferida</string>
|
<string name="settings_stats_rate_title">Avaliação preferida</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (milhas, pés)</string>
|
<string name="settings_stats_units_imperial">Imperial (milhas, pés)</string>
|
||||||
<string name="settings_stats_units_metric">Métrico (km, m)</string>
|
<string name="settings_stats_units_metric">Métrico (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitude/longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Taxa preferencial</string>
|
<string name="settings_stats_rate_title">Taxa preferencial</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (milhas, pés)</string>
|
<string name="settings_stats_units_imperial">Imperial (milhas, pés)</string>
|
||||||
<string name="settings_stats_units_metric">Métrica (km, m)</string>
|
<string name="settings_stats_units_metric">Métrica (km, m)</string>
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitudine/longitudine</string>
|
|
||||||
<string name="settings_stats_rate_title">Rata de preferat</string>
|
<string name="settings_stats_rate_title">Rata de preferat</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrică (km, m)</string>
|
<string name="settings_stats_units_metric">Metrică (km, m)</string>
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Широта/долгота</string>
|
|
||||||
<string name="settings_stats_rate_title">Предпочтение</string>
|
<string name="settings_stats_rate_title">Предпочтение</string>
|
||||||
<string name="settings_stats_units_imperial">Британская (мили, футы)</string>
|
<string name="settings_stats_units_imperial">Британская (мили, футы)</string>
|
||||||
<string name="settings_stats_units_metric">Метрическая (км, м)</string>
|
<string name="settings_stats_units_metric">Метрическая (км, м)</string>
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Zemepis. šírka/dĺžka</string>
|
|
||||||
<string name="settings_stats_rate_title">Preferovaná hodnota</string>
|
<string name="settings_stats_rate_title">Preferovaná hodnota</string>
|
||||||
<string name="settings_stats_units_imperial">Imperiálne jednotky (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperiálne jednotky (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrické jednotky (km, m)</string>
|
<string name="settings_stats_units_metric">Metrické jednotky (km, m)</string>
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Zemlj. širina/dolžina</string>
|
|
||||||
<string name="settings_stats_rate_title">Pred. enot. za hitr.</string>
|
<string name="settings_stats_rate_title">Pred. enot. za hitr.</string>
|
||||||
<string name="settings_stats_units_imperial">Imperialni sistem (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperialni sistem (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrični sistem (km, m)</string>
|
<string name="settings_stats_units_metric">Metrični sistem (km, m)</string>
|
||||||
|
|||||||
@@ -214,7 +214,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Географска шир./дуж.</string>
|
|
||||||
<string name="settings_stats_rate_title">Жељени темпо</string>
|
<string name="settings_stats_rate_title">Жељени темпо</string>
|
||||||
<string name="settings_stats_units_imperial">Империјалне (ми, ст)</string>
|
<string name="settings_stats_units_imperial">Империјалне (ми, ст)</string>
|
||||||
<string name="settings_stats_units_metric">Метричке (км, м)</string>
|
<string name="settings_stats_units_metric">Метричке (км, м)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitud/longitud</string>
|
|
||||||
<string name="settings_stats_rate_title">Föredragen mätning</string>
|
<string name="settings_stats_rate_title">Föredragen mätning</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
|
<string name="settings_stats_units_metric">Metrisk (km, m)</string>
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">บลูทูธ</string>
|
<string name="settings_sensor_bluetooth">บลูทูธ</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">ละติจูด/ลองจิจูด</string>
|
|
||||||
<string name="settings_stats_rate_title">อัตราที่ต้องการ</string>
|
<string name="settings_stats_rate_title">อัตราที่ต้องการ</string>
|
||||||
<string name="settings_stats_units_imperial">หน่วยอังกฤษ (ไมล์, ฟุต)</string>
|
<string name="settings_stats_units_imperial">หน่วยอังกฤษ (ไมล์, ฟุต)</string>
|
||||||
<string name="settings_stats_units_metric">หน่วยเมตริก (กม., เมตร)</string>
|
<string name="settings_stats_units_metric">หน่วยเมตริก (กม., เมตร)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitude/Longtitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Gustong rate</string>
|
<string name="settings_stats_rate_title">Gustong rate</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
||||||
|
|||||||
@@ -213,7 +213,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Enlem/Boylam</string>
|
|
||||||
<string name="settings_stats_rate_title">Tercih edilen oran</string>
|
<string name="settings_stats_rate_title">Tercih edilen oran</string>
|
||||||
<string name="settings_stats_units_imperial">İngiliz (mil, fit)</string>
|
<string name="settings_stats_units_imperial">İngiliz (mil, fit)</string>
|
||||||
<string name="settings_stats_units_metric">Metrik (km, m)</string>
|
<string name="settings_stats_units_metric">Metrik (km, m)</string>
|
||||||
|
|||||||
@@ -215,7 +215,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Широта/довгота</string>
|
|
||||||
<string name="settings_stats_rate_title">Система вимірювання</string>
|
<string name="settings_stats_rate_title">Система вимірювання</string>
|
||||||
<string name="settings_stats_units_imperial">Британська (милі, фути)</string>
|
<string name="settings_stats_units_imperial">Британська (милі, фути)</string>
|
||||||
<string name="settings_stats_units_metric">Метрична (км, м)</string>
|
<string name="settings_stats_units_metric">Метрична (км, м)</string>
|
||||||
|
|||||||
@@ -212,7 +212,6 @@ limitations under the License.
|
|||||||
<!-- Settings Sensor -->
|
<!-- Settings Sensor -->
|
||||||
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
<string name="settings_sensor_bluetooth">Bluetooth</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Vĩ độ/Kinh độ</string>
|
|
||||||
<string name="settings_stats_rate_title">Tốc độ ưa thích</string>
|
<string name="settings_stats_rate_title">Tốc độ ưa thích</string>
|
||||||
<string name="settings_stats_units_imperial">Hệ đo lường Anh (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Hệ đo lường Anh (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Hệ mét (km, m)</string>
|
<string name="settings_stats_units_metric">Hệ mét (km, m)</string>
|
||||||
|
|||||||
@@ -175,7 +175,6 @@
|
|||||||
<string name="settings_reset_confirm_title">確定要立即重設?</string>
|
<string name="settings_reset_confirm_title">確定要立即重設?</string>
|
||||||
<string name="settings_reset_done">所有設定已還原為預設值</string>
|
<string name="settings_reset_done">所有設定已還原為預設值</string>
|
||||||
<string name="settings_sensor_bluetooth">藍牙</string>
|
<string name="settings_sensor_bluetooth">藍牙</string>
|
||||||
<string name="settings_stats_coordinate">緯度/經度</string>
|
|
||||||
<string name="settings_stats_rate_title">偏好速率</string>
|
<string name="settings_stats_rate_title">偏好速率</string>
|
||||||
<string name="settings_stats_units_imperial">英制 (英里、英尺)</string>
|
<string name="settings_stats_units_imperial">英制 (英里、英尺)</string>
|
||||||
<string name="settings_stats_units_metric">公制 (公里、公尺)</string>
|
<string name="settings_stats_units_metric">公制 (公里、公尺)</string>
|
||||||
|
|||||||
@@ -175,7 +175,6 @@
|
|||||||
<string name="settings_reset_confirm_title">確定要立即重設?</string>
|
<string name="settings_reset_confirm_title">確定要立即重設?</string>
|
||||||
<string name="settings_reset_done">所有設定已還原為預設值</string>
|
<string name="settings_reset_done">所有設定已還原為預設值</string>
|
||||||
<string name="settings_sensor_bluetooth">藍牙</string>
|
<string name="settings_sensor_bluetooth">藍牙</string>
|
||||||
<string name="settings_stats_coordinate">緯度/經度</string>
|
|
||||||
<string name="settings_stats_rate_title">偏好速率</string>
|
<string name="settings_stats_rate_title">偏好速率</string>
|
||||||
<string name="settings_stats_units_imperial">英制 (英里、英尺)</string>
|
<string name="settings_stats_units_imperial">英制 (英里、英尺)</string>
|
||||||
<string name="settings_stats_units_metric">公制 (公里、公尺)</string>
|
<string name="settings_stats_units_metric">公制 (公里、公尺)</string>
|
||||||
|
|||||||
@@ -227,7 +227,6 @@ limitations under the License.
|
|||||||
<string name="settings_sensor_bluetooth">蓝牙</string>
|
<string name="settings_sensor_bluetooth">蓝牙</string>
|
||||||
<string name="settings_sensor_wheel_circumference">车轮周长 (mm)</string>
|
<string name="settings_sensor_wheel_circumference">车轮周长 (mm)</string>
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">纬度/经度</string>
|
|
||||||
<string name="settings_stats_rate_title">首选速率</string>
|
<string name="settings_stats_rate_title">首选速率</string>
|
||||||
<string name="settings_stats_units_imperial">英制(英里、英尺)</string>
|
<string name="settings_stats_units_imperial">英制(英里、英尺)</string>
|
||||||
<string name="settings_stats_units_metric">公制(公里、米)</string>
|
<string name="settings_stats_units_metric">公制(公里、米)</string>
|
||||||
|
|||||||
@@ -1,12 +1,6 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
<resources>
|
<resources>
|
||||||
<!-- Do not translate anything in this file directly. -->
|
<!-- Do not translate anything in this file directly. -->
|
||||||
<string name="stats_show_coordinate_key" translatable="false">statsShowCoordinate</string>
|
|
||||||
<bool name="stats_show_coordinate_default" translatable="false">true</bool>
|
|
||||||
|
|
||||||
<string name="stats_show_grade_altitude_key" translatable="false">statsShowGradeElevation</string>
|
|
||||||
<bool name="stats_show_altitude_default" translatable="false">true</bool>
|
|
||||||
|
|
||||||
<string name="stats_show_on_lockscreen_while_recording_key" translatable="false">trackdetail_show_on_lockscreen_while_recording</string>
|
<string name="stats_show_on_lockscreen_while_recording_key" translatable="false">trackdetail_show_on_lockscreen_while_recording</string>
|
||||||
<bool name="stats_show_on_lockscreen_while_recording_default" translatable="false">false</bool>
|
<bool name="stats_show_on_lockscreen_while_recording_default" translatable="false">false</bool>
|
||||||
|
|
||||||
@@ -17,6 +11,7 @@
|
|||||||
<bool name="stats_fullscreen_while_recording_default" translatable="false">false</bool>
|
<bool name="stats_fullscreen_while_recording_default" translatable="false">false</bool>
|
||||||
|
|
||||||
<string name="settings_reset_key" translatable="false">settingsReset</string>
|
<string name="settings_reset_key" translatable="false">settingsReset</string>
|
||||||
|
<string name="settings_layout_reset_key" translatable="false">settingsLayoutReset</string>
|
||||||
|
|
||||||
<string name="settings_sensor_bluetooth_heart_rate_key" translatable="false">bluetoothSensor</string>
|
<string name="settings_sensor_bluetooth_heart_rate_key" translatable="false">bluetoothSensor</string>
|
||||||
<string name="settings_sensor_bluetooth_cycling_cadence_key" translatable="false">bluetoothCyclingCadenceSensor</string>
|
<string name="settings_sensor_bluetooth_cycling_cadence_key" translatable="false">bluetoothCyclingCadenceSensor</string>
|
||||||
@@ -278,4 +273,130 @@
|
|||||||
<item>@string/settings_night_mode_option_day</item>
|
<item>@string/settings_night_mode_option_day</item>
|
||||||
<item>@string/settings_night_mode_option_night</item>
|
<item>@string/settings_night_mode_option_night</item>
|
||||||
</string-array>
|
</string-array>
|
||||||
</resources>
|
|
||||||
|
<!-- Stats layout customization -->
|
||||||
|
<string name="stats_custom_layout_key" translatable="false">statsCustomLayoutKey</string>
|
||||||
|
|
||||||
|
<!-- Stats layout customization: number of columns per row -->
|
||||||
|
<string name="stats_custom_layout_columns_key" translatable="false">statsCustomLayoutColumnsKey</string>
|
||||||
|
<integer name="stats_custom_layout_columns_default" translatable="false">2</integer>
|
||||||
|
|
||||||
|
<!-- Stats layout customization: key -->
|
||||||
|
<string name="stats_custom_layout_fields_key" translatable="false">statsCustomLayoutFieldsKey</string>
|
||||||
|
<!-- Stats keys -->
|
||||||
|
<string name="stats_custom_layout_distance_key" translatable="false">distance</string>
|
||||||
|
<string name="stats_custom_layout_total_time_key" translatable="false">total_time</string>
|
||||||
|
<string name="stats_custom_layout_speed_key" translatable="false">speed</string>
|
||||||
|
<string name="stats_custom_layout_moving_time_key" translatable="false">moving_time</string>
|
||||||
|
<string name="stats_custom_layout_average_speed_key" translatable="false">average_speed</string>
|
||||||
|
<string name="stats_custom_layout_max_speed_key" translatable="false">max_speed</string>
|
||||||
|
<string name="stats_custom_layout_average_moving_speed_key" translatable="false">average_moving_speed</string>
|
||||||
|
<string name="stats_custom_layout_altitude_key" translatable="false">altitude</string>
|
||||||
|
<string name="stats_custom_layout_gain_key" translatable="false">gain</string>
|
||||||
|
<string name="stats_custom_layout_loss_key" translatable="false">loss</string>
|
||||||
|
<string name="stats_custom_layout_pace_key" translatable="false">pace</string>
|
||||||
|
<string name="stats_custom_layout_average_moving_pace_key" translatable="false">average_moving_pace</string>
|
||||||
|
<string name="stats_custom_layout_average_pace_key" translatable="false">average_pace</string>
|
||||||
|
<string name="stats_custom_layout_fastest_pace_key" translatable="false">fastest_pace</string>
|
||||||
|
<string name="stats_custom_layout_coordinates_key" translatable="false">coordinates</string>
|
||||||
|
<string name="stats_custom_layout_heart_rate_key" translatable="false">heart_rate</string>
|
||||||
|
<string name="stats_custom_layout_average_heart_rate_key" translatable="false">average_heart_rate</string>
|
||||||
|
<string name="stats_custom_layout_cadence_key" translatable="false">cadence</string>
|
||||||
|
<string name="stats_custom_layout_average_cadence_key" translatable="false">average_cadence</string>
|
||||||
|
<string name="stats_custom_layout_power_key" translatable="false">power</string>
|
||||||
|
<!--
|
||||||
|
Default dataFields for stats layout customization in a set of arrays.
|
||||||
|
Every array has two items:
|
||||||
|
- Key value for the dataField.
|
||||||
|
- Comma separated flags for: visible, primary and span/wide for the dataField.
|
||||||
|
-->
|
||||||
|
<string name="stats_custom_layout_fields_default_value_separator" translatable="false">_</string>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_0">
|
||||||
|
<item>@string/stats_custom_layout_distance_key</item>
|
||||||
|
<item>1,1,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_1">
|
||||||
|
<item>@string/stats_custom_layout_total_time_key</item>
|
||||||
|
<item>1,1,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_2">
|
||||||
|
<item>@string/stats_custom_layout_speed_key</item>
|
||||||
|
<item>1,1,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_3">
|
||||||
|
<item>@string/stats_custom_layout_moving_time_key</item>
|
||||||
|
<item>1,1,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_4">
|
||||||
|
<item>@string/stats_custom_layout_average_speed_key</item>
|
||||||
|
<item>1,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_5">
|
||||||
|
<item>@string/stats_custom_layout_max_speed_key</item>
|
||||||
|
<item>1,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_6">
|
||||||
|
<item>@string/stats_custom_layout_average_moving_speed_key</item>
|
||||||
|
<item>1,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_7">
|
||||||
|
<item>@string/stats_custom_layout_altitude_key</item>
|
||||||
|
<item>1,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_8">
|
||||||
|
<item>@string/stats_custom_layout_gain_key</item>
|
||||||
|
<item>1,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_9">
|
||||||
|
<item>@string/stats_custom_layout_loss_key</item>
|
||||||
|
<item>1,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_10">
|
||||||
|
<item>@string/stats_custom_layout_pace_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_11">
|
||||||
|
<item>@string/stats_custom_layout_average_moving_pace_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_12">
|
||||||
|
<item>@string/stats_custom_layout_average_pace_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_13">
|
||||||
|
<item>@string/stats_custom_layout_fastest_pace_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_14">
|
||||||
|
<item>@string/stats_custom_layout_coordinates_key</item>
|
||||||
|
<item>0,0,1</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_15">
|
||||||
|
<item>@string/stats_custom_layout_heart_rate_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_16">
|
||||||
|
<item>@string/stats_custom_layout_cadence_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
<string-array name="stats_custom_layout_fields_default_value_17">
|
||||||
|
<item>@string/stats_custom_layout_power_key</item>
|
||||||
|
<item>0,0,0</item>
|
||||||
|
</string-array>
|
||||||
|
|
||||||
|
<!-- Stats empty values -->
|
||||||
|
<string name="stats_empty_value_integer" translatable="false">0</string>
|
||||||
|
<string name="stats_empty_value_float" translatable="false">0.0</string>
|
||||||
|
<string name="stats_empty_value_time" translatable="false">00:00</string>
|
||||||
|
<string name="stats_empty_value_coordinates" translatable="false">0.0, 0.0</string>
|
||||||
|
|
||||||
|
<!-- Statistics dataFields: columns per row -->
|
||||||
|
<integer-array name="stats_custom_layout_fields_columns_per_row">
|
||||||
|
<item>1</item>
|
||||||
|
<item>2</item>
|
||||||
|
<item>3</item>
|
||||||
|
</integer-array>
|
||||||
|
|
||||||
|
<string name="prefs_last_version_key" translatable="false">lastVersionKey</string>
|
||||||
|
|
||||||
|
</resources>
|
||||||
|
|||||||
@@ -44,6 +44,12 @@
|
|||||||
true
|
true
|
||||||
</bool>
|
</bool>
|
||||||
|
|
||||||
|
<string name="stats_show_coordinate_key" translatable="false">statsShowCoordinate</string>
|
||||||
|
<bool name="stats_show_coordinate_default" translatable="false">true</bool>
|
||||||
|
|
||||||
|
<string name="stats_show_grade_altitude_key" translatable="false">statsShowGradeElevation</string>
|
||||||
|
<bool name="stats_show_altitude_default" translatable="false">true</bool>
|
||||||
|
|
||||||
<!-- <string name="auto_resume_track_timeout_key" translatable="false">autoResumeTrackTimeout</string>-->
|
<!-- <string name="auto_resume_track_timeout_key" translatable="false">autoResumeTrackTimeout</string>-->
|
||||||
<!-- <string name="auto_resume_track_timeout_default" translatable="false">10</string>-->
|
<!-- <string name="auto_resume_track_timeout_default" translatable="false">10</string>-->
|
||||||
<!-- <string name="auto_resume_track_timeout_always" translatable="false">-1</string>-->
|
<!-- <string name="auto_resume_track_timeout_always" translatable="false">-1</string>-->
|
||||||
|
|||||||
@@ -196,6 +196,8 @@ limitations under the License.
|
|||||||
<string name="description_time">Time</string>
|
<string name="description_time">Time</string>
|
||||||
<string name="description_total_distance">Total distance: %1$.2f km (%2$.1f mi)</string>
|
<string name="description_total_distance">Total distance: %1$.2f km (%2$.1f mi)</string>
|
||||||
<string name="description_total_time">Total time: %1$s</string>
|
<string name="description_total_time">Total time: %1$s</string>
|
||||||
|
<string name="description_speed_source_sensor">Sensor: %1$s</string>
|
||||||
|
<string name="description_speed_source_gps">GPS</string>
|
||||||
<!-- Export -->
|
<!-- Export -->
|
||||||
<string name="export_with_photos">with photos</string>
|
<string name="export_with_photos">with photos</string>
|
||||||
<string name="export_without_photos">without photos</string>
|
<string name="export_without_photos">without photos</string>
|
||||||
@@ -236,6 +238,7 @@ limitations under the License.
|
|||||||
</plurals>
|
</plurals>
|
||||||
<string name="generic_completed">Completed</string>
|
<string name="generic_completed">Completed</string>
|
||||||
<string name="generic_click_twice_cancel">Click back again to cancel</string>
|
<string name="generic_click_twice_cancel">Click back again to cancel</string>
|
||||||
|
<string name="generic_choose_an_option">Choose an option</string>
|
||||||
<!-- Gps -->
|
<!-- Gps -->
|
||||||
<string name="gps_starting">Starting GPS</string>
|
<string name="gps_starting">Starting GPS</string>
|
||||||
<string name="gps_wait_for_better_signal">Waiting for a better GPS signal</string>
|
<string name="gps_wait_for_better_signal">Waiting for a better GPS signal</string>
|
||||||
@@ -332,6 +335,8 @@ limitations under the License.
|
|||||||
<string name="settings_chart_by_distance">By distance</string>
|
<string name="settings_chart_by_distance">By distance</string>
|
||||||
<string name="settings_chart_by_time">By time</string>
|
<string name="settings_chart_by_time">By time</string>
|
||||||
<!-- Settings Recording -->
|
<!-- Settings Recording -->
|
||||||
|
<string name="settings_recording_customize_layout_title">Customize your recording layout</string>
|
||||||
|
<string name="settings_recording_customize_layout_select_columns">Data fields per row</string>
|
||||||
<string name="settings_recording_show_on_lockscreen_while_recording_title">Show statistics on lockscreen</string>
|
<string name="settings_recording_show_on_lockscreen_while_recording_title">Show statistics on lockscreen</string>
|
||||||
<string name="settings_recording_show_on_lockscreen_while_recording_summary">While recording, show statistics without unlocking the device.</string>
|
<string name="settings_recording_show_on_lockscreen_while_recording_summary">While recording, show statistics without unlocking the device.</string>
|
||||||
<string name="settings_recording_keep_screen_on_while_recording_title">Keep screen on</string>
|
<string name="settings_recording_keep_screen_on_while_recording_title">Keep screen on</string>
|
||||||
@@ -356,8 +361,15 @@ limitations under the License.
|
|||||||
<string name="settings_night_mode_option_day">Day</string>
|
<string name="settings_night_mode_option_day">Day</string>
|
||||||
<string name="settings_night_mode_option_night">Night</string>
|
<string name="settings_night_mode_option_night">Night</string>
|
||||||
|
|
||||||
<!-- Settings Reset -->
|
<!-- Reset -->
|
||||||
<string name="settings_reset">Reset</string>
|
<string name="settings_reset">Reset</string>
|
||||||
|
<!-- Custom Layout Reset -->
|
||||||
|
<string name="settings_layout_reset">Reset Custom Layout</string>
|
||||||
|
<string name="settings_layout_reset_confirm_message">All layout settings will be reverted to the default values. This will not delete any tracks on the device.</string>
|
||||||
|
<string name="settings_layout_reset_confirm_title">Reset your layouts?</string>
|
||||||
|
<string name="settings_layout_reset_done">All layout settings have been reverted to the default values</string>
|
||||||
|
<!-- Settings Reset -->
|
||||||
|
<string name="settings_all_reset">Reset All Settings</string>
|
||||||
<string name="settings_reset_confirm_message">All settings will be reverted to the default values. This will not delete any tracks on the device.</string>
|
<string name="settings_reset_confirm_message">All settings will be reverted to the default values. This will not delete any tracks on the device.</string>
|
||||||
<string name="settings_reset_confirm_title">Reset now?</string>
|
<string name="settings_reset_confirm_title">Reset now?</string>
|
||||||
<string name="settings_reset_done">All settings have been reverted to the default values</string>
|
<string name="settings_reset_done">All settings have been reverted to the default values</string>
|
||||||
@@ -373,7 +385,6 @@ limitations under the License.
|
|||||||
<string name="settings_sensor_wheel_circumference">Wheel circumference (mm)</string>
|
<string name="settings_sensor_wheel_circumference">Wheel circumference (mm)</string>
|
||||||
|
|
||||||
<!-- Settings Stats -->
|
<!-- Settings Stats -->
|
||||||
<string name="settings_stats_coordinate">Latitude/Longitude</string>
|
|
||||||
<string name="settings_stats_rate_title">Preferred rate</string>
|
<string name="settings_stats_rate_title">Preferred rate</string>
|
||||||
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
||||||
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
<string name="settings_stats_units_metric">Metric (km, m)</string>
|
||||||
@@ -392,6 +403,7 @@ limitations under the License.
|
|||||||
<string name="stats_fastest_pace">Fastest pace</string>
|
<string name="stats_fastest_pace">Fastest pace</string>
|
||||||
<string name="stats_gain">Gain</string>
|
<string name="stats_gain">Gain</string>
|
||||||
<string name="stats_loss">Loss</string>
|
<string name="stats_loss">Loss</string>
|
||||||
|
<string name="stats_coordinates">Latitude/Longitude</string>
|
||||||
<string name="stats_latitude">Latitude</string>
|
<string name="stats_latitude">Latitude</string>
|
||||||
<string name="stats_longitude">Longitude</string>
|
<string name="stats_longitude">Longitude</string>
|
||||||
<string name="stats_max_speed">Max speed</string>
|
<string name="stats_max_speed">Max speed</string>
|
||||||
@@ -401,6 +413,9 @@ limitations under the License.
|
|||||||
<string name="stats_distance">Distance</string>
|
<string name="stats_distance">Distance</string>
|
||||||
<string name="stats_total_time">Total time</string>
|
<string name="stats_total_time">Total time</string>
|
||||||
<string name="stats_split_interval">Split interval</string>
|
<string name="stats_split_interval">Split interval</string>
|
||||||
|
<string name="stats_sensors_heart_rate">Heart Rate</string>
|
||||||
|
<string name="stats_sensors_cadence">Cadence</string>
|
||||||
|
<string name="stats_sensors_power">Power</string>
|
||||||
<!-- Track -->
|
<!-- Track -->
|
||||||
<string name="track_name_format">Track %1$d</string>
|
<string name="track_name_format">Track %1$d</string>
|
||||||
<string name="track_recording_notification_accuracy">Location accuracy: %1$s</string>
|
<string name="track_recording_notification_accuracy">Location accuracy: %1$s</string>
|
||||||
@@ -436,6 +451,9 @@ limitations under the License.
|
|||||||
<string name="unit_mile_per_hour">mph</string>
|
<string name="unit_mile_per_hour">mph</string>
|
||||||
<string name="unit_minute_per_kilometer">min/km</string>
|
<string name="unit_minute_per_kilometer">min/km</string>
|
||||||
<string name="unit_minute_per_mile">min/mi</string>
|
<string name="unit_minute_per_mile">min/mi</string>
|
||||||
|
<!-- Location Coordinates -->
|
||||||
|
<string name="location_coordinate">%1$s°</string>
|
||||||
|
<string name="location_latitude_longitude">%1$s, %2$s</string>
|
||||||
<!-- Value -->
|
<!-- Value -->
|
||||||
<string name="value_adapt_accuracy">Adapt for accuracy</string>
|
<string name="value_adapt_accuracy">Adapt for accuracy</string>
|
||||||
<string name="value_adapt_battery_life">Adapt for battery life</string>
|
<string name="value_adapt_battery_life">Adapt for battery life</string>
|
||||||
@@ -553,4 +571,9 @@ limitations under the License.
|
|||||||
<string name="instant_export_enabled_title">Instant post-workout export</string>
|
<string name="instant_export_enabled_title">Instant post-workout export</string>
|
||||||
|
|
||||||
<string name="settings_default_export_uri_title">Track export directory</string>
|
<string name="settings_default_export_uri_title">Track export directory</string>
|
||||||
|
<string name="title_activity_settings_custom_layout">Customize Recording Layout</string>
|
||||||
|
<!-- Fields -->
|
||||||
|
<string name="field_set_primary">Primary</string>
|
||||||
|
<string name="field_set_secondary">Secondary</string>
|
||||||
|
<string name="field_remove_from_layout">Remove</string>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -100,12 +100,16 @@ limitations under the License.
|
|||||||
</style>
|
</style>
|
||||||
<!-- sensor state value -->
|
<!-- sensor state value -->
|
||||||
<!-- stats horizontal line -->
|
<!-- stats horizontal line -->
|
||||||
<style name="StatsHorizontalLine">
|
<style name="HorizontalLine">
|
||||||
<item name="android:background">@color/stats_separator</item>
|
<item name="android:background">@color/stats_separator</item>
|
||||||
<item name="android:layout_height">1dp</item>
|
<item name="android:layout_height">1dp</item>
|
||||||
<item name="android:layout_margin">8dp</item>
|
<item name="android:layout_marginTop">8dp</item>
|
||||||
|
<item name="android:layout_marginBottom">8dp</item>
|
||||||
<item name="android:layout_width">match_parent</item>
|
<item name="android:layout_width">match_parent</item>
|
||||||
</style>
|
</style>
|
||||||
|
<style name="StatsHorizontalLine" parent="HorizontalLine">
|
||||||
|
<item name="android:layout_margin">8dp</item>
|
||||||
|
</style>
|
||||||
<!-- stats large item container -->
|
<!-- stats large item container -->
|
||||||
<style name="StatsLargeItemContainer">
|
<style name="StatsLargeItemContainer">
|
||||||
<item name="android:layout_gravity">center</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
@@ -121,6 +125,7 @@ limitations under the License.
|
|||||||
<item name="android:textAllCaps">true</item>
|
<item name="android:textAllCaps">true</item>
|
||||||
<item name="android:textColor">?attr/colorAccent</item>
|
<item name="android:textColor">?attr/colorAccent</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
|
<item name="android:layout_marginTop">8dp</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="IntervalLabel" parent="@style/LargeLabel">
|
<style name="IntervalLabel" parent="@style/LargeLabel">
|
||||||
@@ -133,26 +138,54 @@ limitations under the License.
|
|||||||
<item name="android:layout_gravity">center</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="StatsLargeLabel" parent="@style/LargeLabel">
|
<style name="StatsPrimaryLabel" parent="@style/TextMicro">
|
||||||
<item name="android:gravity">center</item>
|
<item name="android:gravity">center</item>
|
||||||
<item name="android:layout_gravity">center</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:singleLine">false</item>
|
<item name="android:singleLine">false</item>
|
||||||
<item name="android:textAllCaps">true</item>
|
<item name="android:textAllCaps">true</item>
|
||||||
<item name="android:textColor">?attr/colorAccent</item>
|
<item name="android:textColor">?attr/colorAccent</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:paddingLeft">4dp</item>
|
||||||
|
<item name="android:paddingRight">4dp</item>
|
||||||
|
<item name="android:layout_marginTop">8dp</item>
|
||||||
|
<item name="android:textStyle">normal</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="StatsSecondaryLabel" parent="@style/TextMicro">
|
||||||
|
<item name="android:gravity">center</item>
|
||||||
|
<item name="android:layout_gravity">center</item>
|
||||||
|
<item name="android:singleLine">false</item>
|
||||||
|
<item name="android:textAllCaps">true</item>
|
||||||
<item name="android:paddingLeft">4dp</item>
|
<item name="android:paddingLeft">4dp</item>
|
||||||
<item name="android:paddingRight">4dp</item>
|
<item name="android:paddingRight">4dp</item>
|
||||||
<item name="android:layout_marginTop">16dp</item>
|
<item name="android:layout_marginTop">16dp</item>
|
||||||
|
<item name="android:textStyle">normal</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="StatsLargeValue" parent="@style/TextLarge">
|
<style name="StatsLabelHidden" parent="@style/StatsPrimaryLabel">
|
||||||
|
<item name="android:textColor">@android:color/secondary_text_dark</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="StatsPrimaryValue" parent="@style/TextLarge">
|
||||||
<item name="android:layout_gravity">center</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
<item name="android:layout_height">wrap_content</item>
|
<item name="android:layout_height">wrap_content</item>
|
||||||
<item name="android:layout_width">wrap_content</item>
|
<item name="android:layout_width">wrap_content</item>
|
||||||
<item name="android:singleLine">true</item>
|
<item name="android:singleLine">true</item>
|
||||||
<item name="android:textSize">32sp</item>
|
<item name="android:textSize">36sp</item>
|
||||||
<item name="android:textStyle">bold</item>
|
<item name="android:textStyle">bold</item>
|
||||||
</style>
|
</style>
|
||||||
|
|
||||||
|
<style name="StatsSecondaryValue" parent="@style/TextLarge">
|
||||||
|
<item name="android:layout_gravity">center</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="android:layout_width">wrap_content</item>
|
||||||
|
<item name="android:singleLine">true</item>
|
||||||
|
<item name="android:textSize">28sp</item>
|
||||||
|
<item name="android:textStyle">bold</item>
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style name="StatsValueHidden" parent="@style/StatsPrimaryValue">
|
||||||
|
<item name="android:textColor">@android:color/secondary_text_dark</item>
|
||||||
|
</style>
|
||||||
<!-- stats large value container -->
|
<!-- stats large value container -->
|
||||||
<style name="StatsLargeValueContainer">
|
<style name="StatsLargeValueContainer">
|
||||||
<item name="android:layout_gravity">center</item>
|
<item name="android:layout_gravity">center</item>
|
||||||
@@ -290,4 +323,14 @@ limitations under the License.
|
|||||||
</style>
|
</style>
|
||||||
|
|
||||||
<style name="ProgressBar" parent="@style/Widget.AppCompat.ProgressBar.Horizontal" />
|
<style name="ProgressBar" parent="@style/Widget.AppCompat.ProgressBar.Horizontal" />
|
||||||
|
|
||||||
|
<!-- Card View for stats -->
|
||||||
|
<style name="StatsCardView">
|
||||||
|
<item name="android:layout_width">match_parent</item>
|
||||||
|
<item name="android:layout_height">wrap_content</item>
|
||||||
|
<item name="cardElevation">1dp</item>
|
||||||
|
<item name="cardMaxElevation">1dp</item>
|
||||||
|
<item name="cardPreventCornerOverlap">true</item>
|
||||||
|
<item name="cardUseCompatPadding">true</item>
|
||||||
|
</style>
|
||||||
</resources>
|
</resources>
|
||||||
|
|||||||
@@ -43,14 +43,9 @@ limitations under the License.
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/settings_show">
|
<PreferenceCategory android:title="@string/settings_show">
|
||||||
<SwitchPreferenceCompat
|
<Preference
|
||||||
android:defaultValue="@bool/stats_show_altitude_default"
|
app:key="@string/stats_custom_layout_key"
|
||||||
android:key="@string/stats_show_grade_altitude_key"
|
app:title="@string/settings_recording_customize_layout_title" />
|
||||||
android:title="@string/stats_altitude" />
|
|
||||||
<SwitchPreferenceCompat
|
|
||||||
android:defaultValue="@bool/stats_show_coordinate_default"
|
|
||||||
android:key="@string/stats_show_coordinate_key"
|
|
||||||
android:title="@string/settings_stats_coordinate" />
|
|
||||||
<ListPreference
|
<ListPreference
|
||||||
android:defaultValue="@string/night_mode_default"
|
android:defaultValue="@string/night_mode_default"
|
||||||
android:entries="@array/night_mode_options"
|
android:entries="@array/night_mode_options"
|
||||||
@@ -193,6 +188,14 @@ limitations under the License.
|
|||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/settings_reset">
|
<PreferenceCategory android:title="@string/settings_reset">
|
||||||
|
<de.dennisguse.opentracks.settings.ResetDialogPreference
|
||||||
|
android:dialogMessage="@string/settings_layout_reset_confirm_message"
|
||||||
|
android:dialogTitle="@string/settings_layout_reset_confirm_title"
|
||||||
|
android:key="@string/settings_layout_reset_key"
|
||||||
|
android:negativeButtonText="@android:string/cancel"
|
||||||
|
android:persistent="false"
|
||||||
|
android:positiveButtonText="@android:string/ok"
|
||||||
|
android:title="@string/settings_layout_reset" />
|
||||||
<de.dennisguse.opentracks.settings.ResetDialogPreference
|
<de.dennisguse.opentracks.settings.ResetDialogPreference
|
||||||
android:dialogMessage="@string/settings_reset_confirm_message"
|
android:dialogMessage="@string/settings_reset_confirm_message"
|
||||||
android:dialogTitle="@string/settings_reset_confirm_title"
|
android:dialogTitle="@string/settings_reset_confirm_title"
|
||||||
@@ -200,7 +203,7 @@ limitations under the License.
|
|||||||
android:negativeButtonText="@android:string/cancel"
|
android:negativeButtonText="@android:string/cancel"
|
||||||
android:persistent="false"
|
android:persistent="false"
|
||||||
android:positiveButtonText="@android:string/ok"
|
android:positiveButtonText="@android:string/ok"
|
||||||
android:title="@string/settings_reset" />
|
android:title="@string/settings_all_reset" />
|
||||||
</PreferenceCategory>
|
</PreferenceCategory>
|
||||||
|
|
||||||
<PreferenceCategory android:title="@string/about_preference_title">
|
<PreferenceCategory android:title="@string/about_preference_title">
|
||||||
|
|||||||
Reference in New Issue
Block a user