diff --git a/app/src/main/assets/activity.svg b/app/src/main/assets/activity.svg
new file mode 100644
index 000000000..0d507b3e0
--- /dev/null
+++ b/app/src/main/assets/activity.svg
@@ -0,0 +1,83 @@
+
+
diff --git a/app/src/main/assets/ic_heartrate.svg b/app/src/main/assets/ic_heartrate.svg
new file mode 100644
index 000000000..ee74236cb
--- /dev/null
+++ b/app/src/main/assets/ic_heartrate.svg
@@ -0,0 +1,85 @@
+
+
diff --git a/app/src/main/assets/ic_intensity.svg b/app/src/main/assets/ic_intensity.svg
new file mode 100644
index 000000000..4ea16fff8
--- /dev/null
+++ b/app/src/main/assets/ic_intensity.svg
@@ -0,0 +1,94 @@
+
+
diff --git a/app/src/main/assets/ic_shoe.svg b/app/src/main/assets/ic_shoe.svg
new file mode 100644
index 000000000..0a2397a09
--- /dev/null
+++ b/app/src/main/assets/ic_shoe.svg
@@ -0,0 +1,74 @@
+
+
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java
index ec648091e..0e072542e 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingAdapter.java
@@ -2,47 +2,73 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import android.content.Context;
+import java.text.DecimalFormat;
import java.util.Date;
import java.util.concurrent.TimeUnit;
-import nodomain.freeyourgadget.gadgetbridge.R;
-import nodomain.freeyourgadget.gadgetbridge.adapter.AbstractItemAdapter;
+import nodomain.freeyourgadget.gadgetbridge.adapter.AbstractActivityListingAdapter;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
-public class ActivityListingAdapter extends AbstractItemAdapter {
+public class ActivityListingAdapter extends AbstractActivityListingAdapter {
public ActivityListingAdapter(Context context) {
super(context);
}
@Override
- protected String getName(StepAnalysis.StepSession item) {
- int activityKind = item.getActivityKind();
- String activityKindLabel = ActivityKind.asString(activityKind, getContext());
- Date startTime = item.getStepStart();
- Date endTime = item.getStepEnd();
-
- String fromTime = DateTimeUtils.formatTime(startTime.getHours(), startTime.getMinutes());
- String toTime = DateTimeUtils.formatTime(endTime.getHours(), endTime.getMinutes());
- String duration = DateTimeUtils.formatDurationHoursMinutes(endTime.getTime() - startTime.getTime(), TimeUnit.MILLISECONDS);
-
- if (activityKind == ActivityKind.TYPE_UNKNOWN) {
- return getContext().getString(R.string.chart_no_active_data);
- }
- return activityKindLabel + " " + duration + " (" + fromTime + " - " + toTime + ")";
+ protected String getTimeFrom(StepAnalysis.StepSession item) {
+ Date time = item.getStepStart();
+ return DateTimeUtils.formatTime(time.getHours(), time.getMinutes());
}
@Override
- protected String getDetails(StepAnalysis.StepSession item) {
- String heartRate = "";
- if (item.getActivityKind() == ActivityKind.TYPE_UNKNOWN) {
- return getContext().getString(R.string.chart_get_active_and_synchronize);
- }
- if (item.getHeartRateAverage() > 50) {
- heartRate = " ❤️ " + item.getHeartRateAverage();
- }
+ protected String getTimeTo(StepAnalysis.StepSession item) {
+ Date time = item.getStepEnd();
+ return DateTimeUtils.formatTime(time.getHours(), time.getMinutes());
+ }
- return "👣 " + item.getSteps() + heartRate;
+ @Override
+ protected String getActivityName(StepAnalysis.StepSession item) {
+ return ActivityKind.asString(item.getActivityKind(), getContext());
+ }
+
+ @Override
+ protected String getStepLabel(StepAnalysis.StepSession item) {
+ return String.valueOf(item.getSteps());
+ }
+
+ @Override
+ protected String getDistanceLabel(StepAnalysis.StepSession item) {
+ DecimalFormat df = new DecimalFormat("###m");
+ //DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
+ //symbols.setGroupingSeparator(' ');
+ return df.format(item.getDistance());
+ }
+
+ @Override
+ protected String getHrLabel(StepAnalysis.StepSession item) {
+ return String.valueOf(item.getHeartRateAverage());
+ }
+
+ @Override
+ protected String getIntensityLabel(StepAnalysis.StepSession item) {
+ DecimalFormat df = new DecimalFormat("###.#");
+ return df.format(item.getIntensity());
+ }
+
+ @Override
+ protected String getDurationLabel(StepAnalysis.StepSession item) {
+ long duration = item.getStepEnd().getTime() - item.getStepStart().getTime();
+ return DateTimeUtils.formatDurationHoursMinutes(duration, TimeUnit.MILLISECONDS);
+ }
+
+ @Override
+ public Boolean hasHR(StepAnalysis.StepSession item) {
+ if (item.getHeartRateAverage() > 0) {
+ return true;
+ } else {
+ return false;
+ }
}
@Override
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingChartFragment.java
index 593fe811a..d53fafe10 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingChartFragment.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingChartFragment.java
@@ -46,7 +46,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
public class ActivityListingChartFragment extends AbstractChartFragment {
protected static final Logger LOG = LoggerFactory.getLogger(ActivityListingChartFragment.class);
- int tsDataFrom;
+ int tsDateFrom;
private View rootView;
private List extends ActivitySample> activitySamples;
private ActivityListingAdapter stepListAdapter;
@@ -61,7 +61,8 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
stepListAdapter = new ActivityListingAdapter(getContext());
stepsList.setAdapter(stepListAdapter);
stepsDateView = rootView.findViewById(R.id.stepsDateView);
- //refresh();
+ refresh();
+
return rootView;
}
@@ -76,7 +77,7 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
String action = intent.getAction();
if (action.equals(ChartsHost.REFRESH)) {
// TODO: use LimitLines to visualize smart alarms?
- //refresh();
+ refresh();
} else {
super.onReceive(context, intent);
}
@@ -94,13 +95,17 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
@Override
protected void updateChartsnUIThread(ChartsData chartsData) {
//top displays selected date
- stepsDateView.setText(DateTimeUtils.formatDate(new Date(tsDataFrom * 1000L)));
+ stepsDateView.setText(DateTimeUtils.formatDate(new Date(tsDateFrom * 1000L)));
//calculate active sessions
StepAnalysis stepAnalysis = new StepAnalysis();
if (activitySamples != null) {
List stepSessions = stepAnalysis.calculateStepSessions(activitySamples);
if (stepSessions.toArray().length == 0) {
stepSessions = create_empty_record();
+ getChartsHost().enableSwipeRefresh(true); //try to enable pull to refresh, might be needed
+ } else {
+ getChartsHost().enableSwipeRefresh(false); //disable pull to refresh as it collides with swipable view
+ // this still provides one pull to refresh on the start, in case it is needed
}
//push to the adapter
stepListAdapter.setItems(stepSessions, true);
@@ -109,12 +114,10 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
@Override
protected void renderCharts() {
-
}
@Override
protected void setupLegend(Chart chart) {
-
}
@Override
@@ -124,20 +127,17 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
day.set(Calendar.HOUR_OF_DAY, 0); //and we set time for the start and end of the same day
day.set(Calendar.MINUTE, 0);
day.set(Calendar.SECOND, 0);
-
tsFrom = (int) (day.getTimeInMillis() / 1000);
tsTo = tsFrom + 24 * 60 * 60 - 1;
- tsDataFrom = tsFrom;
+ tsDateFrom = tsFrom;
return getAllSamples(db, device, tsFrom, tsTo);
}
private List create_empty_record() {
//have an "Unknown Activity" in the list in case there are no active sessions
List result = new ArrayList<>();
- int tsTo = tsDataFrom + 24 * 60 * 60 - 1;
- result.add(new StepAnalysis.StepSession(new Date(tsDataFrom * 1000L), new Date(tsTo * 1000L), 0, 0, ActivityKind.TYPE_UNKNOWN));
+ int tsTo = tsDateFrom + 24 * 60 * 60 - 1;
+ result.add(new StepAnalysis.StepSession(new Date(tsDateFrom * 1000L), new Date(tsTo * 1000L), 0, 0, 0, 0, ActivityKind.TYPE_UNKNOWN));
return result;
}
-
-
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java
index 0aea294d8..4512ad355 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsActivity.java
@@ -308,7 +308,8 @@ public class ChartsActivity extends AbstractGBFragmentActivity implements Charts
return super.onOptionsItemSelected(item);
}
- private void enableSwipeRefresh(boolean enable) {
+ @Override
+ public void enableSwipeRefresh(boolean enable) {
DeviceCoordinator coordinator = DeviceHelper.getInstance().getCoordinator(mGBDevice);
swipeLayout.setEnabled(enable && coordinator.allowFetchActivityData(mGBDevice));
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java
index 59185e401..8f93350d6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ChartsHost.java
@@ -46,4 +46,6 @@ public interface ChartsHost {
void setDateInfo(String dateInfo);
ViewGroup getDateBar();
+
+ void enableSwipeRefresh(boolean enable);
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java
index 774798f0b..b117b4470 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepAnalysis.java
@@ -26,100 +26,137 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
+import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
public class StepAnalysis {
protected static final Logger LOG = LoggerFactory.getLogger(StepAnalysis.class);
- private final int MIN_SESSION_STEPS = 100;
+ final double MULTIPLIER_FEMALE = 0.44; //constants to calculate steps from height
+ final double MULTIPLIER_OTHER = 0.45; //thes feel too small though
+ final double MULTIPLIER_MALE = 0.46;
+ private final double MIN_SESSION_INTENSITY = 0.4; //needs tuning
+ private double STEP_SIZE = 1;
public List calculateStepSessions(List extends ActivitySample> samples) {
List result = new ArrayList<>();
final int MIN_SESSION_LENGTH = 60 * GBApplication.getPrefs().getInt("chart_list_min_session_length", 5);
final int MAX_IDLE_PHASE_LENGTH = 60 * GBApplication.getPrefs().getInt("chart_list_max_idle_phase_length", 5);
final int MIN_STEPS_PER_MINUTE = GBApplication.getPrefs().getInt("chart_list_min_steps_per_minute", 40);
+ final int GENDER = GBApplication.getPrefs().getInt("activity_user_gender", 2);
+ final int HEIGHT = GBApplication.getPrefs().getInt("activity_user_height_cm", 170);
+ STEP_SIZE = calculate_step_size(GENDER, HEIGHT);
ActivitySample previousSample = null;
- Date stepStart = null;
- Date stepEnd = null;
- int activeSteps = 0;
- int heartRateForAverage = 0;
- int heartRateToAdd = 0;
- int activeSamplesForAverage = 0;
- int activeSamplesToAdd = 0;
- int stepsBetweenActivities = 0;
- int heartRateBetweenActivities = 0;
+ Date sessionStart = null;
+ Date sessionEnd = null;
+ int activeSteps = 0; //steps that we count
+ int stepsBetweenActivePeriods = 0; //steps during time when we maybe take a rest but then restart
int durationSinceLastActiveStep = 0;
int activityKind;
- for (ActivitySample sample : samples) {
- if (isStep(sample)) { //TODO we could improve/extend this to other activities as well, if in database
+ int heartRateForAverage = 0;
+ int heartRateToAdd = 0;
+ int heartRateBetweenActivePeriods = 0;
+ int activeHrSamplesForAverage = 0;
+ int activeHrSamplesToAdd = 0;
+ float activeIntensity = 0;
+ float intensityBetweenActivePeriods = 0;
+
+
+ for (ActivitySample sample : samples) {
+ if (sample.getKind() != ActivityKind.TYPE_SLEEP) { //anything but sleep counts
if (sample.getHeartRate() != 255 && sample.getHeartRate() != -1) {
heartRateToAdd = sample.getHeartRate();
- activeSamplesToAdd = 1;
+ activeHrSamplesToAdd = 1;
} else {
heartRateToAdd = 0;
- activeSamplesToAdd = 0;
+ activeHrSamplesToAdd = 0;
}
- if (stepStart == null) {
- stepStart = getDateFromSample(sample);
+ if (sessionStart == null) {
+ sessionStart = getDateFromSample(sample);
activeSteps = sample.getSteps();
+ activeIntensity = (int) sample.getIntensity();
heartRateForAverage = heartRateToAdd;
- activeSamplesForAverage = activeSamplesToAdd;
+ activeHrSamplesForAverage = activeHrSamplesToAdd;
durationSinceLastActiveStep = 0;
- stepsBetweenActivities = 0;
- heartRateBetweenActivities = 0;
+ stepsBetweenActivePeriods = 0;
+ heartRateBetweenActivePeriods = 0;
previousSample = null;
}
if (previousSample != null) {
int durationSinceLastSample = sample.getTimestamp() - previousSample.getTimestamp();
- activeSamplesForAverage += activeSamplesToAdd;
- if (sample.getSteps() > MIN_STEPS_PER_MINUTE) {
- activeSteps += sample.getSteps() + stepsBetweenActivities;
- heartRateForAverage += heartRateToAdd + heartRateBetweenActivities;
- stepsBetweenActivities = 0;
- heartRateBetweenActivities = 0;
+ activeHrSamplesForAverage += activeHrSamplesToAdd;
+ if (sample.getSteps() > MIN_STEPS_PER_MINUTE || //either some steps
+ (sample.getIntensity() > MIN_SESSION_INTENSITY && sample.getSteps() > 0)) { //or some intensity plus at least one step
+ activeSteps += sample.getSteps() + stepsBetweenActivePeriods;
+ activeIntensity += sample.getIntensity() + intensityBetweenActivePeriods;
+ heartRateForAverage += heartRateToAdd + heartRateBetweenActivePeriods;
+ stepsBetweenActivePeriods = 0;
+ heartRateBetweenActivePeriods = 0;
+ intensityBetweenActivePeriods = 0;
durationSinceLastActiveStep = 0;
- } else {
- stepsBetweenActivities += sample.getSteps();
- heartRateBetweenActivities += heartRateToAdd;
+
+ } else { //short break data to remember, we will add it to the rest later, if break not too long
+ stepsBetweenActivePeriods += sample.getSteps();
+ heartRateBetweenActivePeriods += heartRateToAdd;
durationSinceLastActiveStep += durationSinceLastSample;
+ intensityBetweenActivePeriods += sample.getIntensity();
}
- if (durationSinceLastActiveStep >= MAX_IDLE_PHASE_LENGTH) {
+ if (durationSinceLastActiveStep >= MAX_IDLE_PHASE_LENGTH) { //break too long, we split here
int current = sample.getTimestamp();
- int starting = (int) (stepStart.getTime() / 1000);
+ int starting = (int) (sessionStart.getTime() / 1000);
int session_length = current - starting - durationSinceLastActiveStep;
- int heartRateAverage = activeSamplesForAverage > 0 ? heartRateForAverage / activeSamplesForAverage : 0;
- if (session_length >= MIN_SESSION_LENGTH) {
- stepEnd = new Date((sample.getTimestamp() - durationSinceLastActiveStep) * 1000L);
- activityKind = detect_activity(session_length, activeSteps, heartRateAverage);
- result.add(new StepSession(stepStart, stepEnd, activeSteps, heartRateAverage, activityKind));
+ if (session_length >= MIN_SESSION_LENGTH) { //valid activity session
+ int heartRateAverage = activeHrSamplesForAverage > 0 ? heartRateForAverage / activeHrSamplesForAverage : 0;
+ float distance = (float) (activeSteps * STEP_SIZE);
+ sessionEnd = new Date((sample.getTimestamp() - durationSinceLastActiveStep) * 1000L);
+ activityKind = detect_activity_kind(session_length, activeSteps, heartRateAverage, activeIntensity);
+ result.add(new StepSession(sessionStart, sessionEnd, activeSteps, heartRateAverage, activeIntensity, distance, activityKind));
}
- stepStart = null;
+ sessionStart = null;
}
}
previousSample = sample;
}
}
//make sure we show the last portion of the data as well in case no further activity is recorded yet
- if (stepStart != null && previousSample != null) {
+ if (sessionStart != null && previousSample != null) {
int current = previousSample.getTimestamp();
- int starting = (int) (stepStart.getTime() / 1000);
+ int starting = (int) (sessionStart.getTime() / 1000);
int session_length = current - starting - durationSinceLastActiveStep;
- int heartRateAverage = activeSamplesForAverage > 0 ? heartRateForAverage / activeSamplesForAverage : 0;
- if (session_length > MIN_SESSION_LENGTH && activeSteps > MIN_SESSION_STEPS) {
- stepEnd = getDateFromSample(previousSample);
- activityKind = detect_activity(session_length, activeSteps, heartRateAverage);
- result.add(new StepSession(stepStart, stepEnd, activeSteps, heartRateAverage, activityKind));
+ if (session_length >= MIN_SESSION_LENGTH) {
+ int heartRateAverage = activeHrSamplesForAverage > 0 ? heartRateForAverage / activeHrSamplesForAverage : 0;
+ float distance = (float) (activeSteps * STEP_SIZE);
+
+ sessionEnd = getDateFromSample(previousSample);
+ activityKind = detect_activity_kind(session_length, activeSteps, heartRateAverage, activeIntensity);
+ result.add(new StepSession(sessionStart, sessionEnd, activeSteps, heartRateAverage, activeIntensity, distance, activityKind));
}
}
return result;
}
- private int detect_activity(int session_length, int activeSteps, int heartRateAverage) {
+ private double calculate_step_size(int gender, int height) {
+ double multiplier = 0;
+ switch (gender) {
+ case ActivityUser.GENDER_MALE:
+ multiplier = MULTIPLIER_MALE;
+ break;
+ case ActivityUser.GENDER_FEMALE:
+ multiplier = MULTIPLIER_FEMALE;
+ break;
+ case ActivityUser.GENDER_OTHER:
+ multiplier = MULTIPLIER_OTHER;
+ break;
+ }
+ return height * multiplier / 100;
+ }
+
+ private int detect_activity_kind(int session_length, int activeSteps, int heartRateAverage, float intensity) {
final int MIN_STEPS_PER_MINUTE_FOR_RUN = GBApplication.getPrefs().getInt("chart_list_min_steps_per_minute_for_run", 120);
int spm = (int) (activeSteps / (session_length / 60));
if (spm > MIN_STEPS_PER_MINUTE_FOR_RUN) {
@@ -128,7 +165,7 @@ public class StepAnalysis {
if (activeSteps > 200) {
return ActivityKind.TYPE_WALKING;
}
- if (heartRateAverage > 90) {
+ if (heartRateAverage > 90 && intensity > 30) { //needs tuning
return ActivityKind.TYPE_EXERCISE;
}
return ActivityKind.TYPE_ACTIVITY;
@@ -147,15 +184,19 @@ public class StepAnalysis {
private final Date stepEnd;
private final int steps;
private final int heartRateAverage;
+ private final float intensity;
+ private final float distance;
private final int activityKind;
StepSession(Date stepStart,
Date stepEnd,
- int steps, int heartRateAverage, int activityKind) {
+ int steps, int heartRateAverage, float intensity, float distance, int activityKind) {
this.stepStart = stepStart;
this.stepEnd = stepEnd;
this.steps = steps;
this.heartRateAverage = heartRateAverage;
+ this.intensity = intensity;
+ this.distance = distance;
this.activityKind = activityKind;
}
@@ -179,5 +220,12 @@ public class StepAnalysis {
return activityKind;
}
+ public float getIntensity() {
+ return intensity;
+ }
+
+ public float getDistance() {
+ return distance;
+ }
}
}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java
new file mode 100644
index 000000000..2a984a0b3
--- /dev/null
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/AbstractActivityListingAdapter.java
@@ -0,0 +1,154 @@
+/* Copyright (C) 2015-2020 Andreas Shimokawa, Carsten Pfeiffer, Daniele
+ Gobbetti
+
+ This file is part of Gadgetbridge.
+
+ Gadgetbridge is free software: you can redistribute it and/or modify
+ it under the terms of the GNU Affero General Public License as published
+ by the Free Software Foundation, either version 3 of the License, or
+ (at your option) any later version.
+
+ Gadgetbridge is distributed in the hope that it will be useful,
+ but WITHOUT ANY WARRANTY; without even the implied warranty of
+ MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ GNU Affero General Public License for more details.
+
+ You should have received a copy of the GNU Affero General Public License
+ along with this program. If not, see . */
+package nodomain.freeyourgadget.gadgetbridge.adapter;
+
+import android.content.Context;
+import android.content.res.Resources;
+import android.util.TypedValue;
+import android.view.LayoutInflater;
+import android.view.View;
+import android.view.ViewGroup;
+import android.widget.ArrayAdapter;
+import android.widget.ImageView;
+import android.widget.LinearLayout;
+import android.widget.RelativeLayout;
+import android.widget.TextView;
+
+import androidx.annotation.DrawableRes;
+
+import java.util.ArrayList;
+import java.util.List;
+
+import nodomain.freeyourgadget.gadgetbridge.R;
+
+import static nodomain.freeyourgadget.gadgetbridge.activities.charts.ActivityAnalysis.LOG;
+
+/**
+ * Adapter for displaying generic ItemWithDetails instances.
+ */
+public abstract class AbstractActivityListingAdapter extends ArrayAdapter {
+
+ private final Context context;
+ private final List items;
+ private int backgroundColor = 0;
+ private int alternateColor = 0;
+
+ public AbstractActivityListingAdapter(Context context) {
+ this(context, new ArrayList());
+ }
+
+ public AbstractActivityListingAdapter(Context context, List items) {
+ super(context, 0, items);
+
+ this.context = context;
+ this.items = items;
+ alternateColor = getAlternateColor(context);
+ }
+
+ public static int getAlternateColor(Context context) {
+ TypedValue typedValue = new TypedValue();
+ Resources.Theme theme = context.getTheme();
+ theme.resolveAttribute(R.attr.alternate_row_background, typedValue, true);
+ return typedValue.data;
+ }
+
+ @Override
+ public View getView(int position, View view, ViewGroup parent) {
+ T item = getItem(position);
+ view = null; //this is ugly (probably we get no recycling), but it is required to keep the layout nice. We have only few items, so this should be OK.
+ if (view == null) {
+ LayoutInflater inflater = (LayoutInflater) context
+ .getSystemService(Context.LAYOUT_INFLATER_SERVICE);
+ view = inflater.inflate(R.layout.activity_list_item, parent, false);
+ }
+ TextView timeFrom = view.findViewById(R.id.line_layout_timeFrom);
+ TextView timeTo = view.findViewById(R.id.line_layout_timeTo);
+ TextView activityName = view.findViewById(R.id.line_layout_activityName);
+ TextView stepLabel = view.findViewById(R.id.line_layout_step_label);
+ TextView distanceLabel = view.findViewById(R.id.line_layout_distance_label);
+ TextView hrLabel = view.findViewById(R.id.line_layout_hr_label);
+ TextView intensityLabel = view.findViewById(R.id.line_layout_intensity_label);
+ TextView durationLabel = view.findViewById(R.id.line_layout_duration_labe);
+
+
+ LinearLayout hrLayout = view.findViewById(R.id.line_layout_hr);
+ LinearLayout stepLayout = view.findViewById(R.id.line_layout_step);
+ LinearLayout intensityLayout = view.findViewById(R.id.line_layout_intensity);
+ RelativeLayout parentLayout = view.findViewById(R.id.list_item_parent_layout);
+
+ ImageView activityIcon = view.findViewById(R.id.line_layout_activityIcon);
+
+ timeFrom.setText(getTimeFrom(item));
+ timeTo.setText(getTimeTo(item));
+ activityName.setText(getActivityName(item));
+ stepLabel.setText(getStepLabel(item));
+ distanceLabel.setText(getDistanceLabel(item));
+ hrLabel.setText(getHrLabel(item));
+ intensityLabel.setText(getIntensityLabel(item));
+ durationLabel.setText(getDurationLabel(item));
+
+ if (!hasHR(item)) {
+ hrLayout.setVisibility(View.GONE);
+ } else {
+ hrLayout.setVisibility(View.VISIBLE);
+ }
+
+ activityIcon.setImageResource(getIcon(item));
+
+ if (position % 2 == 0) {parentLayout.setBackgroundColor(alternateColor);}
+
+ return view;
+ }
+
+ protected abstract String getTimeFrom(T item);
+
+ protected abstract String getTimeTo(T item);
+
+ protected abstract String getActivityName(T item);
+
+ protected abstract String getStepLabel(T item);
+
+ protected abstract String getDistanceLabel(T item);
+
+ protected abstract String getHrLabel(T item);
+
+ protected abstract String getIntensityLabel(T item);
+
+ protected abstract String getDurationLabel(T item);
+
+ protected abstract Boolean hasHR(T item);
+
+ @DrawableRes
+ protected abstract int getIcon(T item);
+
+ public List getItems() {
+ return items;
+ }
+
+ public void loadItems() {
+ }
+
+ public void setItems(List items, boolean notify) {
+ this.items.clear();
+ this.items.addAll(items);
+ if (notify) {
+ notifyDataSetChanged();
+ }
+ }
+
+}
diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityKind.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityKind.java
index 6afe19536..e443b6cc6 100644
--- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityKind.java
+++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityKind.java
@@ -207,7 +207,7 @@ public class ActivityKind {
case TYPE_ACTIVITY: // fall through
case TYPE_UNKNOWN: // fall through
default:
- return R.drawable.ic_activity_unknown;
+ return R.drawable.ic_activity_unknown_small;
}
}
}
diff --git a/app/src/main/res/drawable/ic_activity_unknown.xml b/app/src/main/res/drawable/ic_activity_unknown.xml
index 270c6911f..bbe8bf87f 100644
--- a/app/src/main/res/drawable/ic_activity_unknown.xml
+++ b/app/src/main/res/drawable/ic_activity_unknown.xml
@@ -4,7 +4,7 @@
android:tint="#7E7E7E"
android:viewportWidth="25"
android:viewportHeight="25">
-
-
+
+
\ No newline at end of file
diff --git a/app/src/main/res/drawable/ic_activity_unknown_small.xml b/app/src/main/res/drawable/ic_activity_unknown_small.xml
new file mode 100644
index 000000000..eef0e7d63
--- /dev/null
+++ b/app/src/main/res/drawable/ic_activity_unknown_small.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_heart.xml b/app/src/main/res/drawable/ic_heart.xml
new file mode 100644
index 000000000..aa2379797
--- /dev/null
+++ b/app/src/main/res/drawable/ic_heart.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_heartrate.xml b/app/src/main/res/drawable/ic_heartrate.xml
new file mode 100644
index 000000000..4b61288b4
--- /dev/null
+++ b/app/src/main/res/drawable/ic_heartrate.xml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_intensity.xml b/app/src/main/res/drawable/ic_intensity.xml
new file mode 100644
index 000000000..0ec3b9953
--- /dev/null
+++ b/app/src/main/res/drawable/ic_intensity.xml
@@ -0,0 +1,15 @@
+
+
+
+
diff --git a/app/src/main/res/drawable/ic_place.xml b/app/src/main/res/drawable/ic_place.xml
new file mode 100644
index 000000000..bb1f75229
--- /dev/null
+++ b/app/src/main/res/drawable/ic_place.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_shoe.xml b/app/src/main/res/drawable/ic_shoe.xml
new file mode 100644
index 000000000..eb4d7e539
--- /dev/null
+++ b/app/src/main/res/drawable/ic_shoe.xml
@@ -0,0 +1,10 @@
+
+
+
diff --git a/app/src/main/res/drawable/ic_show_chart.xml b/app/src/main/res/drawable/ic_show_chart.xml
new file mode 100644
index 000000000..0218c0f1c
--- /dev/null
+++ b/app/src/main/res/drawable/ic_show_chart.xml
@@ -0,0 +1,11 @@
+
+
+
diff --git a/app/src/main/res/layout/activity_list_item.xml b/app/src/main/res/layout/activity_list_item.xml
new file mode 100644
index 000000000..243b0e107
--- /dev/null
+++ b/app/src/main/res/layout/activity_list_item.xml
@@ -0,0 +1,231 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/app/src/main/res/xml/charts_preferences.xml b/app/src/main/res/xml/charts_preferences.xml
index 2c625fb51..429aa6e1e 100644
--- a/app/src/main/res/xml/charts_preferences.xml
+++ b/app/src/main/res/xml/charts_preferences.xml
@@ -73,7 +73,7 @@
android:title="@string/activity_prefs_chart_max_idle_phase_length" />