mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2026-07-31 07:44:24 +02:00
Charts: Allow devices to provide their own charts
This commit is contained in:
+18
-163
@@ -50,12 +50,7 @@ import androidx.viewpager2.widget.ViewPager2;
|
||||
import com.google.android.material.tabs.TabLayout;
|
||||
import com.google.android.material.tabs.TabLayoutMediator;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import java.text.SimpleDateFormat;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Calendar;
|
||||
import java.util.Collections;
|
||||
import java.util.Date;
|
||||
@@ -67,7 +62,6 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.AbstractGBFragment;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.ActivityAmounts;
|
||||
@@ -75,11 +69,8 @@ import nodomain.freeyourgadget.gadgetbridge.model.RecordedDataTypes;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.GB;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.LimitedQueue;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
|
||||
|
||||
public class ActivityChartsActivity extends AbstractGBActivity implements ChartsHost {
|
||||
private static final Logger LOG = LoggerFactory.getLogger(ActivityChartsActivity.class);
|
||||
|
||||
public static final String STATE_START_DATE = "stateStartDate";
|
||||
public static final String STATE_END_DATE = "stateEndDate";
|
||||
|
||||
@@ -261,81 +252,17 @@ public class ActivityChartsActivity extends AbstractGBActivity implements Charts
|
||||
return new SectionsStateAdapter(this);
|
||||
}
|
||||
protected List<String> fillChartsTabsList() {
|
||||
return fillChartsTabsList(getDevice(), this);
|
||||
return fillChartsTabsList(getDevice());
|
||||
}
|
||||
|
||||
private static List<String> fillChartsTabsList(final GBDevice device, final Context context) {
|
||||
final List<String> tabList;
|
||||
final Prefs prefs = new Prefs(GBApplication.getDeviceSpecificSharedPrefs(device.getAddress()));
|
||||
final String myTabs = prefs.getString(DeviceSettingsPreferenceConst.PREFS_DEVICE_CHARTS_TABS, null);
|
||||
|
||||
if (myTabs == null) {
|
||||
//make list mutable to be able to remove items later
|
||||
tabList = new ArrayList<>(Arrays.asList(context.getResources().getStringArray(R.array.pref_charts_tabs_items_default)));
|
||||
} else {
|
||||
tabList = new ArrayList<>(Arrays.asList(myTabs.split(",")));
|
||||
}
|
||||
private static List<String> fillChartsTabsList(final GBDevice device) {
|
||||
final DeviceCoordinator coordinator = device.getDeviceCoordinator();
|
||||
if (!coordinator.supportsActivityTabs(device)) {
|
||||
tabList.remove("activity");
|
||||
tabList.remove("activitylist");
|
||||
}
|
||||
if (!coordinator.supportsSleepMeasurement(device)) {
|
||||
tabList.remove("sleep");
|
||||
}
|
||||
if (!coordinator.supportsStressMeasurement(device)) {
|
||||
tabList.remove("stress");
|
||||
}
|
||||
if (!coordinator.supportsPai(device)) {
|
||||
tabList.remove("pai");
|
||||
}
|
||||
if (!coordinator.supportsSpo2(device)) {
|
||||
tabList.remove("spo2");
|
||||
}
|
||||
if (!coordinator.supportsStepCounter(device)) {
|
||||
tabList.remove("stepsweek");
|
||||
}
|
||||
if (!coordinator.supportsSpeedzones(device)) {
|
||||
tabList.remove("speedzones");
|
||||
}
|
||||
if (!coordinator.supportsRealtimeData(device)) {
|
||||
tabList.remove("livestats");
|
||||
}
|
||||
if (!coordinator.supportsTemperatureMeasurement(device)) {
|
||||
tabList.remove("temperature");
|
||||
}
|
||||
if (!coordinator.supportsCyclingData(device)) {
|
||||
tabList.remove("cycling");
|
||||
}
|
||||
if (!coordinator.supportsWeightMeasurement(device)) {
|
||||
tabList.remove("weight");
|
||||
}
|
||||
if (!coordinator.supportsHrvMeasurement(device)) {
|
||||
tabList.remove("hrvstatus");
|
||||
}
|
||||
if (!coordinator.supportsHeartRateMeasurement(device)) {
|
||||
tabList.remove("heartrate");
|
||||
}
|
||||
if (!coordinator.supportsBodyEnergy(device)) {
|
||||
tabList.remove("bodyenergy");
|
||||
}
|
||||
if (!coordinator.supportsVO2Max(device)) {
|
||||
tabList.remove("vo2max");
|
||||
}
|
||||
if (!coordinator.supportsTrainingLoad(device)) {
|
||||
tabList.remove("load");
|
||||
}
|
||||
if (!coordinator.supportsActiveCalories(device)) {
|
||||
tabList.remove("calories");
|
||||
}
|
||||
if (!coordinator.supportsRespiratoryRate(device)) {
|
||||
tabList.remove("respiratoryrate");
|
||||
}
|
||||
return tabList;
|
||||
|
||||
return coordinator.getChartsProvider().getSupportedCharts(device);
|
||||
}
|
||||
|
||||
public static int getChartsTabIndex(final String tab, final GBDevice device, final Context context) {
|
||||
final List<String> enabledTabsList = fillChartsTabsList(device, context);
|
||||
final List<String> enabledTabsList = fillChartsTabsList(device);
|
||||
return enabledTabsList.indexOf(tab);
|
||||
}
|
||||
|
||||
@@ -466,48 +393,13 @@ public class ActivityChartsActivity extends AbstractGBActivity implements Charts
|
||||
}
|
||||
|
||||
public CharSequence getPageTitle(int position) {
|
||||
switch (enabledTabsList.get(position)) {
|
||||
case "activity":
|
||||
return getString(R.string.activity_sleepchart_activity_and_sleep);
|
||||
case "activitylist":
|
||||
return getString(R.string.charts_activity_list);
|
||||
case "sleep":
|
||||
return getString(R.string.sleepchart_your_sleep);
|
||||
case "heartrate":
|
||||
return getString(R.string.menuitem_hr);
|
||||
case "hrvstatus":
|
||||
return getString(R.string.pref_header_hrv_status);
|
||||
case "bodyenergy":
|
||||
return getString(R.string.body_energy);
|
||||
case "vo2max":
|
||||
return getString(R.string.menuitem_vo2_max);
|
||||
case "stress":
|
||||
return getString(R.string.menuitem_stress);
|
||||
case "pai":
|
||||
return getString(getDevice().getDeviceCoordinator().getPaiName());
|
||||
case "stepsweek":
|
||||
return getString(R.string.steps);
|
||||
case "speedzones":
|
||||
return getString(R.string.stats_title);
|
||||
case "livestats":
|
||||
return getString(R.string.liveactivity_live_activity);
|
||||
case "spo2":
|
||||
return getString(R.string.pref_header_spo2);
|
||||
case "temperature":
|
||||
return getString(R.string.menuitem_temperature);
|
||||
case "cycling":
|
||||
return getString(R.string.title_cycling);
|
||||
case "weight":
|
||||
return getString(R.string.menuitem_weight);
|
||||
case "calories":
|
||||
return getString(R.string.calories);
|
||||
case "respiratoryrate":
|
||||
return getString(R.string.respiratoryrate);
|
||||
case "load":
|
||||
return getString(R.string.pref_header_training_load);
|
||||
}
|
||||
|
||||
return String.format(Locale.getDefault(), "Unknown %d", position);
|
||||
final DeviceCoordinator coordinator = getDevice().getDeviceCoordinator();
|
||||
final DeviceChartsProvider chartsProvider = coordinator.getChartsProvider();
|
||||
return chartsProvider.getChartLabel(
|
||||
this,
|
||||
getDevice(),
|
||||
enabledTabsList.get(position)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -523,49 +415,12 @@ public class ActivityChartsActivity extends AbstractGBActivity implements Charts
|
||||
@Override
|
||||
public Fragment createFragment(int position) {
|
||||
final DeviceCoordinator coordinator = getDevice().getDeviceCoordinator();
|
||||
// getItem is called to instantiate the fragment for the given page.
|
||||
switch (enabledTabsList.get(position)) {
|
||||
case "activity":
|
||||
return new ActivitySleepChartFragment();
|
||||
case "activitylist":
|
||||
return new ActivityListingChartFragment();
|
||||
case "sleep":
|
||||
return SleepCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "heartrate":
|
||||
return HeartRateCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "hrvstatus":
|
||||
return new HRVStatusFragment();
|
||||
case "bodyenergy":
|
||||
return BodyEnergyCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "vo2max":
|
||||
return new VO2MaxFragment();
|
||||
case "load":
|
||||
return new LoadFragment();
|
||||
case "stress":
|
||||
return StressCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "pai":
|
||||
return new PaiChartFragment();
|
||||
case "stepsweek":
|
||||
return StepsCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "speedzones":
|
||||
return new SpeedZonesFragment();
|
||||
case "livestats":
|
||||
return new LiveActivityFragment();
|
||||
case "spo2":
|
||||
return Spo2CollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "temperature":
|
||||
return coordinator.supportsContinuousTemperature(getDevice())? new TemperatureDailyFragment(): new TemperatureChartFragment();
|
||||
case "cycling":
|
||||
return new CyclingChartFragment();
|
||||
case "weight":
|
||||
return new WeightChartFragment();
|
||||
case "calories":
|
||||
return CaloriesCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
case "respiratoryrate":
|
||||
return RespiratoryRateCollectionFragment.newInstance(enabledTabsList.size() == 1);
|
||||
}
|
||||
|
||||
return new ActivityChartsActivity.UnknownFragment();
|
||||
final DeviceChartsProvider chartsProvider = coordinator.getChartsProvider();
|
||||
return chartsProvider.getChartFragment(
|
||||
getDevice(),
|
||||
enabledTabsList.get(position),
|
||||
enabledTabsList.size() == 1
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+147
@@ -0,0 +1,147 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.Fragment
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBApplication
|
||||
import nodomain.freeyourgadget.gadgetbridge.R
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.ActivityChartsActivity.UnknownFragment
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice
|
||||
import java.util.Locale
|
||||
|
||||
object DefaultChartsProvider : DeviceChartsProvider {
|
||||
override fun getSupportedCharts(device: GBDevice): List<String> {
|
||||
val coordinator = device.deviceCoordinator
|
||||
val supportedCharts = mutableListOf<String>()
|
||||
|
||||
if (coordinator.supportsCyclingData(device)) {
|
||||
supportedCharts.add("cycling")
|
||||
}
|
||||
if (coordinator.supportsActivityTabs(device)) {
|
||||
supportedCharts.add("activity")
|
||||
supportedCharts.add("activitylist")
|
||||
}
|
||||
if (coordinator.supportsSleepMeasurement(device)) {
|
||||
supportedCharts.add("sleep")
|
||||
}
|
||||
if (coordinator.supportsHrvMeasurement(device)) {
|
||||
supportedCharts.add("hrvstatus")
|
||||
}
|
||||
if (coordinator.supportsBodyEnergy(device)) {
|
||||
supportedCharts.add("bodyenergy")
|
||||
}
|
||||
if (coordinator.supportsVO2Max(device)) {
|
||||
supportedCharts.add("vo2max")
|
||||
}
|
||||
if (coordinator.supportsTrainingLoad(device)) {
|
||||
supportedCharts.add("load")
|
||||
}
|
||||
if (coordinator.supportsHeartRateMeasurement(device)) {
|
||||
supportedCharts.add("heartrate")
|
||||
}
|
||||
if (coordinator.supportsStepCounter(device)) {
|
||||
supportedCharts.add("stepsweek")
|
||||
}
|
||||
if (coordinator.supportsStressMeasurement(device)) {
|
||||
supportedCharts.add("stress")
|
||||
}
|
||||
if (coordinator.supportsPai(device)) {
|
||||
supportedCharts.add("pai")
|
||||
}
|
||||
if (coordinator.supportsSpeedzones(device)) {
|
||||
supportedCharts.add("speedzones")
|
||||
}
|
||||
if (coordinator.supportsRealtimeData(device)) {
|
||||
supportedCharts.add("livestats")
|
||||
}
|
||||
if (coordinator.supportsSpo2(device)) {
|
||||
supportedCharts.add("spo2")
|
||||
}
|
||||
if (coordinator.supportsTemperatureMeasurement(device)) {
|
||||
supportedCharts.add("temperature")
|
||||
}
|
||||
if (coordinator.supportsWeightMeasurement(device)) {
|
||||
supportedCharts.add("weight")
|
||||
}
|
||||
if (coordinator.supportsActiveCalories(device)) {
|
||||
supportedCharts.add("calories")
|
||||
}
|
||||
if (coordinator.supportsRespiratoryRate(device)) {
|
||||
supportedCharts.add("respiratoryrate")
|
||||
}
|
||||
|
||||
return supportedCharts
|
||||
}
|
||||
|
||||
override fun getEnabledCharts(device: GBDevice): List<String> {
|
||||
val prefs = GBApplication.getDevicePrefs(device)
|
||||
val enabledCharts = prefs.getString(DeviceSettingsPreferenceConst.PREFS_DEVICE_CHARTS_TABS, null)
|
||||
return if (!enabledCharts.isNullOrBlank()) {
|
||||
enabledCharts.split(",").intersect(getSupportedCharts(device).toSet()).toList()
|
||||
} else {
|
||||
getSupportedCharts(device)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getChartLabel(
|
||||
context: Context,
|
||||
device: GBDevice,
|
||||
chartName: String
|
||||
): String {
|
||||
return when (chartName) {
|
||||
"activity" -> context.getString(R.string.activity_sleepchart_activity_and_sleep)
|
||||
"activitylist" -> context.getString(R.string.charts_activity_list)
|
||||
"sleep" -> context.getString(R.string.sleepchart_your_sleep)
|
||||
"heartrate" -> context.getString(R.string.menuitem_hr)
|
||||
"hrvstatus" -> context.getString(R.string.pref_header_hrv_status)
|
||||
"bodyenergy" -> context.getString(R.string.body_energy)
|
||||
"vo2max" -> context.getString(R.string.menuitem_vo2_max)
|
||||
"stress" -> context.getString(R.string.menuitem_stress)
|
||||
"pai" -> context.getString(device.deviceCoordinator.getPaiName())
|
||||
"stepsweek" -> context.getString(R.string.steps)
|
||||
"speedzones" -> context.getString(R.string.stats_title)
|
||||
"livestats" -> context.getString(R.string.liveactivity_live_activity)
|
||||
"spo2" -> context.getString(R.string.pref_header_spo2)
|
||||
"temperature" -> context.getString(R.string.menuitem_temperature)
|
||||
"cycling" -> context.getString(R.string.title_cycling)
|
||||
"weight" -> context.getString(R.string.menuitem_weight)
|
||||
"calories" -> context.getString(R.string.calories)
|
||||
"respiratoryrate" -> context.getString(R.string.respiratoryrate)
|
||||
"load" -> context.getString(R.string.pref_header_training_load)
|
||||
else -> String.format(Locale.getDefault(), "Unknown %s", chartName)
|
||||
}
|
||||
}
|
||||
|
||||
override fun getChartFragment(
|
||||
device: GBDevice,
|
||||
chartName: String,
|
||||
allowSwipe: Boolean
|
||||
): Fragment {
|
||||
return when (chartName) {
|
||||
"activity" -> ActivitySleepChartFragment()
|
||||
"activitylist" -> ActivityListingChartFragment()
|
||||
"sleep" -> SleepCollectionFragment.newInstance(allowSwipe)
|
||||
"heartrate" -> HeartRateCollectionFragment.newInstance(allowSwipe)
|
||||
"hrvstatus" -> HRVStatusFragment()
|
||||
"bodyenergy" -> BodyEnergyCollectionFragment.newInstance(allowSwipe)
|
||||
"vo2max" -> VO2MaxFragment()
|
||||
"load" -> LoadFragment()
|
||||
"stress" -> StressCollectionFragment.newInstance(allowSwipe)
|
||||
"pai" -> PaiChartFragment()
|
||||
"stepsweek" -> StepsCollectionFragment.newInstance(allowSwipe)
|
||||
"speedzones" -> SpeedZonesFragment()
|
||||
"livestats" -> LiveActivityFragment()
|
||||
"spo2" -> Spo2CollectionFragment.newInstance(allowSwipe)
|
||||
"temperature" -> {
|
||||
if (device.deviceCoordinator.supportsContinuousTemperature(device))
|
||||
TemperatureDailyFragment() else TemperatureChartFragment()
|
||||
}
|
||||
|
||||
"cycling" -> CyclingChartFragment()
|
||||
"weight" -> WeightChartFragment()
|
||||
"calories" -> CaloriesCollectionFragment.newInstance(allowSwipe)
|
||||
"respiratoryrate" -> RespiratoryRateCollectionFragment.newInstance(allowSwipe)
|
||||
else -> UnknownFragment()
|
||||
}
|
||||
}
|
||||
}
|
||||
+15
@@ -0,0 +1,15 @@
|
||||
package nodomain.freeyourgadget.gadgetbridge.activities.charts
|
||||
|
||||
import android.content.Context
|
||||
import androidx.fragment.app.Fragment
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice
|
||||
|
||||
interface DeviceChartsProvider {
|
||||
fun getSupportedCharts(device: GBDevice): List<String>
|
||||
|
||||
fun getEnabledCharts(device: GBDevice): List<String>
|
||||
|
||||
fun getChartLabel(context: Context, device: GBDevice, chartName: String): String
|
||||
|
||||
fun getChartFragment(device: GBDevice, chartName: String, allowSwipe: Boolean): Fragment
|
||||
}
|
||||
+7
@@ -58,6 +58,8 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.R;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.ExternalPebbleJSActivity;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DefaultChartsProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DeviceChartsProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
@@ -701,6 +703,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public DeviceChartsProvider getChartsProvider() {
|
||||
return DefaultChartsProvider.INSTANCE;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsTemperatureMeasurement(@NonNull final GBDevice device) {
|
||||
return false;
|
||||
|
||||
@@ -37,6 +37,7 @@ import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.GBException;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.charts.DeviceChartsProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
|
||||
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
|
||||
import nodomain.freeyourgadget.gadgetbridge.capabilities.HeartRateCapability;
|
||||
@@ -288,6 +289,8 @@ public interface DeviceCoordinator {
|
||||
boolean supportsWorkoutLoad(@NonNull GBDevice device);
|
||||
boolean supportsGlucoseMeasurement(@NonNull GBDevice device);
|
||||
|
||||
DeviceChartsProvider getChartsProvider();
|
||||
|
||||
/**
|
||||
* Returns true if measurement and fetching of body temperature is supported by the device
|
||||
* (with this coordinator).
|
||||
|
||||
Reference in New Issue
Block a user