From 4ea933b53d420f74e7f1244cb5bff26ce121631a Mon Sep 17 00:00:00 2001 From: a0z Date: Thu, 22 Aug 2024 19:31:51 +0200 Subject: [PATCH] Add nested tabs to sleep and steps + steps refactor --- .../gadgetbridge/GBApplication.java | 34 ++- .../activities/AbstractGBFragment.java | 2 +- .../charts/AbstractWeekChartFragment.java | 35 +-- .../charts/ActivityChartsActivity.java | 19 +- .../charts/AngledLabelsChartRenderer.java | 1 - .../activities/charts/HRVStatusFragment.java | 2 + .../charts/LiveActivityFragment.java | 2 +- .../activities/charts/SleepChartFragment.java | 6 +- .../charts/SleepCollectionFragment.java | 87 ++++++++ .../charts/StepsCollectionFragment.java | 87 ++++++++ .../activities/charts/StepsDailyFragment.java | 173 +++++++++++++++ .../activities/charts/StepsFragment.java | 153 ++++++++++++++ .../charts/StepsPeriodFragment.java | 200 ++++++++++++++++++ .../charts/WeekSleepChartFragment.java | 28 ++- .../charts/WeekStepsChartFragment.java | 125 ----------- .../adapter/NestedFragmentAdapter.java | 36 ++++ .../adapter/SleepFragmentAdapter.java | 30 +++ .../adapter/StepsFragmentAdapter.java | 32 +++ .../main/res/layout/fragment_nested_tabs.xml | 17 ++ app/src/main/res/layout/fragment_steps.xml | 136 ++++++++++++ .../main/res/layout/fragment_steps_period.xml | 182 ++++++++++++++++ app/src/main/res/values/arrays.xml | 3 - app/src/main/res/values/colors.xml | 1 + app/src/main/res/values/strings.xml | 5 + app/src/main/res/values/values.xml | 1 - 25 files changed, 1202 insertions(+), 195 deletions(-) create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/SleepCollectionFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsCollectionFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java delete mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/NestedFragmentAdapter.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/SleepFragmentAdapter.java create mode 100644 app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/StepsFragmentAdapter.java create mode 100644 app/src/main/res/layout/fragment_nested_tabs.xml create mode 100644 app/src/main/res/layout/fragment_steps.xml create mode 100644 app/src/main/res/layout/fragment_steps_period.xml diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java index cfe73e0be..a1356f061 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/GBApplication.java @@ -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 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 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 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(); } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java index 94d6dc656..a1d448a25 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/AbstractGBFragment.java @@ -45,7 +45,7 @@ public abstract class AbstractGBFragment extends Fragment { * @see #isVisibleInActivity() * @see #onMadeVisibleInActivity() */ - protected void onMadeInvisibleInActivity() { + public void onMadeInvisibleInActivity() { mVisibleInActivity = false; } diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java index f4069ecc0..6b4158851 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AbstractWeekChartFragment.java @@ -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 { 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(); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityChartsActivity.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityChartsActivity.java index b1b4925ef..983b40007 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityChartsActivity.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/ActivityChartsActivity.java @@ -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": diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AngledLabelsChartRenderer.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AngledLabelsChartRenderer.java index 3a9694dee..6d034b341 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AngledLabelsChartRenderer.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/AngledLabelsChartRenderer.java @@ -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; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/HRVStatusFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/HRVStatusFragment.java index 4942c9e3b..de4652f5a 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/HRVStatusFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/HRVStatusFragment.java @@ -16,6 +16,8 @@ along with this program. If not, see . */ 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; diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java index ef419f9b6..07f3a1d01 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/LiveActivityFragment.java @@ -382,7 +382,7 @@ public class LiveActivityFragment extends AbstractActivityChartFragment { + 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; + } +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsCollectionFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsCollectionFragment.java new file mode 100644 index 000000000..bb8b2cc77 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsCollectionFragment.java @@ -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; + } +} + diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java new file mode 100644 index 000000000..8c4326ad9 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsDailyFragment.java @@ -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 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; + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java new file mode 100644 index 000000000..322d1e501 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsFragment.java @@ -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 { + 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 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 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 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 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 getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) { + SampleProvider 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 days; + long stepsDailyAvg = 0; + double distanceDailyAvg = 0; + long totalSteps = 0; + double totalDistance = 0; + StepsDay todayStepsDay; + protected StepsData(List 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); + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java new file mode 100644 index 000000000..e79c25469 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/StepsPeriodFragment.java @@ -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 stepsDaysData = getMyStepsDaysData(db, day, device); + return new StepsFragment.StepsData(stepsDaysData); + } + + @Override + protected void updateChartsnUIThread(StepsPeriodFragment.StepsData stepsData) { + stepsChart.setData(null); + + List 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) {} +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java index 4a9f11224..9d5070f58 100644 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekSleepChartFragment.java @@ -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); @@ -84,12 +99,11 @@ public class WeekSleepChartFragment extends AbstractWeekChartFragment { return new MySleepWeeklyData(remWeeklyTotal, deepWeeklyTotal, lightWeeklyTotal); } - @Override + @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, 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); diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java deleted file mode 100644 index fdc31a096..000000000 --- a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/activities/charts/WeekStepsChartFragment.java +++ /dev/null @@ -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 . */ -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); - } -} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/NestedFragmentAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/NestedFragmentAdapter.java new file mode 100644 index 000000000..628556f60 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/NestedFragmentAdapter.java @@ -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 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(); + } + } + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/SleepFragmentAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/SleepFragmentAdapter.java new file mode 100644 index 000000000..b619b4cd3 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/SleepFragmentAdapter.java @@ -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(); + } +} diff --git a/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/StepsFragmentAdapter.java b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/StepsFragmentAdapter.java new file mode 100644 index 000000000..295aa65f4 --- /dev/null +++ b/app/src/main/java/nodomain/freeyourgadget/gadgetbridge/adapter/StepsFragmentAdapter.java @@ -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(); + } +} diff --git a/app/src/main/res/layout/fragment_nested_tabs.xml b/app/src/main/res/layout/fragment_nested_tabs.xml new file mode 100644 index 000000000..a735b8bae --- /dev/null +++ b/app/src/main/res/layout/fragment_nested_tabs.xml @@ -0,0 +1,17 @@ + + + + + + + diff --git a/app/src/main/res/layout/fragment_steps.xml b/app/src/main/res/layout/fragment_steps.xml new file mode 100644 index 000000000..2bed946a0 --- /dev/null +++ b/app/src/main/res/layout/fragment_steps.xml @@ -0,0 +1,136 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/layout/fragment_steps_period.xml b/app/src/main/res/layout/fragment_steps_period.xml new file mode 100644 index 000000000..d2d6e97dd --- /dev/null +++ b/app/src/main/res/layout/fragment_steps_period.xml @@ -0,0 +1,182 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/app/src/main/res/values/arrays.xml b/app/src/main/res/values/arrays.xml index 2306ab0e2..9b12a6071 100644 --- a/app/src/main/res/values/arrays.xml +++ b/app/src/main/res/values/arrays.xml @@ -3015,7 +3015,6 @@ @string/activity_sleepchart_activity_and_sleep @string/charts_activity_list @string/sleepchart_your_sleep - @string/weeksleepchart_sleep_a_week_or_month @string/weekstepschart_steps_a_week_or_month @string/pref_header_hrv_status @string/body_energy @@ -3031,7 +3030,6 @@ @string/p_activity @string/p_activity_list @string/p_sleep - @string/p_sleep_week @string/p_steps_week @string/p_hrv_status @string/p_body_energy @@ -3048,7 +3046,6 @@ @string/p_activity @string/p_activity_list @string/p_sleep - @string/p_sleep_week @string/p_hrv_status @string/p_body_energy @string/p_steps_week diff --git a/app/src/main/res/values/colors.xml b/app/src/main/res/values/colors.xml index 4c98bbde0..9b4dbd14f 100644 --- a/app/src/main/res/values/colors.xml +++ b/app/src/main/res/values/colors.xml @@ -49,6 +49,7 @@ #be03fc #d12a2a #5ac234 + #00c9bf #858585 #383838 diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b9d0d75fb..5dfe12cc7 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -1576,6 +1576,7 @@ %1$d ms %1$d-%2$d ms Baseline + %1$,.2f km Gained Lost Body Energy Level @@ -2071,6 +2072,10 @@ Minimum Average Steps + Steps AVG + Steps Total + Distance AVG + Distance Total Active Calories Maximum diff --git a/app/src/main/res/values/values.xml b/app/src/main/res/values/values.xml index 2015c8d7b..fe23a88b7 100644 --- a/app/src/main/res/values/values.xml +++ b/app/src/main/res/values/values.xml @@ -100,7 +100,6 @@ activity activitylist sleep - sleepweek stepsweek stress pai