diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractActivityChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractActivityChartFragment.java index 8bc2f27dc3..f401290b7f 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractActivityChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractActivityChartFragment.java @@ -33,20 +33,28 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.GregorianCalendar; import java.util.List; +import java.util.Objects; +import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; import nodomain.freeyourgadget.gadgetbridge.activities.charts.sleep.SleepDetailsView; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser; import nodomain.freeyourgadget.gadgetbridge.util.Prefs; public abstract class AbstractActivityChartFragment extends AbstractChartFragment { @@ -166,10 +174,6 @@ public abstract class AbstractActivityChartFragment extend /** * Returns all kinds of samples for the given device. * To be called from a background thread. - * - * @param device - * @param tsFrom - * @param tsTo */ protected List getAllSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { SampleProvider provider = getProvider(db, device); @@ -414,6 +418,29 @@ public abstract class AbstractActivityChartFragment extend return samples; } + protected List getAllWorkouts(DBHandler db, GBDevice device) { + Calendar day = Calendar.getInstance(); + day.setTimeInMillis(getTSEnd() * 1000L); //we need today initially, which is the end of the time range + 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); + final int tsFrom = (int) (day.getTimeInMillis() / 1000); + final int tsTo = tsFrom + 24 * 60 * 60 - 1; + BaseActivitySummaryDao summaryDao = db.getDaoSession().getBaseActivitySummaryDao(); + Device dbDevice = DBHelper.findDevice(device, db.getDaoSession()); + QueryBuilder qb = summaryDao.queryBuilder(); + qb.where(BaseActivitySummaryDao.Properties.DeviceId.eq(Objects.requireNonNull(dbDevice).getId())); + qb.where(BaseActivitySummaryDao.Properties.StartTime.gt(new Date(tsFrom * 1000L))); + qb.where(BaseActivitySummaryDao.Properties.EndTime.lt(new Date(tsTo * 1000L))); + qb.orderAsc(BaseActivitySummaryDao.Properties.StartTime); + final List summaries = qb.build().list(); + final ActivitySummaryParser summaryParser = device.getDeviceCoordinator().getActivitySummaryParser(device, requireContext()); + for (BaseActivitySummary summary : summaries) { + summaryParser.parseBinaryData(summary, false); + } + return summaries; + } + protected List getSamplesHighRes(DBHandler db, GBDevice device) { int tsStart = getTSStart(); int tsEnd = getTSEnd(); 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 9ec11c847e..34034df008 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 @@ -44,7 +44,9 @@ import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; +import nodomain.freeyourgadget.gadgetbridge.activities.workouts.WorkoutDetailsActivity; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession; @@ -71,6 +73,15 @@ public class ActivityListingChartFragment extends AbstractActivityChartFragment< stepListAdapter.setOnItemClickListener(position -> { ActivitySession item = stepListAdapter.getItem(position); + if (item.getSessionType() == ActivitySession.SESSION_WORKOUT) { + final Intent intent = WorkoutDetailsActivity.Companion.createSingleWorkoutIntent( + requireContext(), + item.getWorkoutSummaryId(), + getChartsHost().getDevice() + ); + startActivity(intent); + return; + } if (item.getSessionType() != ActivitySession.SESSION_SUMMARY) { int tsFrom = (int) (item.getStartTime().getTime() / 1000); int tsTo = (int) (item.getEndTime().getTime() / 1000); @@ -82,12 +93,7 @@ public class ActivityListingChartFragment extends AbstractActivityChartFragment< FloatingActionButton fab; fab = rootView.findViewById(R.id.fab); fab.setVisibility(View.VISIBLE); - fab.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - showDashboard(tsDateTo, getChartsHost().getDevice()); - } - }); + fab.setOnClickListener(v -> showDashboard(tsDateTo, getChartsHost().getDevice())); refresh(); return rootView; @@ -125,8 +131,9 @@ public class ActivityListingChartFragment extends AbstractActivityChartFragment< boolean isEmptySummary = false; if (activitySamples != null) { - stepSessions = stepAnalysis.calculateStepSessions(activitySamples); - if (stepSessions.size() == 0) { + final List workouts = getAllWorkouts(db, device); + stepSessions = stepAnalysis.calculateStepSessions(activitySamples, workouts); + if (stepSessions.isEmpty()) { isEmptySummary = true; } ActivitySession stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary); @@ -149,7 +156,7 @@ public class ActivityListingChartFragment extends AbstractActivityChartFragment< } //noinspection RedundantIfStatement - if (mcd.getStepSessions().size() == 0) { + if (mcd.getStepSessions().isEmpty()) { getChartsHost().enableSwipeRefresh(true); //enable pull to refresh, might be needed } else { getChartsHost().enableSwipeRefresh(false); //disable pull to refresh as it collides with swipeable view @@ -197,7 +204,6 @@ public class ActivityListingChartFragment extends AbstractActivityChartFragment< String durationLabel = DateTimeUtils.formatDurationHoursMinutes(ongoingSession.getEndTime().getTime() - ongoingSession.getStartTime().getTime(), TimeUnit.MILLISECONDS); String hrLabel = String.valueOf(ongoingSession.getHeartRateAverage()); String activityName = ongoingSession.getActivityKind().getLabel(requireContext()); - int icon = ongoingSession.getActivityKind().getIcon(); String text = String.format("%s:\u00A0%s, %s:\u00A0%s, %s:\u00A0%s, %s:\u00A0%s", activityName, durationLabel, getString(R.string.heart_rate), hrLabel, getString(R.string.steps), stepLabel, getString(R.string.distance), distanceLabel); final Snackbar snackbar = Snackbar.make(getView(), text, 1000 * 8); @@ -205,13 +211,7 @@ public class ActivityListingChartFragment extends AbstractActivityChartFragment< View snackbarView = snackbar.getView(); snackbarView.setBackgroundColor(requireContext().getResources().getColor(R.color.accent)); snackbar.setActionTextColor(Color.WHITE); - snackbar.setAction(getString(R.string.dialog_hide).toUpperCase(), new View.OnClickListener() { - @Override - public void onClick(View view) { - snackbar.dismiss(); - } - } - ); + snackbar.setAction(getString(R.string.dialog_hide).toUpperCase(), view -> snackbar.dismiss()); snackbar.show(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java index bdf4ac3ac9..e6e12fabbf 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityListingDashboard.java @@ -23,7 +23,6 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.DatePicker; import android.widget.LinearLayout; import android.widget.RelativeLayout; import android.widget.SeekBar; @@ -41,16 +40,22 @@ import java.util.Date; import java.util.List; import java.util.concurrent.TimeUnit; +import de.greenrobot.dao.query.QueryBuilder; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; import nodomain.freeyourgadget.gadgetbridge.database.DBAccess; import nodomain.freeyourgadget.gadgetbridge.database.DBHandler; +import nodomain.freeyourgadget.gadgetbridge.database.DBHelper; import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator; import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider; import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummaryDao; +import nodomain.freeyourgadget.gadgetbridge.entities.Device; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser; import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.FormatUtils; import nodomain.freeyourgadget.gadgetbridge.util.dialogs.MaterialDialogFragment; @@ -117,7 +122,7 @@ public class ActivityListingDashboard extends MaterialDialogFragment { if (!activity_list_debug_extra_time_range_value) { battery_status_time_span_seekbar.setMax(3); } - final TextView battery_status_time_span_text = (TextView) getView().findViewById(R.id.battery_status_time_span_text); + final TextView battery_status_time_span_text = getView().findViewById(R.id.battery_status_time_span_text); battery_status_time_span_seekbar.setOnSeekBarChangeListener(new SeekBar.OnSeekBarChangeListener() { @@ -175,32 +180,25 @@ public class ActivityListingDashboard extends MaterialDialogFragment { } }); - battery_status_date_to_layout.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View v) { - final Calendar currentDate = Calendar.getInstance(); - currentDate.setTimeInMillis(timeTo * 1000L); + battery_status_date_to_layout.setOnClickListener(v -> { + final Calendar currentDate = Calendar.getInstance(); + currentDate.setTimeInMillis(timeTo * 1000L); - new DatePickerDialog(getContext(), new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePicker view, int year, int monthOfYear, int dayOfMonth) { + new DatePickerDialog(requireContext(), (view1, year, monthOfYear, dayOfMonth) -> { + Calendar date = Calendar.getInstance(); + date.set(year, monthOfYear, dayOfMonth); + int time1 = (int) (date.getTimeInMillis() / 1000); + Calendar day1 = Calendar.getInstance(); + day1.setTimeInMillis(time1 * 1000L); + day1.set(Calendar.HOUR_OF_DAY, 23); + day1.set(Calendar.MINUTE, 59); + day1.set(Calendar.SECOND, 59); + timeTo = (int) (day1.getTimeInMillis() / 1000); - Calendar date = Calendar.getInstance(); - date.set(year, monthOfYear, dayOfMonth); - int time = (int) (date.getTimeInMillis() / 1000); - Calendar day = Calendar.getInstance(); - day.setTimeInMillis(time * 1000L); - day.set(Calendar.HOUR_OF_DAY, 23); - day.set(Calendar.MINUTE, 59); - day.set(Calendar.SECOND, 59); - timeTo = (int) (day.getTimeInMillis() / 1000); - - battery_status_date_to_text.setText(DateTimeUtils.formatDate(new Date(timeTo * 1000L))); - battery_status_time_span_seekbar.setProgress(0); - battery_status_time_span_seekbar.setProgress(1); - } - }, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show(); - } + battery_status_date_to_text.setText(DateTimeUtils.formatDate(new Date(timeTo * 1000L))); + battery_status_time_span_seekbar.setProgress(0); + battery_status_time_span_seekbar.setProgress(1); + }, currentDate.get(Calendar.YEAR), currentDate.get(Calendar.MONTH), currentDate.get(Calendar.DATE)).show(); }); battery_status_time_span_seekbar.setProgress(2); } @@ -213,12 +211,13 @@ public class ActivityListingDashboard extends MaterialDialogFragment { List stepSessions; List activitySamples = getAllSamples(db, gbDevice, timeFrom, timeTo); + final List workouts = getAllWorkouts(db, gbDevice, timeFrom, timeTo); StepAnalysis stepAnalysis = new StepAnalysis(); boolean isEmptySummary = false; if (activitySamples != null) { - stepSessions = stepAnalysis.calculateStepSessions(activitySamples); - if (stepSessions.size() == 0) { + stepSessions = stepAnalysis.calculateStepSessions(activitySamples, workouts); + if (stepSessions.isEmpty()) { isEmptySummary = true; } stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary); @@ -236,6 +235,22 @@ public class ActivityListingDashboard extends MaterialDialogFragment { return provider.getAllActivitySamples(tsFrom, tsTo); } + protected List getAllWorkouts(DBHandler db, GBDevice device, int tsFrom, int tsTo) { + BaseActivitySummaryDao summaryDao = db.getDaoSession().getBaseActivitySummaryDao(); + Device dbDevice = DBHelper.findDevice(device, db.getDaoSession()); + QueryBuilder qb = summaryDao.queryBuilder(); + qb.where(BaseActivitySummaryDao.Properties.DeviceId.eq(dbDevice.getId())); + qb.where(BaseActivitySummaryDao.Properties.StartTime.gt(new Date(tsFrom * 1000L))); + qb.where(BaseActivitySummaryDao.Properties.EndTime.lt(new Date(tsTo * 1000L))); + qb.orderAsc(BaseActivitySummaryDao.Properties.StartTime); + final List summaries = qb.build().list(); + final ActivitySummaryParser summaryParser = device.getDeviceCoordinator().getActivitySummaryParser(device, getContext()); + for (BaseActivitySummary summary : summaries) { + summaryParser.parseBinaryData(summary, false); + } + return summaries; + } + void indicate_progress(boolean inProgress) { View view = getView(); if (view == null) { 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 836c649747..d534305192 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 @@ -21,22 +21,58 @@ import org.slf4j.LoggerFactory; import java.util.ArrayList; import java.util.Collection; +import java.util.Comparator; import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession; import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser; +import nodomain.freeyourgadget.gadgetbridge.util.RangeMap; public class StepAnalysis { protected static final Logger LOG = LoggerFactory.getLogger(StepAnalysis.class); private int totalDailySteps = 0; - public List calculateStepSessions(List samples) { - LOG.debug("get all samples activity sessions: {}", samples.size()); + public List calculateStepSessions(List samples, final List workouts) { + LOG.debug("get all samples activity sessions: {}, workouts: {}", samples.size(), workouts.size()); + + totalDailySteps = 0; + + // Exclude all explicit samples that match workouts, but keep track of them, so that we can still count the steps + // some devices do not include steps in non-step workouts (eg. strength training), which will + // otherwise mess up the step count + final Map> samplesDuringWorkouts = new HashMap<>(); + final RangeMap workoutsMap = new RangeMap<>(RangeMap.Mode.LOWER_BOUND); + workoutsMap.put(0L, 0L); + for (BaseActivitySummary workout : workouts) { + workoutsMap.put(workout.getStartTime().getTime(), workout.getStartTime().getTime()); + workoutsMap.put(workout.getEndTime().getTime(), 0L); + } + samples = samples.stream() + .filter(s -> { + final Long workoutStart = workoutsMap.get(s.getTimestamp() * 1000L); + final boolean isWorkout = workoutStart != null && workoutStart != 0L; + if (isWorkout) { + if (s.getSteps() > 0) { + // FIXME: This is hacky, but we need to add the steps to the daily total here, since they + // will not be processed downstream + totalDailySteps += s.getSteps(); + } + samplesDuringWorkouts.computeIfAbsent(workoutStart, absent -> new LinkedList<>()) + .add(s); + } + return !isWorkout; + }).collect(Collectors.toList()); + List result = new ArrayList<>(); ActivityUser activityUser = new ActivityUser(); final int MIN_SESSION_LENGTH = 60 * GBApplication.getPrefs().getInt("chart_list_min_session_length", 5); @@ -45,7 +81,6 @@ public class StepAnalysis { int stepLengthCm = activityUser.getStepLengthCm(); final double STEP_LENGTH_M = stepLengthCm * 0.01; final double MIN_SESSION_INTENSITY = Math.max(0, Math.min(1, MIN_STEPS_PER_MINUTE * 0.01)); - totalDailySteps = 0; ActivitySample previousSample = null; Date sessionStart = null; @@ -169,7 +204,7 @@ public class StepAnalysis { int session_length = current - starting - durationSinceLastActiveStep; if (session_length >= MIN_SESSION_LENGTH) { - int heartRateAverage = heartRateSum.size() > 0 ? calculateSumOfInts(heartRateSum) / heartRateSum.size() : 0; + int heartRateAverage = !heartRateSum.isEmpty() ? calculateSumOfInts(heartRateSum) / heartRateSum.size() : 0; float distance = activeDistanceCm * 0.01f; sessionEnd = getDateFromSample(previousSample); activityKind = detect_activity_kind(session_length, activeSteps, heartRateAverage, activeIntensity); @@ -178,7 +213,15 @@ public class StepAnalysis { result.add(ongoingActivity); } } - return result; + + for (BaseActivitySummary workout : workouts) { + final List samplesDuringThisWorkout = samplesDuringWorkouts.get(workout.getStartTime().getTime()); + result.add(new ActivitySession(workout, samplesDuringThisWorkout)); + } + + return result.stream() + .sorted(Comparator.comparing(ActivitySession::getStartTime)) + .collect(Collectors.toList()); } public ActivitySession calculateSummary(Collection sessions, boolean empty) { diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java index 0d1650c8dc..6482ff5589 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/dashboard/DashboardTodayWidget.java @@ -558,7 +558,7 @@ public class DashboardTodayWidget extends AbstractDashboardWidget { List activitySamples = DashboardUtils.getAllSamples(dbHandler, dev, dashboardData); allActivitySamples.addAll(activitySamples); StepAnalysis stepAnalysis = new StepAnalysis(); - stepSessions.addAll(stepAnalysis.calculateStepSessions(activitySamples)); + stepSessions.addAll(stepAnalysis.calculateStepSessions(activitySamples, Collections.emptyList())); deviceIds.add(DBHelper.getDevice(dev, dbHandler.getDaoSession()).getId()); } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityListItem.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityListItem.java index 022a867d31..c4bc5b6a7c 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityListItem.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivityListItem.java @@ -107,7 +107,7 @@ public class ActivityListItem { hrLayout.setVisibility(View.GONE); } - if (intensity >= 0) { + if (intensity >= 1f) { final DecimalFormat df = new DecimalFormat("###"); intensityLabel.setText(df.format(intensity)); intensityLayout.setVisibility(View.VISIBLE); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySession.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySession.java index 6f379c45d3..b4773a8f87 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySession.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySession.java @@ -18,6 +18,10 @@ package nodomain.freeyourgadget.gadgetbridge.model; import java.io.Serializable; import java.util.Date; +import java.util.List; + +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; +import nodomain.freeyourgadget.gadgetbridge.util.Accumulator; // ActivitySession holds activities detected by the steps/hr/intensity // and is used in the Activity List @@ -27,6 +31,7 @@ public class ActivitySession implements Serializable { public static int SESSION_SUMMARY = 2; public static int SESSION_ONGOING = 3; public static int SESSION_EMPTY = 4; + public static int SESSION_WORKOUT = 5; private final Date startTime; private final Date endTime; @@ -39,6 +44,7 @@ public class ActivitySession implements Serializable { // it is identified by SESSION_SUMMARY private int sessionCount = 0; private int sessionType = SESSION_NORMAL; + private long workoutSummaryId = -1; private boolean isEmptySummary = false; // in case there is no activity on that day private int totalDaySteps; @@ -55,6 +61,45 @@ public class ActivitySession implements Serializable { this.activityKind = activityKind; } + public ActivitySession(final BaseActivitySummary summary, final List samples) { + this.startTime = summary.getStartTime(); + this.endTime = summary.getEndTime(); + final String summaryDataJson = summary.getSummaryData(); + + final Accumulator accSteps = new Accumulator(); + final Accumulator accDistance = new Accumulator(); + final Accumulator accHeartRate = new Accumulator(); + if (samples != null) { + for (ActivitySample s : samples) { + if (s.getSteps() > 0) { + accSteps.add(s.getSteps()); + } + if (s.getDistanceCm() > 0) { + accDistance.add(s.getDistanceCm()); + } + if (s.getHeartRate() > 0) { + accHeartRate.add(s.getHeartRate()); + } + } + } + + if (summaryDataJson != null) { + final ActivitySummaryData summaryData = ActivitySummaryData.fromJson(summaryDataJson); + this.activeSteps = summaryData.getNumber(ActivitySummaryEntries.STEPS, accSteps.getSum()).intValue(); + this.heartRateAverage = summaryData.getNumber(ActivitySummaryEntries.HR_AVG, accHeartRate.getAverage()).intValue(); + this.distance = summaryData.getNumber(ActivitySummaryEntries.DISTANCE_METERS, accDistance.getSum() * 0.01f).floatValue(); + } else { + this.activeSteps = (int) Math.round(accSteps.getSum()); + this.heartRateAverage = (int) Math.round(accHeartRate.getAverage()); + this.distance = (int) Math.round(accDistance.getSum() * 0.01f); + } + this.intensity = 0; + this.sessionType = SESSION_WORKOUT; + this.workoutSummaryId = summary.getId(); + + this.activityKind = ActivityKind.fromCode(summary.getActivityKind()); + } + public ActivitySession(){ this.startTime = null; this.endTime = null; @@ -63,7 +108,7 @@ public class ActivitySession implements Serializable { this.intensity = 0; this.distance = 0; this.activityKind = ActivityKind.UNKNOWN; - }; + } public Date getStartTime() { return startTime; @@ -124,4 +169,8 @@ public class ActivitySession implements Serializable { public void setTotalDaySteps(int totalDaySteps) { this.totalDaySteps = totalDaySteps; } + + public long getWorkoutSummaryId() { + return workoutSummaryId; + } } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DashboardUtils.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DashboardUtils.java index 4e62972ec9..6f225af51e 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DashboardUtils.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/DashboardUtils.java @@ -207,19 +207,15 @@ public class DashboardUtils { } public static long getActiveMinutes(GBDevice gbDevice, DBHandler db, DashboardFragment.DashboardData dashboardData) { - ActivitySession stepSessionsSummary = new ActivitySession(); - List stepSessions; List activitySamples = getAllSamples(db, gbDevice, dashboardData); StepAnalysis stepAnalysis = new StepAnalysis(); boolean isEmptySummary = false; - if (activitySamples != null) { - stepSessions = stepAnalysis.calculateStepSessions(activitySamples); - if (stepSessions.isEmpty()) { - isEmptySummary = true; - } - stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary); + final List stepSessions = stepAnalysis.calculateStepSessions(activitySamples, Collections.emptyList()); + if (stepSessions.isEmpty()) { + isEmptySummary = true; } + final ActivitySession stepSessionsSummary = stepAnalysis.calculateSummary(stepSessions, isEmptySummary); long duration = stepSessionsSummary.getEndTime().getTime() - stepSessionsSummary.getStartTime().getTime(); return duration / 1000 / 60; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/RangeMap.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/RangeMap.java index f34e812f9a..62cb08c465 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/RangeMap.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/util/RangeMap.java @@ -38,16 +38,10 @@ public class RangeMap, V> { } public RangeMap(final Mode mode) { - switch (mode) { - case LOWER_BOUND: - comparator = (k1, k2) -> k1.compareTo(k2); - break; - case UPPER_BOUND: - comparator = (k1, k2) -> k2.compareTo(k1); - break; - default: - throw new IllegalArgumentException("Unknown mode " + mode); - } + comparator = switch (mode) { + case LOWER_BOUND -> Comparable::compareTo; + case UPPER_BOUND -> Comparator.reverseOrder(); + }; } public void put(final K key, final V value) { @@ -82,6 +76,5 @@ public class RangeMap, V> { public enum Mode { LOWER_BOUND, UPPER_BOUND, - ; } } diff --git a/app/src/main/res/layout/fragment_steps_list.xml b/app/src/main/res/layout/fragment_steps_list.xml index 6d869c5c48..6dd3f71a1d 100644 --- a/app/src/main/res/layout/fragment_steps_list.xml +++ b/app/src/main/res/layout/fragment_steps_list.xml @@ -10,11 +10,10 @@ android:id="@+id/stepsDateView" android:layout_width="match_parent" android:layout_height="wrap_content" - android:textAlignment="center" - android:textAllCaps="false" - android:textAppearance="@style/TextAppearance.AppCompat.Medium" - android:textStyle="bold" /> - + android:gravity="center" + android:textSize="20sp" + android:layout_marginBottom="10dp" + android:layout_marginTop="15dp" /> - -