diff --git a/src/main/java/de/dennisguse/opentracks/adapters/SensorsAdapter.java b/src/main/java/de/dennisguse/opentracks/adapters/SensorsAdapter.java new file mode 100644 index 000000000..8e0c939a9 --- /dev/null +++ b/src/main/java/de/dennisguse/opentracks/adapters/SensorsAdapter.java @@ -0,0 +1,155 @@ +package de.dennisguse.opentracks.adapters; + +import android.content.Context; +import android.util.Pair; +import android.view.LayoutInflater; +import android.view.View; +import android.view.ViewGroup; +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.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 SensorsAdapter extends RecyclerView.Adapter { + + public static final int HEART_RATE_TYPE = 0; + public static final int CADENCE_TYPE = 1; + public static final int POWER_TYPE = 2; + + private List> 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; + int type = sensorDataList.get(position).first; + SensorData sensorData = sensorDataList.get(position).second; + viewHolder.setData(sensorData, type); + } + + @Override + public int getItemCount() { + if (sensorDataList == null) { + return 0; + } else { + return sensorDataList.size(); + } + } + + @Override + public int getItemViewType(int position) { + return sensorDataList.get(position).first; + } + + public List> swapData(List> data) { + if (sensorDataList == data) { + return null; + } + + sensorDataList = data; + + if (data != null) { + this.notifyDataSetChanged(); + } + + return data; + } + + private class ViewHolder extends RecyclerView.ViewHolder { + TextView label; + TextView sensorValue; + TextView value; + 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(SensorData sensorData, int type) { + switch (type) { + case HEART_RATE_TYPE: + setHeartRateSensorData((SensorDataHeartRate) sensorData); + break; + case CADENCE_TYPE: + setCadenceSensorData((SensorDataCycling.Cadence) sensorData); + break; + case POWER_TYPE: + setPowerSensorData((SensorDataCyclingPower) sensorData); + break; + default: + throw new RuntimeException("Unknown sensor type"); + } + } + + private void setHeartRateSensorData(SensorDataHeartRate data) { + String sensorValue = context.getString(R.string.value_unknown); + String sensorName = context.getString(R.string.value_unknown); + if (data != null) { + sensorName = data.getSensorNameOrAddress(); + if (data.hasHeartRate_bpm() && data.isRecent()) { + sensorValue = StringUtils.formatDecimal(data.getHeartRate_bpm(), 0); + } + } + + this.label.setText(context.getString(R.string.sensor_state_heart_rate)); + this.sensorValue.setText(sensorName); + this.value.setText(sensorValue); + } + + private void setCadenceSensorData(SensorDataCycling.Cadence data) { + String sensorValue = context.getString(R.string.value_unknown); + String sensorName = context.getString(R.string.value_unknown); + if (data != null) { + sensorName = data.getSensorNameOrAddress(); + + if (data.hasCadence_rpm() && data.isRecent()) { + sensorValue = StringUtils.formatDecimal(data.getCadence_rpm(), 0); + } + } + + this.label.setText(context.getString(R.string.sensor_state_cadence)); + this.sensorValue.setText(sensorName); + this.value.setText(sensorValue); + } + + private void setPowerSensorData(SensorDataCyclingPower data) { + String sensorValue = context.getString(R.string.value_unknown); + String sensorName = context.getString(R.string.value_unknown); + if (data != null) { + sensorName = data.getSensorNameOrAddress(); + + if (data.hasPower_w() && data.isRecent()) { + sensorValue = StringUtils.formatDecimal(data.getPower_w(), 0); + } + } + + this.label.setText(context.getString(R.string.sensor_state_power)); + this.sensorValue.setText(sensorName); + this.value.setText(sensorValue); + } + } +} diff --git a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java index c801de5bc..1ec55f4e0 100644 --- a/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java +++ b/src/main/java/de/dennisguse/opentracks/fragments/StatisticsRecordingFragment.java @@ -13,17 +13,22 @@ import android.view.ViewGroup; import androidx.annotation.NonNull; import androidx.fragment.app.Fragment; +import androidx.recyclerview.widget.GridLayoutManager; +import androidx.recyclerview.widget.RecyclerView; + +import java.util.ArrayList; +import java.util.List; import de.dennisguse.opentracks.R; import de.dennisguse.opentracks.TrackRecordingActivity; +import de.dennisguse.opentracks.adapters.SensorsAdapter; import de.dennisguse.opentracks.content.TrackDataHub; import de.dennisguse.opentracks.content.TrackDataListener; import de.dennisguse.opentracks.content.data.Marker; import de.dennisguse.opentracks.content.data.Track; import de.dennisguse.opentracks.content.data.TrackPoint; +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.content.sensor.SensorDataSet; import de.dennisguse.opentracks.databinding.StatisticsRecordingBinding; import de.dennisguse.opentracks.services.TrackRecordingServiceConnection; @@ -61,6 +66,9 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi private StatisticsRecordingBinding viewBinding; + private SensorsAdapter sensorsAdapter; + private RecyclerView sensorsRecyclerView; + public static Fragment newInstance() { return new StatisticsRecordingFragment(); } @@ -115,6 +123,11 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi } return true; }); + + sensorsAdapter = new SensorsAdapter(getContext()); + sensorsRecyclerView = viewBinding.statsSensorsRecyclerView; + sensorsRecyclerView.setLayoutManager(new GridLayoutManager(getContext(), 2)); + sensorsRecyclerView.setAdapter(sensorsAdapter); } @Override @@ -272,78 +285,23 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi } else { SensorDataSet sensorDataSet = trackRecordingService.getSensorData(); if (sensorDataSet != null) { - setHeartRateSensorData(sensorDataSet); - setCadenceSensorData(sensorDataSet); - setPowerSensorData(sensorDataSet); + List> sensorDataList = new ArrayList<>(); + if (sensorDataSet.getHeartRate() != null) { + sensorDataList.add(new Pair<>(SensorsAdapter.HEART_RATE_TYPE, sensorDataSet.getHeartRate())); + } + if (sensorDataSet.getCyclingCadence() != null) { + sensorDataList.add(new Pair<>(SensorsAdapter.CADENCE_TYPE, sensorDataSet.getCyclingCadence())); + } + if(sensorDataSet.getCyclingPower() != null) { + sensorDataList.add(new Pair<>(SensorsAdapter.POWER_TYPE, sensorDataSet.getCyclingPower())); + } + sensorsAdapter.swapData(sensorDataList); setSpeedSensorData(sensorDataSet); } setTotalElevationGain(trackRecordingService.getElevationGain_m()); } } - private void setHeartRateSensorData(SensorDataSet sensorDataSet) { - int isVisible = sensorDataSet.getHeartRate() != null ? View.VISIBLE : View.GONE; - viewBinding.statsSensorHeartRateGroup.setVisibility(isVisible); - setVisibilitySensorHorizontalLine(); - - String sensorValue = getContext().getString(R.string.value_unknown); - String sensorName = getContext().getString(R.string.value_unknown); - if (sensorDataSet.getHeartRate() != null) { - SensorDataHeartRate data = sensorDataSet.getHeartRate(); - - sensorName = data.getSensorNameOrAddress(); - if (data.hasHeartRate_bpm() && data.isRecent()) { - sensorValue = StringUtils.formatDecimal(data.getHeartRate_bpm(), 0); - } - } - - viewBinding.statsSensorHeartRateSensorValue.setText(sensorName); - viewBinding.statsSensorHeartRateValue.setText(sensorValue); - } - - private void setCadenceSensorData(SensorDataSet sensorDataSet) { - int isVisible = sensorDataSet.getCyclingCadence() != null ? View.VISIBLE : View.GONE; - viewBinding.statsSensorCadenceGroup.setVisibility(isVisible); - setVisibilitySensorHorizontalLine(); - - String sensorValue = getContext().getString(R.string.value_unknown); - String sensorName = getContext().getString(R.string.value_unknown); - if (sensorDataSet.getCyclingCadence() != null) { - SensorDataCycling.Cadence data = sensorDataSet.getCyclingCadence(); - sensorName = data.getSensorNameOrAddress(); - - if (data.hasCadence_rpm() && data.isRecent()) { - sensorValue = StringUtils.formatDecimal(data.getCadence_rpm(), 0); - } - } - - viewBinding.statsSensorCadenceSensorValue.setText(sensorName); - viewBinding.statsSensorCadenceValue.setText(sensorValue); - } - - private void setPowerSensorData(SensorDataSet sensorDataSet) { - int isVisible = View.VISIBLE; - if (PreferencesUtils.isBluetoothCyclingPowerSensorAddressNone(getContext())) { - isVisible = View.GONE; - } - viewBinding.statsSensorPowerGroup.setVisibility(isVisible); - setVisibilitySensorHorizontalLine(); - - String sensorValue = getContext().getString(R.string.value_unknown); - String sensorName = getContext().getString(R.string.value_unknown); - if (sensorDataSet != null && sensorDataSet.getCyclingPower() != null) { - SensorDataCyclingPower data = sensorDataSet.getCyclingPower(); - sensorName = data.getSensorName(); - - if (data.hasPower_w() && data.isRecent()) { - sensorValue = StringUtils.formatDecimal(data.getPower_w(), 0); - } - } - - viewBinding.statsSensorPowerSensorValue.setText(sensorName); - viewBinding.statsSensorPowerValue.setText(sensorValue); - } - // Set elevation gain private void setTotalElevationGain(Float elevationGain_m) { //TODO Check if we can distribute the total elevation gain via trackStatistics instead of doing some computation in the UI layer. @@ -364,15 +322,6 @@ public class StatisticsRecordingFragment extends Fragment implements TrackDataLi viewBinding.statsElevationGainUnit.setText(parts.second); } - /** - * If cadence and hear rate groups are invisible then sensor horizontal line hast to be invisible too. - */ - private void setVisibilitySensorHorizontalLine() { - if (viewBinding.statsSensorCadenceGroup.getVisibility() != View.VISIBLE && viewBinding.statsSensorHeartRateGroup.getVisibility() != View.VISIBLE) { - viewBinding.statsSensorHorizontalLine.setVisibility(View.GONE); - } - } - private void setSpeedSensorData(SensorDataSet sensorDataSet) { if (sensorDataSet != null && sensorDataSet.getCyclingSpeed() != null) { SensorDataCycling.Speed data = sensorDataSet.getCyclingSpeed(); diff --git a/src/main/res/layout/sensor_item.xml b/src/main/res/layout/sensor_item.xml new file mode 100644 index 000000000..4d89022bf --- /dev/null +++ b/src/main/res/layout/sensor_item.xml @@ -0,0 +1,41 @@ + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/res/layout/statistics_recording.xml b/src/main/res/layout/statistics_recording.xml index 94d8b1b48..33d7320ba 100644 --- a/src/main/res/layout/statistics_recording.xml +++ b/src/main/res/layout/statistics_recording.xml @@ -403,131 +403,14 @@ app:layout_constraintRight_toLeftOf="@+id/guideline3" app:layout_constraintTop_toBottomOf="@+id/stats_location_barrier" /> - - + - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - \ No newline at end of file