mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-12-30 20:45:49 +01:00
Add Steps streaks screen
This commit is contained in:
parent
4dc4a4f988
commit
c6104f5332
340
app/src/main/assets/olive_laurel.svg
Normal file
340
app/src/main/assets/olive_laurel.svg
Normal file
File diff suppressed because one or more lines are too long
After Width: | Height: | Size: 23 KiB |
@ -20,11 +20,15 @@ package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
import android.app.Activity;
|
||||
import android.graphics.Color;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.github.mikephil.charting.charts.BarChart;
|
||||
import com.github.mikephil.charting.charts.PieChart;
|
||||
import com.github.mikephil.charting.components.LimitLine;
|
||||
@ -69,6 +73,7 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
|
||||
private TextView mBalanceView;
|
||||
|
||||
private int mOffsetHours = getOffsetHours();
|
||||
ImageView stepsStreaksButton;
|
||||
|
||||
@Override
|
||||
protected ChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
|
||||
@ -98,6 +103,20 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
|
||||
mWeekChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter());
|
||||
|
||||
mBalanceView.setText(mcd.getWeekBeforeData().getBalanceMessage());
|
||||
|
||||
//disable the streak FAB once we move away from today
|
||||
Calendar day = Calendar.getInstance();
|
||||
day.setTime(getChartsHost().getEndDate());
|
||||
if (DateUtils.isToday(day.getTimeInMillis()) && enableStepStreaksButton()){
|
||||
stepsStreaksButton.setVisibility(View.VISIBLE);
|
||||
}else
|
||||
{
|
||||
stepsStreaksButton.setVisibility(View.GONE);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean enableStepStreaksButton(){
|
||||
return this.getClass().getSimpleName().equals("WeekStepsChartFragment");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -225,7 +244,7 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
|
||||
|
||||
View rootView = inflater.inflate(R.layout.fragment_weeksteps_chart, container, false);
|
||||
|
||||
int goal = getGoal();
|
||||
final int goal = getGoal();
|
||||
if (goal >= 0) {
|
||||
mTargetValue = goal;
|
||||
}
|
||||
@ -237,12 +256,28 @@ public abstract class AbstractWeekChartFragment extends AbstractChartFragment {
|
||||
setupWeekChart();
|
||||
setupTodayPieChart();
|
||||
|
||||
stepsStreaksButton = rootView.findViewById(R.id.steps_streaks_button);
|
||||
if (enableStepStreaksButton()) {
|
||||
stepsStreaksButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
FragmentManager fm = getActivity().getSupportFragmentManager();
|
||||
StepStreaksDashboard stepStreaksDashboard = StepStreaksDashboard.newInstance(getGoal(), getChartsHost().getDevice());
|
||||
stepStreaksDashboard.show(fm, "steps_streaks_dashboard");
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
// refresh immediately instead of use refreshIfVisible(), for perceived performance
|
||||
refresh();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
private void setupTodayPieChart() {
|
||||
mTodayPieChart.setBackgroundColor(BACKGROUND_COLOR);
|
||||
mTodayPieChart.getDescription().setTextColor(DESCRIPTION_COLOR);
|
||||
|
@ -0,0 +1,319 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.text.format.DateUtils;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.ProgressBar;
|
||||
import android.widget.TextView;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.fragment.app.DialogFragment;
|
||||
import androidx.fragment.app.FragmentActivity;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBAccess;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.DailyTotals;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
|
||||
public class StepStreaksDashboard extends DialogFragment {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(StepStreaksDashboard.class);
|
||||
GBDevice gbDevice;
|
||||
int stepsGoal;
|
||||
boolean cancelTasks = false;
|
||||
boolean backgroundTaskFinished = false;
|
||||
private View fragmentView;
|
||||
private final StepsStreaks stepsStreaks = new StepsStreaks();
|
||||
private static final String GOAL = "goal";
|
||||
private static final String PERIOD_CURRENT = "current";
|
||||
private static final String PERIOD_TOTALS = "totals";
|
||||
private static final int MAX_YEAR = 2015;
|
||||
|
||||
public StepStreaksDashboard() {
|
||||
|
||||
}
|
||||
|
||||
//Calculates some stats for longest streak (daily steps goal being reached for subsequent days
|
||||
//without interruption (day with steps less then goal)
|
||||
//Possible improvements/nice to haves:
|
||||
//- cache values until new activity fetch is performed
|
||||
//- create a parcel to allow screen rotation without recalculation
|
||||
//- read the goals from the USER_ATTRIBUTES table. But, this would also require to be able
|
||||
//to edit/add values there...
|
||||
|
||||
public static StepStreaksDashboard newInstance(int goal, GBDevice device) {
|
||||
|
||||
StepStreaksDashboard fragment = new StepStreaksDashboard();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt(GOAL, goal);
|
||||
args.putParcelable(GBDevice.EXTRA_DEVICE, device);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
return inflater.inflate(R.layout.steps_streaks_dashboard, container);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStop() {
|
||||
super.onStop();
|
||||
cancelTasks = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
super.onDestroy();
|
||||
cancelTasks = true;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onViewCreated(final View view, @Nullable Bundle savedInstanceState) {
|
||||
super.onViewCreated(view, savedInstanceState);
|
||||
|
||||
stepsGoal = getArguments().getInt(GOAL, 0);
|
||||
gbDevice = getArguments().getParcelable(GBDevice.EXTRA_DEVICE);
|
||||
fragmentView = view;
|
||||
if (gbDevice == null) {
|
||||
throw new IllegalArgumentException("Must provide a device when invoking this activity");
|
||||
}
|
||||
createTaskCalculateLatestStepsStreak("Visualizing data current", getActivity(), PERIOD_CURRENT).execute();
|
||||
createTaskCalculateLatestStepsStreak("Visualizing data maximum", getActivity(), PERIOD_TOTALS).execute();
|
||||
}
|
||||
|
||||
|
||||
void indicate_progress(boolean inProgress) {
|
||||
ProgressBar step_streak_dashboard_loading_circle = fragmentView.findViewById(R.id.step_streak_dashboard_loading_circle);
|
||||
if (inProgress) {
|
||||
step_streak_dashboard_loading_circle.setAlpha(0.4f); //make it a bit softer
|
||||
} else {
|
||||
step_streak_dashboard_loading_circle.setAlpha(0);
|
||||
}
|
||||
}
|
||||
|
||||
void populateData() {
|
||||
|
||||
LinearLayout current = getView().findViewById(R.id.step_streak_current_layout);
|
||||
TextView days_current = current.findViewById(R.id.step_streak_days_value);
|
||||
TextView average_current = current.findViewById(R.id.step_streak_average_value);
|
||||
TextView total_current = current.findViewById(R.id.step_streak_total_value);
|
||||
TextView date_current_value = current.findViewById(R.id.step_streak_current_date_value);
|
||||
|
||||
LinearLayout maximum = getView().findViewById(R.id.step_streak_maximum_layout);
|
||||
TextView days_maximum = maximum.findViewById(R.id.step_streak_days_value);
|
||||
TextView average_maximum = maximum.findViewById(R.id.step_streak_average_value);
|
||||
TextView total_maximum = maximum.findViewById(R.id.step_streak_total_value);
|
||||
TextView date_maximum_value = maximum.findViewById(R.id.step_streak_maximum_date_value);
|
||||
|
||||
LinearLayout total = getView().findViewById(R.id.step_streak_total_layout);
|
||||
TextView days_total = total.findViewById(R.id.step_streak_days_value);
|
||||
TextView days_total_label = total.findViewById(R.id.step_streak_days_label);
|
||||
TextView total_total = total.findViewById(R.id.step_streak_total_value);
|
||||
TextView date_total_value = total.findViewById(R.id.step_streak_total_date_value);
|
||||
TextView date_total_label = total.findViewById(R.id.step_streak_total_label);
|
||||
|
||||
if (stepsStreaks.current.days > 0) {
|
||||
current.setVisibility(View.VISIBLE);
|
||||
days_current.setText(Integer.toString(stepsStreaks.current.days));
|
||||
average_current.setText(Integer.toString(stepsStreaks.current.steps / stepsStreaks.current.days));
|
||||
total_current.setText(Integer.toString(stepsStreaks.current.steps));
|
||||
|
||||
Date startDate = new Date(stepsStreaks.current.timestamp * 1000L);
|
||||
Date endDate = DateTimeUtils.shiftByDays(startDate, stepsStreaks.current.days - 1); //first day is 1 not 0
|
||||
date_current_value.setText(DateTimeUtils.formatDateRange(startDate, endDate));
|
||||
}
|
||||
|
||||
if (stepsStreaks.maximum.days > 0) {
|
||||
maximum.setVisibility(View.VISIBLE);
|
||||
days_maximum.setText(Integer.toString(stepsStreaks.maximum.days));
|
||||
average_maximum.setText(Integer.toString(stepsStreaks.maximum.steps / stepsStreaks.maximum.days));
|
||||
total_maximum.setText(Integer.toString(stepsStreaks.maximum.steps));
|
||||
|
||||
Date startDate = new Date(stepsStreaks.maximum.timestamp * 1000L);
|
||||
Date endDate = DateTimeUtils.shiftByDays(startDate, stepsStreaks.maximum.days - 1); //first day is 1 not 0
|
||||
date_maximum_value.setText(DateTimeUtils.formatDateRange(startDate, endDate));
|
||||
}
|
||||
if (stepsStreaks.total.steps > 0 || backgroundTaskFinished) {
|
||||
total.setVisibility(View.VISIBLE);
|
||||
days_total_label.setText(R.string.steps_streaks_achievement_rate);
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
//labels here have diferent meaning, so we must also add proper hint
|
||||
days_total_label.setTooltipText(getString(R.string.steps_streaks_total_days_hint_totals));
|
||||
days_total.setTooltipText(getString(R.string.steps_streaks_total_days_hint_totals));
|
||||
date_total_label.setTooltipText(getString(R.string.steps_streaks_total_steps_hint_totals));
|
||||
}
|
||||
|
||||
days_total.setText(String.format("%.1f%%", 0.0));
|
||||
if (stepsStreaks.total.total_days > 0) {
|
||||
days_total.setText(String.format("%.1f%%", (float) stepsStreaks.total.days / stepsStreaks.total.total_days * 100));
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
|
||||
total_total.setTooltipText(String.format(getString(R.string.steps_streaks_total_steps_average_hint), stepsStreaks.total.steps / stepsStreaks.total.total_days));
|
||||
}
|
||||
|
||||
}
|
||||
if (stepsStreaks.total.timestamp > 0) {
|
||||
date_total_value.setVisibility(View.VISIBLE);
|
||||
date_total_value.setText(String.format(getString(R.string.steps_streaks_since_date), DateTimeUtils.formatDate(new Date(stepsStreaks.total.timestamp * 1000L))));
|
||||
} else {
|
||||
date_total_value.setVisibility(View.GONE);
|
||||
}
|
||||
total_total.setText(Integer.toString(stepsStreaks.total.steps));
|
||||
}
|
||||
}
|
||||
|
||||
protected TaskCalculateLatestStepsStreak createTaskCalculateLatestStepsStreak(String taskName, Context context, String period) {
|
||||
return new TaskCalculateLatestStepsStreak(taskName, context, period);
|
||||
}
|
||||
|
||||
public class TaskCalculateLatestStepsStreak extends DBAccess {
|
||||
String period;
|
||||
|
||||
public TaskCalculateLatestStepsStreak(String taskName, Context context, String period) {
|
||||
super(taskName, context);
|
||||
this.period = period;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void doInBackground(DBHandler db) {
|
||||
switch (period) {
|
||||
case PERIOD_CURRENT:
|
||||
calculateStreakData(db, PERIOD_CURRENT, gbDevice, stepsGoal);
|
||||
|
||||
break;
|
||||
case PERIOD_TOTALS:
|
||||
calculateStreakData(db, PERIOD_TOTALS, gbDevice, stepsGoal);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPreExecute() {
|
||||
indicate_progress(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onPostExecute(Object o) {
|
||||
super.onPostExecute(o);
|
||||
FragmentActivity activity = getActivity();
|
||||
if (activity != null && !activity.isFinishing() && !activity.isDestroyed()) {
|
||||
if (period.equals(PERIOD_TOTALS)) {
|
||||
backgroundTaskFinished = true;
|
||||
indicate_progress(false);
|
||||
}
|
||||
populateData();
|
||||
} else {
|
||||
LOG.info("Not filling data because activity is not available anymore");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void calculateStreakData(DBHandler db, String period, GBDevice device, int goal) {
|
||||
Calendar day = Calendar.getInstance();
|
||||
int streak_steps = 0;
|
||||
int streak_days = 0;
|
||||
int timestamp = 0;
|
||||
|
||||
int all_step_days = 0;
|
||||
int all_streak_days = 0;
|
||||
int all_steps = 0;
|
||||
int firstDataTimestamp = 0;
|
||||
|
||||
DailyTotals dailyTotals = new DailyTotals();
|
||||
ActivitySample firstSample = dailyTotals.getFirstSample(db, device);
|
||||
if (firstSample == null) { //no data at all
|
||||
return;
|
||||
}
|
||||
Calendar firstDate = Calendar.getInstance();
|
||||
firstDate.setTime(DateTimeUtils.shiftByDays(new Date(firstSample.getTimestamp() * 1000L), -1));
|
||||
//go one day back, to ensure we are before the first day, to calculate first day data as well
|
||||
|
||||
while (true) {
|
||||
if (cancelTasks) {
|
||||
GB.toast("Cancelling background jobs", Toast.LENGTH_SHORT, GB.INFO);
|
||||
break;
|
||||
}
|
||||
|
||||
long[] daily_data = dailyTotals.getDailyTotalsForDevice(device, day, db);
|
||||
int steps_this_day = (int) daily_data[0];
|
||||
|
||||
if (steps_this_day > 0) {
|
||||
all_step_days++;
|
||||
all_steps += steps_this_day;
|
||||
firstDataTimestamp = (int) (day.getTimeInMillis() / 1000);
|
||||
}
|
||||
|
||||
if (steps_this_day >= goal) {
|
||||
streak_steps += steps_this_day;
|
||||
streak_days++;
|
||||
all_streak_days++;
|
||||
timestamp = (int) (day.getTimeInMillis() / 1000);
|
||||
Date newDate = DateTimeUtils.shiftByDays(new Date(day.getTimeInMillis()), -1);
|
||||
day.setTime(newDate);
|
||||
} else if (DateUtils.isToday(day.getTimeInMillis())) {
|
||||
//if goal is not reached today, we might still get our steps later
|
||||
// so do not count this day but do not interrupt
|
||||
Date newDate = DateTimeUtils.shiftByDays(new Date(day.getTimeInMillis()), -1);
|
||||
day.setTime(newDate);
|
||||
} else {
|
||||
if (period.equals(PERIOD_CURRENT)) {
|
||||
stepsStreaks.current.days = streak_days;
|
||||
stepsStreaks.current.steps = streak_steps;
|
||||
stepsStreaks.current.timestamp = timestamp;
|
||||
return;
|
||||
} else if (period.equals(PERIOD_TOTALS)) {
|
||||
//reset max
|
||||
if (streak_days > stepsStreaks.maximum.days) {
|
||||
stepsStreaks.maximum.steps = streak_steps;
|
||||
stepsStreaks.maximum.days = streak_days;
|
||||
stepsStreaks.maximum.timestamp = timestamp;
|
||||
}
|
||||
stepsStreaks.total.steps = all_steps;
|
||||
stepsStreaks.total.days = all_streak_days;
|
||||
stepsStreaks.total.total_days = all_step_days;
|
||||
stepsStreaks.total.timestamp = firstDataTimestamp;
|
||||
|
||||
streak_days = 0;
|
||||
streak_steps = 0;
|
||||
Date newDate = DateTimeUtils.shiftByDays(new Date(day.getTimeInMillis()), -1);
|
||||
day.setTime(newDate);
|
||||
if (day.before(firstDate) || day.get(Calendar.YEAR) < MAX_YEAR) {
|
||||
//avoid rolling back too far, if the data has a timestamp too far into future
|
||||
//we could make this date configurable if needed for people who imported old data
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class StepsStreak {
|
||||
private int days = 0;
|
||||
private int steps = 0;
|
||||
private int timestamp;
|
||||
private int total_days = 0;
|
||||
}
|
||||
|
||||
private class StepsStreaks {
|
||||
private StepsStreak current = new StepsStreak();
|
||||
private StepsStreak maximum = new StepsStreak();
|
||||
private StepsStreak total = new StepsStreak();
|
||||
}
|
||||
}
|
||||
|
@ -110,6 +110,26 @@ public abstract class AbstractSampleProvider<T extends AbstractActivitySample> i
|
||||
return sample;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public T getFirstActivitySample() {
|
||||
QueryBuilder<T> qb = getSampleDao().queryBuilder();
|
||||
Device dbDevice = DBHelper.findDevice(getDevice(), getSession());
|
||||
if (dbDevice == null) {
|
||||
// no device, no sample
|
||||
return null;
|
||||
}
|
||||
Property deviceProperty = getDeviceIdentifierSampleProperty();
|
||||
qb.where(deviceProperty.eq(dbDevice.getId())).orderAsc(getTimestampSampleProperty()).limit(1);
|
||||
List<T> samples = qb.build().list();
|
||||
if (samples.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
T sample = samples.get(0);
|
||||
sample.setProvider(this);
|
||||
return sample;
|
||||
}
|
||||
|
||||
protected List<T> getGBActivitySamples(int timestamp_from, int timestamp_to, int activityType) {
|
||||
if (getRawKindSampleProperty() == null && activityType != ActivityKind.TYPE_ALL) {
|
||||
// if we do not have a raw kind property we cannot query anything else then TYPE_ALL
|
||||
|
@ -99,4 +99,12 @@ public interface SampleProvider<T extends AbstractActivitySample> {
|
||||
*/
|
||||
@Nullable
|
||||
T getLatestActivitySample();
|
||||
|
||||
/**
|
||||
* Returns the activity sample with the oldest timestamp or null if none
|
||||
* @return the oldest sample or null
|
||||
*/
|
||||
@Nullable
|
||||
T getFirstActivitySample();
|
||||
|
||||
}
|
||||
|
@ -87,6 +87,13 @@ public class UnknownDeviceCoordinator extends AbstractDeviceCoordinator {
|
||||
public AbstractActivitySample getLatestActivitySample() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public AbstractActivitySample getFirstActivitySample() {
|
||||
return null;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
public UnknownDeviceCoordinator() {
|
||||
|
@ -143,9 +143,14 @@ public class DailyTotals {
|
||||
return coordinator.getSampleProvider(device, db.getDaoSession());
|
||||
}
|
||||
|
||||
|
||||
protected List<? extends ActivitySample> getAllSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
|
||||
SampleProvider<? extends ActivitySample> provider = getProvider(db, device);
|
||||
return provider.getAllActivitySamples(tsFrom, tsTo);
|
||||
}
|
||||
|
||||
public ActivitySample getFirstSample(DBHandler db, GBDevice device) {
|
||||
SampleProvider<? extends ActivitySample> provider = getProvider(db, device);
|
||||
return provider.getFirstActivitySample();
|
||||
}
|
||||
|
||||
}
|
||||
|
10
app/src/main/res/drawable/ic_events.xml
Normal file
10
app/src/main/res/drawable/ic_events.xml
Normal file
@ -0,0 +1,10 @@
|
||||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:tint="#7E7E7E"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path
|
||||
android:fillColor="@android:color/white"
|
||||
android:pathData="M19,5h-2V3H7v2H5C3.9,5 3,5.9 3,7v1c0,2.55 1.92,4.63 4.39,4.94c0.63,1.5 1.98,2.63 3.61,2.96V19H7v2h10v-2h-4v-3.1c1.63,-0.33 2.98,-1.46 3.61,-2.96C19.08,12.63 21,10.55 21,8V7C21,5.9 20.1,5 19,5zM5,8V7h2v3.82C5.84,10.4 5,9.3 5,8zM12,14c-1.65,0 -3,-1.35 -3,-3V5h6v6C15,12.65 13.65,14 12,14zM19,8c0,1.3 -0.84,2.4 -2,2.82V7h2V8z" />
|
||||
</vector>
|
21
app/src/main/res/drawable/ic_events_gold.xml
Normal file
21
app/src/main/res/drawable/ic_events_gold.xml
Normal file
File diff suppressed because one or more lines are too long
@ -1,37 +1,58 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"
|
||||
android:orientation="horizontal">
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="40"
|
||||
android:orientation="vertical">
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
android:orientation="horizontal"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment">
|
||||
|
||||
<com.github.mikephil.charting.charts.PieChart
|
||||
android:id="@+id/todaystepschart"
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_weight="40"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.github.mikephil.charting.charts.PieChart
|
||||
android:id="@+id/todaystepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="40" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/weekstepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="40" />
|
||||
android:layout_weight="20" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/weekstepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="20" />
|
||||
|
||||
<!--<TextView-->
|
||||
<!--<TextView-->
|
||||
<!--android:text="Test"-->
|
||||
<!--android:layout_width="fill_parent"-->
|
||||
<!--android:layout_height="fill_parent"-->
|
||||
<!--android:layout_weight="20" />-->
|
||||
|
||||
</LinearLayout>
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/steps_streaks_button"
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginStart="5dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:visibility="visible"
|
||||
app:srcCompat="@drawable/ic_events" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
|
@ -1,25 +1,44 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment"
|
||||
android:orientation="vertical">
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context="nodomain.freeyourgadget.gadgetbridge.activities.charts.ChartsActivity$PlaceholderFragment">
|
||||
|
||||
<com.github.mikephil.charting.charts.PieChart
|
||||
android:id="@+id/todaystepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="20" />
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/weekstepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="20" />
|
||||
<com.github.mikephil.charting.charts.PieChart
|
||||
android:id="@+id/todaystepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="20" />
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/weekstepschart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="20" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="50dp"
|
||||
android:layout_height="50dp"
|
||||
android:id="@+id/steps_streaks_button"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginEnd="0dp"
|
||||
android:visibility="visible"
|
||||
app:srcCompat="@drawable/ic_events" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
38
app/src/main/res/layout/steps_streak_average.xml
Normal file
38
app/src/main/res/layout/steps_streak_average.xml
Normal file
@ -0,0 +1,38 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center|top"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center|top"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
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/steps_streaks_average_steps"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:tooltipText="@string/step_streak_average_steps_hint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_average_value"
|
||||
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"
|
||||
android:textSize="24sp"
|
||||
android:tooltipText="@string/step_streak_average_steps_hint" />
|
||||
|
||||
</LinearLayout>
|
52
app/src/main/res/layout/steps_streak_current_line_layout.xml
Normal file
52
app/src/main/res/layout/steps_streak_current_line_layout.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/step_streak_current_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false"
|
||||
android:text="@string/step_streak_ongoing"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_current_date_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="bottom|center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include layout="@layout/steps_streak_days" />
|
||||
|
||||
<include layout="@layout/steps_streak_average" />
|
||||
|
||||
<include layout="@layout/steps_streak_total" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
40
app/src/main/res/layout/steps_streak_days.xml
Normal file
40
app/src/main/res/layout/steps_streak_days.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/step_streak_days_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center|top"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center|top"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_days_label"
|
||||
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/steps_streaks_streak_days"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:tooltipText="@string/step_streak_days_hint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_days_value"
|
||||
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="9150000"
|
||||
android:textSize="24sp"
|
||||
android:tooltipText="@string/step_streak_days_hint" />
|
||||
|
||||
</LinearLayout>
|
52
app/src/main/res/layout/steps_streak_maximum_line_layout.xml
Normal file
52
app/src/main/res/layout/steps_streak_maximum_line_layout.xml
Normal file
@ -0,0 +1,52 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/step_streak_maximum_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false"
|
||||
android:text="@string/step_streak_longest"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_maximum_date_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="bottom|center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include layout="@layout/steps_streak_days" />
|
||||
|
||||
<include layout="@layout/steps_streak_average" />
|
||||
|
||||
<include layout="@layout/steps_streak_total" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
40
app/src/main/res/layout/steps_streak_total.xml
Normal file
40
app/src/main/res/layout/steps_streak_total.xml
Normal file
@ -0,0 +1,40 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_gravity="center|top"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center|top"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_total_label"
|
||||
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/steps_streaks_total_steps"
|
||||
android:textAllCaps="true"
|
||||
android:textColor="@color/accent"
|
||||
android:textStyle="bold"
|
||||
android:tooltipText="@string/steps_streaks_total_steps_hint" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_total_value"
|
||||
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="9150000"
|
||||
android:textSize="24sp"
|
||||
android:tooltipText="@string/steps_streaks_total_steps_hint" />
|
||||
|
||||
|
||||
</LinearLayout>
|
50
app/src/main/res/layout/steps_streak_total_line_layout.xml
Normal file
50
app/src/main/res/layout/steps_streak_total_line_layout.xml
Normal file
@ -0,0 +1,50 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/step_streak_total_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false"
|
||||
android:text="@string/step_streak_total"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/step_streak_total_date_value"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:baselineAligned="false"
|
||||
android:gravity="bottom|center"
|
||||
android:orientation="horizontal">
|
||||
|
||||
<include layout="@layout/steps_streak_days" />
|
||||
|
||||
<include layout="@layout/steps_streak_total" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</LinearLayout>
|
69
app/src/main/res/layout/steps_streaks_dashboard.xml
Normal file
69
app/src/main/res/layout/steps_streaks_dashboard.xml
Normal file
@ -0,0 +1,69 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/about_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
|
||||
<LinearLayout xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="0dp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:gravity="center|center_vertical"
|
||||
android:minWidth="1000dp"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_weight="1"
|
||||
android:gravity="center"
|
||||
android:maxLines="2"
|
||||
android:scrollHorizontally="false"
|
||||
android:text="@string/steps_streaks"
|
||||
android:textAllCaps="true"
|
||||
android:textSize="24sp"
|
||||
android:textStyle="bold"
|
||||
android:tooltipText="@string/steps_streaks_hint" />
|
||||
|
||||
<include
|
||||
layout="@layout/steps_streak_current_line_layout"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include
|
||||
layout="@layout/steps_streak_maximum_line_layout"
|
||||
android:visibility="gone" />
|
||||
|
||||
<include
|
||||
layout="@layout/steps_streak_total_line_layout"
|
||||
android:visibility="gone" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="0dp"
|
||||
android:layout_marginBottom="0dp"
|
||||
android:gravity="center"
|
||||
android:orientation="vertical">
|
||||
|
||||
<ImageView
|
||||
android:layout_width="100dp"
|
||||
android:layout_height="100dp"
|
||||
android:layout_marginStart="35dp"
|
||||
android:layout_marginTop="39dp"
|
||||
app:srcCompat="@drawable/ic_events_gold" />
|
||||
|
||||
<ProgressBar
|
||||
android:id="@+id/step_streak_dashboard_loading_circle"
|
||||
android:layout_width="171dp"
|
||||
android:layout_height="171dp"
|
||||
android:indeterminate="true" />
|
||||
</RelativeLayout>
|
||||
|
||||
|
||||
</LinearLayout>
|
||||
</ScrollView>
|
@ -1730,4 +1730,22 @@
|
||||
<string name="connection_over_bt_classic">Connection over Bluetooth classic</string>
|
||||
<string name="autoconnect_from_device_title">Connect on connection from device</string>
|
||||
<string name="autoconnect_from_device_summary">Establish a connection when connection is initiated by device, like headphones</string>
|
||||
<!-- related to steps streak view -->
|
||||
<string name="steps_streaks">Steps streaks</string>
|
||||
<string name="steps_streaks_hint">Series of consecutive days without interruption with steps goal being reached</string>
|
||||
<string name="step_streak_ongoing">Ongoing</string>
|
||||
<string name="step_streak_longest">Longest</string>
|
||||
<string name="step_streak_total">Total</string>
|
||||
<string name="steps_streaks_total_steps">Total \n steps</string>
|
||||
<string name="steps_streaks_streak_days">Streak \n Days</string>
|
||||
<string name="steps_streaks_average_steps">Average \n steps</string>
|
||||
<string name="steps_streaks_achievement_rate">Achievement \n rate</string>
|
||||
<string name="steps_streaks_since_date">Since %s</string>
|
||||
<string name="step_streak_average_steps_hint">Average steps per day of the streak</string>
|
||||
<string name="steps_streaks_total_steps_hint_totals">Total number of steps ever recorded</string>
|
||||
<string name="steps_streaks_total_days_hint_totals">Percentage of days with achieved goal in relation to all days with steps</string>
|
||||
<string name="step_streak_days_hint">Number of consecutive days with steps goal being reached</string>
|
||||
<string name="steps_streaks_total_steps_hint">Total number of steps in the whole streak</string>
|
||||
<string name="steps_streaks_total_steps_average_hint">Total average %d steps per day</string>
|
||||
|
||||
</resources>
|
||||
|
Loading…
Reference in New Issue
Block a user