mirror of
https://codeberg.org/OpenTracksApp/OpenTracks.git
synced 2026-10-02 17:43:06 +02:00
Add settings toggles for chart series
Adds toggles to the User Interface section of the app Settings that allow the user to display or hide the three series available in the chart: Elevation, Speed/Pace, and Heart Rate. As a user of a heart rate monitor primarily during strength workouts and combat sports, the distance and elevation graphs are not helpful to me - in addition, their scale means that I am not able to easily see my exact heart rate. This should allow users in a similar situation to better determine exactly what is most helpful for them to be seen on the graph. Also updates heart rate series possible intervals - the smallest interval was 25, which was too low for most zone 1 cardio charts - if your heart rate goes from 70 to 125, with a 25 interval, most of the chart will be whitespace.
This commit is contained in:
@@ -86,6 +86,7 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (PreferencesUtils.isKey(R.string.stats_rate_key, key)) {
|
||||
boolean reportSpeed = PreferencesUtils.isReportSpeed(activityTypeLocalized);
|
||||
if (reportSpeed != viewBinding.chartView.getReportSpeed()) {
|
||||
@@ -99,6 +100,21 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (PreferencesUtils.isKey(R.string.chart_display_elevation_key, key)) {
|
||||
viewBinding.chartView.setShowElevation(PreferencesUtils.shouldShowElevation());
|
||||
refreshChart();
|
||||
}
|
||||
|
||||
if (PreferencesUtils.isKey(R.string.chart_display_pace_or_speed_key, key)) {
|
||||
viewBinding.chartView.setShowPaceOrSpeed(PreferencesUtils.shouldShowPaceOrSpeed());
|
||||
refreshChart();
|
||||
}
|
||||
|
||||
if (PreferencesUtils.isKey(R.string.chart_display_heart_rate_key, key)) {
|
||||
viewBinding.chartView.setShowHeartRate(PreferencesUtils.shouldShowHeartRate());
|
||||
refreshChart();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -273,4 +289,13 @@ public class ChartFragment extends Fragment implements TrackDataHub.Listener {
|
||||
fragmentActivity.runOnUiThread(runnable);
|
||||
}
|
||||
}
|
||||
|
||||
private void refreshChart() {
|
||||
runOnUiThread(() -> {
|
||||
if (isResumed()) {
|
||||
viewBinding.chartView.invalidate();
|
||||
viewBinding.chartView.requestLayout();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -86,8 +86,10 @@ public class ChartView extends View {
|
||||
}
|
||||
|
||||
private final List<ChartValueSeries> seriesList = new LinkedList<>();
|
||||
private final ChartValueSeries elevationSeries;
|
||||
private final ChartValueSeries speedSeries;
|
||||
private final ChartValueSeries paceSeries;
|
||||
private final ChartValueSeries heartRateSeries;
|
||||
|
||||
private final LinkedList<ChartPoint> chartPoints = new LinkedList<>();
|
||||
private final List<Marker> markers = new LinkedList<>();
|
||||
@@ -123,6 +125,7 @@ public class ChartView extends View {
|
||||
private boolean chartByDistance = false;
|
||||
private UnitSystem unitSystem = UnitSystem.defaultUnitSystem();
|
||||
private boolean reportSpeed = true;
|
||||
private boolean showPaceOrSpeed = true;
|
||||
private boolean showPointer = false;
|
||||
|
||||
private final GestureDetectorCompat detectorScrollFlingTab = new GestureDetectorCompat(getContext(), new GestureDetector.SimpleOnGestureListener() {
|
||||
@@ -176,17 +179,17 @@ public class ChartView extends View {
|
||||
int fontSizeSmall = ThemeUtils.getFontSizeSmallInPx(context);
|
||||
int fontSizeMedium = ThemeUtils.getFontSizeMediumInPx(context);
|
||||
|
||||
seriesList.add(new ChartValueSeries(context,
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
new int[]{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000},
|
||||
R.string.description_altitude_metric,
|
||||
R.string.description_altitude_imperial,
|
||||
R.string.description_altitude_imperial,
|
||||
R.color.chart_altitude_fill,
|
||||
R.color.chart_altitude_border,
|
||||
fontSizeSmall,
|
||||
fontSizeMedium) {
|
||||
elevationSeries = new ChartValueSeries(context,
|
||||
Integer.MIN_VALUE,
|
||||
Integer.MAX_VALUE,
|
||||
new int[]{5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000},
|
||||
R.string.description_altitude_metric,
|
||||
R.string.description_altitude_imperial,
|
||||
R.string.description_altitude_imperial,
|
||||
R.color.chart_altitude_fill,
|
||||
R.color.chart_altitude_border,
|
||||
fontSizeSmall,
|
||||
fontSizeMedium) {
|
||||
@Override
|
||||
protected Double extractDataFromChartPoint(@NonNull ChartPoint chartPoint) {
|
||||
return chartPoint.altitude();
|
||||
@@ -196,7 +199,8 @@ public class ChartView extends View {
|
||||
protected boolean drawIfChartPointHasNoData() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
seriesList.add(elevationSeries);
|
||||
|
||||
speedSeries = new ChartValueSeries(context,
|
||||
0,
|
||||
@@ -244,10 +248,15 @@ public class ChartView extends View {
|
||||
};
|
||||
seriesList.add(paceSeries);
|
||||
|
||||
seriesList.add(new ChartValueSeries(context,
|
||||
heartRateSeries = new ChartValueSeries(context,
|
||||
0,
|
||||
Integer.MAX_VALUE,
|
||||
new int[]{25, 50},
|
||||
// For Zone 5 cardio, the 25 value should result in nice visuals, as the values
|
||||
// will range from ~70 - ~180 (around 4.5 intervals).
|
||||
// For Zone 1 cardio, the 15 value should result in nice visuals, as the values
|
||||
// will range from ~70 - ~120 (around 3.5 intervals)
|
||||
// The fallback of 50 should give appropriate visuals for values outside this range.
|
||||
new int[]{15, 25, 50},
|
||||
R.string.description_sensor_heart_rate,
|
||||
R.string.description_sensor_heart_rate,
|
||||
R.string.description_sensor_heart_rate,
|
||||
@@ -264,7 +273,8 @@ public class ChartView extends View {
|
||||
protected boolean drawIfChartPointHasNoData() {
|
||||
return false;
|
||||
}
|
||||
});
|
||||
};
|
||||
seriesList.add(heartRateSeries);
|
||||
|
||||
seriesList.add(new ChartValueSeries(context,
|
||||
0,
|
||||
@@ -343,9 +353,15 @@ public class ChartView extends View {
|
||||
setClickable(true);
|
||||
updateDimensions();
|
||||
|
||||
// either speedSeries or paceSeries should be enabled.
|
||||
speedSeries.setEnabled(reportSpeed);
|
||||
paceSeries.setEnabled(!reportSpeed);
|
||||
// Either speedSeries or paceSeries should be enabled, if one is shown.
|
||||
if (showPaceOrSpeed) {
|
||||
speedSeries.setEnabled(reportSpeed);
|
||||
paceSeries.setEnabled(!reportSpeed);
|
||||
}
|
||||
|
||||
// Defaults for our chart series.
|
||||
heartRateSeries.setEnabled(true);
|
||||
elevationSeries.setEnabled(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -379,6 +395,12 @@ public class ChartView extends View {
|
||||
}
|
||||
|
||||
public boolean applyReportSpeed() {
|
||||
if (!showPaceOrSpeed) {
|
||||
paceSeries.setEnabled(false);
|
||||
speedSeries.setEnabled(false);
|
||||
return true;
|
||||
}
|
||||
|
||||
if (reportSpeed) {
|
||||
if (!speedSeries.isEnabled()) {
|
||||
speedSeries.setEnabled(true);
|
||||
@@ -396,6 +418,20 @@ public class ChartView extends View {
|
||||
return false;
|
||||
}
|
||||
|
||||
void setShowElevation(boolean value) {
|
||||
elevationSeries.setEnabled(value);
|
||||
}
|
||||
void setShowPaceOrSpeed(boolean value) {
|
||||
showPaceOrSpeed = value;
|
||||
|
||||
// we want to make sure we show whatever version the user has
|
||||
// selected when we turn this back on.
|
||||
applyReportSpeed();
|
||||
}
|
||||
void setShowHeartRate(boolean value) {
|
||||
heartRateSeries.setEnabled(value);
|
||||
}
|
||||
|
||||
public void setShowPointer(boolean value) {
|
||||
showPointer = value;
|
||||
}
|
||||
@@ -644,10 +680,18 @@ public class ChartView extends View {
|
||||
*/
|
||||
private void drawSeriesTitles(Canvas canvas) {
|
||||
Iterator<TitlePosition> tpI = titleDimensions.titlePositions.iterator();
|
||||
|
||||
for (ChartValueSeries chartValueSeries : seriesList) {
|
||||
if (chartValueSeries.isEnabled() && chartValueSeries.hasData() || allowIfEmpty(chartValueSeries)) {
|
||||
String title = getContext().getString(chartValueSeries.getTitleId(unitSystem));
|
||||
Paint paint = chartValueSeries.getTitlePaint();
|
||||
|
||||
// It is possible for the titlePositions to become empty temporarily, while switching between
|
||||
// chart screens quickly.
|
||||
if (!tpI.hasNext()) {
|
||||
return;
|
||||
}
|
||||
|
||||
TitlePosition tp = tpI.next();
|
||||
int y = topBorder - spacer - (titleDimensions.lineCount - tp.line) * (titleDimensions.lineHeight + spacer);
|
||||
canvas.drawText(title, tp.xPos + getScrollX(), y, paint);
|
||||
@@ -774,7 +818,7 @@ public class ChartView extends View {
|
||||
|
||||
//TODO
|
||||
int markerXPosition = x - spacer;
|
||||
int index = titleDimensions.titlePositions.size() - 1; // index only onver the visible chart series
|
||||
int index = titleDimensions.titlePositions.size() - 1; // index only over the visible chart series
|
||||
final int lastDrawn2ndLineMarkerIndex = getYmarkerCountOn1stLine();
|
||||
for (int i = seriesList.size()-1; i>=0 ;--i) { // draw markers from the last series to achieve right alignment
|
||||
ChartValueSeries chartValueSeries = seriesList.get(i);
|
||||
|
||||
@@ -318,6 +318,21 @@ public class PreferencesUtils {
|
||||
return getBoolean(R.string.stats_fullscreen_while_recording_key, DEFAULT);
|
||||
}
|
||||
|
||||
public static boolean shouldShowElevation() {
|
||||
final boolean DEFAULT = resources.getBoolean(R.bool.chart_display_elevation_default);
|
||||
return getBoolean(R.string.chart_display_elevation_key, DEFAULT);
|
||||
}
|
||||
|
||||
public static boolean shouldShowPaceOrSpeed() {
|
||||
final boolean DEFAULT = resources.getBoolean(R.bool.chart_display_pace_or_speed_default);
|
||||
return getBoolean(R.string.chart_display_pace_or_speed_key, DEFAULT);
|
||||
}
|
||||
|
||||
public static boolean shouldShowHeartRate() {
|
||||
final boolean DEFAULT = resources.getBoolean(R.bool.chart_display_heart_rate_default);
|
||||
return getBoolean(R.string.chart_display_heart_rate_key, DEFAULT);
|
||||
}
|
||||
|
||||
public static boolean shouldUseDynamicColors() {
|
||||
final boolean DEFAULT = resources.getBoolean(R.bool.settings_ui_dynamic_colors_default);
|
||||
return getBoolean(R.string.settings_ui_dynamic_colors_key, DEFAULT);
|
||||
|
||||
@@ -1,14 +1,6 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<resources>
|
||||
<!-- Do not translate anything in this file directly. -->
|
||||
<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>
|
||||
|
||||
<string name="stats_keep_screen_on_while_recording_key" translatable="false">trackdetail_keep_screen_on_while_recording</string>
|
||||
<bool name="stats_keep_screen_on_while_recording_default" translatable="false">false</bool>
|
||||
|
||||
<string name="stats_fullscreen_while_recording_key" translatable="false">trackdetail_fullscreen_while_recording</string>
|
||||
<bool name="stats_fullscreen_while_recording_default" translatable="false">false</bool>
|
||||
|
||||
<!-- Main settings -->
|
||||
<string name="settings_defaults_key" translatable="false">settingsDefaults</string>
|
||||
@@ -279,9 +271,32 @@
|
||||
<string name="show_introduction_screen_key" translatable="false">showIntroduction</string>
|
||||
<bool name="show_introduction_screen_default">true</bool>
|
||||
|
||||
<!-- User Interface Settings -->
|
||||
|
||||
<string name="settings_ui_dynamic_colors_key" translatable="false">uiDynamicColors</string>
|
||||
<bool name="settings_ui_dynamic_colors_default" translatable="false">false</bool>
|
||||
|
||||
<!-- Recording Settings -->
|
||||
<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>
|
||||
|
||||
<string name="stats_keep_screen_on_while_recording_key" translatable="false">trackdetail_keep_screen_on_while_recording</string>
|
||||
<bool name="stats_keep_screen_on_while_recording_default" translatable="false">false</bool>
|
||||
|
||||
<string name="stats_fullscreen_while_recording_key" translatable="false">trackdetail_fullscreen_while_recording</string>
|
||||
<bool name="stats_fullscreen_while_recording_default" translatable="false">false</bool>
|
||||
|
||||
<!-- Chart Settings -->
|
||||
<string name="chart_display_elevation_key" translatable="false">chart_display_elevation</string>
|
||||
<bool name="chart_display_elevation_default" translatable="false">true</bool>
|
||||
|
||||
<string name="chart_display_pace_or_speed_key" translatable="false">chart_display_pace_or_speed</string>
|
||||
<bool name="chart_display_pace_or_speed_default" translatable="false">true</bool>
|
||||
|
||||
<string name="chart_display_heart_rate_key" translatable="false">chart_display_heart_rate</string>
|
||||
<bool name="chart_display_heart_rate_default" translatable="false">true</bool>
|
||||
|
||||
|
||||
<!-- androidx.appcompat.app.AppCompatDelegate.setDefaultNightMode() -->
|
||||
<string name="locale_key" translatable="false">localeKey</string>
|
||||
|
||||
|
||||
@@ -344,6 +344,11 @@ limitations under the License.
|
||||
<!-- Settings Chart -->
|
||||
<string name="settings_chart_by_distance">By distance</string>
|
||||
<string name="settings_chart_by_time">By time</string>
|
||||
<string name="settings_charts_title">Charts</string>
|
||||
<string name="settings_chart_display_elevation_title">Display elevation</string>
|
||||
<string name="settings_chart_display_pace_or_speed_title">Display pace or speed</string>
|
||||
<string name="settings_chart_display_heart_rate_title">Display heart rate</string>
|
||||
|
||||
<!-- Settings Recording -->
|
||||
<string name="settings_recording_title">Recording</string>
|
||||
<string name="settings_theme_switch_restart">Theme changes may require a manual restart.</string>
|
||||
|
||||
@@ -58,4 +58,23 @@
|
||||
android:title="@string/settings_recording_fullscreen_on_while_recording_title" />
|
||||
</PreferenceCategory>
|
||||
|
||||
<PreferenceCategory app:title="@string/settings_charts_title">
|
||||
<SwitchPreferenceCompat
|
||||
android:icon="@drawable/ic_activity_climbing_24dp"
|
||||
android:defaultValue="@bool/chart_display_elevation_default"
|
||||
android:key="@string/chart_display_elevation_key"
|
||||
android:title="@string/settings_chart_display_elevation_title" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:icon="@drawable/ic_activity_snowboarding_24dp"
|
||||
android:defaultValue="@bool/chart_display_pace_or_speed_default"
|
||||
android:key="@string/chart_display_pace_or_speed_key"
|
||||
android:title="@string/settings_chart_display_pace_or_speed_title" />
|
||||
|
||||
<SwitchPreferenceCompat
|
||||
android:icon="@drawable/ic_activity_workout_24dp"
|
||||
android:defaultValue="@bool/chart_display_heart_rate_default"
|
||||
android:key="@string/chart_display_heart_rate_key"
|
||||
android:title="@string/settings_chart_display_heart_rate_title" />
|
||||
</PreferenceCategory>
|
||||
</PreferenceScreen>
|
||||
Reference in New Issue
Block a user