From b236a6af160a1bbc079f64ebba6d5537592b6401 Mon Sep 17 00:00:00 2001 From: vanous Date: Thu, 20 Aug 2020 09:03:26 +0200 Subject: [PATCH] Add Activity Summary Statistics Drawer Move SummaryStatistics JSON Summary to own place --- .../activities/ActivitySummariesActivity.java | 106 ++++++++- .../activities/ActivitySummaryDetail.java | 101 +-------- .../gadgetbridge/model/ActivitySummary.java | 3 + .../model/ActivitySummaryJsonSummary.java | 131 ++++++++++++ app/src/main/res/anim/slidefromtop.xml | 11 + .../res/drawable/ic_outline_filter_9_plus.xml | 10 + app/src/main/res/layout/activity_list.xml | 1 + .../layout/activity_summary_statistics.xml | 202 ++++++++++++++++++ app/src/main/res/menu/activity_list_menu.xml | 6 + app/src/main/res/values/strings.xml | 12 +- 10 files changed, 478 insertions(+), 105 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummaryJsonSummary.java create mode 100644 app/src/main/res/anim/slidefromtop.xml create mode 100644 app/src/main/res/drawable/ic_outline_filter_9_plus.xml create mode 100644 app/src/main/res/layout/activity_summary_statistics.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesActivity.java index dc7d0ef67..4deff97d9 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/ActivitySummariesActivity.java @@ -17,7 +17,6 @@ along with this program. If not, see . */ package nodomain.freeyourgadget.gadgetbridge.activities; -import android.app.Activity; import android.app.DatePickerDialog; import android.content.BroadcastReceiver; import android.content.Context; @@ -31,12 +30,14 @@ import android.view.ActionMode; import android.view.Menu; import android.view.MenuItem; import android.view.View; +import android.view.animation.Animation; +import android.view.animation.AnimationUtils; import android.widget.AbsListView; import android.widget.AdapterView; -import android.widget.ArrayAdapter; import android.widget.DatePicker; +import android.widget.LinearLayout; import android.widget.ListView; -import android.widget.Spinner; +import android.widget.TextView; import android.widget.Toast; import androidx.core.content.FileProvider; @@ -45,26 +46,33 @@ import androidx.swiperefreshlayout.widget.SwipeRefreshLayout; import com.google.android.material.floatingactionbutton.FloatingActionButton; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import java.io.File; +import java.text.DecimalFormat; import java.util.ArrayList; import java.util.Calendar; +import java.util.Date; import java.util.HashMap; import java.util.LinkedHashMap; import java.util.List; import java.util.Objects; +import java.util.concurrent.TimeUnit; import nodomain.freeyourgadget.gadgetbridge.GBApplication; import nodomain.freeyourgadget.gadgetbridge.R; -import nodomain.freeyourgadget.gadgetbridge.activities.appmanager.AppManagerActivity; import nodomain.freeyourgadget.gadgetbridge.adapter.ActivitySummariesAdapter; import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice; import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind; import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummary; +import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryJsonSummary; import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes; +import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils; import nodomain.freeyourgadget.gadgetbridge.util.GB; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; @@ -76,6 +84,7 @@ public class ActivitySummariesActivity extends AbstractListActivity keys = data.keys(); DecimalFormat df = new DecimalFormat("#.##"); @@ -294,76 +274,9 @@ public class ActivitySummaryDetail extends AbstractGBActivity { } } - private JSONObject setGroups(){ - String groupDefinitions = "{'Strokes':['averageStrokeDistance','averageStrokesPerSecond','strokes'], " + - "'Swimming':['swolfIndex','swimStyle'], " + - "'Elevation':['ascentMeters','descentMeters','maxAltitude','minAltitude','ascentSeconds','descentSeconds','flatSeconds'], " + - "'Speed':['maxSpeed','minPace','maxPace','averageKMPaceSeconds'], " + - "'Activity':['distanceMeters','steps','activeSeconds','caloriesBurnt','totalStride'," + - "'averageHR','averageStride'], " + - "'Laps':['averageLapPace','laps']}"; - JSONObject data = null; - try { - data = new JSONObject(groupDefinitions); - } catch (JSONException e) { - LOG.error("SportsActivity", e); - } - return data; - } - private String getGroup(String searchItem) { - String defaultGroup = "Activity"; - if (groupData == null) return defaultGroup; - Iterator keys = groupData.keys(); - while (keys.hasNext()) { - String key = keys.next(); - try { - JSONArray itemList = (JSONArray) groupData.get(key); - for (int i = 0; i < itemList.length(); i++) { - if (itemList.getString(i).equals(searchItem)) { - return key; - } - } - } catch (JSONException e) { - LOG.error("SportsActivity", e); - } - } - return defaultGroup; -} - private JSONObject makeSummaryList(JSONObject summaryData){ - //make dictionary with data for each group - JSONObject list = new JSONObject(); - Iterator keys = summaryData.keys(); - LOG.error("SportsActivity JSON:" + summaryData + keys); - while (keys.hasNext()) { - String key = keys.next(); - - try { - LOG.error("SportsActivity:" + key + ": " + summaryData.get(key) + "\n"); - JSONObject innerData = (JSONObject) summaryData.get(key); - Object value = innerData.get("value"); - String unit = innerData.getString("unit"); - String group = getGroup(key); - - if (!list.has(group)) { - list.put(group,new JSONArray()); - } - - JSONArray tmpl = (JSONArray) list.get(group); - JSONObject innernew = new JSONObject(); - innernew.put("name", key); - innernew.put("value", value); - innernew.put("unit", unit); - tmpl.put(innernew); - list.put(group, tmpl); - } catch (JSONException e) { - LOG.error("SportsActivity", e); - } - } - return list; - } public static int getAlternateColor(Context context) { TypedValue typedValue = new TypedValue(); Resources.Theme theme = context.getTheme(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummary.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummary.java index a9846c110..897696cc6 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummary.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummary.java @@ -21,6 +21,9 @@ import org.json.JSONObject; import java.io.Serializable; import java.util.Date; +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiActivitySummaryParser; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; + /** * Summarized information about a temporal activity. * diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummaryJsonSummary.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummaryJsonSummary.java new file mode 100644 index 000000000..ac880d819 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/model/ActivitySummaryJsonSummary.java @@ -0,0 +1,131 @@ +package nodomain.freeyourgadget.gadgetbridge.model; + +import org.json.JSONArray; +import org.json.JSONException; +import org.json.JSONObject; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.util.Iterator; + +import nodomain.freeyourgadget.gadgetbridge.devices.huami.HuamiActivitySummaryParser; +import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary; + +public class ActivitySummaryJsonSummary { + private static final Logger LOG = LoggerFactory.getLogger(ActivitySummaryJsonSummary.class); + private JSONObject groupData; + private JSONObject summaryData; + private JSONObject summaryGroupedList; + private BaseActivitySummary baseActivitySummary; + + public ActivitySummaryJsonSummary(BaseActivitySummary baseActivitySummary){ + this.baseActivitySummary=baseActivitySummary; + } + + private JSONObject setSummaryData(BaseActivitySummary item){ + String summary = getCorrectSummary(item); + JSONObject jsonSummary = getJSONSummary(summary); + return jsonSummary; + } + + public JSONObject getSummaryData(){ + //returns json with summaryData + if (summaryData==null) summaryData=setSummaryData(baseActivitySummary); + return summaryData; + } + + private String getCorrectSummary(BaseActivitySummary item){ + if (item.getRawSummaryData() != null) { + ActivitySummaryParser parser = new HuamiActivitySummaryParser(); // FIXME: if something else than huami supports that make sure to have the right parser + item = parser.parseBinaryData(item); + } + return item.getSummaryData(); + } + + private JSONObject getJSONSummary(String sumData){ + JSONObject summarySubdata = null; + if (sumData != null) { + try { + summarySubdata = new JSONObject(sumData); + } catch (JSONException e) { + } + } + return summarySubdata; + } + + public JSONObject getSummaryGroupedList() { + //returns list grouped by activity groups as per createActivitySummaryGroups + if (summaryData==null) summaryData=setSummaryData(baseActivitySummary); + if (summaryGroupedList==null) summaryGroupedList=setSummaryGroupedList(summaryData); + return summaryGroupedList; + } + private JSONObject setSummaryGroupedList(JSONObject summaryDatalist){ + this.groupData = createActivitySummaryGroups(); //structure for grouping activities into groups, when vizualizing + + if (summaryDatalist ==null ) return null; + Iterator keys = summaryDatalist.keys(); + JSONObject list=new JSONObject(); + + while (keys.hasNext()) { + String key = keys.next(); + try { + JSONObject innerData = (JSONObject) summaryDatalist.get(key); + Object value = innerData.get("value"); + String unit = innerData.getString("unit"); + String group = getGroup(key); + + if (!list.has(group)) { + list.put(group,new JSONArray()); + } + + JSONArray tmpl = (JSONArray) list.get(group); + JSONObject innernew = new JSONObject(); + innernew.put("name", key); + innernew.put("value", value); + innernew.put("unit", unit); + tmpl.put(innernew); + list.put(group, tmpl); + } catch (JSONException e) { + LOG.error("SportsActivity", e); + } + } + return list; + } + + private String getGroup(String searchItem) { + String defaultGroup = "Activity"; + if (groupData == null) return defaultGroup; + Iterator keys = groupData.keys(); + while (keys.hasNext()) { + String key = keys.next(); + try { + JSONArray itemList = (JSONArray) groupData.get(key); + for (int i = 0; i < itemList.length(); i++) { + if (itemList.getString(i).equals(searchItem)) { + return key; + } + } + } catch (JSONException e) { + LOG.error("SportsActivity", e); + } + } + return defaultGroup; + } + private JSONObject createActivitySummaryGroups(){ + String groupDefinitions = "{'Strokes':['averageStrokeDistance','averageStrokesPerSecond','strokes'], " + + "'Swimming':['swolfIndex','swimStyle'], " + + "'Elevation':['ascentMeters','descentMeters','maxAltitude','minAltitude','ascentSeconds','descentSeconds','flatSeconds'], " + + "'Speed':['maxSpeed','minPace','maxPace','averageKMPaceSeconds'], " + + "'Activity':['distanceMeters','steps','activeSeconds','caloriesBurnt','totalStride'," + + "'averageHR','averageStride'], " + + "'Laps':['averageLapPace','laps']}"; + JSONObject data = null; + try { + data = new JSONObject(groupDefinitions); + } catch (JSONException e) { + LOG.error("SportsActivity", e); + } + return data; + } + +} diff --git a/app/src/main/res/anim/slidefromtop.xml b/app/src/main/res/anim/slidefromtop.xml new file mode 100644 index 000000000..ee6056c37 --- /dev/null +++ b/app/src/main/res/anim/slidefromtop.xml @@ -0,0 +1,11 @@ + + + + + + \ No newline at end of file diff --git a/app/src/main/res/drawable/ic_outline_filter_9_plus.xml b/app/src/main/res/drawable/ic_outline_filter_9_plus.xml new file mode 100644 index 000000000..90a643aea --- /dev/null +++ b/app/src/main/res/drawable/ic_outline_filter_9_plus.xml @@ -0,0 +1,10 @@ + + + diff --git a/app/src/main/res/layout/activity_list.xml b/app/src/main/res/layout/activity_list.xml index 9d3b605cb..75721b465 100644 --- a/app/src/main/res/layout/activity_list.xml +++ b/app/src/main/res/layout/activity_list.xml @@ -17,6 +17,7 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/menu/activity_list_menu.xml b/app/src/main/res/menu/activity_list_menu.xml index 468160a2c..4db46fef8 100644 --- a/app/src/main/res/menu/activity_list_menu.xml +++ b/app/src/main/res/menu/activity_list_menu.xml @@ -13,5 +13,11 @@ android:title="@string/pref_header_filter" app:iconTint="@color/primarytext_dark" app:showAsAction="ifRoom" /> + \ No newline at end of file diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index 54a0a2135..4db708430 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -952,6 +952,7 @@ sec/m min/km bpm + km Strokes Swimming @@ -961,9 +962,9 @@ Activity Steps - Start: - End: - Duration: + Start + End + Duration Show GPS Track Use device events to trigger actions and Android broadcasts @@ -977,11 +978,12 @@ Broadcast message Run action Sports Activities Filter - From: - To: + From + To Reset Filter Filter Apply Filter + Statistics