mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Add weekly/monthly views for calories charts
This commit is contained in:
+1
-4
@@ -17,7 +17,6 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
@@ -196,9 +195,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
case "weight":
|
||||
return new WeightChartFragment();
|
||||
case "calories":
|
||||
Intent intent = getIntent();
|
||||
String mode = intent.getStringExtra(ActivityChartsActivity.EXTRA_MODE);
|
||||
return CaloriesDailyFragment.newInstance(mode);
|
||||
return CaloriesCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "respiratoryrate":
|
||||
return RespiratoryRateCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
}
|
||||
|
||||
+45
@@ -0,0 +1,45 @@
|
||||
/* Copyright (C) 2024 a0z, José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.CaloriesFragmentAdapter;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.NestedFragmentAdapter;
|
||||
|
||||
public class CaloriesCollectionFragment extends AbstractCollectionFragment {
|
||||
public CaloriesCollectionFragment() {
|
||||
|
||||
}
|
||||
|
||||
public static CaloriesCollectionFragment newInstance(final boolean allowSwipe) {
|
||||
final CaloriesCollectionFragment fragment = new CaloriesCollectionFragment();
|
||||
final Bundle args = new Bundle();
|
||||
args.putBoolean(ARG_ALLOW_SWIPE, allowSwipe);
|
||||
fragment.setArguments(args);
|
||||
return fragment;
|
||||
}
|
||||
|
||||
@Override
|
||||
public NestedFragmentAdapter getNestedFragmentAdapter(AbstractGBFragment fragment, FragmentManager childFragmentManager) {
|
||||
return new CaloriesFragmentAdapter(this, getChildFragmentManager());
|
||||
}
|
||||
}
|
||||
|
||||
+138
@@ -0,0 +1,138 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.app.Activity;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DefaultRestingMetabolicRateProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
|
||||
abstract class CaloriesFragment<T extends ChartsData> extends AbstractChartFragment<T> {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(CaloriesFragment.class);
|
||||
|
||||
protected int CHART_TEXT_COLOR;
|
||||
protected int TEXT_COLOR;
|
||||
|
||||
protected int BACKGROUND_COLOR;
|
||||
protected int DESCRIPTION_COLOR;
|
||||
protected int TOTAL_DAYS = 1;
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return getString(R.string.steps);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
TEXT_COLOR = GBApplication.getTextColor(requireContext());
|
||||
CHART_TEXT_COLOR = GBApplication.getSecondaryTextColor(requireContext());
|
||||
BACKGROUND_COLOR = GBApplication.getBackgroundColor(getContext());
|
||||
DESCRIPTION_COLOR = GBApplication.getTextColor(getContext());
|
||||
CHART_TEXT_COLOR = GBApplication.getSecondaryTextColor(getContext());
|
||||
}
|
||||
|
||||
protected List<CaloriesFragment.CaloriesDay> getMyCaloriesDaysData(DBHandler db, Calendar day, GBDevice device) {
|
||||
RestingMetabolicRateSample metabolicRate = getRestingMetabolicRate(db, device);
|
||||
int restingCalories = metabolicRate.getRestingMetabolicRate();
|
||||
|
||||
day = (Calendar) day.clone(); // do not modify the caller's argument
|
||||
day.add(Calendar.DATE, -TOTAL_DAYS + 1);
|
||||
|
||||
List<CaloriesDay> daysData = new ArrayList<>();
|
||||
for (int counter = 0; counter < TOTAL_DAYS; counter++) {
|
||||
long activeCalories = 0;
|
||||
ActivityAmounts amounts = getActivityAmountsForDay(db, day, device);
|
||||
for (ActivityAmount amount : amounts.getAmounts()) {
|
||||
if (amount.getTotalActiveCalories() > 0) {
|
||||
activeCalories += amount.getTotalActiveCalories() / 1000;
|
||||
}
|
||||
}
|
||||
Calendar d = (Calendar) day.clone();
|
||||
daysData.add(new CaloriesDay(d, activeCalories, restingCalories));
|
||||
day.add(Calendar.DATE, 1);
|
||||
}
|
||||
return daysData;
|
||||
}
|
||||
|
||||
protected RestingMetabolicRateSample getRestingMetabolicRate(DBHandler db, GBDevice device) {
|
||||
TimeSampleProvider<? extends RestingMetabolicRateSample> provider = device.getDeviceCoordinator().getRestingMetabolicRateProvider(device, db.getDaoSession());
|
||||
RestingMetabolicRateSample latestSample = provider.getLatestSample();
|
||||
if (latestSample != null) {
|
||||
return latestSample;
|
||||
}
|
||||
DefaultRestingMetabolicRateProvider defaultProvider = new DefaultRestingMetabolicRateProvider(device, db.getDaoSession());
|
||||
return defaultProvider.getLatestSample();
|
||||
}
|
||||
|
||||
protected ActivityAmounts getActivityAmountsForDay(DBHandler db, Calendar day, GBDevice device) {
|
||||
LimitedQueue<Integer, ActivityAmounts> activityAmountCache = null;
|
||||
ActivityAmounts amounts = null;
|
||||
|
||||
Activity activity = getActivity();
|
||||
int key = (int) (day.getTimeInMillis() / 1000);
|
||||
if (activity != null) {
|
||||
activityAmountCache = ((ActivityChartsActivity) activity).mActivityAmountCache;
|
||||
amounts = activityAmountCache.lookup(key);
|
||||
}
|
||||
|
||||
if (amounts == null) {
|
||||
ActivityAnalysis analysis = new ActivityAnalysis();
|
||||
amounts = analysis.calculateActivityAmounts(getSamplesOfDay(db, day, 0, device));
|
||||
if (activityAmountCache != null) {
|
||||
activityAmountCache.add(key, amounts);
|
||||
}
|
||||
}
|
||||
|
||||
return amounts;
|
||||
}
|
||||
|
||||
protected List<? extends ActivitySample> getSamplesOfDay(DBHandler db, Calendar day, int offsetHours, GBDevice device) {
|
||||
int startTs;
|
||||
int endTs;
|
||||
|
||||
day = (Calendar) day.clone(); // do not modify the caller's argument
|
||||
day.set(Calendar.HOUR_OF_DAY, 0);
|
||||
day.set(Calendar.MINUTE, 0);
|
||||
day.set(Calendar.SECOND, 0);
|
||||
day.add(Calendar.HOUR, offsetHours);
|
||||
|
||||
startTs = (int) (day.getTimeInMillis() / 1000);
|
||||
endTs = startTs + 24 * 60 * 60 - 1;
|
||||
|
||||
return getSamples(db, device, startTs, endTs);
|
||||
}
|
||||
|
||||
protected List<? extends ActivitySample> getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
|
||||
SampleProvider<? extends ActivitySample> provider = device.getDeviceCoordinator().getSampleProvider(device, db.getDaoSession());
|
||||
return provider.getAllActivitySamples(tsFrom, tsTo);
|
||||
}
|
||||
|
||||
protected static class CaloriesDay {
|
||||
public long activeCalories;
|
||||
public long restingCalories;
|
||||
public Calendar day;
|
||||
|
||||
protected CaloriesDay(Calendar day, long activeCalories, long restingCalories) {
|
||||
this.activeCalories = activeCalories;
|
||||
this.restingCalories = restingCalories;
|
||||
this.day = day;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+244
@@ -0,0 +1,244 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.content.Context;
|
||||
import android.graphics.Color;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.mikephil.charting.charts.BarChart;
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.components.LimitLine;
|
||||
import com.github.mikephil.charting.components.XAxis;
|
||||
import com.github.mikephil.charting.components.YAxis;
|
||||
import com.github.mikephil.charting.data.BarData;
|
||||
import com.github.mikephil.charting.data.BarDataSet;
|
||||
import com.github.mikephil.charting.data.BarEntry;
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Calendar;
|
||||
import java.util.Date;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
|
||||
public class CaloriesPeriodFragment extends CaloriesFragment<CaloriesPeriodFragment.CaloriesData> {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(CaloriesPeriodFragment.class);
|
||||
|
||||
private TextView mDateView;
|
||||
private TextView activeCaloriesAvg;
|
||||
private TextView activeCaloriesTotal;
|
||||
private TextView restingCaloriesAvg;
|
||||
private TextView restingCaloriesTotal;
|
||||
private BarChart caloriesChart;
|
||||
|
||||
private TextView mBalanceView;
|
||||
|
||||
protected int CHART_TEXT_COLOR;
|
||||
protected int TEXT_COLOR;
|
||||
protected int CALORIES_GOAL;
|
||||
|
||||
protected int BACKGROUND_COLOR;
|
||||
protected int DESCRIPTION_COLOR;
|
||||
|
||||
public static CaloriesPeriodFragment newInstance(int totalDays) {
|
||||
CaloriesPeriodFragment fragmentFirst = new CaloriesPeriodFragment();
|
||||
Bundle args = new Bundle();
|
||||
args.putInt("totalDays", totalDays);
|
||||
fragmentFirst.setArguments(args);
|
||||
return fragmentFirst;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate(Bundle savedInstanceState) {
|
||||
super.onCreate(savedInstanceState);
|
||||
TOTAL_DAYS = getArguments() != null ? getArguments().getInt("totalDays") : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_calories_period, container, false);
|
||||
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
|
||||
rootView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
|
||||
getChartsHost().enableSwipeRefresh(scrollY == 0);
|
||||
});
|
||||
}
|
||||
|
||||
mDateView = rootView.findViewById(R.id.calories_date_view);
|
||||
caloriesChart = rootView.findViewById(R.id.calories_chart);
|
||||
activeCaloriesAvg = rootView.findViewById(R.id.active_calories_avg);
|
||||
activeCaloriesTotal = rootView.findViewById(R.id.active_calories_total);
|
||||
restingCaloriesAvg = rootView.findViewById(R.id.resting_calories_avg);
|
||||
restingCaloriesTotal = rootView.findViewById(R.id.resting_calories_total);
|
||||
CALORIES_GOAL = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_CALORIES_BURNT, ActivityUser.defaultUserCaloriesBurntGoal);
|
||||
|
||||
mBalanceView = rootView.findViewById(R.id.balance);
|
||||
|
||||
setupCaloriesChart();
|
||||
refresh();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
protected void setupCaloriesChart() {
|
||||
caloriesChart.getDescription().setEnabled(false);
|
||||
if (TOTAL_DAYS <= 7) {
|
||||
caloriesChart.setTouchEnabled(false);
|
||||
caloriesChart.setPinchZoom(false);
|
||||
}
|
||||
caloriesChart.setDoubleTapToZoomEnabled(false);
|
||||
caloriesChart.getLegend().setEnabled(false);
|
||||
|
||||
final XAxis xAxisBottom = caloriesChart.getXAxis();
|
||||
xAxisBottom.setPosition(XAxis.XAxisPosition.BOTTOM);
|
||||
xAxisBottom.setDrawLabels(true);
|
||||
xAxisBottom.setDrawGridLines(false);
|
||||
xAxisBottom.setEnabled(true);
|
||||
xAxisBottom.setDrawLimitLinesBehindData(true);
|
||||
xAxisBottom.setTextColor(CHART_TEXT_COLOR);
|
||||
|
||||
final YAxis yAxisLeft = caloriesChart.getAxisLeft();
|
||||
yAxisLeft.setDrawGridLines(true);
|
||||
yAxisLeft.setDrawTopYLabelEntry(true);
|
||||
yAxisLeft.setEnabled(true);
|
||||
yAxisLeft.setTextColor(CHART_TEXT_COLOR);
|
||||
yAxisLeft.setAxisMinimum(0f);
|
||||
final LimitLine goalLine = new LimitLine(CALORIES_GOAL);
|
||||
goalLine.setLineColor(getResources().getColor(R.color.calories_color));
|
||||
goalLine.setLineWidth(1.5f);
|
||||
goalLine.enableDashedLine(15f, 10f, 0f);
|
||||
yAxisLeft.addLimitLine(goalLine);
|
||||
|
||||
final YAxis yAxisRight = caloriesChart.getAxisRight();
|
||||
yAxisRight.setEnabled(true);
|
||||
yAxisRight.setDrawLabels(false);
|
||||
yAxisRight.setDrawGridLines(false);
|
||||
yAxisRight.setDrawAxisLine(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return getString(R.string.calories);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void init() {
|
||||
TEXT_COLOR = GBApplication.getTextColor(requireContext());
|
||||
CHART_TEXT_COLOR = GBApplication.getSecondaryTextColor(requireContext());
|
||||
BACKGROUND_COLOR = GBApplication.getBackgroundColor(getContext());
|
||||
DESCRIPTION_COLOR = GBApplication.getTextColor(getContext());
|
||||
CHART_TEXT_COLOR = GBApplication.getSecondaryTextColor(getContext());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CaloriesData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
|
||||
Calendar day = Calendar.getInstance();
|
||||
day.setTime(getEndDate());
|
||||
List<CaloriesDay> caloriesDaysData = getMyCaloriesDaysData(db, day, device);
|
||||
return new CaloriesData(caloriesDaysData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChartsnUIThread(CaloriesData caloriesData) {
|
||||
mDateView.setText(DateTimeUtils.formatDaysUntil(TOTAL_DAYS, getTSEnd()));
|
||||
caloriesChart.setData(null);
|
||||
|
||||
List<BarEntry> entries = new ArrayList<>();
|
||||
int counter = 0;
|
||||
for (CaloriesDay day : caloriesData.days) {
|
||||
entries.add(new BarEntry(counter, day.activeCalories));
|
||||
counter++;
|
||||
}
|
||||
BarDataSet set = new BarDataSet(entries, "Calories");
|
||||
set.setDrawValues(true);
|
||||
set.setColors(getResources().getColor(R.color.calories_color));
|
||||
final XAxis x = caloriesChart.getXAxis();
|
||||
x.setValueFormatter(getCaloriesChartDayValueFormatter(caloriesData));
|
||||
caloriesChart.getAxisLeft().setAxisMaximum((float) Math.max(set.getYMax() * 1.1, CALORIES_GOAL));
|
||||
|
||||
BarData barData = new BarData(set);
|
||||
barData.setValueTextColor(Color.GRAY); //prevent tearing other graph elements with the black text. Another approach would be to hide the values cmpletely with data.setDrawValues(false);
|
||||
barData.setValueTextSize(10f);
|
||||
if (TOTAL_DAYS > 7) {
|
||||
caloriesChart.setRenderer(new AngledLabelsChartRenderer(caloriesChart, caloriesChart.getAnimator(), caloriesChart.getViewPortHandler()));
|
||||
}
|
||||
caloriesChart.setData(barData);
|
||||
activeCaloriesAvg.setText(String.format(String.valueOf(caloriesData.activeCaloriesDailyAvg)));
|
||||
activeCaloriesTotal.setText(String.format(String.valueOf(caloriesData.totalActiveCalories)));
|
||||
restingCaloriesAvg.setText(String.format(String.valueOf(caloriesData.restingCaloriesDailyAvg)));
|
||||
restingCaloriesTotal.setText(String.format(String.valueOf(caloriesData.totalRestingCalories)));
|
||||
|
||||
mBalanceView.setText(caloriesData.getBalanceMessage(getContext(), CALORIES_GOAL));
|
||||
}
|
||||
|
||||
ValueFormatter getCaloriesChartDayValueFormatter(CaloriesPeriodFragment.CaloriesData caloriesData) {
|
||||
return new ValueFormatter() {
|
||||
@Override
|
||||
public String getFormattedValue(float value) {
|
||||
CaloriesPeriodFragment.CaloriesDay day = caloriesData.days.get((int) value);
|
||||
String pattern = TOTAL_DAYS > 7 ? "dd" : "EEE";
|
||||
SimpleDateFormat formatLetterDay = new SimpleDateFormat(pattern, Locale.getDefault());
|
||||
return formatLetterDay.format(new Date(day.day.getTimeInMillis()));
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderCharts() {
|
||||
caloriesChart.invalidate();
|
||||
}
|
||||
|
||||
protected void setupLegend(Chart<?> chart) {
|
||||
}
|
||||
|
||||
protected static class CaloriesData extends ChartsData {
|
||||
List<CaloriesDay> days;
|
||||
long activeCaloriesDailyAvg = 0;
|
||||
long totalActiveCalories = 0;
|
||||
long restingCaloriesDailyAvg = 0;
|
||||
long totalRestingCalories = 0;
|
||||
CaloriesDay todayCaloriesDay;
|
||||
|
||||
protected CaloriesData(List<CaloriesDay> days) {
|
||||
this.days = days;
|
||||
int daysCounter = days.size();
|
||||
for (CaloriesDay day : days) {
|
||||
this.totalActiveCalories += day.activeCalories;
|
||||
this.totalRestingCalories += day.restingCalories;
|
||||
}
|
||||
if (daysCounter > 0) {
|
||||
this.activeCaloriesDailyAvg = this.totalActiveCalories / daysCounter;
|
||||
this.restingCaloriesDailyAvg = this.totalRestingCalories / daysCounter;
|
||||
}
|
||||
this.todayCaloriesDay = days.get(days.size() - 1);
|
||||
}
|
||||
|
||||
protected String getBalanceMessage(final Context context, final int targetValue) {
|
||||
if (totalActiveCalories == 0) {
|
||||
return context.getString(R.string.no_data);
|
||||
}
|
||||
|
||||
final long totalBalance = totalActiveCalories - ((long) targetValue * days.size());
|
||||
if (totalBalance > 0) {
|
||||
return context.getString(R.string.calorie_over_goal, Math.abs(totalBalance));
|
||||
} else {
|
||||
return context.getString(R.string.calorie_under_goal, Math.abs(totalBalance));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+32
@@ -0,0 +1,32 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.Fragment;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.CaloriesDailyFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.CaloriesPeriodFragment;
|
||||
|
||||
public class CaloriesFragmentAdapter extends NestedFragmentAdapter {
|
||||
protected FragmentManager fragmentManager;
|
||||
|
||||
public CaloriesFragmentAdapter(AbstractGBFragment fragment, FragmentManager childFragmentManager) {
|
||||
super(fragment, childFragmentManager);
|
||||
fragmentManager = childFragmentManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new CaloriesDailyFragment();
|
||||
case 1:
|
||||
return CaloriesPeriodFragment.newInstance(7);
|
||||
case 2:
|
||||
return CaloriesPeriodFragment.newInstance(30);
|
||||
}
|
||||
return new CaloriesDailyFragment();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,131 @@
|
||||
<ScrollView 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"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
>
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent">
|
||||
<TextView
|
||||
android:id="@+id/calories_date_view"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:gravity="center"
|
||||
android:textSize="20sp"
|
||||
android:layout_marginTop="15dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:gravity="center">
|
||||
<TextView
|
||||
android:id="@+id/balance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
</LinearLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250sp"
|
||||
>
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/calories_chart"
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="2" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<GridLayout
|
||||
android:background="@color/gauge_line_color"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:columnCount="2"
|
||||
android:layout_marginTop="15dp"
|
||||
>
|
||||
<LinearLayout
|
||||
style="@style/GridTile"
|
||||
android:layout_marginEnd="1dp"
|
||||
android:layout_marginTop="2dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/active_calories_avg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/active_calories_avg"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
style="@style/GridTile"
|
||||
android:layout_marginStart="1dp"
|
||||
android:layout_marginTop="2dp"
|
||||
>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/active_calories_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/active_calories_total"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
style="@style/GridTile"
|
||||
android:layout_marginEnd="1dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/resting_calories_avg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/metabolic_rate"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
style="@style/GridTile"
|
||||
android:layout_marginStart="1dp"
|
||||
>
|
||||
<TextView
|
||||
android:id="@+id/resting_calories_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/resting_calories_total"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</GridLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
||||
@@ -2393,6 +2393,11 @@
|
||||
<string name="caloriesBurnt">Calories</string>
|
||||
<string name="restingCalories">Resting Calories</string>
|
||||
<string name="metabolic_rate">Metabolic Rate</string>
|
||||
<string name="active_calories_avg">Active AVG</string>
|
||||
<string name="active_calories_total">Active Total</string>
|
||||
<string name="resting_calories_total">Resting Total</string>
|
||||
<string name="calorie_over_goal">Above goal: %1$d kcal</string>
|
||||
<string name="calorie_under_goal">Below goal: %1$d kcal</string>
|
||||
<string name="maxSpeed">Maximum</string>
|
||||
<string name="minSpeed">Minimum</string>
|
||||
<string name="minPace">Slowest Pace</string>
|
||||
|
||||
Reference in New Issue
Block a user