mirror of
https://codeberg.org/Freeyourgadget/Gadgetbridge.git
synced 2025-01-10 17:11:56 +01:00
Xiaomi: Add Vitality Score (PAI-like metric)
This commit is contained in:
parent
bddec00de1
commit
372cf563ea
@ -172,7 +172,7 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
|
||||
case "stress":
|
||||
return getString(R.string.menuitem_stress);
|
||||
case "pai":
|
||||
return getString(R.string.menuitem_pai);
|
||||
return getString(getDevice().getDeviceCoordinator().getPaiName());
|
||||
case "stepsweek":
|
||||
return getStepsTitle();
|
||||
case "speedzones":
|
||||
|
@ -58,7 +58,6 @@ import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DateTimeUtils;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.DeviceHelper;
|
||||
import nodomain.freeyourgadget.gadgetbridge.util.Optional;
|
||||
|
||||
public class PaiChartFragment extends AbstractChartFragment<PaiChartFragment.PaiChartsData> {
|
||||
@ -118,6 +117,12 @@ public class PaiChartFragment extends AbstractChartFragment<PaiChartFragment.Pai
|
||||
mLineHighInc = rootView.findViewById(R.id.pai_line_high_inc);
|
||||
mLineHighTime = rootView.findViewById(R.id.pai_line_high_time);
|
||||
|
||||
if (!getChartsHost().getDevice().getDeviceCoordinator().supportsPaiTime()) {
|
||||
mLineLowTime.setVisibility(View.GONE);
|
||||
mLineModerateTime.setVisibility(View.GONE);
|
||||
mLineHighTime.setVisibility(View.GONE);
|
||||
}
|
||||
|
||||
setupWeekChart();
|
||||
setupTodayPieChart();
|
||||
|
||||
|
@ -956,6 +956,20 @@ public class DeviceSpecificSettingsFragment extends AbstractPreferenceFragment i
|
||||
}
|
||||
}
|
||||
|
||||
// Replace the PAI with the device-specific name
|
||||
if (chartsTabsOrderSelection != null) {
|
||||
final ListPreference chartsTabsListPref = (ListPreference) chartsTabsOrderSelection;
|
||||
final CharSequence[] entries = chartsTabsListPref.getEntries();
|
||||
final CharSequence[] entryValues = chartsTabsListPref.getEntryValues();
|
||||
for (int i = 0; i < entries.length; i++) {
|
||||
if ("pai".equals(entryValues[i].toString())) {
|
||||
entries[i] = getString(coordinator.getPaiName());
|
||||
break;
|
||||
}
|
||||
}
|
||||
chartsTabsListPref.setEntries(entries);
|
||||
}
|
||||
|
||||
final Preference loyaltyCards = findPreference(LoyaltyCardsSettingsConst.PREF_KEY_LOYALTY_CARDS);
|
||||
if (loyaltyCards != null) {
|
||||
loyaltyCards.setOnPreferenceClickListener(preference -> {
|
||||
|
@ -398,6 +398,16 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPaiName() {
|
||||
return R.string.menuitem_pai;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsPaiTime() {
|
||||
return supportsPai();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsSleepRespiratoryRate() {
|
||||
return false;
|
||||
|
@ -209,6 +209,18 @@ public interface DeviceCoordinator {
|
||||
*/
|
||||
boolean supportsPai();
|
||||
|
||||
/**
|
||||
* Returns the device-specific name for PAI (eg. Vitality Score).
|
||||
*/
|
||||
@StringRes
|
||||
int getPaiName();
|
||||
|
||||
/**
|
||||
* Returns true if the device is capable of providing the time contribution for each PAI type
|
||||
* (light, moderate, high).
|
||||
*/
|
||||
boolean supportsPaiTime();
|
||||
|
||||
/**
|
||||
* Returns true if sleep respiratory rate measurement and fetching is supported by
|
||||
* the device (with this coordinator).
|
||||
|
@ -140,8 +140,7 @@ public abstract class XiaomiCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public TimeSampleProvider<? extends PaiSample> getPaiSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
// TODO XiaomiPaiSampleProvider
|
||||
return super.getPaiSampleProvider(device, session);
|
||||
return new XiaomiPaiSampleProvider(device, session);
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -245,13 +244,23 @@ public abstract class XiaomiCoordinator extends AbstractBLEDeviceCoordinator {
|
||||
|
||||
@Override
|
||||
public boolean supportsHeartRateStats() {
|
||||
// TODO it does - see DailySummaryParser
|
||||
// TODO it does, and they're persisted - see DailySummaryParser
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsPai() {
|
||||
// TODO it does - vitality score
|
||||
// Vitality Score
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getPaiName() {
|
||||
return R.string.pref_vitality_score_title;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean supportsPaiTime() {
|
||||
return false;
|
||||
}
|
||||
|
||||
|
@ -0,0 +1,56 @@
|
||||
/* Copyright (C) 2023 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import de.greenrobot.dao.AbstractDao;
|
||||
import de.greenrobot.dao.Property;
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractTimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.XiaomiDailySummarySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.XiaomiDailySummarySampleDao;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
|
||||
public class XiaomiDailySummarySampleProvider extends AbstractTimeSampleProvider<XiaomiDailySummarySample> {
|
||||
public XiaomiDailySummarySampleProvider(final GBDevice device, final DaoSession session) {
|
||||
super(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public AbstractDao<XiaomiDailySummarySample, ?> getSampleDao() {
|
||||
return getSession().getXiaomiDailySummarySampleDao();
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getTimestampSampleProperty() {
|
||||
return XiaomiDailySummarySampleDao.Properties.Timestamp;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
protected Property getDeviceIdentifierSampleProperty() {
|
||||
return XiaomiDailySummarySampleDao.Properties.DeviceId;
|
||||
}
|
||||
|
||||
@Override
|
||||
public XiaomiDailySummarySample createSample() {
|
||||
return new XiaomiDailySummarySample();
|
||||
}
|
||||
}
|
@ -0,0 +1,144 @@
|
||||
/* Copyright (C) 2023 José Rebelo
|
||||
|
||||
This file is part of Gadgetbridge.
|
||||
|
||||
Gadgetbridge is free software: you can redistribute it and/or modify
|
||||
it under the terms of the GNU Affero General Public License as published
|
||||
by the Free Software Foundation, either version 3 of the License, or
|
||||
(at your option) any later version.
|
||||
|
||||
Gadgetbridge is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
GNU Affero General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Affero General Public License
|
||||
along with this program. If not, see <http://www.gnu.org/licenses/>. */
|
||||
package nodomain.freeyourgadget.gadgetbridge.devices.xiaomi;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.annotation.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
|
||||
import nodomain.freeyourgadget.gadgetbridge.entities.XiaomiDailySummarySample;
|
||||
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
|
||||
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
|
||||
|
||||
public class XiaomiPaiSampleProvider implements TimeSampleProvider<PaiSample> {
|
||||
private final XiaomiDailySummarySampleProvider dailySummarySampleProvider;
|
||||
|
||||
public XiaomiPaiSampleProvider(final GBDevice device, final DaoSession session) {
|
||||
this.dailySummarySampleProvider = new XiaomiDailySummarySampleProvider(device, session);
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public List<PaiSample> getAllSamples(final long timestampFrom, final long timestampTo) {
|
||||
final List<XiaomiDailySummarySample> allSamples = dailySummarySampleProvider.getAllSamples(timestampFrom, timestampTo);
|
||||
final List<PaiSample> ret = new ArrayList<>(allSamples.size());
|
||||
for (final XiaomiDailySummarySample sample : allSamples) {
|
||||
ret.add(new XiaomiPaiSample(sample));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSample(final PaiSample timeSample) {
|
||||
throw new UnsupportedOperationException("This sample provider is read-only!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addSamples(final List<PaiSample> timeSamples) {
|
||||
throw new UnsupportedOperationException("This sample provider is read-only!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public PaiSample createSample() {
|
||||
throw new UnsupportedOperationException("This sample provider is read-only!");
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PaiSample getLatestSample() {
|
||||
final XiaomiDailySummarySample sample = dailySummarySampleProvider.getLatestSample();
|
||||
if (sample != null) {
|
||||
return new XiaomiPaiSample(sample);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
@Override
|
||||
public PaiSample getFirstSample() {
|
||||
final XiaomiDailySummarySample sample = dailySummarySampleProvider.getFirstSample();
|
||||
if (sample != null) {
|
||||
return new XiaomiPaiSample(sample);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static class XiaomiPaiSample implements PaiSample {
|
||||
private final long timestamp;
|
||||
private final int paiLow;
|
||||
private final int paiModerate;
|
||||
private final int paiHigh;
|
||||
private final int paiTotal;
|
||||
|
||||
public XiaomiPaiSample(final XiaomiDailySummarySample sample) {
|
||||
this.timestamp = sample.getTimestamp();
|
||||
this.paiLow = sample.getVitalityIncreaseLight();
|
||||
this.paiModerate = sample.getVitalityIncreaseModerate();
|
||||
this.paiHigh = sample.getVitalityIncreaseHigh();
|
||||
this.paiTotal = sample.getVitalityCurrent();
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getTimestamp() {
|
||||
return timestamp;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPaiLow() {
|
||||
return paiLow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPaiModerate() {
|
||||
return paiModerate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPaiHigh() {
|
||||
return paiHigh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeLow() {
|
||||
return 0; // not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeModerate() {
|
||||
return 0; // not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getTimeHigh() {
|
||||
return 0; // not supported
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPaiToday() {
|
||||
return paiLow + paiModerate + paiHigh;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getPaiTotal() {
|
||||
return paiTotal;
|
||||
}
|
||||
}
|
||||
}
|
@ -2043,8 +2043,8 @@
|
||||
<string name="stress_mild">Mild</string>
|
||||
<string name="stress_moderate">Moderate</string>
|
||||
<string name="stress_high">High</string>
|
||||
<string name="pai_total">PAI Total</string>
|
||||
<string name="pai_day">Day PAI increase</string>
|
||||
<string name="pai_total">Total</string>
|
||||
<string name="pai_day">Day increase</string>
|
||||
<string name="sony_ambient_sound">Mode</string>
|
||||
<string name="sony_ambient_sound_off">Off</string>
|
||||
<string name="sony_ambient_sound_noise_cancelling">Noise Cancelling</string>
|
||||
|
Loading…
Reference in New Issue
Block a user