diff --git a/src/androidTest/java/de/dennisguse/opentracks/ui/customRecordingLayout/EspressoCustomRecordingLayoutTest.java b/src/androidTest/java/de/dennisguse/opentracks/ui/customRecordingLayout/EspressoCustomRecordingLayoutTest.java deleted file mode 100644 index 1a0317334..000000000 --- a/src/androidTest/java/de/dennisguse/opentracks/ui/customRecordingLayout/EspressoCustomRecordingLayoutTest.java +++ /dev/null @@ -1,76 +0,0 @@ -package de.dennisguse.opentracks.ui.customRecordingLayout; - - -import static androidx.test.espresso.Espresso.onView; -import static androidx.test.espresso.action.ViewActions.click; -import static androidx.test.espresso.action.ViewActions.longClick; -import static androidx.test.espresso.matcher.ViewMatchers.assertThat; -import static androidx.test.espresso.matcher.ViewMatchers.withId; -import static org.hamcrest.CoreMatchers.is; - -import android.view.View; - -import androidx.recyclerview.widget.RecyclerView; -import androidx.test.espresso.NoMatchingViewException; -import androidx.test.espresso.ViewAssertion; -import androidx.test.espresso.ViewInteraction; -import androidx.test.espresso.matcher.ViewMatchers; -import androidx.test.ext.junit.rules.ActivityScenarioRule; -import androidx.test.ext.junit.runners.AndroidJUnit4; -import androidx.test.filters.LargeTest; -import androidx.test.rule.GrantPermissionRule; - -import org.junit.Rule; -import org.junit.Test; -import org.junit.runner.RunWith; - -import de.dennisguse.opentracks.R; -import de.dennisguse.opentracks.TrackListActivity; -import de.dennisguse.opentracks.settings.PreferencesUtils; - -@LargeTest -@RunWith(AndroidJUnit4.class) -public class EspressoCustomRecordingLayoutTest { - - @Rule - public ActivityScenarioRule mActivityTestRule = new ActivityScenarioRule<>(TrackListActivity.class); - - @Rule - public GrantPermissionRule mGrantPermissionRule = GrantPermissionRule.grant(android.Manifest.permission.ACCESS_FINE_LOCATION); - - @Test - public void customLayoutTest() { - // TrackListActivity: start recording - ViewInteraction trackControllerRecordButton = onView(ViewMatchers.withId(R.id.track_list_fab_action)); - trackControllerRecordButton.perform(click()); - - // Get custom layout preferences and check all data fields are showed. - RecordingLayout recordingLayout = PreferencesUtils.getCustomLayout(); - - onView(withId(R.id.recycler_view)).check(new RecyclerViewItemCountAssertion((int) recordingLayout.getFields().stream().filter(DataField::isVisible).count())); - - // stop recording - ViewInteraction trackControllerStopButton = onView(withId(R.id.track_recording_fab_action)); - trackControllerStopButton.perform(longClick()); - } - - 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)); - } - } - -} diff --git a/src/main/java/de/dennisguse/opentracks/data/models/HeartRateZones.java b/src/main/java/de/dennisguse/opentracks/data/models/HeartRateZones.java new file mode 100644 index 000000000..3fe04de03 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/data/models/HeartRateZones.java @@ -0,0 +1,33 @@ +package de.dennisguse.opentracks.data.models; + +import androidx.annotation.NonNull; + +import de.dennisguse.opentracks.R; + +public class HeartRateZones { + + private final HeartRate max; + + public HeartRateZones(@NonNull HeartRate max) { + this.max = max; + } + + public int getColorForZone(HeartRate current) { + if (current != null) { + if (current.getBPM() >= max.getBPM() * 0.9) { + return R.color.heart_rate_zone_textcolor_5; + } + if (current.getBPM() >= max.getBPM() * 0.8) { + return R.color.heart_rate_zone_textcolor_4; + } + if (current.getBPM() >= max.getBPM() * 0.7) { + return R.color.heart_rate_zone_textcolor_3; + } + if (current.getBPM() >= max.getBPM() * 0.6) { + return R.color.heart_rate_zone_textcolor_2; + } + } + + return R.color.heart_rate_zone_textcolor_1; + } +} diff --git a/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java b/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java index 883818e7e..f7f42d54a 100644 --- a/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java +++ b/src/main/java/de/dennisguse/opentracks/data/models/TrackPoint.java @@ -385,10 +385,6 @@ public class TrackPoint { return this; } - public boolean hasSensorData() { - return hasHeartRate() || hasCadence() || hasPower(); - } - public boolean hasHeartRate() { return heartRate != null; } diff --git a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java index 2b8a6e426..d6335d252 100644 --- a/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java +++ b/src/main/java/de/dennisguse/opentracks/settings/PreferencesUtils.java @@ -42,6 +42,8 @@ import java.util.stream.Stream; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.Distance; import de.dennisguse.opentracks.data.models.DistanceFormatter; +import de.dennisguse.opentracks.data.models.HeartRate; +import de.dennisguse.opentracks.data.models.HeartRateZones; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.io.file.TrackFileFormat; import de.dennisguse.opentracks.io.file.TrackFilenameGenerator; @@ -279,6 +281,12 @@ public class PreferencesUtils { return getBoolean(R.string.settings_sensor_bluetooth_service_filter_enabled_key, DEFAULT); } + public static HeartRateZones getHeartRateZones() { + final int DEFAULT = Integer.parseInt(resources.getString(R.string.settings_sensor_heart_rate_max_default)); + int value = getInt(R.string.settings_sensor_heart_rate_max_key, DEFAULT); + return new HeartRateZones(HeartRate.of(value)); + } + public static boolean shouldShowStatsOnLockscreen() { final boolean STATS_SHOW_ON_LOCKSCREEN_DEFAULT = resources.getBoolean(R.bool.stats_show_on_lockscreen_while_recording_default); return getBoolean(R.string.stats_show_on_lockscreen_while_recording_key, STATS_SHOW_ON_LOCKSCREEN_DEFAULT); diff --git a/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java b/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java index 61e0354b9..050d802fa 100644 --- a/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java +++ b/src/main/java/de/dennisguse/opentracks/viewmodels/GenericStatisticsViewHolder.java @@ -2,15 +2,20 @@ package de.dennisguse.opentracks.viewmodels; import android.util.Pair; import android.view.LayoutInflater; +import android.view.View; + +import androidx.core.content.ContextCompat; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.data.models.DistanceFormatter; +import de.dennisguse.opentracks.data.models.HeartRateZones; import de.dennisguse.opentracks.data.models.Speed; import de.dennisguse.opentracks.data.models.SpeedFormatter; import de.dennisguse.opentracks.data.models.TrackPoint; import de.dennisguse.opentracks.databinding.StatsGenericItemBinding; import de.dennisguse.opentracks.sensors.sensorData.SensorDataSet; import de.dennisguse.opentracks.services.RecordingData; +import de.dennisguse.opentracks.settings.PreferencesUtils; import de.dennisguse.opentracks.settings.UnitSystem; import de.dennisguse.opentracks.ui.customRecordingLayout.DataField; import de.dennisguse.opentracks.util.StringUtils; @@ -269,10 +274,23 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder#272727 + #FF0000 + #FFBD04 + #6ACC2B + #64D1FD + @color/opentracks_on_primary_color \ No newline at end of file diff --git a/src/main/res/values/settings.xml b/src/main/res/values/settings.xml index 5b12fb8d1..b7e6abb86 100644 --- a/src/main/res/values/settings.xml +++ b/src/main/res/values/settings.xml @@ -44,6 +44,9 @@ true + maxHeartRate + 220 + showOnMapFormatKey totalRowsDeletedKey diff --git a/src/main/res/values/strings.xml b/src/main/res/values/strings.xml index 99549cc76..dec125e1d 100644 --- a/src/main/res/values/strings.xml +++ b/src/main/res/values/strings.xml @@ -434,6 +434,8 @@ limitations under the License. Wheel Circumference (mm) Only show Bluetooth devices that announce required services + Zones: maximum Heart rate (bpm) + Preferred rate Imperial (mi, ft) @@ -479,7 +481,7 @@ limitations under the License. Distance Total time Split interval - Heart Rate + Heart rate Cadence Power Clock diff --git a/src/main/res/xml/settings_sensors.xml b/src/main/res/xml/settings_sensors.xml index 23a4be516..1a8130066 100644 --- a/src/main/res/xml/settings_sensors.xml +++ b/src/main/res/xml/settings_sensors.xml @@ -9,6 +9,12 @@ android:defaultValue="@string/sensor_type_value_none" android:key="@string/settings_sensor_bluetooth_heart_rate_key" android:title="@string/sensor_state_heart_rate" /> +