mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge
synced 2024-09-01 03:55:47 +02:00
Add nested tabs to sleep and steps + steps refactor
This commit is contained in:
parent
b01169a307
commit
4ea933b53d
@ -122,7 +122,7 @@ public class GBApplication extends Application {
|
||||
private static SharedPreferences sharedPrefs;
|
||||
private static final String PREFS_VERSION = "shared_preferences_version";
|
||||
//if preferences have to be migrated, increment the following and add the migration logic in migratePrefs below; see http://stackoverflow.com/questions/16397848/how-can-i-migrate-android-preferences-with-a-new-version
|
||||
private static final int CURRENT_PREFS_VERSION = 32;
|
||||
private static final int CURRENT_PREFS_VERSION = 33;
|
||||
|
||||
private static final LimitedQueue<Integer, String> mIDSenderLookup = new LimitedQueue<>(16);
|
||||
private static GBPrefs prefs;
|
||||
@ -1514,7 +1514,7 @@ public class GBApplication extends Application {
|
||||
}
|
||||
|
||||
if (oldVersion < 32) {
|
||||
// Add the new HRV Status tab to all devices
|
||||
// Add the new body energy tab to all devices
|
||||
try (DBHandler db = acquireDB()) {
|
||||
final DaoSession daoSession = db.getDaoSession();
|
||||
final List<Device> activeDevices = DBHelper.getActiveDevices(daoSession);
|
||||
@ -1543,6 +1543,36 @@ public class GBApplication extends Application {
|
||||
}
|
||||
}
|
||||
|
||||
if (oldVersion < 33) {
|
||||
// Remove sleep week tab from all devices, since it does not exist anymore
|
||||
try (DBHandler db = acquireDB()) {
|
||||
final DaoSession daoSession = db.getDaoSession();
|
||||
final List<Device> activeDevices = DBHelper.getActiveDevices(daoSession);
|
||||
|
||||
for (final Device dbDevice : activeDevices) {
|
||||
final SharedPreferences deviceSharedPrefs = GBApplication.getDeviceSpecificSharedPrefs(dbDevice.getIdentifier());
|
||||
|
||||
final String chartsTabsValue = deviceSharedPrefs.getString("charts_tabs", null);
|
||||
if (chartsTabsValue == null) {
|
||||
continue;
|
||||
}
|
||||
|
||||
final String newPrefValue;
|
||||
if (!StringUtils.isBlank(chartsTabsValue)) {
|
||||
newPrefValue = chartsTabsValue.replace(",sleepweek", "");
|
||||
} else {
|
||||
newPrefValue = chartsTabsValue;
|
||||
}
|
||||
|
||||
final SharedPreferences.Editor deviceSharedPrefsEdit = deviceSharedPrefs.edit();
|
||||
deviceSharedPrefsEdit.putString("charts_tabs", newPrefValue);
|
||||
deviceSharedPrefsEdit.apply();
|
||||
}
|
||||
} catch (Exception e) {
|
||||
Log.w(TAG, "error acquiring DB lock");
|
||||
}
|
||||
}
|
||||
|
||||
editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION));
|
||||
editor.apply();
|
||||
}
|
||||
|
@ -45,7 +45,7 @@ public abstract class AbstractGBFragment extends Fragment {
|
||||
* @see #isVisibleInActivity()
|
||||
* @see #onMadeVisibleInActivity()
|
||||
*/
|
||||
protected void onMadeInvisibleInActivity() {
|
||||
public void onMadeInvisibleInActivity() {
|
||||
mVisibleInActivity = false;
|
||||
}
|
||||
|
||||
|
@ -20,15 +20,11 @@ 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;
|
||||
@ -62,7 +58,7 @@ import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
|
||||
public abstract class AbstractWeekChartFragment extends AbstractActivityChartFragment<AbstractWeekChartFragment.MyChartsData> {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(AbstractWeekChartFragment.class);
|
||||
protected final int TOTAL_DAYS = getRangeDays();
|
||||
protected int TOTAL_DAYS = getRangeDays();
|
||||
protected int TOTAL_DAYS_FOR_AVERAGE = 0;
|
||||
|
||||
protected Locale mLocale;
|
||||
@ -73,7 +69,6 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
protected TextView mBalanceView;
|
||||
|
||||
private int mOffsetHours = getOffsetHours();
|
||||
ImageView stepsStreaksButton;
|
||||
|
||||
@Override
|
||||
protected MyChartsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
|
||||
@ -101,20 +96,6 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
protected boolean enableStepStreaksButton(){
|
||||
return this.getClass().getSimpleName().equals("WeekStepsChartFragment");
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -125,7 +106,7 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
}
|
||||
|
||||
protected String getWeeksChartsLabel(Calendar day){
|
||||
if (GBApplication.getPrefs().getBoolean("charts_range", true)) {
|
||||
if (TOTAL_DAYS > 7) {
|
||||
//month, show day date
|
||||
return String.valueOf(day.get(Calendar.DAY_OF_MONTH));
|
||||
}
|
||||
@ -253,18 +234,6 @@ public abstract class AbstractWeekChartFragment extends AbstractActivityChartFra
|
||||
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();
|
||||
|
||||
|
@ -85,7 +85,6 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
}
|
||||
if (!coordinator.supportsSleepMeasurement()) {
|
||||
tabList.remove("sleep");
|
||||
tabList.remove("sleepweek");
|
||||
}
|
||||
if (!coordinator.supportsStressMeasurement()) {
|
||||
tabList.remove("stress");
|
||||
@ -143,9 +142,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
case "activitylist":
|
||||
return new ActivityListingChartFragment();
|
||||
case "sleep":
|
||||
return new SleepChartFragment();
|
||||
case "sleepweek":
|
||||
return new WeekSleepChartFragment();
|
||||
return new SleepCollectionFragment();
|
||||
case "hrvstatus":
|
||||
return new HRVStatusFragment();
|
||||
case "bodyenergy":
|
||||
@ -155,7 +152,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
case "pai":
|
||||
return new PaiChartFragment();
|
||||
case "stepsweek":
|
||||
return new WeekStepsChartFragment();
|
||||
return new StepsCollectionFragment();
|
||||
case "speedzones":
|
||||
return new SpeedZonesFragment();
|
||||
case "livestats":
|
||||
@ -183,14 +180,6 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
}
|
||||
}
|
||||
|
||||
public String getStepsTitle() {
|
||||
if (GBApplication.getPrefs().getBoolean("charts_range", true)) {
|
||||
return getString(R.string.weekstepschart_steps_a_month);
|
||||
} else {
|
||||
return getString(R.string.weekstepschart_steps_a_week);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (enabledTabsList.get(position)) {
|
||||
@ -200,8 +189,6 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
return getString(R.string.charts_activity_list);
|
||||
case "sleep":
|
||||
return getString(R.string.sleepchart_your_sleep);
|
||||
case "sleepweek":
|
||||
return getSleepTitle();
|
||||
case "hrvstatus":
|
||||
return getString(R.string.pref_header_hrv_status);
|
||||
case "bodyenergy":
|
||||
@ -211,7 +198,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
case "pai":
|
||||
return getString(getDevice().getDeviceCoordinator().getPaiName());
|
||||
case "stepsweek":
|
||||
return getStepsTitle();
|
||||
return getString(R.string.steps);
|
||||
case "speedzones":
|
||||
return getString(R.string.stats_title);
|
||||
case "livestats":
|
||||
|
@ -30,7 +30,6 @@ public class AngledLabelsChartRenderer extends BarChartRenderer {
|
||||
|
||||
@Override
|
||||
public void drawValue(Canvas canvas, String valueText, float x, float y, int color) {
|
||||
|
||||
mValuePaint.setColor(color);
|
||||
//move position to the center of bar
|
||||
x = x + 8;
|
||||
|
@ -16,6 +16,8 @@
|
||||
along with this program. If not, see <https://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import static java.util.stream.Collectors.toCollection;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
|
@ -382,7 +382,7 @@ public class LiveActivityFragment extends AbstractActivityChartFragment<ChartsDa
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onMadeInvisibleInActivity() {
|
||||
public void onMadeInvisibleInActivity() {
|
||||
enableRealtimeTracking(false);
|
||||
super.onMadeInvisibleInActivity();
|
||||
}
|
||||
|
@ -26,12 +26,9 @@ import android.text.method.ScrollingMovementMethod;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.constraintlayout.widget.ConstraintLayout;
|
||||
|
||||
import com.github.mikephil.charting.animation.Easing;
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.charts.LineChart;
|
||||
@ -41,7 +38,6 @@ import com.github.mikephil.charting.data.LineData;
|
||||
import com.github.mikephil.charting.data.PieData;
|
||||
import com.github.mikephil.charting.data.PieDataSet;
|
||||
import com.github.mikephil.charting.data.PieEntry;
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter;
|
||||
|
||||
import org.apache.commons.lang3.tuple.Triple;
|
||||
import org.slf4j.Logger;
|
||||
@ -239,7 +235,7 @@ public class SleepChartFragment extends AbstractActivityChartFragment<SleepChart
|
||||
highestHrText.setText(String.valueOf(heartRateMax != 0 ? heartRateMax : "-"));
|
||||
movementIntensityText.setText(intensityTotal != 0 ? new DecimalFormat("###.#").format(intensityTotal) : "-");
|
||||
|
||||
mSleepAmountChart.setHoleRadius(75);
|
||||
mSleepAmountChart.setHoleRadius(85);
|
||||
mSleepAmountChart.setDrawEntryLabels(false);
|
||||
mSleepAmountChart.getLegend().setEnabled(false);
|
||||
|
||||
|
@ -0,0 +1,87 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.SleepFragmentAdapter;
|
||||
|
||||
public class SleepCollectionFragment extends AbstractGBFragment {
|
||||
protected SleepFragmentAdapter nestedFragmentsAdapter;
|
||||
protected ViewPager2 viewPager;
|
||||
private int last_position = 0;
|
||||
|
||||
@Override
|
||||
protected void onMadeVisibleInActivity() {
|
||||
super.onMadeVisibleInActivity();
|
||||
nestedFragmentsAdapter.updateFragments(last_position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMadeInvisibleInActivity() {
|
||||
if (nestedFragmentsAdapter != null) {
|
||||
nestedFragmentsAdapter.updateFragments(-1);
|
||||
}
|
||||
}
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_nested_tabs, container, false);
|
||||
nestedFragmentsAdapter = new SleepFragmentAdapter(this, getChildFragmentManager());
|
||||
viewPager = rootView.findViewById(R.id.pager);
|
||||
viewPager.setAdapter(nestedFragmentsAdapter);
|
||||
viewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
|
||||
viewPager.setUserInputEnabled(false);
|
||||
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
last_position = position;
|
||||
viewPager.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isVisibleInActivity()) {
|
||||
nestedFragmentsAdapter.updateFragments(position);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case 0:
|
||||
tab.setText(getString(R.string.calendar_day));
|
||||
break;
|
||||
case 1:
|
||||
tab.setText(getString(R.string.calendar_week));
|
||||
break;
|
||||
case 2:
|
||||
tab.setText(getString(R.string.calendar_month));
|
||||
break;
|
||||
}
|
||||
}).attach();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected CharSequence getTitle() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,87 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.viewpager2.widget.ViewPager2;
|
||||
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.adapter.StepsFragmentAdapter;
|
||||
|
||||
public class StepsCollectionFragment extends AbstractGBFragment {
|
||||
protected StepsFragmentAdapter nestedFragmentsAdapter;
|
||||
protected ViewPager2 viewPager;
|
||||
private int last_position = 0;
|
||||
|
||||
@Override
|
||||
protected void onMadeVisibleInActivity() {
|
||||
super.onMadeVisibleInActivity();
|
||||
nestedFragmentsAdapter.updateFragments(last_position);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onMadeInvisibleInActivity() {
|
||||
if (nestedFragmentsAdapter != null) {
|
||||
nestedFragmentsAdapter.updateFragments(-1);
|
||||
}
|
||||
}
|
||||
|
||||
public View onCreateView(@NonNull LayoutInflater inflater, @Nullable ViewGroup container,
|
||||
@Nullable Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_nested_tabs, container, false);
|
||||
nestedFragmentsAdapter = new StepsFragmentAdapter(this, getChildFragmentManager());
|
||||
viewPager = rootView.findViewById(R.id.pager);
|
||||
viewPager.setAdapter(nestedFragmentsAdapter);
|
||||
viewPager.setOrientation(ViewPager2.ORIENTATION_VERTICAL);
|
||||
viewPager.setUserInputEnabled(false);
|
||||
viewPager.registerOnPageChangeCallback(new ViewPager2.OnPageChangeCallback() {
|
||||
@Override
|
||||
public void onPageSelected(int position) {
|
||||
super.onPageSelected(position);
|
||||
last_position = position;
|
||||
viewPager.post(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
if (isVisibleInActivity()) {
|
||||
nestedFragmentsAdapter.updateFragments(position);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
public void onViewCreated(@NonNull View view, @Nullable Bundle savedInstanceState) {
|
||||
TabLayout tabLayout = view.findViewById(R.id.tab_layout);
|
||||
new TabLayoutMediator(tabLayout, viewPager, (tab, position) -> {
|
||||
switch (position) {
|
||||
case 0:
|
||||
tab.setText(getString(R.string.calendar_day));
|
||||
break;
|
||||
case 1:
|
||||
tab.setText(getString(R.string.calendar_week));
|
||||
break;
|
||||
case 2:
|
||||
tab.setText(getString(R.string.calendar_month));
|
||||
break;
|
||||
}
|
||||
}).attach();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
protected CharSequence getTitle() {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,173 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.Canvas;
|
||||
import android.graphics.Paint;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.TypedValue;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.ColorInt;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
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.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
|
||||
public class StepsDailyFragment extends StepsFragment {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(BodyEnergyFragment.class);
|
||||
|
||||
private TextView mDateView;
|
||||
private ImageView stepsGauge;
|
||||
private TextView steps;
|
||||
private TextView distance;
|
||||
ImageView stepsStreaksButton;
|
||||
|
||||
protected int STEPS_GOAL;
|
||||
protected int TOTAL_DAYS = 1;
|
||||
|
||||
|
||||
@Override
|
||||
public void onResume() {
|
||||
super.onResume();
|
||||
}
|
||||
|
||||
@Override
|
||||
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
|
||||
View rootView = inflater.inflate(R.layout.fragment_steps, 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.steps_date_view);
|
||||
stepsGauge = rootView.findViewById(R.id.steps_gauge);
|
||||
steps = rootView.findViewById(R.id.steps_count);
|
||||
distance = rootView.findViewById(R.id.steps_distance);
|
||||
STEPS_GOAL = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_STEPS_GOAL, ActivityUser.defaultUserStepsGoal);
|
||||
refresh();
|
||||
|
||||
stepsStreaksButton = rootView.findViewById(R.id.steps_streaks_button);
|
||||
stepsStreaksButton.setOnClickListener(new View.OnClickListener() {
|
||||
@Override
|
||||
public void onClick(View v) {
|
||||
FragmentManager fm = getActivity().getSupportFragmentManager();
|
||||
StepStreaksDashboard stepStreaksDashboard = StepStreaksDashboard.newInstance(STEPS_GOAL, getChartsHost().getDevice());
|
||||
stepStreaksDashboard.show(fm, "steps_streaks_dashboard");
|
||||
}
|
||||
});
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getTitle() {
|
||||
return getString(R.string.steps);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StepsDailyFragment.StepsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
|
||||
Calendar day = Calendar.getInstance();
|
||||
day.setTime(chartsHost.getEndDate());
|
||||
String formattedDate = new SimpleDateFormat("E, MMM dd").format(chartsHost.getEndDate());
|
||||
mDateView.setText(formattedDate);
|
||||
List<StepsDay> stepsDaysData = getMyStepsDaysData(db, day, device);
|
||||
return new StepsDailyFragment.StepsData(stepsDaysData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChartsnUIThread(StepsDailyFragment.StepsData stepsData) {
|
||||
final int width = (int) TypedValue.applyDimension(
|
||||
TypedValue.COMPLEX_UNIT_DIP,
|
||||
300,
|
||||
GBApplication.getContext().getResources().getDisplayMetrics()
|
||||
);
|
||||
|
||||
stepsGauge.setImageBitmap(drawGauge(
|
||||
width,
|
||||
width / 15,
|
||||
getResources().getColor(R.color.steps_color),
|
||||
(int) stepsData.todayStepsDay.steps,
|
||||
STEPS_GOAL
|
||||
));
|
||||
|
||||
steps.setText(String.format(String.valueOf(stepsData.todayStepsDay.steps)));
|
||||
distance.setText(getString(R.string.steps_distance_unit, stepsData.todayStepsDay.distance));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void renderCharts() {}
|
||||
|
||||
protected void setupLegend(Chart<?> chart) {}
|
||||
|
||||
Bitmap drawGauge(int width, int barWidth, @ColorInt int filledColor, int value, int maxValue) {
|
||||
int height = width;
|
||||
int barMargin = (int) Math.ceil(barWidth / 2f);
|
||||
float filledFactor = (float) value / maxValue;
|
||||
|
||||
Bitmap bitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
|
||||
Canvas canvas = new Canvas(bitmap);
|
||||
Paint paint = new Paint();
|
||||
paint.setAntiAlias(true);
|
||||
paint.setStyle(Paint.Style.STROKE);
|
||||
paint.setStrokeCap(Paint.Cap.ROUND);
|
||||
paint.setStrokeWidth(barWidth);
|
||||
paint.setColor(getResources().getColor(R.color.gauge_line_color));
|
||||
canvas.drawArc(
|
||||
barMargin,
|
||||
barMargin,
|
||||
width - barMargin,
|
||||
width - barMargin,
|
||||
90,
|
||||
360,
|
||||
false,
|
||||
paint);
|
||||
paint.setStrokeWidth(barWidth);
|
||||
paint.setColor(filledColor);
|
||||
canvas.drawArc(
|
||||
barMargin,
|
||||
barMargin,
|
||||
width - barMargin,
|
||||
height - barMargin,
|
||||
270,
|
||||
360 * filledFactor,
|
||||
false,
|
||||
paint
|
||||
);
|
||||
|
||||
Paint textPaint = new Paint();
|
||||
textPaint.setColor(TEXT_COLOR);
|
||||
float textPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, width * 0.06f, requireContext().getResources().getDisplayMetrics());
|
||||
textPaint.setTextSize(textPixels);
|
||||
textPaint.setTextAlign(Paint.Align.CENTER);
|
||||
int yPos = (int) ((float) height / 2 - ((textPaint.descent() + textPaint.ascent()) / 2)) ;
|
||||
canvas.drawText(String.valueOf(value), width / 2f, yPos, textPaint);
|
||||
Paint textLowerPaint = new Paint();
|
||||
textLowerPaint.setColor(TEXT_COLOR);
|
||||
textLowerPaint.setTextAlign(Paint.Align.CENTER);
|
||||
float textLowerPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, width * 0.025f, requireContext().getResources().getDisplayMetrics());
|
||||
textLowerPaint.setTextSize(textLowerPixels);
|
||||
int yPosLowerText = (int) ((float) height / 2 - textPaint.ascent()) ;
|
||||
canvas.drawText(String.valueOf(maxValue), width / 2f, yPosLowerText, textLowerPaint);
|
||||
|
||||
return bitmap;
|
||||
}
|
||||
}
|
@ -0,0 +1,153 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.os.Bundle;
|
||||
|
||||
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.SampleProvider;
|
||||
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.ActivityUser;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
|
||||
abstract class StepsFragment extends AbstractChartFragment<StepsDailyFragment.StepsData> {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(StepsDailyFragment.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<StepsFragment.StepsDay> getMyStepsDaysData(DBHandler db, Calendar day, GBDevice device) {
|
||||
day = (Calendar) day.clone(); // do not modify the caller's argument
|
||||
day.add(Calendar.DATE, -TOTAL_DAYS + 1);
|
||||
|
||||
List<StepsDay> daysData = new ArrayList<>();;
|
||||
for (int counter = 0; counter < TOTAL_DAYS; counter++) {
|
||||
long totalSteps = 0;
|
||||
ActivityAmounts amounts = getActivityAmountsForDay(db, day, device);
|
||||
for (ActivityAmount amount : amounts.getAmounts()) {
|
||||
if (amount.getTotalSteps() > 0) {
|
||||
totalSteps += amount.getTotalSteps();
|
||||
}
|
||||
}
|
||||
double distance = 0;
|
||||
if (totalSteps > 0) {
|
||||
ActivityUser activityUser = new ActivityUser();
|
||||
int stepLength = activityUser.getStepLengthCm();
|
||||
distance = ((stepLength * 1.0 / 100) * totalSteps) / 1000;
|
||||
}
|
||||
Calendar d = (Calendar) day.clone();
|
||||
daysData.add(new StepsDay(d, totalSteps, distance));
|
||||
day.add(Calendar.DATE, 1);
|
||||
}
|
||||
return daysData;
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private 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 StepsDay {
|
||||
public long steps;
|
||||
public double distance;
|
||||
public Calendar day;
|
||||
|
||||
protected StepsDay(Calendar day, long steps, double distance) {
|
||||
this.steps = steps;
|
||||
this.distance = distance;
|
||||
this.day = day;
|
||||
}
|
||||
}
|
||||
|
||||
protected static class StepsData extends ChartsData {
|
||||
List<StepsDay> days;
|
||||
long stepsDailyAvg = 0;
|
||||
double distanceDailyAvg = 0;
|
||||
long totalSteps = 0;
|
||||
double totalDistance = 0;
|
||||
StepsDay todayStepsDay;
|
||||
protected StepsData(List<StepsDay> days) {
|
||||
this.days = days;
|
||||
int daysCounter = 0;
|
||||
for(StepsDay day : days) {
|
||||
this.totalSteps += day.steps;
|
||||
this.totalDistance += day.distance;
|
||||
if (day.steps > 0) {
|
||||
daysCounter++;
|
||||
}
|
||||
}
|
||||
if (daysCounter > 0) {
|
||||
this.stepsDailyAvg = this.totalSteps / daysCounter;
|
||||
this.distanceDailyAvg = this.totalDistance / daysCounter;
|
||||
}
|
||||
this.todayStepsDay = days.get(days.size() - 1);
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,200 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
|
||||
|
||||
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.apache.commons.lang3.time.DateUtils;
|
||||
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.service.devices.sony.wena3.protocol.packets.settings.DayStartHourSetting;
|
||||
|
||||
public class StepsPeriodFragment extends StepsFragment {
|
||||
protected static final Logger LOG = LoggerFactory.getLogger(BodyEnergyFragment.class);
|
||||
|
||||
private TextView mDateView;
|
||||
private TextView stepsAvg;
|
||||
private TextView stepsTotal;
|
||||
private TextView distanceAvg;
|
||||
private TextView distanceTotal;
|
||||
private BarChart stepsChart;
|
||||
|
||||
protected int CHART_TEXT_COLOR;
|
||||
protected int TEXT_COLOR;
|
||||
protected int STEPS_GOAL;
|
||||
|
||||
protected int BACKGROUND_COLOR;
|
||||
protected int DESCRIPTION_COLOR;
|
||||
|
||||
public static StepsPeriodFragment newInstance ( int totalDays ) {
|
||||
StepsPeriodFragment fragmentFirst = new StepsPeriodFragment();
|
||||
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_steps_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.steps_date_view);
|
||||
stepsChart = rootView.findViewById(R.id.steps_chart);
|
||||
stepsAvg = rootView.findViewById(R.id.steps_avg);
|
||||
distanceAvg = rootView.findViewById(R.id.distance_avg);
|
||||
stepsTotal = rootView.findViewById(R.id.steps_total);
|
||||
distanceTotal = rootView.findViewById(R.id.distance_total);
|
||||
STEPS_GOAL = GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_STEPS_GOAL, ActivityUser.defaultUserStepsGoal);
|
||||
setupStepsChart();
|
||||
refresh();
|
||||
|
||||
return rootView;
|
||||
}
|
||||
|
||||
protected void setupStepsChart() {
|
||||
stepsChart.getDescription().setEnabled(false);
|
||||
if (TOTAL_DAYS <= 7) {
|
||||
stepsChart.setTouchEnabled(false);
|
||||
stepsChart.setPinchZoom(false);
|
||||
}
|
||||
stepsChart.setDoubleTapToZoomEnabled(false);
|
||||
stepsChart.getLegend().setEnabled(false);
|
||||
|
||||
final XAxis xAxisBottom = stepsChart.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 = stepsChart.getAxisLeft();
|
||||
yAxisLeft.setDrawGridLines(true);
|
||||
yAxisLeft.setDrawTopYLabelEntry(true);
|
||||
yAxisLeft.setEnabled(true);
|
||||
yAxisLeft.setTextColor(CHART_TEXT_COLOR);
|
||||
yAxisLeft.setAxisMinimum(0f);
|
||||
LimitLine target = new LimitLine(STEPS_GOAL);
|
||||
yAxisLeft.addLimitLine(target);
|
||||
|
||||
final YAxis yAxisRight = stepsChart.getAxisRight();
|
||||
yAxisRight.setEnabled(true);
|
||||
yAxisRight.setDrawLabels(false);
|
||||
yAxisRight.setDrawGridLines(false);
|
||||
yAxisRight.setDrawAxisLine(true);
|
||||
}
|
||||
|
||||
@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());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected StepsFragment.StepsData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
|
||||
Calendar day = Calendar.getInstance();
|
||||
Date to = new Date((long) this.getTSEnd() * 1000);
|
||||
Date from = DateUtils.addDays(to,-(TOTAL_DAYS - 1));
|
||||
String toFormattedDate = new SimpleDateFormat("E, MMM dd").format(to);
|
||||
String fromFormattedDate = new SimpleDateFormat("E, MMM dd").format(from);
|
||||
mDateView.setText(fromFormattedDate + " - " + toFormattedDate);
|
||||
day.setTime(to);
|
||||
List<StepsDay> stepsDaysData = getMyStepsDaysData(db, day, device);
|
||||
return new StepsFragment.StepsData(stepsDaysData);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateChartsnUIThread(StepsPeriodFragment.StepsData stepsData) {
|
||||
stepsChart.setData(null);
|
||||
|
||||
List<BarEntry> entries = new ArrayList<>();
|
||||
int counter = 0;
|
||||
for(StepsDay day : stepsData.days) {
|
||||
entries.add(new BarEntry(counter, day.steps));
|
||||
counter++;
|
||||
}
|
||||
BarDataSet set = new BarDataSet(entries, "Steps");
|
||||
set.setDrawValues(true);
|
||||
set.setColors(getResources().getColor(R.color.steps_color));
|
||||
final XAxis x = stepsChart.getXAxis();
|
||||
x.setValueFormatter(getStepsChartDayValueFormatter(stepsData));
|
||||
|
||||
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) {
|
||||
stepsChart.setRenderer(new AngledLabelsChartRenderer(stepsChart, stepsChart.getAnimator(), stepsChart.getViewPortHandler()));
|
||||
}
|
||||
stepsChart.setData(barData);
|
||||
stepsAvg.setText(String.format(String.valueOf(stepsData.stepsDailyAvg)));
|
||||
distanceAvg.setText(getString(R.string.steps_distance_unit, stepsData.distanceDailyAvg));
|
||||
stepsTotal.setText(String.format(String.valueOf(stepsData.totalSteps)));
|
||||
distanceTotal.setText(getString(R.string.steps_distance_unit, stepsData.totalDistance));
|
||||
}
|
||||
|
||||
ValueFormatter getStepsChartDayValueFormatter(StepsPeriodFragment.StepsData stepsData) {
|
||||
return new ValueFormatter() {
|
||||
@Override
|
||||
public String getFormattedValue(float value) {
|
||||
StepsPeriodFragment.StepsDay day = stepsData.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() {
|
||||
stepsChart.invalidate();
|
||||
}
|
||||
|
||||
protected void setupLegend(Chart<?> chart) {}
|
||||
}
|
@ -23,6 +23,7 @@ import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.components.Legend;
|
||||
import com.github.mikephil.charting.components.LegendEntry;
|
||||
@ -58,6 +59,20 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
private TextView sleepDatesText;
|
||||
private MySleepWeeklyData mySleepWeeklyData;
|
||||
|
||||
public static WeekSleepChartFragment newInstance ( int totalDays ) {
|
||||
WeekSleepChartFragment fragmentFirst = new WeekSleepChartFragment();
|
||||
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;
|
||||
}
|
||||
|
||||
private MySleepWeeklyData getMySleepWeeklyData(DBHandler db, Calendar day, GBDevice device) {
|
||||
day = (Calendar) day.clone(); // do not modify the caller's argument
|
||||
day.add(Calendar.DATE, -TOTAL_DAYS + 1);
|
||||
@ -89,7 +104,6 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
Bundle savedInstanceState) {
|
||||
mLocale = getResources().getConfiguration().locale;
|
||||
View rootView = inflater.inflate(R.layout.fragment_weeksleep_chart, container, false);
|
||||
|
||||
final int goal = getGoal();
|
||||
if (goal >= 0) {
|
||||
mTargetValue = goal;
|
||||
@ -114,17 +128,17 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment {
|
||||
protected void updateChartsnUIThread(MyChartsData mcd) {
|
||||
setupLegend(mWeekChart);
|
||||
|
||||
//set custom renderer for 30days bar charts
|
||||
if (GBApplication.getPrefs().getBoolean("charts_range", true)) {
|
||||
if (TOTAL_DAYS > 7) {
|
||||
mWeekChart.setRenderer(new AngledLabelsChartRenderer(mWeekChart, mWeekChart.getAnimator(), mWeekChart.getViewPortHandler()));
|
||||
} else {
|
||||
mWeekChart.setScaleEnabled(false);
|
||||
mWeekChart.setTouchEnabled(false);
|
||||
}
|
||||
|
||||
mWeekChart.setData(null); // workaround for https://github.com/PhilJay/MPAndroidChart/issues/2317
|
||||
mWeekChart.setData(mcd.getWeekBeforeData().getData());
|
||||
mWeekChart.getXAxis().setValueFormatter(mcd.getWeekBeforeData().getXValueFormatter());
|
||||
mWeekChart.getBarData().setValueTextSize(14f);
|
||||
mWeekChart.setScaleEnabled(false);
|
||||
mWeekChart.setTouchEnabled(false);
|
||||
mWeekChart.getBarData().setValueTextSize(10f);
|
||||
|
||||
if (TOTAL_DAYS_FOR_AVERAGE > 0) {
|
||||
float avgDeep = Math.abs(this.mySleepWeeklyData.getTotalDeep() / TOTAL_DAYS_FOR_AVERAGE);
|
||||
|
@ -1,125 +0,0 @@
|
||||
/* Copyright (C) 2015-2024 Andreas Shimokawa, Carsten Pfeiffer, Daniele
|
||||
Gobbetti, José Rebelo, Pavel Elagin, Petr Vaněk
|
||||
|
||||
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 com.github.mikephil.charting.charts.Chart;
|
||||
import com.github.mikephil.charting.formatter.ValueFormatter;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmount;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
|
||||
|
||||
public class WeekStepsChartFragment extends AbstractWeekChartFragment {
|
||||
@Override
|
||||
public String getTitle() {
|
||||
if (GBApplication.getPrefs().getBoolean("charts_range", true)) {
|
||||
return getString(R.string.weekstepschart_steps_a_month);
|
||||
}
|
||||
else{
|
||||
return getString(R.string.weekstepschart_steps_a_week);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
String getPieDescription(int targetValue) {
|
||||
return getString(R.string.weeksteps_today_steps_description, String.valueOf(targetValue));
|
||||
}
|
||||
|
||||
@Override
|
||||
int getGoal() {
|
||||
return GBApplication.getPrefs().getInt(ActivityUser.PREF_USER_STEPS_GOAL, ActivityUser.defaultUserStepsGoal);
|
||||
}
|
||||
|
||||
@Override
|
||||
int getOffsetHours() {
|
||||
return 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
float[] getTotalsForActivityAmounts(ActivityAmounts activityAmounts) {
|
||||
long totalSteps = 0;
|
||||
for (ActivityAmount amount : activityAmounts.getAmounts()) {
|
||||
totalSteps += amount.getTotalSteps();
|
||||
}
|
||||
return new float[]{totalSteps};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected long calculateBalance(ActivityAmounts activityAmounts) {
|
||||
long balance = 0;
|
||||
for (ActivityAmount amount : activityAmounts.getAmounts()) {
|
||||
balance += amount.getTotalSteps();
|
||||
}
|
||||
return balance;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String formatPieValue(long value) {
|
||||
return String.valueOf(value);
|
||||
}
|
||||
|
||||
@Override
|
||||
String[] getPieLabels() {
|
||||
return new String[]{""};
|
||||
}
|
||||
|
||||
@Override
|
||||
ValueFormatter getPieValueFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
ValueFormatter getBarValueFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
ValueFormatter getYAxisFormatter() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
int[] getColors() {
|
||||
return new int[]{akActivity.color};
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void setupLegend(Chart<?> chart) {
|
||||
// no legend here, it is all about the steps here
|
||||
chart.getLegend().setEnabled(false);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getBalanceMessage(long balance, int targetValue) {
|
||||
if (balance > 0) {
|
||||
final long totalBalance = balance - ((long)targetValue * TOTAL_DAYS_FOR_AVERAGE);
|
||||
if (totalBalance > 0)
|
||||
return getString(R.string.overstep, Math.abs(totalBalance));
|
||||
else
|
||||
return getString(R.string.lack_of_step, Math.abs(totalBalance));
|
||||
} else
|
||||
return getString(R.string.no_data);
|
||||
}
|
||||
|
||||
@Override
|
||||
String getAverage(float value) {
|
||||
return String.format("%.0f", value);
|
||||
}
|
||||
}
|
@ -0,0 +1,36 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.adapter;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.viewpager2.adapter.FragmentStateAdapter;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.stream.Collectors;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
|
||||
|
||||
abstract class NestedFragmentAdapter extends FragmentStateAdapter {
|
||||
protected FragmentManager fragmentManager;
|
||||
|
||||
public NestedFragmentAdapter(AbstractGBFragment fragment, FragmentManager childFragmentManager) {
|
||||
super(fragment);
|
||||
fragmentManager = childFragmentManager;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return 3;
|
||||
}
|
||||
|
||||
public void updateFragments(int position) {
|
||||
List<AbstractGBFragment> fragments = fragmentManager.getFragments()
|
||||
.stream()
|
||||
.map(e -> (AbstractGBFragment) e)
|
||||
.collect(Collectors.toList());
|
||||
for (AbstractGBFragment fragment : fragments) {
|
||||
if (position < 0 || fragment != fragmentManager.findFragmentByTag("f" + position)) {
|
||||
fragment.onMadeInvisibleInActivity();
|
||||
} else {
|
||||
fragment.onMadeVisibleInActivityInternal();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -0,0 +1,30 @@
|
||||
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.SleepChartFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.WeekSleepChartFragment;
|
||||
|
||||
public class SleepFragmentAdapter extends NestedFragmentAdapter {
|
||||
public SleepFragmentAdapter(AbstractGBFragment fragment, FragmentManager childFragmentManager) {
|
||||
super(fragment, childFragmentManager);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new SleepChartFragment();
|
||||
case 1:
|
||||
return WeekSleepChartFragment.newInstance(7);
|
||||
case 2:
|
||||
return WeekSleepChartFragment.newInstance(30);
|
||||
}
|
||||
return new SleepChartFragment();
|
||||
}
|
||||
}
|
@ -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.StepsDailyFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.StepsPeriodFragment;
|
||||
|
||||
public class StepsFragmentAdapter extends NestedFragmentAdapter {
|
||||
protected FragmentManager fragmentManager;
|
||||
|
||||
public StepsFragmentAdapter(AbstractGBFragment fragment, FragmentManager childFragmentManager) {
|
||||
super(fragment, childFragmentManager);
|
||||
fragmentManager = childFragmentManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
switch (position) {
|
||||
case 0:
|
||||
return new StepsDailyFragment();
|
||||
case 1:
|
||||
return StepsPeriodFragment.newInstance(7);
|
||||
case 2:
|
||||
return StepsPeriodFragment.newInstance(30);
|
||||
}
|
||||
return new StepsDailyFragment();
|
||||
}
|
||||
}
|
17
app/src/main/res/layout/fragment_nested_tabs.xml
Normal file
17
app/src/main/res/layout/fragment_nested_tabs.xml
Normal file
@ -0,0 +1,17 @@
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical">
|
||||
|
||||
<com.google.android.material.tabs.TabLayout
|
||||
android:id="@+id/tab_layout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<androidx.viewpager2.widget.ViewPager2
|
||||
android:id="@+id/pager"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="0dp"
|
||||
android:layout_weight="1" />
|
||||
|
||||
</LinearLayout>
|
136
app/src/main/res/layout/fragment_steps.xml
Normal file
136
app/src/main/res/layout/fragment_steps.xml
Normal file
@ -0,0 +1,136 @@
|
||||
<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/steps_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="20dp"
|
||||
/>
|
||||
<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>
|
||||
|
||||
<ImageView
|
||||
android:layout_width="180dp"
|
||||
android:layout_height="180dp"
|
||||
android:layout_gravity="center"
|
||||
android:layout_centerHorizontal="true"
|
||||
android:scaleType="fitStart"
|
||||
android:id="@+id/steps_gauge" />
|
||||
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:layout_weight="3"
|
||||
android:shrinkColumns="*"
|
||||
android:stretchColumns="*">
|
||||
|
||||
<TableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:weightSum="2">
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingTop="20dip"
|
||||
android:paddingRight="20dip">
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="5px"
|
||||
android:background="@color/value_line_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/steps_count"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="20dip"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/steps"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingTop="20dip"
|
||||
android:paddingRight="20dip">
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="5px"
|
||||
android:background="@color/value_line_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/steps_distance"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="20dip"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/distance"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/steps_chart_title"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text=""
|
||||
android:paddingLeft="20dip"
|
||||
android:textSize="20sp" />
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
182
app/src/main/res/layout/fragment_steps_period.xml
Normal file
182
app/src/main/res/layout/fragment_steps_period.xml
Normal file
@ -0,0 +1,182 @@
|
||||
<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/steps_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="20dp"
|
||||
/>
|
||||
</RelativeLayout>
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="250sp"
|
||||
>
|
||||
|
||||
<com.github.mikephil.charting.charts.BarChart
|
||||
android:id="@+id/steps_chart"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
android:layout_weight="2" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
<TableLayout
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="30dp"
|
||||
android:layout_weight="3"
|
||||
android:shrinkColumns="*"
|
||||
android:stretchColumns="*">
|
||||
<TableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:weightSum="2">
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingTop="20dip"
|
||||
android:paddingRight="20dip">
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="5px"
|
||||
android:background="@color/value_line_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/steps_avg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="20dip"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/steps_avg"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingTop="20dip"
|
||||
android:paddingRight="20dip">
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="5px"
|
||||
android:background="@color/value_line_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/steps_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="20dip"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/steps_total"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
<TableRow
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:weightSum="2">
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingTop="20dip"
|
||||
android:paddingRight="20dip">
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="5px"
|
||||
android:background="@color/value_line_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/distance_avg"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="20dip"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/distance_avg"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
<LinearLayout
|
||||
android:layout_width="0dp"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_weight="1"
|
||||
android:orientation="vertical"
|
||||
android:paddingLeft="20dip"
|
||||
android:paddingTop="20dip"
|
||||
android:paddingRight="20dip">
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="5px"
|
||||
android:background="@color/value_line_color" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/distance_total"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:layout_marginTop="20dip"
|
||||
android:text="0"
|
||||
android:textSize="20sp" />
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="left"
|
||||
android:text="@string/distance_total"
|
||||
android:textSize="12sp" />
|
||||
</LinearLayout>
|
||||
</TableRow>
|
||||
</TableLayout>
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
@ -3015,7 +3015,6 @@
|
||||
<item>@string/activity_sleepchart_activity_and_sleep</item>
|
||||
<item>@string/charts_activity_list</item>
|
||||
<item>@string/sleepchart_your_sleep</item>
|
||||
<item>@string/weeksleepchart_sleep_a_week_or_month</item>
|
||||
<item>@string/weekstepschart_steps_a_week_or_month</item>
|
||||
<item>@string/pref_header_hrv_status</item>
|
||||
<item>@string/body_energy</item>
|
||||
@ -3031,7 +3030,6 @@
|
||||
<item>@string/p_activity</item>
|
||||
<item>@string/p_activity_list</item>
|
||||
<item>@string/p_sleep</item>
|
||||
<item>@string/p_sleep_week</item>
|
||||
<item>@string/p_steps_week</item>
|
||||
<item>@string/p_hrv_status</item>
|
||||
<item>@string/p_body_energy</item>
|
||||
@ -3048,7 +3046,6 @@
|
||||
<item>@string/p_activity</item>
|
||||
<item>@string/p_activity_list</item>
|
||||
<item>@string/p_sleep</item>
|
||||
<item>@string/p_sleep_week</item>
|
||||
<item>@string/p_hrv_status</item>
|
||||
<item>@string/p_body_energy</item>
|
||||
<item>@string/p_steps_week</item>
|
||||
|
@ -49,6 +49,7 @@
|
||||
<color name="hrv_status_poor" type="color">#be03fc</color>
|
||||
<color name="hrv_status_char_line_color" type="color">#d12a2a</color>
|
||||
<color name="body_energy_level_color" type="color">#5ac234</color>
|
||||
<color name="steps_color" type="color">#00c9bf</color>
|
||||
|
||||
<color name="value_line_color" type="color">#858585</color>
|
||||
<color name="gauge_line_color" type="color">#383838</color>
|
||||
|
@ -1576,6 +1576,7 @@
|
||||
<string name="hrv_status_unit">%1$d ms</string>
|
||||
<string name="hrv_status_baseline">%1$d-%2$d ms</string>
|
||||
<string name="hrv_status_baseline_label">Baseline</string>
|
||||
<string name="steps_distance_unit">%1$,.2f km</string>
|
||||
<string name="body_energy_gained">Gained</string>
|
||||
<string name="body_energy_lost">Lost</string>
|
||||
<string name="body_energy_legend_level">Body Energy Level</string>
|
||||
@ -2071,6 +2072,10 @@
|
||||
<string name="minAltitude">Minimum</string>
|
||||
<string name="averageAltitude">Average</string>
|
||||
<string name="steps">Steps</string>
|
||||
<string name="steps_avg">Steps AVG</string>
|
||||
<string name="steps_total">Steps Total</string>
|
||||
<string name="distance_avg">Distance AVG</string>
|
||||
<string name="distance_total">Distance Total</string>
|
||||
<string name="activeSeconds">Active</string>
|
||||
<string name="caloriesBurnt">Calories</string>
|
||||
<string name="maxSpeed">Maximum</string>
|
||||
|
@ -100,7 +100,6 @@
|
||||
<item name="p_activity" type="string">activity</item>
|
||||
<item name="p_activity_list" type="string">activitylist</item>
|
||||
<item name="p_sleep" type="string">sleep</item>
|
||||
<item name="p_sleep_week" type="string">sleepweek</item>
|
||||
<item name="p_steps_week" type="string">stepsweek</item>
|
||||
<item name="p_stress" type="string">stress</item>
|
||||
<item name="p_pai" type="string">pai</item>
|
||||
|
Loading…
Reference in New Issue
Block a user