1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-08 22:28:20 +02:00

Add Activity List Dashboard/Summary view

This commit is contained in:
vanous 2020-11-07 17:31:15 +01:00
parent 9c90452f92
commit 551a5c1a66
22 changed files with 1246 additions and 157 deletions

View File

@ -0,0 +1,102 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
width="26"
height="26"
tint="#7E7E7E"
viewportWidth="25"
viewportHeight="25"
version="1.1"
id="svg1967"
sodipodi:docname="activity_stacked.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata1973">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs1971" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1042"
id="namedview1969"
showgrid="false"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="16"
inkscape:cx="1.5628297"
inkscape:cy="3.351769"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="g5608"
inkscape:document-rotation="0"
inkscape:snap-nodes="false">
<sodipodi:guide
position="18.131447,189.15957"
orientation="0,-1"
id="guide2551" />
<sodipodi:guide
position="6.8118842,20.241473"
orientation="1,0"
id="guide2553" />
</sodipodi:namedview>
<g
id="g5608"
transform="matrix(0.6107681,0,0,0.6107681,-0.50776959,-2.4214301)"
style="stroke-width:1.63728">
<g
id="g2806"
transform="matrix(1.8819341,0,-1.0509142,4.0780968,7.7001407,-9.1852646)"
style="stroke-width:0.591009">
<g
id="g2123"
transform="matrix(1,0,0,0.33594705,0,3.7327618)"
style="stroke-width:1.01966;stroke-miterlimit:4;stroke-dasharray:none">
<path
fill="#000000"
d="m 12,18 a 6,6 0 0 1 -6,-6 6,6 0 0 1 6,-6 6,6 0 0 1 6,6 6,6 0 0 1 -6,6 M 20,15.31 23.31,12 20,8.69 V 4 H 15.31 L 12,0.69 8.69,4 H 4 V 8.69 L 0.69,12 4,15.31 V 20 H 8.69 L 12,23.31 15.31,20 H 20 Z"
id="path1965"
style="stroke-width:1.01966;stroke-miterlimit:4;stroke-dasharray:none" />
<path
fill="currentColor"
d="m 4.4762317,12.388718 h 3.561751 l 2.0837443,-5.0286723 1.932068,5.4893343 1.823648,-2.726785 h 6.48905 l -0.488068,1.38717 H 14.61543 l -2.938854,4.509156 -1.60202,-4.54569 -0.9505983,2.403348 -3.506487,-4.01e-4 z"
id="path2361"
sodipodi:nodetypes="ccccccccccccc"
style="stroke-width:1.01966;stroke-miterlimit:4;stroke-dasharray:none"
inkscape:transform-center-x="1.0957646"
inkscape:transform-center-y="-1.4792654" />
</g>
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.591009;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
d="m 3.9815232,10.751128 v 0.490234 h 4.6484375 l 3.3515623,1.126953 3.349609,-1.126953 h 4.650391 v -0.490234 h -4.730469 l -3.269531,1.097656 -3.2714842,-1.097656 z"
id="path2783" />
<path
style="color:#000000;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:medium;line-height:normal;font-family:sans-serif;font-variant-ligatures:normal;font-variant-position:normal;font-variant-caps:normal;font-variant-numeric:normal;font-variant-alternates:normal;font-variant-east-asian:normal;font-feature-settings:normal;font-variation-settings:normal;text-indent:0;text-align:start;text-decoration:none;text-decoration-line:none;text-decoration-style:solid;text-decoration-color:#000000;letter-spacing:normal;word-spacing:normal;text-transform:none;writing-mode:lr-tb;direction:ltr;text-orientation:mixed;dominant-baseline:auto;baseline-shift:baseline;text-anchor:start;white-space:normal;shape-padding:0;shape-margin:0;inline-size:0;clip-rule:nonzero;display:inline;overflow:visible;visibility:visible;isolation:auto;mix-blend-mode:normal;color-interpolation:sRGB;color-interpolation-filters:linearRGB;solid-color:#000000;solid-opacity:1;vector-effect:none;fill:#000000;fill-opacity:1;fill-rule:evenodd;stroke:none;stroke-width:0.591009;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1;color-rendering:auto;image-rendering:auto;shape-rendering:auto;text-rendering:auto;enable-background:accumulate;stop-color:#000000"
d="m 3.9892109,11.549912 v 0.490234 h 4.6503907 l 3.3496094,1.126953 3.349609,-1.126953 h 4.650391 v -0.490234 h -4.730469 l -3.269531,1.097656 -3.2695313,-1.097656 z"
id="path2787" />
</g>
</g>
</svg>

After

Width:  |  Height:  |  Size: 6.2 KiB

View File

@ -0,0 +1,59 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
height="24"
viewBox="0 0 24 24"
width="24"
version="1.1"
id="svg6"
sodipodi:docname="ic_intensity_hollow.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata12">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs10" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1042"
id="namedview8"
showgrid="false"
inkscape:zoom="32.125"
inkscape:cx="12"
inkscape:cy="12"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="svg6" />
<path
d="M0 0h24v24H0V0z"
fill="none"
id="path2" />
<path
d="m 13.5,0.67 c 0,0 0.74,2.65 0.74,4.8 0,2.06 -1.35,3.73 -3.41,3.73 C 8.76,9.2 7.2,7.53 7.2,5.47 L 7.23,5.11 C 5.21,7.51 4,10.62 4,14 c 0,4.42 3.58,8 8,8 4.42,0 8,-3.58 8,-8 C 20,8.61 17.41,3.8 13.5,0.67 Z M 12,20 C 8.69,20 6,17.31 6,14 6,12.47 6.3,10.96 6.86,9.57 c 1.01,1.01 2.41,1.63 3.97,1.63 2.66,0 4.75,-1.83 5.28,-4.43 1.23,2.2 1.89,4.67 1.89,7.23 0,3.31 -2.69,6 -6,6 z"
id="path4"
sodipodi:nodetypes="cssccssscsscscss" />
</svg>

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,70 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
version="1.1"
width="24"
height="24"
viewBox="0 0 24 24"
id="svg4"
sodipodi:docname="ic_shoe_prints_many.svg"
inkscape:version="1.0.1 (3bc2e813f5, 2020-09-07)">
<metadata
id="metadata10">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs8" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1042"
id="namedview6"
showgrid="true"
showguides="true"
inkscape:guide-bbox="true"
inkscape:zoom="16.0625"
inkscape:cx="20.274468"
inkscape:cy="17.69706"
inkscape:window-x="0"
inkscape:window-y="38"
inkscape:window-maximized="1"
inkscape:current-layer="svg4"
inkscape:document-rotation="0">
<inkscape:grid
type="xygrid"
id="grid880" />
<sodipodi:guide
position="16,24"
orientation="0,-1"
id="guide882" />
</sodipodi:namedview>
<path
d="m 6.4801431,14.379265 c 0.3823082,1.031063 0.3416371,2.10404 -0.8052874,2.531554 C 3.3159331,17.807761 2.787209,15.452241 2.7546721,15.334884 l 3.725471,-0.955619 M 2.3886324,13.700271 5.9026138,12.80333 c -0.1545501,-0.880176 0.081342,-1.760353 0.081342,-2.799798 0,-1.4082825 -1.0818507,-4.1661681 -2.8063045,-3.7218887 -1.9684802,0.5029579 -2.2531778,2.7578856 -2.1799698,3.8476277 0.097611,1.089742 1.3340114,3.420113 1.3909509,3.571 m 9.8749386,7.494073 C 12.239171,21.320083 11.70231,23.66722 9.343387,22.778661 8.204597,22.342764 8.155792,21.269787 8.5381,20.238724 l 3.725471,0.95562 m 1.748856,-5.197232 c 0.08134,-1.089742 -0.195221,-3.353052 -2.171836,-3.85601 -1.716319,-0.461045 -2.79817,2.313606 -2.79817,3.730271 0,1.031064 0.227758,1.91124 0.08948,2.791416 l 3.497713,0.896942 c 0.06507,-0.150888 1.293341,-2.481259 1.382817,-3.562619 z"
id="path2"
style="stroke-width:0.999999" />
<path
d="M 14.730838,7.4902842 C 14.986006,8.2347895 14.958862,9.00956 14.193361,9.3182576 12.618928,9.9659169 12.266038,8.2650539 12.244321,8.1803133 L 14.730838,7.4902842 M 12.000011,7 14.345374,6.3523407 c -0.103162,-0.6355538 0.05428,-1.2711071 0.05428,-2.0216657 0,-1.0168858 -0.722068,-3.0082871 -1.873034,-2.6874837 -1.313836,0.3631733 -1.503856,1.9914011 -1.454993,2.778277 C 11.136774,5.2083444 11.961996,6.8910478 12,7 m 6.590901,5.411286 c -0.0162,0.09079 -0.374605,1.785603 -1.949038,1.143996 -0.760065,-0.314751 -0.79264,-1.089521 -0.537473,-1.834026 l 2.486519,0.69003 m 1.16726,-3.7527936 c 0.05428,-0.7868766 -0.130305,-2.4211567 -1.449564,-2.78433 -1.145536,-0.3329091 -1.867604,1.670598 -1.867604,2.6935367 0,0.7445054 0.152015,1.3800583 0.05971,2.0156119 l 2.334511,0.647659 c 0.04345,-0.108954 0.863221,-1.7916547 0.922943,-2.5724776 z"
id="path2-3"
style="stroke-width:0.999998" />
</svg>

After

Width:  |  Height:  |  Size: 3.5 KiB

View File

@ -1,59 +1,273 @@
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import android.content.Context;
import android.graphics.Color;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import com.github.mikephil.charting.charts.PieChart;
import com.github.mikephil.charting.data.PieData;
import com.github.mikephil.charting.data.PieDataSet;
import com.github.mikephil.charting.data.PieEntry;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.adapter.AbstractActivityListingAdapter;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
public class ActivityListingAdapter extends AbstractActivityListingAdapter<StepAnalysis.StepSession> {
public class ActivityListingAdapter extends AbstractActivityListingAdapter<ActivitySession> {
public static final String ACTIVE_STEPS_CHART_COLOR = "#3498db";
public static final String DISTANCE_CHART_COLOR = "#f1c40f";
public static final String ACTIVE_TIME_CHART_COLOR = "#e74c3c";
protected static final Logger LOG = LoggerFactory.getLogger(AbstractWeekChartFragment.class);
private final int SESSION_SUMMARY = ActivitySession.SESSION_SUMMARY;
ActivityUser activityUser = new ActivityUser();
int stepsGoal = activityUser.getStepsGoal();
int distanceMeters = activityUser.getDistanceMeters();
long activeTimeMillis = activityUser.getActiveTimeMinutes() * 60 * 1000L;
public ActivityListingAdapter(Context context) {
super(context);
}
@Override
protected String getDateLabel(StepAnalysis.StepSession item) {
protected View fill_dashboard(ActivitySession item, int position, View view, ViewGroup parent, Context context) {
LayoutInflater inflater = (LayoutInflater) context
.getSystemService(Context.LAYOUT_INFLATER_SERVICE);
view = inflater.inflate(R.layout.activity_list_dashboard_item, parent, false);
PieChart ActiveStepsChart;
PieChart DistanceChart;
PieChart ActiveTimeChart;
ActiveStepsChart = view.findViewById(R.id.activity_dashboard_piechart1);
setUpChart(ActiveStepsChart);
setStepsData(item, ActiveStepsChart, context);
DistanceChart = view.findViewById(R.id.activity_dashboard_piechart2);
setUpChart(DistanceChart);
setDistanceData(item, DistanceChart, context);
ActiveTimeChart = view.findViewById(R.id.activity_dashboard_piechart3);
setUpChart(ActiveTimeChart);
setDurationData(item, ActiveTimeChart, context);
TextView stepLabel = view.findViewById(R.id.line_layout_step_label);
TextView stepTotalLabel = view.findViewById(R.id.line_layout_total_step_label);
TextView distanceLabel = view.findViewById(R.id.line_layout_distance_label);
TextView hrLabel = view.findViewById(R.id.heartrate_widget_label);
TextView intensityLabel = view.findViewById(R.id.intensity_widget_label);
TextView intensity2Label = view.findViewById(R.id.line_layout_intensity2_label);
TextView durationLabel = view.findViewById(R.id.line_layout_duration_label);
TextView sessionCountLabel = view.findViewById(R.id.line_layout_count_label);
LinearLayout durationLayout = view.findViewById(R.id.line_layout_duration);
LinearLayout countLayout = view.findViewById(R.id.line_layout_count);
View hrLayout = view.findViewById(R.id.heartrate_widget_icon);
LinearLayout stepsLayout = view.findViewById(R.id.line_layout_step);
LinearLayout stepsTotalLayout = view.findViewById(R.id.line_layout_total_step);
LinearLayout distanceLayout = view.findViewById(R.id.line_layout_distance);
View intensityLayout = view.findViewById(R.id.intensity_widget_icon);
View intensity2Layout = view.findViewById(R.id.line_layout_intensity2);
stepLabel.setText(getStepLabel(item));
stepTotalLabel.setText(getStepTotalLabel(item));
distanceLabel.setText(getDistanceLabel(item));
hrLabel.setText(getHrLabel(item));
intensityLabel.setText(getIntensityLabel(item));
intensity2Label.setText(getIntensityLabel(item));
durationLabel.setText(getDurationLabel(item));
sessionCountLabel.setText(getSessionCountLabel(item));
if (!hasHR(item)) {
hrLayout.setVisibility(View.GONE);
hrLabel.setVisibility(View.GONE);
} else {
hrLayout.setVisibility(View.VISIBLE);
hrLabel.setVisibility(View.VISIBLE);
}
if (!hasIntensity(item)) {
intensityLayout.setVisibility(View.GONE);
intensity2Layout.setVisibility(View.GONE);
intensityLabel.setVisibility(View.GONE);
intensity2Label.setVisibility(View.GONE);
} else {
intensityLayout.setVisibility(View.VISIBLE);
intensity2Layout.setVisibility(View.VISIBLE);
intensityLabel.setVisibility(View.VISIBLE);
intensity2Label.setVisibility(View.VISIBLE);
}
if (!hasDistance(item)) {
distanceLayout.setVisibility(View.GONE);
} else {
distanceLayout.setVisibility(View.VISIBLE);
}
if (!hasSteps(item)) {
stepsLayout.setVisibility(View.GONE);
} else {
stepsLayout.setVisibility(View.VISIBLE);
}
if (!hasTotalSteps(item)) {
stepsTotalLayout.setVisibility(View.GONE);
countLayout.setVisibility(View.GONE);
durationLayout.setVisibility(View.GONE);
} else {
stepsTotalLayout.setVisibility(View.VISIBLE);
countLayout.setVisibility(View.VISIBLE);
durationLayout.setVisibility(View.VISIBLE);
}
return view;
}
private void setStepsData(ActivitySession item, PieChart DashboardChart, Context context) {
ArrayList<PieEntry> entries = new ArrayList<>();
int steps = item.getActiveSteps();
entries.add(new PieEntry((float) steps));
if (steps < stepsGoal) {
entries.add(new PieEntry((float) (stepsGoal - steps)));
}
DashboardChart.setCenterText(String.format("%d%%\n%s", (int) (steps * 100 / stepsGoal), context.getString(R.string.activity_list_summary_active_steps)));
PieDataSet dataSet = new PieDataSet(entries, "");
dataSet.setSliceSpace(0f);
dataSet.setSelectionShift(5f);
dataSet.setColors(Color.parseColor(ACTIVE_STEPS_CHART_COLOR), Color.LTGRAY);
PieData data = new PieData(dataSet);
data.setValueTextSize(0f);
data.setValueTextColor(Color.WHITE);
DashboardChart.setData(data);
DashboardChart.invalidate();
}
private void setDistanceData(ActivitySession item, PieChart DashboardChart, Context context) {
ArrayList<PieEntry> entries = new ArrayList<>();
float distance = item.getDistance();
entries.add(new PieEntry(distance));
if (distance < distanceMeters) {
entries.add(new PieEntry((float) (distanceMeters - distance)));
}
DashboardChart.setCenterText(String.format("%d%%\n%s", (int) (distance * 100 / distanceMeters), context.getString(R.string.distance)));
PieDataSet dataSet = new PieDataSet(entries, "");
dataSet.setSliceSpace(0f);
dataSet.setSelectionShift(5f);
dataSet.setColors(Color.parseColor(DISTANCE_CHART_COLOR), Color.LTGRAY);
PieData data = new PieData(dataSet);
data.setValueTextSize(0f);
data.setValueTextColor(Color.WHITE);
DashboardChart.setData(data);
DashboardChart.invalidate();
}
private void setDurationData(ActivitySession item, PieChart DashboardChart, Context context) {
ArrayList<PieEntry> entries = new ArrayList<>();
long duration = item.getEndTime().getTime() - item.getStartTime().getTime();
entries.add(new PieEntry((float) duration));
if (duration < activeTimeMillis) {
entries.add(new PieEntry((float) (activeTimeMillis - duration)));
}
DashboardChart.setCenterText(String.format("%d%%\n%s", (int) (duration * 100 / activeTimeMillis), context.getString(R.string.activity_list_summary_active_time)));
PieDataSet dataSet = new PieDataSet(entries, "");
dataSet.setSliceSpace(0f);
dataSet.setSelectionShift(5f);
dataSet.setColors(Color.parseColor(ACTIVE_TIME_CHART_COLOR), Color.LTGRAY);
PieData data = new PieData(dataSet);
data.setValueTextSize(0f);
data.setValueTextColor(Color.WHITE);
DashboardChart.setData(data);
DashboardChart.invalidate();
}
private void setUpChart(PieChart DashboardChart) {
DashboardChart.setNoDataText("");
DashboardChart.getLegend().setEnabled(false);
DashboardChart.setDrawHoleEnabled(true);
DashboardChart.setHoleColor(Color.WHITE);
DashboardChart.getDescription().setText("");
DashboardChart.setTransparentCircleColor(Color.WHITE);
DashboardChart.setTransparentCircleAlpha(110);
DashboardChart.setHoleRadius(70f);
DashboardChart.setTransparentCircleRadius(75f);
DashboardChart.setDrawCenterText(true);
DashboardChart.setRotationEnabled(true);
DashboardChart.setHighlightPerTapEnabled(true);
DashboardChart.setCenterTextOffset(0, 0);
}
@Override
protected String getDateLabel(ActivitySession item) {
return "";
}
@Override
protected boolean hasGPS(StepAnalysis.StepSession item) {
protected boolean hasGPS(ActivitySession item) {
return false;
}
@Override
protected boolean hasDate(StepAnalysis.StepSession item) {
protected boolean hasDate(ActivitySession item) {
return false;
}
@Override
protected String getTimeFrom(StepAnalysis.StepSession item) {
protected String getTimeFrom(ActivitySession item) {
Date time = item.getStartTime();
return DateTimeUtils.formatTime(time.getHours(), time.getMinutes());
}
@Override
protected String getTimeTo(StepAnalysis.StepSession item) {
protected String getTimeTo(ActivitySession item) {
Date time = item.getEndTime();
return DateTimeUtils.formatTime(time.getHours(), time.getMinutes());
}
@Override
protected String getActivityName(StepAnalysis.StepSession item) {
protected String getActivityName(ActivitySession item) {
return ActivityKind.asString(item.getActivityKind(), getContext());
}
@Override
protected String getStepLabel(StepAnalysis.StepSession item) {
return String.valueOf(item.getSteps());
protected String getStepLabel(ActivitySession item) {
return String.valueOf(item.getActiveSteps());
}
@Override
protected String getDistanceLabel(StepAnalysis.StepSession item) {
protected String getDistanceLabel(ActivitySession item) {
float distance = item.getDistance();
String unit = "###m";
if (distance > 2000) {
@ -61,69 +275,74 @@ public class ActivityListingAdapter extends AbstractActivityListingAdapter<StepA
unit = "###.#km";
}
DecimalFormat df = new DecimalFormat(unit);
//DecimalFormatSymbols symbols = df.getDecimalFormatSymbols();
//symbols.setGroupingSeparator(' ');
return df.format(distance);
}
@Override
protected String getHrLabel(StepAnalysis.StepSession item) {
protected String getHrLabel(ActivitySession item) {
return String.valueOf(item.getHeartRateAverage());
}
@Override
protected String getIntensityLabel(StepAnalysis.StepSession item) {
DecimalFormat df = new DecimalFormat("###.#");
protected String getIntensityLabel(ActivitySession item) {
DecimalFormat df = new DecimalFormat("###");
return df.format(item.getIntensity());
}
@Override
protected String getDurationLabel(StepAnalysis.StepSession item) {
protected String getDurationLabel(ActivitySession item) {
long duration = item.getEndTime().getTime() - item.getStartTime().getTime();
return DateTimeUtils.formatDurationHoursMinutes(duration, TimeUnit.MILLISECONDS);
}
@Override
public boolean hasHR(StepAnalysis.StepSession item) {
if (item.getHeartRateAverage() > 0) {
return true;
} else {
return false;
}
protected String getSessionCountLabel(ActivitySession item) {
return String.valueOf(item.getSessionCount());
}
@Override
public boolean hasIntensity(StepAnalysis.StepSession item) {
if (item.getIntensity() > 0) {
return true;
} else {
return false;
}
public boolean hasHR(ActivitySession item) {
return item.getHeartRateAverage() > 0;
}
@Override
protected boolean hasDistance(StepAnalysis.StepSession item) {
if (item.getDistance() > 0) {
return true;
} else {
return false;
}
public boolean hasIntensity(ActivitySession item) {
return item.getIntensity() > 0;
}
@Override
protected boolean hasSteps(StepAnalysis.StepSession item) {
if (item.getSteps() > 0) {
return true;
} else {
return false;
}
protected boolean hasDistance(ActivitySession item) {
return item.getDistance() > 0;
}
@Override
protected boolean hasSteps(ActivitySession item) {
return item.getActiveSteps() > 0;
}
@Override
protected int getIcon(StepAnalysis.StepSession item) {
protected boolean hasTotalSteps(ActivitySession item) {
return item.getTotalDaySteps() > 0;
}
@Override
protected boolean isSummary(ActivitySession item) {
int sessionType = item.getSessionType();
return sessionType == SESSION_SUMMARY;
}
@Override
protected boolean isEmptySummary(ActivitySession item) {
return item.getIsEmptySummary();
}
@Override
protected String getStepTotalLabel(ActivitySession item) {
return String.valueOf(item.getTotalDaySteps());
}
@Override
protected int getIcon(ActivitySession item) {
return ActivityKind.getIconId(item.getActivityKind());
}
}

View File

@ -42,14 +42,14 @@ import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession;
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
public class ActivityListingChartFragment extends AbstractChartFragment {
protected static final Logger LOG = LoggerFactory.getLogger(ActivityListingChartFragment.class);
int tsDateFrom;
private View rootView;
private List<? extends ActivitySample> activitySamples;
private ActivityListingAdapter stepListAdapter;
private TextView stepsDateView;
@ -57,18 +57,16 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
public View onCreateView(LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) {
rootView = inflater.inflate(R.layout.fragment_steps_list, container, false);
getChartsHost().enableSwipeRefresh(false);
ListView stepsList = rootView.findViewById(R.id.itemListView);
View headerView = inflater.inflate(R.layout.heartrate_average_widget,null, false);
stepsList.addHeaderView(headerView);
stepListAdapter = new ActivityListingAdapter(getContext());
stepsList.setAdapter(stepListAdapter);
stepsDateView = rootView.findViewById(R.id.stepsDateView);
refresh();
return rootView;
}
@Override
public String getTitle() {
return "Steps list";
@ -86,36 +84,40 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
}
}
@Override
protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
//trying to fit found peg into square hole of the Gb Charts fragment system
//get the data
List<? extends ActivitySample> activitySamples;
activitySamples = getSamples(db, device);
return null;
List<ActivitySession> stepSessions = null;
StepAnalysis stepAnalysis = new StepAnalysis();
boolean isEmptySummary = false;
if (activitySamples != null) {
stepSessions = stepAnalysis.calculateStepSessions(activitySamples);
if (stepSessions.toArray().length == 0) {
isEmptySummary = true;
}
stepSessions = stepAnalysis.calculateSummary(stepSessions, isEmptySummary);
}
return new MyChartsData(stepSessions);
}
@Override
protected void updateChartsnUIThread(ChartsData chartsData) {
//top displays selected date
stepsDateView.setText(DateTimeUtils.formatDate(new Date(tsDateFrom * 1000L)));
//calculate active sessions
StepAnalysis stepAnalysis = new StepAnalysis();
if (activitySamples != null) {
List<StepAnalysis.StepSession> 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
}
//push to the adapter
stepListAdapter.setItems(stepSessions, true);
MyChartsData mcd = (MyChartsData) chartsData;
if (mcd.getStepSessions().toArray().length == 0) {
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
}
stepsDateView.setText(DateTimeUtils.formatDate(new Date(tsDateFrom * 1000L)));
stepListAdapter.setItems(mcd.getStepSessions(), true);
}
@Override
protected void renderCharts() {
}
@Override
@ -135,16 +137,17 @@ public class ActivityListingChartFragment extends AbstractChartFragment {
return getAllSamples(db, device, tsFrom, tsTo);
}
private List<StepAnalysis.StepSession> create_empty_record() {
//have an "Unknown Activity" in the list in case there are no active sessions
List<StepAnalysis.StepSession> result = new ArrayList<>();
int tsTo = tsDateFrom + 24 * 60 * 60 - 1;
if (DateUtils.isToday(tsDateFrom * 1000L)) {
Calendar day = Calendar.getInstance();
day.set(Calendar.SECOND, 0);
tsTo = (int) (day.getTimeInMillis() / 1000);
private static class MyChartsData extends ChartsData {
private final List<ActivitySession> stepSessions;
MyChartsData(List<ActivitySession> stepSessions) {
this.stepSessions = stepSessions;
}
public List<ActivitySession> getStepSessions() {
return stepSessions;
}
result.add(new StepAnalysis.StepSession(new Date(tsDateFrom * 1000L), new Date(tsTo * 1000L), 0, 0, 0, 0, ActivityKind.TYPE_UNKNOWN));
return result;
}
}

View File

@ -21,7 +21,6 @@ import android.content.Context;
import android.content.Intent;
import android.graphics.Color;
import android.os.Bundle;
import android.util.Pair;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -244,7 +243,7 @@ public class SleepChartFragment extends AbstractChartFragment {
int min = Collections.min(heartRateValues);
int max = Collections.max(heartRateValues);
int count = heartRateValues.toArray().length;
float sum = calculateHRSum(heartRateValues);
float sum = calculateSumOfInts(heartRateValues);
float average = sum / count;
return Triple.of(average, min, max);
}
@ -257,7 +256,7 @@ public class SleepChartFragment extends AbstractChartFragment {
return result;
}
private float calculateHRSum(List<Integer> samples) {
private float calculateSumOfInts(List<Integer> samples) {
float result = 0;
for (Integer sample : samples) {
result += sample;

View File

@ -28,12 +28,14 @@ import nodomain.freeyourgadget.gadgetbridge.activities.HeartRateUtils;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession;
public class StepAnalysis {
protected static final Logger LOG = LoggerFactory.getLogger(StepAnalysis.class);
private int totalDailySteps = 0;
public List<StepSession> calculateStepSessions(List<? extends ActivitySample> samples) {
List<StepSession> result = new ArrayList<>();
public List<ActivitySession> calculateStepSessions(List<? extends ActivitySample> samples) {
List<ActivitySession> result = new ArrayList<>();
ActivityUser activityUser = new ActivityUser();
double STEP_LENGTH_M;
final int MIN_SESSION_LENGTH = 60 * GBApplication.getPrefs().getInt("chart_list_min_session_length", 5);
@ -41,6 +43,7 @@ public class StepAnalysis {
final int MIN_STEPS_PER_MINUTE = GBApplication.getPrefs().getInt("chart_list_min_steps_per_minute", 40);
int stepLengthCm = activityUser.getStepLengthCm();
int heightCm = activityUser.getHeightCm();
totalDailySteps = 0;
if (stepLengthCm == 0 && heightCm != 0) {
STEP_LENGTH_M = heightCm * 0.43 * 0.01;
@ -68,6 +71,11 @@ public class StepAnalysis {
HeartRateUtils heartRateUtilsInstance = HeartRateUtils.getInstance();
for (ActivitySample sample : samples) {
int steps = sample.getSteps();
if (steps > 0) {
totalDailySteps += steps;
}
if (sample.getKind() != ActivityKind.TYPE_SLEEP //anything but sleep counts
&& !(sample instanceof TrailingActivitySample)) { //trailing samples have wrong date and make trailing activity have 0 duration
if (heartRateUtilsInstance.isValidHeartRateValue(sample.getHeartRate())) {
@ -119,7 +127,7 @@ public class StepAnalysis {
float distance = (float) (activeSteps * STEP_LENGTH_M);
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));
result.add(new ActivitySession(sessionStart, sessionEnd, activeSteps, heartRateAverage, activeIntensity, distance, activityKind));
}
sessionStart = null;
}
@ -139,12 +147,69 @@ public class StepAnalysis {
float distance = (float) (activeSteps * STEP_LENGTH_M);
sessionEnd = getDateFromSample(previousSample);
activityKind = detect_activity_kind(session_length, activeSteps, heartRateAverage, activeIntensity);
result.add(new StepSession(sessionStart, sessionEnd, activeSteps, heartRateAverage, activeIntensity, distance, activityKind));
result.add(new ActivitySession(sessionStart, sessionEnd, activeSteps, heartRateAverage, activeIntensity, distance, activityKind));
}
}
return result;
}
public List<ActivitySession> calculateSummary(List<ActivitySession> sessions, boolean empty) {
HeartRateUtils heartRateUtilsInstance = HeartRateUtils.getInstance();
Date startTime = null;
Date endTime = null;
int stepsSum = 0;
int heartRateAverage = 0;
List<Integer> heartRateSum = new ArrayList<>();
int distanceSum = 0;
float intensitySum = 0;
int sessionCount;
int durationSum = 0;
for (ActivitySession session : sessions) {
startTime = session.getStartTime();
endTime = session.getEndTime();
durationSum += endTime.getTime() - startTime.getTime();
stepsSum += session.getActiveSteps();
distanceSum += session.getDistance();
heartRateSum.add(session.getHeartRateAverage());
intensitySum += session.getIntensity();
}
sessionCount = sessions.toArray().length;
if (heartRateSum.toArray().length > 0) {
heartRateAverage = calculateSumOfInts(heartRateSum) / heartRateSum.toArray().length;
}
if (!heartRateUtilsInstance.isValidHeartRateValue(heartRateAverage)) {
heartRateAverage = 0;
}
startTime = new Date(0);
endTime = new Date(durationSum);
ActivitySession stepSessionSummary = new ActivitySession(startTime, endTime,
stepsSum, heartRateAverage, intensitySum, distanceSum, 0);
stepSessionSummary.setSessionCount(sessionCount);
stepSessionSummary.setSessionType(ActivitySession.SESSION_SUMMARY);
stepSessionSummary.setEmptySummary(empty);
stepSessionSummary.setTotalDaySteps(totalDailySteps);
List<ActivitySession> newList = new ArrayList<>();
newList.add(stepSessionSummary);
newList.addAll(sessions);
return newList;
}
private int calculateSumOfInts(List<Integer> samples) {
int result = 0;
for (Integer sample : samples) {
result += sample;
}
return result;
}
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));
@ -160,61 +225,7 @@ public class StepAnalysis {
return ActivityKind.TYPE_ACTIVITY;
}
private boolean isStep(ActivitySample sample) {
return sample.getKind() == ActivityKind.TYPE_WALKING || sample.getKind() == ActivityKind.TYPE_RUNNING || sample.getKind() == ActivityKind.TYPE_ACTIVITY;
}
private Date getDateFromSample(ActivitySample sample) {
return new Date(sample.getTimestamp() * 1000L);
}
public static class StepSession {
private final Date startTime;
private final Date endTime;
private final int steps;
private final int heartRateAverage;
private final float intensity;
private final float distance;
private final int activityKind;
StepSession(Date startTime,
Date endTime,
int steps, int heartRateAverage, float intensity, float distance, int activityKind) {
this.startTime = startTime;
this.endTime = endTime;
this.steps = steps;
this.heartRateAverage = heartRateAverage;
this.intensity = intensity;
this.distance = distance;
this.activityKind = activityKind;
}
public Date getStartTime() {
return startTime;
}
public Date getEndTime() {
return endTime;
}
public int getSteps() {
return steps;
}
public int getHeartRateAverage() {
return heartRateAverage;
}
public int getActivityKind() {
return activityKind;
}
public float getIntensity() {
return intensity;
}
public float getDistance() {
return distance;
}
}
}

View File

@ -35,6 +35,8 @@ import java.util.ArrayList;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.StepAnalysis;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySession;
/**
* Adapter for displaying generic ItemWithDetails instances.
@ -43,6 +45,7 @@ public abstract class AbstractActivityListingAdapter<T> extends ArrayAdapter<T>
private final Context context;
private final List<T> items;
private final int SESSION_SUMMARY = ActivitySession.SESSION_SUMMARY;
private int backgroundColor = 0;
private int alternateColor = 0;
private boolean zebraStripes = true;
@ -67,15 +70,27 @@ public abstract class AbstractActivityListingAdapter<T> extends ArrayAdapter<T>
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);
if (isSummary(item)) {
view = fill_dashboard(item, position, view, parent, context);
} else {
view = fill_item(item, position, view, parent);
}
return view;
}
private View fill_item(T item, int position, View view, ViewGroup parent) {
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_time_from);
TextView timeTo = view.findViewById(R.id.line_layout_time_to);
TextView activityName = view.findViewById(R.id.line_layout_activity_name);
@ -160,6 +175,9 @@ public abstract class AbstractActivityListingAdapter<T> extends ArrayAdapter<T>
return view;
}
protected abstract View fill_dashboard(T item, int position, View view, ViewGroup parent, Context context);
protected abstract String getDateLabel(T item);
protected abstract boolean hasGPS(T item);
@ -182,6 +200,8 @@ public abstract class AbstractActivityListingAdapter<T> extends ArrayAdapter<T>
protected abstract String getDurationLabel(T item);
protected abstract String getSessionCountLabel(T item);
protected abstract boolean hasHR(T item);
protected abstract boolean hasIntensity(T item);
@ -190,6 +210,14 @@ public abstract class AbstractActivityListingAdapter<T> extends ArrayAdapter<T>
protected abstract boolean hasSteps(T item);
protected abstract boolean hasTotalSteps(T item);
protected abstract boolean isSummary(T item);
protected abstract boolean isEmptySummary(T item);
protected abstract String getStepTotalLabel(T item);
public void setZebraStripes(boolean enable) {
zebraStripes = enable;
}

View File

@ -18,6 +18,8 @@ package nodomain.freeyourgadget.gadgetbridge.adapter;
import android.content.Context;
import android.text.format.DateUtils;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;
import java.util.Calendar;
@ -134,6 +136,11 @@ public class ActivitySummariesAdapter extends AbstractActivityListingAdapter<Bas
this.deviceFilter = device;
}
@Override
protected View fill_dashboard(BaseActivitySummary item, int position, View view, ViewGroup parent, Context context) {
return null;
}
@Override
protected String getDateLabel(BaseActivitySummary item) {
Date startTime = item.getStartTime();
@ -219,6 +226,11 @@ public class ActivitySummariesAdapter extends AbstractActivityListingAdapter<Bas
return DateTimeUtils.formatDurationHoursMinutes(duration, TimeUnit.MILLISECONDS);
}
@Override
protected String getSessionCountLabel(BaseActivitySummary item) {
return "";
}
@Override
protected boolean hasHR(BaseActivitySummary item) {
return false;
@ -239,6 +251,26 @@ public class ActivitySummariesAdapter extends AbstractActivityListingAdapter<Bas
return false;
}
@Override
protected boolean hasTotalSteps(BaseActivitySummary item) {
return false;
}
@Override
protected boolean isSummary(BaseActivitySummary item) {
return false;
}
@Override
protected boolean isEmptySummary(BaseActivitySummary item) {
return false;
}
@Override
protected String getStepTotalLabel(BaseActivitySummary item) {
return null;
}
@Override
protected int getIcon(BaseActivitySummary item) {
return ActivityKind.getIconId(item.getActivityKind());

View File

@ -0,0 +1,98 @@
package nodomain.freeyourgadget.gadgetbridge.model;
import java.util.Date;
// ActivitySession holds activities detected by the steps/hr/intensity
// and is used in the Activity List
public class ActivitySession {
public static int SESSION_NORMAL = 1;
public static int SESSION_SUMMARY = 2;
private final Date startTime;
private final Date endTime;
private final int activeSteps;
private final int heartRateAverage;
private final float intensity;
private final float distance;
private final int activityKind;
// following is related to step session, we hold it here for the listview
// it is identified by SESSION_SUMMARY
private int sessionCount = 0;
private int sessionType = SESSION_NORMAL;
private boolean isEmptySummary = false; // in case there is no activity on that day
private int totalDaySteps;
public ActivitySession(Date startTime,
Date endTime,
int steps, int heartRateAverage, float intensity, float distance, int activityKind) {
this.startTime = startTime;
this.endTime = endTime;
this.activeSteps = steps;
this.heartRateAverage = heartRateAverage;
this.intensity = intensity;
this.distance = distance;
this.activityKind = activityKind;
}
public Date getStartTime() {
return startTime;
}
public Date getEndTime() {
return endTime;
}
public int getActiveSteps() {
return activeSteps;
}
public int getHeartRateAverage() {
return heartRateAverage;
}
public int getActivityKind() {
return activityKind;
}
public float getIntensity() {
return intensity;
}
public float getDistance() {
return distance;
}
public int getSessionCount() {
return sessionCount;
}
public void setSessionCount(int sessionCount) {
this.sessionCount = sessionCount;
}
public int getSessionType() {
return sessionType;
}
public void setSessionType(int sessionType) {
this.sessionType = sessionType;
}
public boolean getIsEmptySummary() {
return isEmptySummary;
}
public void setEmptySummary(boolean emptySummary) {
this.isEmptySummary = emptySummary;
}
public int getTotalDaySteps() {
return totalDaySteps;
}
public void setTotalDaySteps(int totalDaySteps) {
this.totalDaySteps = totalDaySteps;
}
}

View File

@ -0,0 +1,31 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="26dp"
android:height="26dp"
android:tint="#7E7E7E"
android:viewportWidth="26"
android:viewportHeight="26">
<path
android:pathData="m11.711,16.3278a4.8542,7.133 75.8015,0 1,-5.6028 -5.0206,4.8542 7.133,75.8015 0,1 8.1903,-5.0206 4.8542,7.133 75.8015,0 1,5.6028 5.0206,4.8542 7.133,75.8015 0,1 -8.1903,5.0206M21.4865,14.0769 L26.0048,11.3072 22.914,8.5375L23.9253,4.613L18.5345,4.613L15.4436,1.8433 10.9253,4.613L5.5345,4.613L4.5232,8.5375L0.0048,11.3072 3.0957,14.0769L2.0844,18.0013L7.4752,18.0013L10.566,20.771 15.0844,18.0013L20.4752,18.0013Z"
android:strokeWidth="1.01966"
android:fillColor="#000000"/>
<path
android:pathData="m4.273,11.6324l4.094,0l3.4795,-4.2078 1.0371,4.5933 2.6841,-2.2817l7.4587,0l-0.8601,1.1607L16.1168,10.897l-4.3503,3.7731 -0.8612,-3.8037 -1.6109,2.011 -4.0304,-0.0003z"
android:strokeWidth="1.01966"
android:fillColor="#000000"/>
<path
android:pathData="m1.8709,18.7471l-0.3147,1.2211l5.343,0l3.129,2.807 4.5735,-2.807l5.3453,0l0.3147,-1.2211l-5.4373,0l-4.4626,2.734 -3.0558,-2.734z"
android:strokeLineJoin="miter"
android:strokeWidth="0.591009"
android:fillColor="#000000"
android:strokeColor="#00000000"
android:fillType="evenOdd"
android:strokeLineCap="butt"/>
<path
android:pathData="m1.367,20.7367l-0.3147,1.2211l5.3453,0l3.1268,2.807 4.5735,-2.807l5.3453,0l0.3147,-1.2211l-5.4373,0l-4.4626,2.734 -3.0535,-2.734z"
android:strokeLineJoin="miter"
android:strokeWidth="0.591009"
android:fillColor="#000000"
android:strokeColor="#00000000"
android:fillType="evenOdd"
android:strokeLineCap="butt"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="?attr/colorControlNormal">
<path
android:fillColor="@android:color/white"
android:pathData="M3,5L1,5v16c0,1.1 0.9,2 2,2h16v-2L3,21L3,5zM21,1L7,1c-1.1,0 -2,0.9 -2,2v14c0,1.1 0.9,2 2,2h14c1.1,0 2,-0.9 2,-2L23,3c0,-1.1 -0.9,-2 -2,-2zM21,17L7,17L7,3h14v14z"/>
</vector>

View File

@ -0,0 +1,11 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:viewportHeight="24"
android:tint="#7E7E7E"
>
<path
android:fillColor="@android:color/white"
android:pathData="M18,4H6v2l6.5,6L6,18v2h12v-3h-7l5,-5 -5,-5h7V4z"/>
</vector>

View File

@ -1,15 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="21.367056dp"
android:width="24dp"
android:height="24dp"
android:tint="#7E7E7E"
android:viewportWidth="21.367056"
android:viewportWidth="24"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="m2.5,15.5784h4.1775L8.9012,9.8743 11.3875,16.1187 13.8885,6.0045 18.8671,15.5784 18.7123,18.896 14.4568,10.4989 11.965,21.5 8.9404,14.1173 7.9512,17.3235 3.8385,17.323Z"
android:strokeWidth="0.999994" />
<path
android:fillColor="#FF000000"
android:pathData="M8.9696,4.2276C9.4586,4.1648 9.801,3.7264 9.7306,3.2534 9.6601,2.7804 9.2023,2.4448 8.7133,2.5076 8.2243,2.5704 7.8819,3.0088 7.9524,3.4818 8.0229,3.9548 8.4806,4.2904 8.9696,4.2276ZM8.4469,10.4135 L8.5536,8.4877 10.1225,8.8668 10.2231,10.2646 11.2606,10.2284 11.0342,8.158 9.2155,7.7021 9.29,6.3777C9.964,6.9486 10.9171,7.2644 11.8951,7.1388L11.767,6.2788C10.9224,6.3872 10.147,6.0486 9.7017,5.4922L9.1546,4.8612C8.9384,4.6261 8.646,4.4883 8.3348,4.5283 8.2015,4.5454 8.119,4.5998 7.9856,4.617L5.8149,5.8599 6.1161,7.881 7.0052,7.7668 6.7873,6.3047 7.5427,5.9009 7.3579,9.9383l-1.3898,1.6275 0.4224,0.9079z"
android:strokeWidth="1" />
android:fillColor="@android:color/white"
android:pathData="M11.57,13.16c-1.36,0.28 -2.17,1.16 -2.17,2.41 0,1.34 1.11,2.42 2.49,2.42 2.05,0 3.71,-1.66 3.71,-3.71 0,-1.07 -0.15,-2.12 -0.46,-3.12 -0.79,1.07 -2.2,1.72 -3.57,2zM13.5,0.67s0.74,2.65 0.74,4.8c0,2.06 -1.35,3.73 -3.41,3.73 -2.07,0 -3.63,-1.67 -3.63,-3.73l0.03,-0.36C5.21,7.51 4,10.62 4,14c0,4.42 3.58,8 8,8s8,-3.58 8,-8C20,8.61 17.41,3.8 13.5,0.67zM12,20c-3.31,0 -6,-2.69 -6,-6 0,-1.53 0.3,-3.04 0.86,-4.43 1.01,1.01 2.41,1.63 3.97,1.63 2.66,0 4.75,-1.83 5.28,-4.43C17.34,8.97 18,11.44 18,14c0,3.31 -2.69,6 -6,6z" />
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:tint="#7E7E7E"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="m13.5,0.67c0,0 0.74,2.65 0.74,4.8 0,2.06 -1.35,3.73 -3.41,3.73C8.76,9.2 7.2,7.53 7.2,5.47L7.23,5.11C5.21,7.51 4,10.62 4,14c0,4.42 3.58,8 8,8 4.42,0 8,-3.58 8,-8C20,8.61 17.41,3.8 13.5,0.67ZM12,20C8.69,20 6,17.31 6,14 6,12.47 6.3,10.96 6.86,9.57c1.01,1.01 2.41,1.63 3.97,1.63 2.66,0 4.75,-1.83 5.28,-4.43 1.23,2.2 1.89,4.67 1.89,7.23 0,3.31 -2.69,6 -6,6z"/>
</vector>

View File

@ -0,0 +1,10 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:height="24dp"
android:viewportHeight="24"
android:viewportWidth="24"
android:tint="#7E7E7E"
android:width="24dp">
<path
android:fillColor="#000"
android:pathData="M10.74,11.72C11.21,12.95 11.16,14.23 9.75,14.74C6.85,15.81 6.2,13 6.16,12.86L10.74,11.72M5.71,10.91L10.03,9.84C9.84,8.79 10.13,7.74 10.13,6.5C10.13,4.82 8.8,1.53 6.68,2.06C4.26,2.66 3.91,5.35 4,6.65C4.12,7.95 5.64,10.73 5.71,10.91M17.85,19.85C17.82,20 17.16,22.8 14.26,21.74C12.86,21.22 12.8,19.94 13.27,18.71L17.85,19.85M20,13.65C20.1,12.35 19.76,9.65 17.33,9.05C15.22,8.5 13.89,11.81 13.89,13.5C13.89,14.73 14.17,15.78 14,16.83L18.3,17.9C18.38,17.72 19.89,14.94 20,13.65Z" />
</vector>

View File

@ -0,0 +1,15 @@
<vector xmlns:android="http://schemas.android.com/apk/res/android"
android:width="24dp"
android:height="24dp"
android:viewportWidth="24"
android:tint="#7E7E7E"
android:viewportHeight="24">
<path
android:fillColor="#FF000000"
android:pathData="m6.4801,14.3793c0.3823,1.0311 0.3416,2.104 -0.8053,2.5316C3.3159,17.8078 2.7872,15.4522 2.7547,15.3349l3.7255,-0.9556M2.3886,13.7003 L5.9026,12.8033c-0.1546,-0.8802 0.0813,-1.7604 0.0813,-2.7998 0,-1.4083 -1.0819,-4.1662 -2.8063,-3.7219 -1.9685,0.503 -2.2532,2.7579 -2.18,3.8476 0.0976,1.0897 1.334,3.4201 1.391,3.571m9.8749,7.4941C12.2392,21.3201 11.7023,23.6672 9.3434,22.7787 8.2046,22.3428 8.1558,21.2698 8.5381,20.2387l3.7255,0.9556m1.7489,-5.1972c0.0813,-1.0897 -0.1952,-3.3531 -2.1718,-3.856 -1.7163,-0.461 -2.7982,2.3136 -2.7982,3.7303 0,1.0311 0.2278,1.9112 0.0895,2.7914l3.4977,0.8969c0.0651,-0.1509 1.2933,-2.4813 1.3828,-3.5626z"
android:strokeWidth="0.999999"/>
<path
android:fillColor="#FF000000"
android:pathData="M14.7308,7.4903C14.986,8.2348 14.9589,9.0096 14.1934,9.3183 12.6189,9.9659 12.266,8.2651 12.2443,8.1803L14.7308,7.4903M12,7 L14.3454,6.3523c-0.1032,-0.6356 0.0543,-1.2711 0.0543,-2.0217 0,-1.0169 -0.7221,-3.0083 -1.873,-2.6875 -1.3138,0.3632 -1.5039,1.9914 -1.455,2.7783C11.1368,5.2083 11.962,6.891 12,7m6.5909,5.4113c-0.0162,0.0908 -0.3746,1.7856 -1.949,1.144 -0.7601,-0.3148 -0.7926,-1.0895 -0.5375,-1.834l2.4865,0.69m1.1673,-3.7528c0.0543,-0.7869 -0.1303,-2.4212 -1.4496,-2.7843 -1.1455,-0.3329 -1.8676,1.6706 -1.8676,2.6935 0,0.7445 0.152,1.3801 0.0597,2.0156l2.3345,0.6477c0.0435,-0.109 0.8632,-1.7917 0.9229,-2.5725z"
android:strokeWidth="0.999998"/>
</vector>

View File

@ -0,0 +1,379 @@
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:id="@+id/list_item_parent_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<!--
android:background="?android:attr/activatedBackgroundIndicator"
-->
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginBottom="10dp"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:gravity="center"
android:orientation="horizontal">
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/activity_dashboard_piechart1"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="0dp"
android:layout_weight="1" />
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/activity_dashboard_piechart2"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="0dp"
android:layout_weight="1" />
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/activity_dashboard_piechart3"
android:layout_width="110dp"
android:layout_height="110dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="0dp"
android:layout_weight="1" />
<!--
<com.github.mikephil.charting.charts.PieChart
android:id="@+id/activity_dashboard_piechart4"
android:layout_width="90dp"
android:layout_height="90dp"
android:layout_gravity="bottom|center"
android:layout_marginBottom="0dp" />
-->
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_gravity="center"
android:layout_marginBottom="5dp"
android:gravity="center"
android:orientation="horizontal">
<View
android:layout_width="25dp"
android:layout_height="0dp"
android:layout_weight="0.5" />
<include
layout="@layout/heartrate_average_widget"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="bottom|center"
android:layout_weight="1" />
<include
layout="@layout/intensity_total_widget"
android:layout_width="50dp"
android:layout_height="50dp"
android:layout_gravity="bottom|center"
android:layout_marginTop="0dp"
android:layout_marginEnd="0dp"
android:layout_weight="1" />
<View
android:layout_width="25dp"
android:layout_height="0dp"
android:layout_weight="0.5" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:baselineAligned="false"
android:gravity="bottom|center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/line_layout_step"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:gravity="center|top"
android:orientation="vertical">
<ImageView
android:id="@+id/line_layout_step_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_gravity="center"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_shoe_print" />
<TextView
android:id="@+id/line_layout_step_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxLines="2"
android:scrollHorizontally="false"
android:text="@string/activity_list_summary_active_steps" />
<TextView
android:id="@+id/line_layout_step_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="15000" />
</LinearLayout>
<LinearLayout
android:id="@+id/line_layout_distance"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:gravity="center|top"
android:orientation="vertical">
<ImageView
android:id="@+id/line_layout_distance_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_gravity="center"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_distance" />
<TextView
android:id="@+id/line_layout_distance_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxLines="2"
android:scrollHorizontally="false"
android:text="@string/distance" />
<TextView
android:id="@+id/line_layout_distance_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="15.1km" />
</LinearLayout>
<LinearLayout
android:id="@+id/line_layout_duration"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:gravity="center|top"
android:orientation="vertical">
<ImageView
android:id="@+id/line_layout_duration_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_gravity="center"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_access_time" />
<TextView
android:id="@+id/line_layout_duration_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxLines="2"
android:scrollHorizontally="false"
android:text="@string/activity_list_summary_active_time" />
<TextView
android:id="@+id/line_layout_duration_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="122" />
</LinearLayout>
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="5dp"
android:layout_marginBottom="5dp"
android:baselineAligned="false"
android:gravity="center"
android:orientation="horizontal">
<LinearLayout
android:id="@+id/line_layout_total_step"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/line_layout_total_step_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_gravity="center"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_shoe_prints_many" />
<TextView
android:id="@+id/line_layout_total_step_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxLines="2"
android:scrollHorizontally="false"
android:text="@string/live_activity_total_steps" />
<TextView
android:id="@+id/line_layout_total_step_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="15000" />
</LinearLayout>
<LinearLayout
android:id="@+id/line_layout_count"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center|top"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:gravity="center"
android:orientation="vertical">
<ImageView
android:id="@+id/line_layout_count_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_gravity="center"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_activity_stacked" />
<TextView
android:id="@+id/line_layout_count_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxLines="2"
android:scrollHorizontally="false"
android:text="@string/activity_list_summary_activities" />
<TextView
android:id="@+id/line_layout_count_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="15" />
</LinearLayout>
<LinearLayout
android:id="@+id/line_layout_intensity2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="bottom|center"
android:layout_marginStart="1dp"
android:layout_marginEnd="1dp"
android:layout_weight="1"
android:gravity="bottom|center"
android:orientation="vertical">
<ImageView
android:id="@+id/line_layout_intensity2_icon"
android:layout_width="19dp"
android:layout_height="19dp"
android:layout_gravity="center"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_intensity" />
<TextView
android:id="@+id/line_layout_intensity2_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:gravity="center"
android:maxLines="2"
android:scrollHorizontally="false"
android:text="@string/activity_list_summary_intensity" />
<TextView
android:id="@+id/line_layout_intensity2_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:fontFamily="sans-serif-black"
android:gravity="center"
android:maxLines="1"
android:scrollHorizontally="false"
android:text="15" />
</LinearLayout>
</LinearLayout>
</LinearLayout>
</RelativeLayout>

View File

@ -134,7 +134,7 @@
android:layout_height="19dp"
android:layout_gravity="bottom|start"
android:contentDescription="@string/candidate_item_device_image"
app:srcCompat="@drawable/ic_shoe" />
app:srcCompat="@drawable/ic_shoe_print" />
<TextView
android:id="@+id/line_layout_step_label"

View File

@ -4,7 +4,6 @@
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment">
<TextView
android:id="@+id/stepsDateView"
android:layout_width="match_parent"
@ -14,8 +13,12 @@
android:textAppearance="@style/TextAppearance.AppCompat.Medium"
android:textStyle="bold" />
<ListView
android:id="@+id/itemListView"
android:layout_marginTop="0dp"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
</LinearLayout>

View File

@ -14,14 +14,13 @@
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/ic_activity_unknown" />
app:srcCompat="@drawable/ic_intensity_hollow" />
<TextView
android:id="@+id/intensity_widget_label"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:paddingBottom="3dp"
android:paddingEnd="3dp"
android:paddingTop="10dp"
android:text=""
android:textAlignment="center"
android:textSize="12sp"

View File

@ -443,6 +443,11 @@
<string name="weekstepschart_steps_a_week">Steps per week</string>
<string name="activity_sleepchart_activity_and_sleep">Activity</string>
<string name="charts_activity_list">Activity list</string>
<string name="activity_list_summary_active_steps">Active steps</string>
<string name="activity_list_summary_distance">Distance</string>
<string name="activity_list_summary_active_time">Active time</string>
<string name="activity_list_summary_intensity">Movement\nIntensity</string>
<string name="activity_list_summary_activities">Activities</string>
<string name="lack_of_sleep">Lack of sleep: %1$s</string>
<string name="overslept">Overslept: %1$s</string>
<!-- Firmware updating -->