forked from upstream-mirrors/OpenTracks
Merge pull request #1427 from OpenTracksApp/heartrate#1118
Heartrate zones
This commit is contained in:
-76
@@ -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<TrackListActivity> 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));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -385,10 +385,6 @@ public class TrackPoint {
|
||||
return this;
|
||||
}
|
||||
|
||||
public boolean hasSensorData() {
|
||||
return hasHeartRate() || hasCadence() || hasPower();
|
||||
}
|
||||
|
||||
public boolean hasHeartRate() {
|
||||
return heartRate != null;
|
||||
}
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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<St
|
||||
valueAndUnit = StringUtils.getHeartRateParts(getContext(), null);
|
||||
}
|
||||
|
||||
//TODO Loads preference every time
|
||||
HeartRateZones zones = PreferencesUtils.getHeartRateZones();
|
||||
int textColor;
|
||||
if (sensorDataSet != null) {
|
||||
textColor = zones.getColorForZone(sensorDataSet.getHeartRate().first);
|
||||
} else {
|
||||
textColor = zones.getColorForZone(null);
|
||||
}
|
||||
|
||||
getBinding().statsValue.setText(valueAndUnit.first);
|
||||
getBinding().statsUnit.setText(valueAndUnit.second);
|
||||
getBinding().statsDescriptionMain.setText(R.string.stats_sensors_heart_rate);
|
||||
|
||||
getBinding().statsDescriptionSecondary.setVisibility(View.VISIBLE);
|
||||
getBinding().statsDescriptionSecondary.setText(sensorName);
|
||||
|
||||
getBinding().statsValue.setTextColor(ContextCompat.getColor(getContext(), textColor));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -294,6 +312,8 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
|
||||
getBinding().statsValue.setText(valueAndUnit.first);
|
||||
getBinding().statsUnit.setText(valueAndUnit.second);
|
||||
getBinding().statsDescriptionMain.setText(R.string.stats_sensors_cadence);
|
||||
|
||||
getBinding().statsDescriptionSecondary.setVisibility(View.VISIBLE);
|
||||
getBinding().statsDescriptionSecondary.setText(sensorName);
|
||||
}
|
||||
}
|
||||
@@ -316,6 +336,8 @@ public abstract class GenericStatisticsViewHolder extends StatisticViewHolder<St
|
||||
getBinding().statsValue.setText(valueAndUnit.first);
|
||||
getBinding().statsUnit.setText(valueAndUnit.second);
|
||||
getBinding().statsDescriptionMain.setText(R.string.stats_sensors_power);
|
||||
|
||||
getBinding().statsDescriptionSecondary.setVisibility(View.VISIBLE);
|
||||
getBinding().statsDescriptionSecondary.setText(sensorName);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,4 +57,9 @@ limitations under the License.
|
||||
|
||||
<color name="splashscreen_background">#272727</color>
|
||||
|
||||
<color name="heart_rate_zone_textcolor_5">#FF0000</color>
|
||||
<color name="heart_rate_zone_textcolor_4">#FFBD04</color>
|
||||
<color name="heart_rate_zone_textcolor_3">#6ACC2B</color>
|
||||
<color name="heart_rate_zone_textcolor_2">#64D1FD</color>
|
||||
<color name="heart_rate_zone_textcolor_1">@color/opentracks_on_primary_color</color>
|
||||
</resources>
|
||||
@@ -44,6 +44,9 @@
|
||||
true
|
||||
</bool>
|
||||
|
||||
<string name="settings_sensor_heart_rate_max_key" translatable="false">maxHeartRate</string>
|
||||
<string name="settings_sensor_heart_rate_max_default" translatable="false">220</string>
|
||||
|
||||
<string name="show_on_map_format_key" translatable="false">showOnMapFormatKey</string>
|
||||
|
||||
<string name="total_rows_deleted_key" translatable="false">totalRowsDeletedKey</string>
|
||||
|
||||
@@ -434,6 +434,8 @@ limitations under the License.
|
||||
<string name="settings_sensor_wheel_circumference">Wheel Circumference (mm)</string>
|
||||
<string name="settings_sensor_bluetooth_service_filter_enabled">Only show Bluetooth devices that announce required services</string>
|
||||
|
||||
<string name="settings_sensor_heart_rate_max">Zones: maximum Heart rate (bpm)</string>
|
||||
|
||||
<!-- Settings Stats -->
|
||||
<string name="settings_stats_rate_title">Preferred rate</string>
|
||||
<string name="settings_stats_units_imperial">Imperial (mi, ft)</string>
|
||||
@@ -479,7 +481,7 @@ limitations under the License.
|
||||
<string name="stats_distance">Distance</string>
|
||||
<string name="stats_total_time">Total time</string>
|
||||
<string name="stats_split_interval">Split interval</string>
|
||||
<string name="stats_sensors_heart_rate">Heart Rate</string>
|
||||
<string name="stats_sensors_heart_rate">Heart rate</string>
|
||||
<string name="stats_sensors_cadence">Cadence</string>
|
||||
<string name="stats_sensors_power">Power</string>
|
||||
<string name="stats_clock">Clock</string>
|
||||
|
||||
@@ -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" />
|
||||
<EditTextPreference
|
||||
android:defaultValue="@string/settings_sensor_heart_rate_max_default"
|
||||
android:inputType="number"
|
||||
android:key="@string/settings_sensor_heart_rate_max_key"
|
||||
android:title="@string/settings_sensor_heart_rate_max"
|
||||
app:useSimpleSummaryProvider="true" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory android:title="@string/settings_cycling_sensor">
|
||||
|
||||
Reference in New Issue
Block a user