1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-11-23 10:26:49 +01:00

Compare commits

...

80 Commits

Author SHA1 Message Date
a0z
a1c8a2ce04 Calories: fix loading lag, gap 2024-11-01 13:01:13 +01:00
a0z
68ff0dfa0b Calories: add fragment 2024-11-01 13:01:13 +01:00
José Rebelo
c119b04478 Garmin: Resting metabolic rate 2024-11-01 13:01:13 +01:00
José Rebelo
46dd45cb4e Garmin Forerunner 235: Initial support 2024-10-31 23:47:20 +00:00
José Rebelo
cd068abdd3 Update androidx.camera to v1.4.0 2024-10-31 23:44:46 +00:00
José Rebelo
aa2b6d142a Update androidx.constraintlayout to v2.2.0 2024-10-31 23:44:27 +00:00
José Rebelo
d9cc15e3c5 Update androidx.fragment:fragment to v1.8.5 2024-10-31 23:43:51 +00:00
Me7c7
a7c19c8190 Huawei: calculate HR Zones for walking and running workouts. 2024-10-31 23:14:04 +00:00
Thomas Di Cristofaro
d038c589c1
Translated using Weblate (Italian)
Currently translated at 100.0% (3295 of 3295 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-31 14:40:21 +01:00
Fjuro
8df3dac11c
Translated using Weblate (Czech)
Currently translated at 100.0% (3295 of 3295 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-31 14:18:19 +01:00
Thomas Di Cristofaro
a12b56fb37
Translated using Weblate (Italian)
Currently translated at 100.0% (3294 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-30 21:31:26 +00:00
Yusuf Cihan
2315b56ff8 Add screenshot script & update F-Droid screenshots 2024-10-30 21:23:49 +00:00
José Rebelo
ed1f1735c5 Update changelogs 2024-10-30 20:51:39 +00:00
José Rebelo
292a5d11b5 Activity Charts: Update date info when refreshed 2024-10-30 20:51:02 +00:00
Zahnstocher
a6053eda77 Add support for Sony WI-C100 2024-10-30 20:47:37 +00:00
Zahnstocher
cbd9a7b8af Add voice notifications for Sony WF-C500 2024-10-30 14:31:16 +01:00
José Rebelo
29866c2b41 Fix linter 2024-10-29 11:23:12 +00:00
Andreas Shimokawa
1e0117727e fix xml 2024-10-29 11:49:59 +01:00
Andreas Shimokawa
3a152978d7 bump version, update changelog
trim changelog_master.xml to include changes for the last 2 years only
2024-10-29 11:45:00 +01:00
Thomas Di Cristofaro
7f9c571d63
Translated using Weblate (Italian)
Currently translated at 96.7% (3186 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-29 07:04:36 +01:00
Thomas Di Cristofaro
16b12e099f
Translated using Weblate (Italian)
Currently translated at 93.6% (3084 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-28 22:40:28 +01:00
arjan-s
dae338fdc5
Translated using Weblate (Dutch)
Currently translated at 100.0% (3294 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-28 22:40:27 +01:00
a0z
a79cd94de9 HRV Status: segment detection fix 2024-10-28 22:37:54 +01:00
Arjan Schrijver
d5c2207a48 Colmi R0x: Improve sleep handling around DST changes 2024-10-28 11:41:31 +01:00
José Rebelo
35ca3f947e Fix nightly healthcheck variables 2024-10-27 23:11:20 +00:00
José Rebelo
7acda0d52c Add basic nightly pipeline monitoring 2024-10-27 14:18:08 +00:00
José Rebelo
212bf996c3 Update changelog 2024-10-27 14:15:28 +00:00
Thomas Di Cristofaro
026fc80c8d
Translated using Weblate (Italian)
Currently translated at 92.4% (3046 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-27 15:13:54 +01:00
Yaron Shahrabani
95cb3f881d
Translated using Weblate (Hebrew)
Currently translated at 85.2% (2809 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/he/
2024-10-27 15:13:53 +01:00
Thomas Di Cristofaro
2ee28d8f00
Translated using Weblate (Italian)
Currently translated at 92.3% (3041 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-27 10:00:32 +01:00
Thomas Di Cristofaro
665df850eb
Translated using Weblate (Italian)
Currently translated at 92.0% (3032 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-27 10:00:32 +01:00
Thomas Di Cristofaro
4f34714d70
Translated using Weblate (Italian)
Currently translated at 88.7% (2924 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
2024-10-27 10:00:31 +01:00
Rex_sa
99120df6d9
Translated using Weblate (Arabic)
Currently translated at 100.0% (3294 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ar/
2024-10-27 10:00:30 +01:00
陈少举
a0aed0279e
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3294 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:30 +01:00
Fjuro
4b3806f7c0
Translated using Weblate (Czech)
Currently translated at 100.0% (3294 of 3294 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:29 +01:00
Rex_sa
a35f64a68b
Translated using Weblate (Arabic)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ar/
2024-10-27 10:00:28 +01:00
gallegonovato
112253ea27
Translated using Weblate (Spanish)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
2024-10-27 10:00:28 +01:00
Fjuro
18c8b45669
Translated using Weblate (Czech)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:27 +01:00
陈少举
6edc5d9d0a
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:26 +01:00
arjan-s
7fe9bd3c6c
Translated using Weblate (Dutch)
Currently translated at 99.9% (3289 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-27 10:00:25 +01:00
qtm
bf717749c1
Translated using Weblate (Russian)
Currently translated at 91.2% (3002 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
2024-10-27 10:00:24 +01:00
Fjuro
6a74d6dea3
Translated using Weblate (Czech)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:23 +01:00
Jens Metschkoll
444744d2aa
Translated using Weblate (German)
Currently translated at 94.4% (3108 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/de/
2024-10-27 10:00:23 +01:00
Rex_sa
4527037132
Translated using Weblate (Arabic)
Currently translated at 93.0% (3062 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ar/
2024-10-27 10:00:22 +01:00
Ihor Hordiichuk
9eb7f9d74c
Translated using Weblate (Ukrainian)
Currently translated at 82.4% (2714 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/uk/
2024-10-27 10:00:21 +01:00
Oğuz Ersen
8f3bc719c3
Translated using Weblate (Turkish)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 10:00:20 +01:00
CaptKentish
95c7f74bb9
Translated using Weblate (French)
Currently translated at 99.8% (3286 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/fr/
2024-10-27 10:00:19 +01:00
arjan-s
3861be7c35
Translated using Weblate (Dutch)
Currently translated at 99.9% (3289 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-27 10:00:18 +01:00
陈少举
7c11d7935c
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:17 +01:00
Gregory Blanco
63f1e66798
Translated using Weblate (Polish)
Currently translated at 97.0% (3194 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/pl/
2024-10-27 10:00:16 +01:00
gallegonovato
1dd3b7585f
Translated using Weblate (Spanish)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
2024-10-27 10:00:15 +01:00
Fjuro
ceeeaee498
Translated using Weblate (Czech)
Currently translated at 100.0% (3291 of 3291 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:14 +01:00
陈少举
ca0d3caa88
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3282 of 3282 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:14 +01:00
Oğuz Ersen
cff09bfa82
Translated using Weblate (Turkish)
Currently translated at 100.0% (3282 of 3282 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 10:00:13 +01:00
Fjuro
4d2743dea6
Translated using Weblate (Czech)
Currently translated at 100.0% (3282 of 3282 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:12 +01:00
陈少举
90320616fc
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3281 of 3281 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:12 +01:00
arjan-s
7ad6a8b665
Translated using Weblate (Dutch)
Currently translated at 100.0% (3281 of 3281 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-27 10:00:11 +01:00
Oğuz Ersen
f2d656dce8
Translated using Weblate (Turkish)
Currently translated at 100.0% (3281 of 3281 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 10:00:10 +01:00
Yaron Shahrabani
eb18415e39
Translated using Weblate (Hebrew)
Currently translated at 85.6% (2810 of 3281 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/he/
2024-10-27 10:00:10 +01:00
Manuel Treuheit
41da2f15cc
Translated using Weblate (German)
Currently translated at 94.6% (3106 of 3281 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/de/
2024-10-27 10:00:09 +01:00
Fjuro
2b2a68d5bd
Translated using Weblate (Czech)
Currently translated at 100.0% (3281 of 3281 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:08 +01:00
gallegonovato
3007bba863
Translated using Weblate (Spanish)
Currently translated at 100.0% (3274 of 3274 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
2024-10-27 10:00:07 +01:00
arjan-s
0a7f8e7731
Translated using Weblate (Dutch)
Currently translated at 100.0% (3273 of 3273 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-27 10:00:07 +01:00
Oğuz Ersen
69623f48b6
Translated using Weblate (Turkish)
Currently translated at 100.0% (3273 of 3273 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 10:00:06 +01:00
gallegonovato
46fffdced2
Translated using Weblate (Spanish)
Currently translated at 100.0% (3273 of 3273 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
2024-10-27 10:00:05 +01:00
陈少举
68aed79c02
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3266 of 3266 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:05 +01:00
arjan-s
240b4f155b
Translated using Weblate (Dutch)
Currently translated at 100.0% (3266 of 3266 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-27 10:00:04 +01:00
Oğuz Ersen
e3b4d506be
Translated using Weblate (Turkish)
Currently translated at 100.0% (3266 of 3266 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 10:00:03 +01:00
Fjuro
97aa1e81cd
Translated using Weblate (Czech)
Currently translated at 100.0% (3266 of 3266 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 10:00:02 +01:00
gallegonovato
8ad6b3681a
Translated using Weblate (Spanish)
Currently translated at 100.0% (3266 of 3266 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
2024-10-27 10:00:02 +01:00
陈少举
a9c3a676ee
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3264 of 3264 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 10:00:01 +01:00
Oğuz Ersen
4a8c938a79
Translated using Weblate (Turkish)
Currently translated at 100.0% (3264 of 3264 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 10:00:00 +01:00
gallegonovato
bc577f0702
Translated using Weblate (Spanish)
Currently translated at 100.0% (3262 of 3262 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
2024-10-27 10:00:00 +01:00
Linerly
d08d6bc212
Translated using Weblate (Indonesian)
Currently translated at 90.3% (2941 of 3254 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/id/
2024-10-27 09:59:59 +01:00
陈少举
3d9861d53b
Translated using Weblate (Chinese (Simplified Han script))
Currently translated at 100.0% (3254 of 3254 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
2024-10-27 09:59:58 +01:00
arjan-s
3846eab20d
Translated using Weblate (Dutch)
Currently translated at 100.0% (3254 of 3254 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
2024-10-27 09:59:58 +01:00
Oğuz Ersen
0c969164a2
Translated using Weblate (Turkish)
Currently translated at 100.0% (3254 of 3254 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
2024-10-27 09:59:57 +01:00
JuTonic
b332ff54aa
Translated using Weblate (Russian)
Currently translated at 92.2% (3001 of 3254 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
2024-10-27 09:59:57 +01:00
Fjuro
aacd75c823
Translated using Weblate (Czech)
Currently translated at 100.0% (3254 of 3254 strings)

Translation: Freeyourgadget/Gadgetbridge
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/cs/
2024-10-27 09:59:56 +01:00
Me7c7
d95b2afad3 Huawei: map activity type 4 to mountain hike activity 2024-10-27 10:50:40 +02:00
85 changed files with 3664 additions and 1730 deletions

View File

@ -7,7 +7,11 @@ clone:
steps:
check-if-released:
image: codeberg.org/freeyourgadget/android-fdroid-tools:33.0.0
secrets:
- hc_url_nightly_deploy
commands: |
curl -fsS -m 10 --retry 5 "$${HC_URL_NIGHTLY_DEPLOY}/start"
RELEASED_VERSION_CODE=$(curl https://freeyourgadget.codeberg.page/fdroid/repo/index-v1.json | jq '.packages."nodomain.freeyourgadget.gadgetbridge.nightly"[0].versionCode')
CURRENT_VERSION_CODE=$(git rev-list HEAD --count)
@ -17,6 +21,7 @@ steps:
then
echo "This version is already released, we quit!"
touch .do_not_build
curl -fsS -m 10 --retry 5 "$${HC_URL_NIGHTLY_DEPLOY}"
fi
@ -104,9 +109,19 @@ steps:
# bump
secrets: [ commit_token ]
on-success:
image: codeberg.org/freeyourgadget/android-fdroid-tools:33.0.0
commands:
- curl -fsS -m 10 --retry 5 "$${HC_URL_NIGHTLY_DEPLOY}"
when:
status: success
secrets:
- hc_url_nightly_deploy
on-error:
image: codeberg.org/freeyourgadget/android-fdroid-tools:33.0.0
commands:
- curl -fsS -m 10 --retry 5 "$${HC_URL_NIGHTLY_DEPLOY}/fail"
- cd ..
- mkdir -p repoconfig
- cd repoconfig
@ -114,7 +129,9 @@ steps:
- ./fdroid-repo-config/repoconfig/create_issue_comment.sh "CI failed"
when:
status: failure
secrets: [ commit_token ]
secrets:
- hc_url_nightly_deploy
- commit_token
when:
- event: cron

View File

@ -1,6 +1,6 @@
### Changelog
#### Next version (WIP)
#### 0.82.0
* Initial support for Anker Soundcore Liberty 4 NC
* Initial support for CMF Buds Pro 2 / Watch Pro 2
* Initial support for Colmi R02/R03/R06/R10 smart rings
@ -65,9 +65,11 @@
* Garmin: Display resting heart rate
* Garmin: Fetch SKIP_TEMP files
* Garmin: Fix agps upload for some URLs
* Garmin: Fix all-day events
* Garmin: Fix auto-activity fetch on some devices
* Garmin: Fix canned replies reset to defaults
* Garmin: Fix crash on call with privacy mode on
* Garmin: Fix crash on timezones without DST
* Garmin: Fix daily weather missing current day
* Garmin: Fix weather temperature and speed units
* Garmin: Improve activity, sleep and workout parsing
@ -76,7 +78,7 @@
* Garmin: Map some unknown realtime settings
* Garmin: Parse workout physiological metrics, strength training workout sets
* Garmin: Re-parse workout summary when opening details page
* Garmin: Upload gpx to watch
* Garmin: Upload gpx and workout fit files to watch
* Garmin: Use distance and calories provided by the watch
* Garmin: View and share gpx files
* Huami: Fetch workouts during normal sync
@ -90,6 +92,7 @@
* Huawei: Enable emoji for HarmonyOS watches
* Huawei: Fix crash when notification has no text
* Huawei: Fix initialization issues on some watches
* Huawei: Fix notifications for Huawei Band 4e
* Huawei: Fix some reconnection issues
* Huawei: Fix watchface upload, activity sync, event alarms, weather for some devices
* Huawei: Fix workout altitude, pace, workout re-parsing
@ -98,7 +101,10 @@
* Huawei: Improve weather support
* Huawei: Initial ephemeris update support
* Huawei: Map more workout types
* Huawei: Music upload support
* Huawei: Provide an activity sample every minute
* Huawei: Re-parse workout details when opening details
* Huawei: Send default HR zones
* Huawei: Workout GPS synchronization
* Huawei: Simple TruSleep support
* Huawei: Use distance and calories provided by the watch
@ -113,6 +119,7 @@
* UI: Add new activity icons
* UI: Fix changelog on device rotation
* UI: Fix HR samples displayed on wrong device
* UI: Fix light navbar buttons on light themes for Android 8+
* UI: Fix pull-down to refresh for some devices
* UI: Improvements for large screen resolutions, font sizes, landscape
* UI: Reduce stutters on device changes / data fetch / scrolling

View File

@ -127,6 +127,7 @@ public class GBDaoGenerator {
addGarminHrvValueSample(schema, user, device);
addGarminRespiratoryRateSample(schema, user, device);
addGarminHeartRateRestingSample(schema, user, device);
addGarminRestingMetabolicRateSample(schema, user, device);
addPendingFile(schema, user, device);
addWena3EnergySample(schema, user, device);
addWena3BehaviorSample(schema, user, device);
@ -867,6 +868,14 @@ public class GBDaoGenerator {
return hrRestingSample;
}
private static Entity addGarminRestingMetabolicRateSample(Schema schema, Entity user, Entity device) {
Entity sample = addEntity(schema, "GarminRestingMetabolicRateSample");
sample.addImport(MAIN_PACKAGE + ".model.RestingMetabolicRateSample");
addCommonTimeSampleProperties("RestingMetabolicRateSample", sample, user, device);
sample.addIntProperty("restingMetabolicRate").notNull().codeBeforeGetter(OVERRIDE);
return sample;
}
private static Entity addPendingFile(Schema schema, Entity user, Entity device) {
Entity pendingFile = addEntity(schema, "PendingFile");
pendingFile.setJavaDoc(

View File

@ -79,8 +79,8 @@ android {
minSdkVersion 21
// Note: always bump BOTH versionCode and versionName!
versionName "0.81.0"
versionCode 232
versionName "0.82.0"
versionCode 233
vectorDrawables.useSupportLibrary = true
buildConfigField "String", "GIT_HASH_SHORT", "\"${getGitHashShort()}\""
buildConfigField "boolean", "INTERNET_ACCESS", "false"
@ -200,11 +200,11 @@ android {
dependencies {
coreLibraryDesugaring 'com.android.tools:desugar_jdk_libs:2.1.2'
implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
implementation "androidx.camera:camera-core:1.3.4"
implementation "androidx.camera:camera-camera2:1.3.4"
implementation 'androidx.camera:camera-view:1.3.4'
implementation 'androidx.camera:camera-lifecycle:1.3.4'
implementation 'androidx.constraintlayout:constraintlayout:2.2.0'
implementation "androidx.camera:camera-core:1.4.0"
implementation "androidx.camera:camera-camera2:1.4.0"
implementation 'androidx.camera:camera-view:1.4.0'
implementation 'androidx.camera:camera-lifecycle:1.4.0'
testImplementation "junit:junit:4.13.2"
testImplementation "org.mockito:mockito-core:5.14.2"
@ -219,7 +219,7 @@ dependencies {
implementation "androidx.gridlayout:gridlayout:1.0.0"
implementation "androidx.palette:palette:1.0.0"
implementation "androidx.activity:activity:1.9.3"
implementation "androidx.fragment:fragment:1.8.4"
implementation "androidx.fragment:fragment:1.8.5"
implementation "androidx.viewpager2:viewpager2:1.1.0"
// Not latest version because of https://github.com/material-components/material-components-android/issues/3924

View File

@ -127,7 +127,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 = 42;
private static final int CURRENT_PREFS_VERSION = 44;
private static final LimitedQueue<Integer, String> mIDSenderLookup = new LimitedQueue<>(16);
private static GBPrefs prefs;
@ -1838,6 +1838,44 @@ public class GBApplication extends Application {
}
}
if (oldVersion < 43) {
// Add the new calories tab to all devices.
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 + ",calories";
} else {
newPrefValue = "calories";
}
final SharedPreferences.Editor deviceSharedPrefsEdit = deviceSharedPrefs.edit();
deviceSharedPrefsEdit.putString("charts_tabs", newPrefValue);
deviceSharedPrefsEdit.apply();
}
} catch (Exception e) {
Log.e(TAG, "Failed to migrate prefs to version 43", e);
}
}
if (oldVersion < 44) {
// Add new dashboard calories widgets.
final String dashboardWidgetsOrder = sharedPrefs.getString("pref_dashboard_widgets_order", null);
if (!StringUtils.isBlank(dashboardWidgetsOrder) && !dashboardWidgetsOrder.contains("calories")) {
editor.putString("pref_dashboard_widgets_order", dashboardWidgetsOrder + ",calories,calories_active,calories_segmented");
}
}
editor.putString(PREFS_VERSION, Integer.toString(CURRENT_PREFS_VERSION));
editor.apply();
}

View File

@ -63,9 +63,12 @@ import java.util.function.Supplier;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.AbstractDashboardWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardCaloriesActiveGoalWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardActiveTimeWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardBodyEnergyWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardCalendarActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardCaloriesTotalSegmentedWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardCaloriesGoalWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardDistanceWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardGoalsWidget;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.DashboardHrvWidget;
@ -310,6 +313,15 @@ public class DashboardFragment extends Fragment implements MenuProvider {
case "vo2max":
widget = DashboardVO2MaxAnyWidget.newInstance(dashboardData);
break;
case "calories":
widget = DashboardCaloriesGoalWidget.newInstance(dashboardData);
break;
case "calories_active":
widget = DashboardCaloriesActiveGoalWidget.newInstance(dashboardData);
break;
case "calories_segmented":
widget = DashboardCaloriesTotalSegmentedWidget.newInstance(dashboardData);
break;
default:
LOG.error("Unknown dashboard widget {}", widgetName);
continue;
@ -372,6 +384,11 @@ public class DashboardFragment extends Fragment implements MenuProvider {
public final List<GeneralizedActivity> generalizedActivities = Collections.synchronizedList(new ArrayList<>());
private int stepsTotal;
private float stepsGoalFactor;
private int restingCaloriesTotal;
private int activeCaloriesTotal;
private float activeCaloriesGoalFactor;
private int caloriesTotal;
private float caloriesGoalFactor;
private long sleepTotalMinutes;
private float sleepGoalFactor;
private float distanceTotalMeters;
@ -381,6 +398,11 @@ public class DashboardFragment extends Fragment implements MenuProvider {
private final Map<String, Serializable> genericData = new ConcurrentHashMap<>();
public void clear() {
restingCaloriesTotal = 0;
activeCaloriesTotal = 0;
activeCaloriesGoalFactor = 0;
caloriesTotal = 0;
caloriesGoalFactor = 0;
stepsTotal = 0;
stepsGoalFactor = 0;
sleepTotalMinutes = 0;
@ -396,6 +418,11 @@ public class DashboardFragment extends Fragment implements MenuProvider {
public boolean isEmpty() {
return (stepsTotal == 0 &&
stepsGoalFactor == 0 &&
restingCaloriesTotal == 0 &&
activeCaloriesTotal == 0 &&
activeCaloriesGoalFactor == 0 &&
caloriesTotal == 0 &&
caloriesGoalFactor == 0 &&
sleepTotalMinutes == 0 &&
sleepGoalFactor == 0 &&
distanceTotalMeters == 0 &&
@ -454,6 +481,36 @@ public class DashboardFragment extends Fragment implements MenuProvider {
return sleepGoalFactor;
}
public synchronized int getActiveCaloriesTotal() {
if (activeCaloriesTotal == 0)
activeCaloriesTotal = DashboardUtils.getActiveCaloriesTotal(this);
return activeCaloriesTotal;
}
public synchronized int getRestingCaloriesTotal() {
if (restingCaloriesTotal == 0)
restingCaloriesTotal = DashboardUtils.getRestingCaloriesTotal(this);
return restingCaloriesTotal;
}
public synchronized float getActiveCaloriesGoalFactor() {
if (activeCaloriesGoalFactor == 0)
activeCaloriesGoalFactor = DashboardUtils.getActiveCaloriesGoalFactor(this);
return activeCaloriesGoalFactor;
}
public synchronized int getCaloriesTotal() {
if (caloriesTotal == 0)
caloriesTotal = getRestingCaloriesTotal() + getActiveCaloriesTotal();
return caloriesTotal;
}
public synchronized float getCaloriesGoalFactor() {
if (caloriesGoalFactor == 0)
caloriesGoalFactor = DashboardUtils.getCaloriesGoalFactor(this);
return caloriesGoalFactor;
}
public void put(final String key, final Serializable value) {
genericData.put(key, value);
}

View File

@ -207,6 +207,7 @@ public abstract class AbstractChartFragment<D extends ChartsData> extends Abstra
protected void onReceive(Context context, Intent intent) {
String action = intent.getAction();
if (ChartsHost.REFRESH.equals(action)) {
updateDateInfo(getStartDate(), getEndDate());
refresh();
} else if (ChartsHost.DATE_NEXT_DAY.equals(action)) {
handleDate(getStartDate(), getEndDate(), +1);

View File

@ -70,6 +70,7 @@ public abstract class AbstractChartsActivity extends AbstractGBFragmentActivity
public static final String EXTRA_SINGLE_FRAGMENT_NAME = "singleFragmentName";
public static final String EXTRA_ACTIONBAR_TITLE = "actionbarTitle";
public static final String EXTRA_TIMESTAMP = "timestamp";
public static final String EXTRA_MODE = "mode";
private TextView mDateControl;

View File

@ -80,6 +80,11 @@ public class ActivityAnalysis {
amount.addDistance(distance);
}
final int activeCalories = sample.getActiveCalories();
if (activeCalories > 0) {
amount.addActiveCalories(activeCalories);
}
if (previousSample != null) {
long timeDifference = sample.getTimestamp() - previousSample.getTimestamp();
if (previousSample.getRawKind() == sample.getRawKind()) {

View File

@ -17,6 +17,7 @@
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.view.LayoutInflater;
import android.view.View;
@ -133,6 +134,9 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
if (!coordinator.supportsVO2Max()) {
tabList.remove("vo2max");
}
if (!coordinator.supportsActiveCalories() && !coordinator.supportsRestingCalories()) {
tabList.remove("calories");
}
return tabList;
}
@ -187,6 +191,10 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
return new CyclingChartFragment();
case "weight":
return new WeightChartFragment();
case "calories":
Intent intent = getIntent();
String mode = intent.getStringExtra(ActivityChartsActivity.EXTRA_MODE);
return CaloriesDailyFragment.newInstance(mode);
}
return new UnknownFragment();
@ -232,6 +240,8 @@ public class ActivityChartsActivity extends AbstractChartsActivity {
return getString(R.string.title_cycling);
case "weight":
return getString(R.string.menuitem_weight);
case "calories":
return getString(R.string.calories);
}
return String.format(Locale.getDefault(), "Unknown %d", position);

View File

@ -0,0 +1,254 @@
package nodomain.freeyourgadget.gadgetbridge.activities.charts;
import android.content.Intent;
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.LinearLayout;
import android.widget.TextView;
import androidx.core.content.ContextCompat;
import com.github.mikephil.charting.charts.Chart;
import org.apache.commons.lang3.EnumUtils;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.GaugeDrawer;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.TimeSample;
public class CaloriesDailyFragment extends AbstractChartFragment<CaloriesDailyFragment.CaloriesData> {
private ImageView caloriesGauge;
private TextView dateView;
private TextView caloriesResting;
private TextView caloriesActive;
private LinearLayout caloriesActiveWrapper;
private TextView caloriesActiveGoal;
private LinearLayout caloriesActiveGoalWrapper;
private TextView caloriesTotalGoal;
protected int CALORIES_GOAL;
protected int TOTAL_CALORIES_GOAL;
protected int ACTIVE_CALORIES_GOAL;
public enum GaugeViewMode {
ACTIVE_CALORIES_GOAL,
TOTAL_CALORIES_GOAL,
TOTAL_CALORIES_SEGMENT
}
private GaugeViewMode gaugeViewMode;
@Override
public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (getArguments() != null) {
String mode = getArguments().getString(ActivityChartsActivity.EXTRA_MODE, "");
if (EnumUtils.isValidEnum(GaugeViewMode.class, mode)) {
gaugeViewMode = GaugeViewMode.valueOf(mode);
}
}
}
public static CaloriesDailyFragment newInstance(final String mode) {
final CaloriesDailyFragment fragment = new CaloriesDailyFragment();
final Bundle args = new Bundle();
args.putString(ActivityChartsActivity.EXTRA_MODE, mode);
fragment.setArguments(args);
return fragment;
}
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View rootView = inflater.inflate(R.layout.fragment_calories, container, false);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M) {
rootView.setOnScrollChangeListener((v, scrollX, scrollY, oldScrollX, oldScrollY) -> {
getChartsHost().enableSwipeRefresh(scrollY == 0);
});
}
caloriesGauge = rootView.findViewById(R.id.calories_gauge);
dateView = rootView.findViewById(R.id.date_view);
caloriesResting = rootView.findViewById(R.id.calories_resting);
caloriesActive = rootView.findViewById(R.id.calories_active);
caloriesActiveWrapper = rootView.findViewById(R.id.calories_active_wrapper);
caloriesActiveGoal = rootView.findViewById(R.id.calories_active_goal);
caloriesActiveGoalWrapper = rootView.findViewById(R.id.calories_active_goal_wrapper);
caloriesTotalGoal = rootView.findViewById(R.id.calories_total_goal);
ActivityUser activityUser = new ActivityUser();
TOTAL_CALORIES_GOAL = activityUser.getCaloriesBurntGoal();
ACTIVE_CALORIES_GOAL = activityUser.getActiveCaloriesBurntGoal();
refresh();
if (!supportsActiveCalories()) {
caloriesActiveWrapper.setVisibility(View.GONE);
caloriesActiveGoalWrapper.setVisibility(View.GONE);
}
if (gaugeViewMode == null) {
gaugeViewMode = GaugeViewMode.TOTAL_CALORIES_SEGMENT;
}
if (gaugeViewMode.equals(GaugeViewMode.ACTIVE_CALORIES_GOAL)) {
CALORIES_GOAL = ACTIVE_CALORIES_GOAL;
} else if (gaugeViewMode.equals(GaugeViewMode.TOTAL_CALORIES_GOAL)) {
CALORIES_GOAL = TOTAL_CALORIES_GOAL;
}
return rootView;
}
public boolean supportsActiveCalories() {
final GBDevice device = getChartsHost().getDevice();
return device.getDeviceCoordinator().supportsActiveCalories();
}
protected TimeSample getRestingMetabolicRate(DBHandler db, GBDevice device) {
TimeSampleProvider<? extends RestingMetabolicRateSample> provider = device.getDeviceCoordinator().getRestingMetabolicRateProvider(device, db.getDaoSession());
return provider.getLatestSample();
}
protected List<? extends AbstractActivitySample> getActivitySamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
SampleProvider<? extends ActivitySample> provider = device.getDeviceCoordinator().getSampleProvider(device, db.getDaoSession());
return provider.getAllActivitySamples(tsFrom, tsTo);
}
@Override
public String getTitle() {
return getString(R.string.calories);
}
@Override
protected void init() {}
@Override
protected CaloriesDailyFragment.CaloriesData refreshInBackground(ChartsHost chartsHost, DBHandler db, GBDevice device) {
Calendar calendar = Calendar.getInstance();
Calendar day = Calendar.getInstance();
day.setTime(chartsHost.getEndDate());
day.add(Calendar.DATE, 0);
day.set(Calendar.HOUR_OF_DAY, 0);
day.set(Calendar.MINUTE, 0);
day.set(Calendar.SECOND, 0);
day.add(Calendar.HOUR, 0);
int startTs = (int) (day.getTimeInMillis() / 1000);
int endTs = startTs + 24 * 60 * 60 - 1;
Date date = new Date((long) endTs * 1000);
String formattedDate = new SimpleDateFormat("E, MMM dd").format(date);
dateView.setText(formattedDate);
List<? extends ActivitySample> samples = getActivitySamples(db, device, startTs, endTs);
TimeSample metabolicRate = getRestingMetabolicRate(db, device);
int totalBurnt;
int activeBurnt = 0;
boolean sameDay = calendar.get(Calendar.DAY_OF_YEAR) == day.get(Calendar.DAY_OF_YEAR) &&
calendar.get(Calendar.YEAR) == day.get(Calendar.YEAR);
double passedDayProportion = 1;
if (sameDay) {
passedDayProportion = (double) (calendar.getTimeInMillis() - day.getTimeInMillis()) / (24L * 60 * 60 * 1000);
}
int restingBurnt = (int) ((double) ((GarminRestingMetabolicRateSample) metabolicRate).getRestingMetabolicRate() * passedDayProportion);
for (int i = 0; i <= samples.size() - 1; i++) {
ActivitySample sample = samples.get(i);
if (sample.getActiveCalories() > 0) {
activeBurnt += sample.getActiveCalories();
}
}
totalBurnt = restingBurnt + activeBurnt;
return new CaloriesData(totalBurnt, activeBurnt, restingBurnt);
}
@Override
protected void updateChartsnUIThread(CaloriesDailyFragment.CaloriesData data) {
int restingCalories = data.restingBurnt;
int activeCalories = data.activeBurnt;
int totalCalories = activeCalories + restingCalories;
caloriesActive.setText(String.valueOf(activeCalories));
caloriesResting.setText(String.valueOf(restingCalories));
caloriesTotalGoal.setText(String.valueOf(TOTAL_CALORIES_GOAL));
caloriesActiveGoal.setText(String.valueOf(ACTIVE_CALORIES_GOAL));
if (gaugeViewMode.equals(GaugeViewMode.TOTAL_CALORIES_SEGMENT)) {
int[] colors = new int[] {
ContextCompat.getColor(GBApplication.getContext(), R.color.calories_resting_color),
ContextCompat.getColor(GBApplication.getContext(), R.color.calories_color)
};
float[] segments = new float[] {
restingCalories > 0 ? (float) restingCalories / totalCalories : 0,
activeCalories > 0 ? (float) activeCalories / totalCalories : 0
};
final int width = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
300,
GBApplication.getContext().getResources().getDisplayMetrics()
);
caloriesGauge.setImageBitmap(GaugeDrawer.drawCircleGaugeSegmented(
width,
width / 15,
colors,
segments,
true,
String.valueOf(totalCalories),
getContext().getString(R.string.total_burnt),
getContext()
));
} else {
int value = 0;
if (gaugeViewMode.equals(GaugeViewMode.ACTIVE_CALORIES_GOAL)) {
value = activeCalories;
} else if (gaugeViewMode.equals(GaugeViewMode.TOTAL_CALORIES_GOAL)) {
value = totalCalories;
}
final int width = (int) TypedValue.applyDimension(
TypedValue.COMPLEX_UNIT_DIP,
300,
GBApplication.getContext().getResources().getDisplayMetrics()
);
caloriesGauge.setImageBitmap(GaugeDrawer.drawCircleGauge(
width,
width / 15,
getResources().getColor(R.color.calories_color),
value,
CALORIES_GOAL,
getContext()
));
}
}
@Override
protected void renderCharts() {}
@Override
protected void setupLegend(Chart<?> chart) {}
protected static class CaloriesData extends ChartsData {
public int activeBurnt;
public int restingBurnt;
public int totalBurnt;
protected CaloriesData(int totalBurnt, int activeBurnt, int restingBurnt) {
this.totalBurnt = totalBurnt;
this.activeBurnt = activeBurnt;
this.restingBurnt = restingBurnt;
}
}
}

View File

@ -37,6 +37,7 @@ import java.util.List;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.dashboard.GaugeDrawer;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
@ -123,12 +124,13 @@ public class StepsDailyFragment extends StepsFragment<StepsDailyFragment.StepsDa
GBApplication.getContext().getResources().getDisplayMetrics()
);
stepsGauge.setImageBitmap(drawGauge(
stepsGauge.setImageBitmap(GaugeDrawer.drawCircleGauge(
width,
width / 15,
getResources().getColor(R.color.steps_color),
(int) stepsData.todayStepsDay.steps,
STEPS_GOAL
STEPS_GOAL,
getContext()
));
steps.setText(String.format(String.valueOf(stepsData.todayStepsDay.steps)));
@ -225,59 +227,6 @@ public class StepsDailyFragment extends StepsFragment<StepsDailyFragment.StepsDa
yAxisRight.setDrawAxisLine(true);
}
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;
}
protected static class StepsData extends ChartsData {
StepsDay todayStepsDay;
List<? extends ActivitySample> samples;

View File

@ -87,7 +87,7 @@ public abstract class AbstractDashboardWidget extends Fragment {
.collect(Collectors.toList());
}
protected void onClickOpenChart(final View view, final String chart, final int label) {
protected void onClickOpenChart(final View view, final String chart, final int label, final String mode) {
view.setOnClickListener(v -> {
chooseDevice(dashboardData, device -> {
final Intent startIntent;
@ -96,6 +96,7 @@ public abstract class AbstractDashboardWidget extends Fragment {
startIntent.putExtra(ActivityChartsActivity.EXTRA_SINGLE_FRAGMENT_NAME, chart);
startIntent.putExtra(ActivityChartsActivity.EXTRA_ACTIONBAR_TITLE, label);
startIntent.putExtra(ActivityChartsActivity.EXTRA_TIMESTAMP, dashboardData.timeTo);
startIntent.putExtra(ActivityChartsActivity.EXTRA_MODE, mode);
requireContext().startActivity(startIntent);
});
});

View File

@ -42,18 +42,24 @@ public abstract class AbstractGaugeWidget extends AbstractDashboardWidget {
private final int label;
private final String targetActivityTab;
private String mode = "";
public AbstractGaugeWidget(@StringRes final int label, @Nullable final String targetActivityTab) {
this.label = label;
this.targetActivityTab = targetActivityTab;
}
public AbstractGaugeWidget(@StringRes final int label, @Nullable final String targetActivityTab, final String mode) {
this(label, targetActivityTab);
this.mode = mode;
}
@Override
public View onCreateView(final LayoutInflater inflater, final ViewGroup container, final Bundle savedInstanceState) {
final View fragmentView = inflater.inflate(R.layout.dashboard_widget_generic_gauge, container, false);
if (targetActivityTab != null) {
onClickOpenChart(fragmentView, targetActivityTab, label);
onClickOpenChart(fragmentView, targetActivityTab, label, mode);
}
gaugeValue = fragmentView.findViewById(R.id.gauge_value);

View File

@ -0,0 +1,58 @@
package nodomain.freeyourgadget.gadgetbridge.activities.dashboard;
import android.os.Bundle;
import androidx.core.content.ContextCompat;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.DashboardFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.CaloriesDailyFragment;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
/**
* A simple {@link AbstractDashboardWidget} subclass.
* Use the {@link DashboardCaloriesActiveGoalWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardCaloriesActiveGoalWidget extends AbstractGaugeWidget {
public DashboardCaloriesActiveGoalWidget() {
super(R.string.active_calories, "calories", CaloriesDailyFragment.GaugeViewMode.ACTIVE_CALORIES_GOAL.toString());
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param dashboardData An instance of DashboardFragment.DashboardData.
* @return A new instance of fragment DashboardStepsWidget.
*/
public static DashboardCaloriesActiveGoalWidget newInstance(final DashboardFragment.DashboardData dashboardData) {
final DashboardCaloriesActiveGoalWidget fragment = new DashboardCaloriesActiveGoalWidget();
final Bundle args = new Bundle();
args.putSerializable(ARG_DASHBOARD_DATA, dashboardData);
fragment.setArguments(args);
return fragment;
}
@Override
protected boolean isSupportedBy(final GBDevice device) {
return device.getDeviceCoordinator().supportsActiveCalories();
}
@Override
protected void populateData(final DashboardFragment.DashboardData dashboardData) {
dashboardData.getActiveCaloriesTotal();
dashboardData.getActiveCaloriesGoalFactor();
}
@Override
protected void draw(final DashboardFragment.DashboardData dashboardData) {
setText(String.valueOf(dashboardData.getActiveCaloriesTotal()));
final int colorCalories = ContextCompat.getColor(GBApplication.getContext(), R.color.calories_color);
drawSimpleGauge(
colorCalories,
dashboardData.getActiveCaloriesGoalFactor()
);
}
}

View File

@ -0,0 +1,58 @@
package nodomain.freeyourgadget.gadgetbridge.activities.dashboard;
import android.os.Bundle;
import androidx.core.content.ContextCompat;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.DashboardFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.CaloriesDailyFragment;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
/**
* A simple {@link AbstractDashboardWidget} subclass.
* Use the {@link DashboardCaloriesGoalWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardCaloriesGoalWidget extends AbstractGaugeWidget {
public DashboardCaloriesGoalWidget() {
super(R.string.calories, "calories", CaloriesDailyFragment.GaugeViewMode.TOTAL_CALORIES_GOAL.toString());
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param dashboardData An instance of DashboardFragment.DashboardData.
* @return A new instance of fragment DashboardStepsWidget.
*/
public static DashboardCaloriesGoalWidget newInstance(final DashboardFragment.DashboardData dashboardData) {
final DashboardCaloriesGoalWidget fragment = new DashboardCaloriesGoalWidget();
final Bundle args = new Bundle();
args.putSerializable(ARG_DASHBOARD_DATA, dashboardData);
fragment.setArguments(args);
return fragment;
}
@Override
protected boolean isSupportedBy(final GBDevice device) {
return device.getDeviceCoordinator().supportsActiveCalories();
}
@Override
protected void populateData(final DashboardFragment.DashboardData dashboardData) {
dashboardData.getCaloriesTotal();
dashboardData.getCaloriesGoalFactor();
}
@Override
protected void draw(final DashboardFragment.DashboardData dashboardData) {
setText(String.valueOf(dashboardData.getCaloriesTotal()));
final int colorCalories = ContextCompat.getColor(GBApplication.getContext(), R.color.calories_color);
drawSimpleGauge(
colorCalories,
dashboardData.getCaloriesGoalFactor()
);
}
}

View File

@ -0,0 +1,78 @@
package nodomain.freeyourgadget.gadgetbridge.activities.dashboard;
import android.graphics.Color;
import android.os.Bundle;
import androidx.core.content.ContextCompat;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.DashboardFragment;
import nodomain.freeyourgadget.gadgetbridge.activities.charts.CaloriesDailyFragment;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
/**
* A simple {@link AbstractDashboardWidget} subclass.
* Use the {@link DashboardCaloriesTotalSegmentedWidget#newInstance} factory method to
* create an instance of this fragment.
*/
public class DashboardCaloriesTotalSegmentedWidget extends AbstractGaugeWidget {
public DashboardCaloriesTotalSegmentedWidget() {
super(R.string.calories, "calories", CaloriesDailyFragment.GaugeViewMode.TOTAL_CALORIES_SEGMENT.toString());
}
/**
* Use this factory method to create a new instance of
* this fragment using the provided parameters.
*
* @param dashboardData An instance of DashboardFragment.DashboardData.
* @return A new instance of fragment DashboardStepsWidget.
*/
public static DashboardCaloriesTotalSegmentedWidget newInstance(final DashboardFragment.DashboardData dashboardData) {
final DashboardCaloriesTotalSegmentedWidget fragment = new DashboardCaloriesTotalSegmentedWidget();
final Bundle args = new Bundle();
args.putSerializable(ARG_DASHBOARD_DATA, dashboardData);
fragment.setArguments(args);
return fragment;
}
@Override
protected void populateData(final DashboardFragment.DashboardData dashboardData) {
dashboardData.getActiveCaloriesTotal();
dashboardData.getRestingCaloriesTotal();
}
@Override
protected void draw(final DashboardFragment.DashboardData dashboardData) {
int activeCalories = dashboardData.getActiveCaloriesTotal();
int restingCalories = dashboardData.getRestingCaloriesTotal();
int totalCalories = activeCalories + restingCalories;
setText(String.valueOf(totalCalories));
final int[] colors;
final float[] segments;
if (totalCalories != 0) {
colors = new int[] {
ContextCompat.getColor(GBApplication.getContext(), R.color.calories_resting_color),
ContextCompat.getColor(GBApplication.getContext(), R.color.calories_color)
};
segments = new float[] {
restingCalories > 0 ? (float) restingCalories / totalCalories : 0,
activeCalories > 0 ? (float) activeCalories / totalCalories : 0
};
} else {
colors = new int[]{
Color.argb(25, 128, 128, 128)
};
segments = new float[] {
1f
};
}
drawSegmentedGauge(
colors,
segments,
-1,
false,
false
);
}
}

View File

@ -126,14 +126,14 @@ public class DashboardHrvWidget extends AbstractGaugeWidget {
public static float calculateGaugeValue(int weeklyAverage, int baselineLowUpper, int baselineBalancedLower, int baselineBalancedUpper) {
final float value;
if (weeklyAverage != 0 && baselineLowUpper != 0 && baselineBalancedLower != 0 && baselineBalancedUpper != 0) {
if (weeklyAverage < baselineLowUpper) {
value = 0.125f * (float) GaugeDrawer.normalize(weeklyAverage, 0f, baselineLowUpper);
if (weeklyAverage <= baselineLowUpper) {
value = (float) GaugeDrawer.normalize(weeklyAverage, 0f, baselineLowUpper, 0, 0.124f);
} else if (weeklyAverage < baselineBalancedLower) {
value = 0.125f + 0.125f * (float) GaugeDrawer.normalize((float) weeklyAverage, baselineLowUpper, baselineBalancedLower);
} else if (weeklyAverage < baselineBalancedUpper) {
value = 0.125f + 0.125f + 0.5f * (float) GaugeDrawer.normalize((float) weeklyAverage, baselineBalancedLower, baselineBalancedUpper);
value = (float) GaugeDrawer.normalize((float) weeklyAverage, baselineLowUpper + 1, baselineBalancedLower - 1, 0.126f, 0.249f);
} else if (weeklyAverage <= baselineBalancedUpper) {
value = (float) GaugeDrawer.normalize((float) weeklyAverage, baselineBalancedLower, baselineBalancedUpper, 0.251f, 0.749f);
} else {
value = 0.125f + 0.125f + 0.5f + 0.125f * (float) GaugeDrawer.normalize((float) weeklyAverage, baselineBalancedUpper, 2 * baselineBalancedUpper);
value = (float) GaugeDrawer.normalize((float) weeklyAverage, baselineBalancedUpper, 2 * baselineBalancedUpper, 0.751f, 1);
}
} else {
value = -1;

View File

@ -1,5 +1,6 @@
package nodomain.freeyourgadget.gadgetbridge.activities.dashboard;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
@ -15,6 +16,7 @@ import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
public class GaugeDrawer {
private static final Logger LOG = LoggerFactory.getLogger(GaugeDrawer.class);
@ -194,6 +196,131 @@ public class GaugeDrawer {
gaugeBar.setImageBitmap(bitmap);
}
public static Bitmap drawCircleGaugeSegmented(int width, int barWidth, final int[] colors, final float[] segments, final boolean gapBetweenSegments, String text, String lowerText, Context context) {
int TEXT_COLOR = GBApplication.getTextColor(context);
int height = width;
int barMargin = (int) Math.ceil(barWidth / 2f);
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.BUTT);
paint.setStrokeWidth(barWidth);
paint.setColor(context.getResources().getColor(R.color.gauge_line_color));
canvas.drawArc(
barMargin,
barMargin,
width - barMargin,
width - barMargin,
90,
360,
false,
paint);
paint.setStrokeWidth(barWidth);
float angleSum = 0;
for (int i = 0; i < segments.length; i++) {
if (segments[i] == 0) {
continue;
}
paint.setColor(colors[i]);
paint.setStrokeWidth(barWidth);
float startAngleDegrees = 270 + angleSum * 360;
float sweepAngleDegrees = segments[i] * 360;
if (gapBetweenSegments) {
sweepAngleDegrees -= 1;
}
canvas.drawArc(
barMargin,
barMargin,
width - barMargin,
height - barMargin,
startAngleDegrees,
sweepAngleDegrees,
false,
paint
);
angleSum += segments[i];
}
Paint textPaint = new Paint();
textPaint.setColor(TEXT_COLOR);
float textPixels = TypedValue.applyDimension(TypedValue.COMPLEX_UNIT_SP, width * 0.06f, context.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(text), 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, context.getResources().getDisplayMetrics());
textLowerPaint.setTextSize(textLowerPixels);
int yPosLowerText = (int) ((float) height / 2 - textPaint.ascent()) ;
canvas.drawText(String.valueOf(lowerText), width / 2f, yPosLowerText, textLowerPaint);
return bitmap;
}
public static Bitmap drawCircleGauge(int width, int barWidth, @ColorInt int filledColor, int value, int maxValue, Context context) {
int TEXT_COLOR = GBApplication.getTextColor(context);
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(context.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, context.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, context.getResources().getDisplayMetrics());
textLowerPaint.setTextSize(textLowerPixels);
int yPosLowerText = (int) ((float) height / 2 - textPaint.ascent()) ;
canvas.drawText(String.valueOf(maxValue), width / 2f, yPosLowerText, textLowerPaint);
return bitmap;
}
public static double normalize(final double value, final double min, final double max) {
return normalize(value, min, max, 0, 1);
}

View File

@ -77,6 +77,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
@ -280,6 +281,11 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return null;
}
@Override
public TimeSampleProvider<? extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
return null; // FIXME return new DefaultRestingMetabolicRateProvider(device, session);
}
@Override
@Nullable
public ActivitySummaryParser getActivitySummaryParser(final GBDevice device, final Context context) {
@ -490,6 +496,16 @@ public abstract class AbstractDeviceCoordinator implements DeviceCoordinator {
return false;
}
@Override
public boolean supportsActiveCalories() {
return false;
}
@Override
public boolean supportsRestingCalories() {
return false;
}
@Override
public boolean supportsActivityTabs() {
return supportsActivityTracking();

View File

@ -57,6 +57,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.PaiSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.TemperatureSample;
@ -226,6 +227,8 @@ public interface DeviceCoordinator {
boolean supportsStepCounter();
boolean supportsSpeedzones();
boolean supportsActivityTabs();
boolean supportsRestingCalories();
boolean supportsActiveCalories();
/**
* Returns true if measurement and fetching of body temperature is supported by the device
@ -372,6 +375,8 @@ public interface DeviceCoordinator {
*/
TimeSampleProvider<? extends WeightSample> getWeightSampleProvider(GBDevice device, DaoSession session);
TimeSampleProvider<? extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(GBDevice device, DaoSession session);
/**
* Returns the {@link ActivitySummaryParser} for the device being supported.
*

View File

@ -338,11 +338,14 @@ public class ColmiR0xPacketHandler {
index++;
int dayBytes = value[index];
index++;
// sleepStart is received as "minutes after midnight"
int sleepStart = BLETypeConversions.toUint16(value[index], value[index + 1]);
index += 2;
// sleepEnd is received as "minutes after midnight"
int sleepEnd = BLETypeConversions.toUint16(value[index], value[index + 1]);
index += 2;
// Calculate sleep start timestamp
LOG.info("Sleep session daysAgo={}, dayBytes={}, sleepStart={}, sleepEnd={}", daysAgo, dayBytes, sleepStart, sleepEnd);
Calendar sessionStart = Calendar.getInstance();
sessionStart.add(Calendar.DAY_OF_MONTH, 0 - daysAgo);
sessionStart.set(Calendar.HOUR_OF_DAY, 0);
@ -351,8 +354,7 @@ public class ColmiR0xPacketHandler {
sessionStart.set(Calendar.MILLISECOND, 0);
if (sleepStart > sleepEnd) {
// Sleep started a day earlier, so before midnight
sessionStart.add(Calendar.DAY_OF_MONTH, -1);
sessionStart.add(Calendar.MINUTE, sleepStart);
sessionStart.add(Calendar.MINUTE, sleepStart - 1440);
} else {
// Sleep started this day, so after midnight
sessionStart.add(Calendar.MINUTE, sleepStart);
@ -374,15 +376,22 @@ public class ColmiR0xPacketHandler {
Calendar sleepStage = (Calendar) sessionStart.clone();
for (int j = 4; j < dayBytes; j += 2) {
int sleepMinutes = value[index + 1];
LOG.info("Sleep stage type={} starts at {} and lasts for {} minutes", value[index], sleepStage.getTime(), sleepMinutes);
final ColmiSleepStageSample sample = new ColmiSleepStageSample();
sample.setTimestamp(sleepStage.getTimeInMillis());
sample.setDuration(value[index + 1]);
sample.setStage(value[index]);
stageSamples.add(sample);
if (sleepMinutes > 0) {
LOG.info("Sleep stage type={} starts at {} and lasts for {} minutes", value[index], sleepStage.getTime(), sleepMinutes);
if (sleepStage.getTimeInMillis() + sleepMinutes * 60 * 1000 > sessionEnd.getTimeInMillis()) {
LOG.warn("Warning: sleep stage exceeds end of sleep session, received data may be corrupt");
}
stageSamples.add(sample);
sleepStage.add(Calendar.MINUTE, sleepMinutes);
} else {
LOG.info("Ignoring sleep stage type={} starts at {} and lasts for {} minutes", value[index], sleepStage.getTime(), sleepMinutes);
}
// Prepare for next sample
index += 2;
sleepStage.add(Calendar.MINUTE, sleepMinutes);
}
// Persist sleep session
try (DBHandler handler = GBApplication.acquireDB()) {

View File

@ -45,6 +45,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.BodyEnergySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.model.HrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.model.RespiratoryRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.model.Spo2Sample;
import nodomain.freeyourgadget.gadgetbridge.model.StressSample;
import nodomain.freeyourgadget.gadgetbridge.model.Vo2MaxSample;
@ -153,6 +154,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return new GarminRespiratoryRateSampleProvider(device, session);
}
@Override
public TimeSampleProvider<? extends RestingMetabolicRateSample> getRestingMetabolicRateProvider(final GBDevice device, final DaoSession session) {
return new GarminRestingMetabolicRateSampleProvider(device, session);
}
@Override
public GarminHeartRateRestingSampleProvider getHeartRateRestingSampleProvider(final GBDevice device, final DaoSession session) {
return new GarminHeartRateRestingSampleProvider(device, session);
@ -244,6 +250,16 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return true;
}
@Override
public boolean supportsActiveCalories() {
return true;
}
@Override
public boolean supportsRestingCalories() {
return true;
}
@Override
public int[] getStressRanges() {
// 1-25 = relaxed

View File

@ -0,0 +1,56 @@
/* Copyright (C) 2024 José Rebelo
This file is part of Gadgetbridge.
Gadgetbridge is free software: you can redistribute it and/or modify
it under the terms of the GNU Affero General Public License as published
by the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
Gadgetbridge is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU Affero General Public License for more details.
You should have received a copy of the GNU Affero General Public License
along with this program. If not, see <https://www.gnu.org/licenses/>. */
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
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.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSampleDao;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
public class GarminRestingMetabolicRateSampleProvider extends AbstractTimeSampleProvider<GarminRestingMetabolicRateSample> {
public GarminRestingMetabolicRateSampleProvider(final GBDevice device, final DaoSession session) {
super(device, session);
}
@NonNull
@Override
public AbstractDao<GarminRestingMetabolicRateSample, ?> getSampleDao() {
return getSession().getGarminRestingMetabolicRateSampleDao();
}
@NonNull
@Override
protected Property getTimestampSampleProperty() {
return GarminRestingMetabolicRateSampleDao.Properties.Timestamp;
}
@NonNull
@Override
protected Property getDeviceIdentifierSampleProperty() {
return GarminRestingMetabolicRateSampleDao.Properties.DeviceId;
}
@Override
public GarminRestingMetabolicRateSample createSample() {
return new GarminRestingMetabolicRateSample();
}
}

View File

@ -0,0 +1,18 @@
package nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.forerunner;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminCoordinator;
public class GarminForerunner235Coordinator extends GarminCoordinator {
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile("^Forerunner 235$");
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_garmin_forerunner_235;
}
}

View File

@ -16,7 +16,7 @@ public class HeartRateZonesConfig {
public static final int MAXIMUM_HEART_RATE = 220;
private final int configType;
private int calculateMethod = 0;
private int calculateMethod = 0; // 0 - MHR, 1 - HRR, 3 - LTHR
private int maxHRThreshold;
private int restHeartRate = DEFAULT_REST_HEART_RATE;
@ -231,4 +231,35 @@ public class HeartRateZonesConfig {
return LTHRThresholdHeartRate > 0 && LTHRAnaerobic > 0 && LTHRLactate > 0 && LTHRAdvancedAerobic > 0 && LTHRBasicAerobic > 0 && LTHRWarmUp > 0;
}
private int getZoneForHR(int heartRate, int zone5Threshold, int zone4Threshold, int zone3Threshold, int zone2Threshold, int zone1Threshold) {
if (heartRate >= MAXIMUM_HEART_RATE) {
return -1;
}
if (heartRate >= zone5Threshold) {
return 4;
}
if (heartRate >= zone4Threshold) {
return 3;
}
if (heartRate >= zone3Threshold) {
return 2;
}
if (heartRate >= zone2Threshold) {
return 1;
}
return heartRate >= zone1Threshold ? 0 : -1;
}
public int getMHRZone(int heartRate) {
return getZoneForHR(heartRate, MHRExtreme, MHRAnaerobic, MHRAerobic, MHRFatBurning, MHRWarmUp);
}
public int getHHRZone(int heartRate) {
return getZoneForHR(heartRate, HRRAdvancedAnaerobic, HRRBasicAnaerobic, HRRLactate, HRRAdvancedAerobic, HRRBasicAerobic);
}
public int getLTHRZone(int heartRate) {
return getZoneForHR(heartRate, LTHRAnaerobic, LTHRLactate, LTHRAdvancedAerobic, LTHRBasicAerobic, LTHRWarmUp);
}
}

View File

@ -37,6 +37,7 @@ public class SonyWFC500Coordinator extends SonyHeadphonesCoordinator {
SonyHeadphonesCapabilities.EqualizerSimple,
SonyHeadphonesCapabilities.EqualizerWithCustomBands,
SonyHeadphonesCapabilities.AudioUpsampling,
SonyHeadphonesCapabilities.VoiceNotifications,
SonyHeadphonesCapabilities.PowerOffFromPhone
);
}

View File

@ -0,0 +1,59 @@
/* Copyright (C) 2024 Zahnstocher
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.devices.sony.headphones.coordinators;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCapabilities;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.SonyHeadphonesCoordinator;
public class SonyWIC100Coordinator extends SonyHeadphonesCoordinator {
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile(".*WI-C100.*");
}
@Override
public List<SonyHeadphonesCapabilities> getCapabilities() {
return Arrays.asList(
SonyHeadphonesCapabilities.BatterySingle,
SonyHeadphonesCapabilities.EqualizerSimple,
SonyHeadphonesCapabilities.EqualizerWithCustomBands,
SonyHeadphonesCapabilities.AudioUpsampling,
SonyHeadphonesCapabilities.VoiceNotifications,
SonyHeadphonesCapabilities.PowerOffFromPhone
);
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_sony_wi_c100;
}
@Override
public int getDefaultIconResource() {
return R.drawable.ic_device_galaxy_buds;
}
@Override
public int getDisabledIconResource() {
return R.drawable.ic_device_galaxy_buds_disabled;
}
}

View File

@ -24,6 +24,7 @@ public class ActivityAmount {
private long totalSeconds;
private long totalSteps;
private long totalDistance;
private long totalActiveCalories;
private Date startDate = null;
private Date endDate = null;
@ -43,6 +44,10 @@ public class ActivityAmount {
totalDistance += distance;
}
public void addActiveCalories(long activeCalories) {
totalActiveCalories += activeCalories;
}
public long getTotalSeconds() {
return totalSeconds;
}
@ -55,6 +60,10 @@ public class ActivityAmount {
return totalDistance;
}
public long getTotalActiveCalories() {
return totalActiveCalories;
}
public ActivityKind getActivityKind() {
return activityKind;
}

View File

@ -44,6 +44,7 @@ public class ActivityUser {
private int activityUserSleepDurationGoal;
private int activityUserStepsGoal;
private int activityUserCaloriesBurntGoal;
private int activityUserActiveCaloriesBurntGoal;
private int activityUserDistanceGoalMeters;
private int activityUserActiveTimeGoalMinutes;
private int activityUserStandingTimeGoalHours;
@ -58,6 +59,7 @@ public class ActivityUser {
public static final int defaultUserSleepDurationGoal = 7;
public static final int defaultUserStepsGoal = 8000;
public static final int defaultUserCaloriesBurntGoal = 2000;
public static final int defaultUserActiveCaloriesBurntGoal = 350;
public static final int defaultUserDistanceGoalMeters = 5000;
public static final int defaultUserActiveTimeGoalMinutes = 60;
public static final int defaultUserStepLengthCm = 0;
@ -73,6 +75,7 @@ public class ActivityUser {
public static final String PREF_USER_SLEEP_DURATION = "activity_user_sleep_duration";
public static final String PREF_USER_STEPS_GOAL = "fitness_goal"; // FIXME: for compatibility
public static final String PREF_USER_CALORIES_BURNT = "activity_user_calories_burnt";
public static final String PREF_USER_ACTIVE_CALORIES_BURNT = "activity_user_active_calories_burnt";
public static final String PREF_USER_DISTANCE_METERS = "activity_user_distance_meters";
public static final String PREF_USER_ACTIVETIME_MINUTES = "activity_user_activetime_minutes";
public static final String PREF_USER_STEP_LENGTH_CM = "activity_user_step_length_cm";
@ -160,6 +163,7 @@ public class ActivityUser {
activityUserSleepDurationGoal = prefs.getInt(PREF_USER_SLEEP_DURATION, defaultUserSleepDurationGoal);
activityUserStepsGoal = prefs.getInt(PREF_USER_STEPS_GOAL, defaultUserStepsGoal);
activityUserCaloriesBurntGoal = prefs.getInt(PREF_USER_CALORIES_BURNT, defaultUserCaloriesBurntGoal);
activityUserActiveCaloriesBurntGoal = prefs.getInt(PREF_USER_ACTIVE_CALORIES_BURNT, defaultUserActiveCaloriesBurntGoal);
activityUserDistanceGoalMeters = prefs.getInt(PREF_USER_DISTANCE_METERS, defaultUserDistanceGoalMeters);
activityUserActiveTimeGoalMinutes = prefs.getInt(PREF_USER_ACTIVETIME_MINUTES, defaultUserActiveTimeGoalMinutes);
activityUserStandingTimeGoalHours = prefs.getInt(PREF_USER_GOAL_STANDING_TIME_HOURS, defaultUserGoalStandingTimeHours);
@ -187,6 +191,14 @@ public class ActivityUser {
return activityUserCaloriesBurntGoal;
}
public int getActiveCaloriesBurntGoal()
{
if (activityUserActiveCaloriesBurntGoal < 1) {
activityUserActiveCaloriesBurntGoal = defaultUserActiveCaloriesBurntGoal;
}
return activityUserActiveCaloriesBurntGoal;
}
public int getDistanceGoalMeters()
{
if (activityUserDistanceGoalMeters < 1) {

View File

@ -33,7 +33,9 @@ import nodomain.freeyourgadget.gadgetbridge.activities.charts.ActivityAnalysis;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.TimeSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -42,22 +44,34 @@ public class DailyTotals implements Serializable {
private final long steps;
private final long distance;
private final long activeCalories;
private final long restingCalories;
private final long[] sleep; // light deep rem awake
public DailyTotals() {
this(0, 0, new long[]{0, 0, 0 ,0});
this(0, 0, new long[]{0, 0, 0 ,0}, 0, 0);
}
public DailyTotals(final long steps, final long distance, final long[] sleep) {
public DailyTotals(final long steps, final long distance, final long[] sleep, final long activeCalories, final long restingCalories) {
this.steps = steps;
this.distance = distance;
this.sleep = sleep;
this.activeCalories = activeCalories;
this.restingCalories = restingCalories;
}
public long getSteps() {
return steps;
}
public long getActiveCalories() {
return activeCalories;
}
public long getRestingCalories() {
return restingCalories;
}
public long getDistance() {
return distance;
}
@ -79,17 +93,27 @@ public class DailyTotals implements Serializable {
public static DailyTotals getDailyTotalsForDevice(GBDevice device, Calendar day, DBHandler handler) {
ActivityAnalysis analysis = new ActivityAnalysis();
ActivityAmounts amountsSteps;
ActivityAmounts totalAmounts;
ActivityAmounts amountsSleep;
amountsSteps = analysis.calculateActivityAmounts(getSamplesOfDay(handler, day, 0, device));
totalAmounts = analysis.calculateActivityAmounts(getSamplesOfDay(handler, day, 0, device));
amountsSleep = analysis.calculateActivityAmounts(getSamplesOfDay(handler, day, -12, device));
long[] sleep = getTotalsSleepForActivityAmounts(amountsSleep);
Pair<Long, Long> stepsDistance = getTotalsStepsForActivityAmounts(amountsSteps);
long totalSteps = 0;
long totalDistance = 0;
long totalActiveCalories = 0;
long totalRestingCalories = 0;
for (ActivityAmount amount : totalAmounts.getAmounts()) {
totalSteps += amount.getTotalSteps();
totalDistance += amount.getTotalDistance();
totalActiveCalories += amount.getTotalActiveCalories();
}
totalRestingCalories = getRestingCaloriesOfDay(handler, day, device);
// Purposely not including awake sleep
return new DailyTotals(stepsDistance.getLeft(), stepsDistance.getRight(), sleep);
return new DailyTotals(totalSteps, totalDistance, sleep, totalActiveCalories, totalRestingCalories);
}
private static long[] getTotalsSleepForActivityAmounts(ActivityAmounts activityAmounts) {
@ -115,17 +139,6 @@ public class DailyTotals implements Serializable {
return new long[]{totalMinutesLightSleep, totalMinutesDeepSleep, totalMinutesRemSleep, totalMinutesAwakeSleep};
}
public static Pair<Long, Long> getTotalsStepsForActivityAmounts(ActivityAmounts activityAmounts) {
long totalSteps = 0;
long totalDistance = 0;
for (ActivityAmount amount : activityAmounts.getAmounts()) {
totalSteps += amount.getTotalSteps();
totalDistance += amount.getTotalDistance();
}
return Pair.of(totalSteps, totalDistance);
}
private static List<? extends ActivitySample> getSamplesOfDay(DBHandler db, Calendar day, int offsetHours, GBDevice device) {
int startTs;
int endTs;
@ -142,10 +155,32 @@ public class DailyTotals implements Serializable {
return getSamples(db, device, startTs, endTs);
}
private static int getRestingCaloriesOfDay(DBHandler db, Calendar day, GBDevice device) {
Calendar calendar = Calendar.getInstance();
day.add(Calendar.DATE, 0);
day.set(Calendar.HOUR_OF_DAY, 0);
day.set(Calendar.MINUTE, 0);
day.set(Calendar.SECOND, 0);
day.add(Calendar.HOUR, 0);
TimeSample metabolicRate = getRestingMetabolicRate(db, device);
double passedDayProportion = 1;
boolean sameDay = calendar.get(Calendar.DAY_OF_YEAR) == day.get(Calendar.DAY_OF_YEAR) &&
calendar.get(Calendar.YEAR) == day.get(Calendar.YEAR);
if (sameDay) {
passedDayProportion = (double) (calendar.getTimeInMillis() - day.getTimeInMillis()) / (24L * 60 * 60 * 1000);
}
return (int) ((double) ((GarminRestingMetabolicRateSample) metabolicRate).getRestingMetabolicRate() * passedDayProportion);
}
public static List<? extends ActivitySample> getSamples(DBHandler db, GBDevice device, int tsFrom, int tsTo) {
return getAllSamples(db, device, tsFrom, tsTo);
}
protected static TimeSample getRestingMetabolicRate(DBHandler db, GBDevice device) {
TimeSampleProvider<? extends RestingMetabolicRateSample> provider = device.getDeviceCoordinator().getRestingMetabolicRateProvider(device, db.getDaoSession());
return provider.getLatestSample();
}
protected static SampleProvider<? extends AbstractActivitySample> getProvider(DBHandler db, GBDevice device) {
DeviceCoordinator coordinator = device.getDeviceCoordinator();
return coordinator.getSampleProvider(device, db.getDaoSession());

View File

@ -68,6 +68,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.fenix.GarminF
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.fenix.GarminFenix7SCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.fenix.GarminFenix8Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.forerunner.GarminForerunner165Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.forerunner.GarminForerunner235Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.forerunner.GarminForerunner245Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.forerunner.GarminForerunner245MusicCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.watches.forerunner.GarminForerunner255Coordinator;
@ -241,6 +242,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM3Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM4Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWH1000XM5Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWIC100Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.headphones.coordinators.SonyWISP600NCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sony.wena3.SonyWena3Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.sonyswr12.SonySWR12DeviceCoordinator;
@ -424,6 +426,7 @@ public enum DeviceType {
GARMIN_FENIX_7_PRO(GarminFenix7ProCoordinator.class),
GARMIN_FENIX_8(GarminFenix8Coordinator.class),
GARMIN_FORERUNNER_165(GarminForerunner165Coordinator.class),
GARMIN_FORERUNNER_235(GarminForerunner235Coordinator.class),
GARMIN_FORERUNNER_245(GarminForerunner245Coordinator.class),
GARMIN_FORERUNNER_245_MUSIC(GarminForerunner245MusicCoordinator.class),
GARMIN_FORERUNNER_255(GarminForerunner255Coordinator.class),
@ -478,6 +481,7 @@ public enum DeviceType {
GALAXY_BUDS2_PRO(GalaxyBuds2ProDeviceCoordinator.class),
SONY_WH_1000XM3(SonyWH1000XM3Coordinator.class),
SONY_WF_SP800N(SonyWFSP800NCoordinator.class),
SONY_WI_C100(SonyWIC100Coordinator.class),
SONY_WI_SP600N(SonyWISP600NCoordinator.class),
SONY_WH_1000XM4(SonyWH1000XM4Coordinator.class),
SONY_WF_1000XM3(SonyWF1000XM3Coordinator.class),

View File

@ -0,0 +1,23 @@
/* Copyright (C) 2024 Severin von Wnuck-Lipinski
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.model;
import nodomain.freeyourgadget.gadgetbridge.entities.AbstractTimeSample;
public abstract class RestingMetabolicRateSample extends AbstractTimeSample {
public abstract int getRestingMetabolicRate();
}

View File

@ -26,6 +26,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHeartRateRestin
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvSummarySampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminHrvValueSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminRespiratoryRateSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminRestingMetabolicRateSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSleepStageSampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminSpo2SampleProvider;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminStressSampleProvider;
@ -37,6 +38,7 @@ import nodomain.freeyourgadget.gadgetbridge.entities.GarminActivitySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminBodyEnergySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminEventSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHeartRateRestingSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvSummarySample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminHrvValueSample;
import nodomain.freeyourgadget.gadgetbridge.entities.GarminRespiratoryRateSample;
@ -48,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySample;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
import nodomain.freeyourgadget.gadgetbridge.model.RestingMetabolicRateSample;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.FileType;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionHrvStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.fieldDefinitions.FieldDefinitionSleepStage;
@ -57,6 +60,7 @@ import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitHrvValue;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoring;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoringHrData;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitMonitoringInfo;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitPhysiologicalMetrics;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRecord;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.fit.messages.FitRespirationRate;
@ -86,6 +90,7 @@ public class FitImporter {
private final List<GarminSleepStageSample> sleepStageSamples = new ArrayList<>();
private final List<GarminHrvSummarySample> hrvSummarySamples = new ArrayList<>();
private final List<GarminHrvValueSample> hrvValueSamples = new ArrayList<>();
private final List<GarminRestingMetabolicRateSample> restingMetabolicRateSamples = new ArrayList<>();
private final Map<Integer, Integer> unknownRecords = new HashMap<>();
private FitSleepDataInfo fitSleepDataInfo = null;
private final List<FitSleepDataRaw> fitSleepDataRawSamples = new ArrayList<>();
@ -264,6 +269,16 @@ public class FitImporter {
sample.setTimestamp(ts * 1000L);
sample.setValue(Math.round(hrvValue.getValue()));
hrvValueSamples.add(sample);
} else if (record instanceof FitMonitoringInfo) {
final FitMonitoringInfo monitoringInfo = (FitMonitoringInfo) record;
if (monitoringInfo.getRestingMetabolicRate() == null) {
continue;
}
LOG.trace("Monitoring info at {}: {}", ts, record);
final GarminRestingMetabolicRateSample sample = new GarminRestingMetabolicRateSample();
sample.setTimestamp(ts * 1000L);
sample.setRestingMetabolicRate(monitoringInfo.getRestingMetabolicRate());
restingMetabolicRateSamples.add(sample);
} else if (record instanceof FitMonitoringHrData) {
final FitMonitoringHrData monitoringHrData = (FitMonitoringHrData) record;
if (monitoringHrData.getRestingHeartRate() == null) {
@ -308,6 +323,7 @@ public class FitImporter {
persistRestingHrSamples();
persistStressSamples();
persistBodyEnergySamples();
persistRestingMetabolicRateSamples();
break;
case SLEEP:
persistEvents();
@ -374,6 +390,7 @@ public class FitImporter {
sleepStageSamples.clear();
hrvSummarySamples.clear();
hrvValueSamples.clear();
restingMetabolicRateSamples.clear();
unknownRecords.clear();
fitSleepDataInfo = null;
fitSleepDataRawSamples.clear();
@ -801,4 +818,30 @@ public class FitImporter {
GB.toast(context, "Error saving body energy samples", Toast.LENGTH_LONG, GB.ERROR, e);
}
}
private void persistRestingMetabolicRateSamples() {
if (restingMetabolicRateSamples.isEmpty()) {
return;
}
LOG.debug("Will persist {} resting metabolic rate samples", restingMetabolicRateSamples.size());
try (DBHandler handler = GBApplication.acquireDB()) {
final DaoSession session = handler.getDaoSession();
final Device device = DBHelper.getDevice(gbDevice, session);
final User user = DBHelper.getUser(session);
final GarminRestingMetabolicRateSampleProvider sampleProvider = new GarminRestingMetabolicRateSampleProvider(gbDevice, session);
for (final GarminRestingMetabolicRateSample sample : restingMetabolicRateSamples) {
sample.setDevice(device);
sample.setUser(user);
}
sampleProvider.addSamples(restingMetabolicRateSamples);
} catch (final Exception e) {
GB.toast(context, "Error saving body energy samples", Toast.LENGTH_LONG, GB.ERROR, e);
}
}
}

View File

@ -36,10 +36,13 @@ import de.greenrobot.dao.query.QueryBuilder;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.SettingsActivity;
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.entries.ActivitySummaryProgressEntry;
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.entries.ActivitySummaryTableRowEntry;
import nodomain.freeyourgadget.gadgetbridge.activities.workouts.entries.ActivitySummaryValue;
import nodomain.freeyourgadget.gadgetbridge.database.DBHandler;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HeartRateZonesConfig;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiSportHRZones;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.packets.Workout;
import nodomain.freeyourgadget.gadgetbridge.entities.BaseActivitySummary;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
@ -58,6 +61,7 @@ import nodomain.freeyourgadget.gadgetbridge.model.ActivityKind;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryData;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryEntries;
import nodomain.freeyourgadget.gadgetbridge.model.ActivitySummaryParser;
import nodomain.freeyourgadget.gadgetbridge.model.ActivityUser;
import nodomain.freeyourgadget.gadgetbridge.util.GB;
import nodomain.freeyourgadget.gadgetbridge.util.StringUtils;
@ -113,6 +117,7 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
RUNNING(1, ActivityKind.RUNNING),
WALKING(2, ActivityKind.WALKING),
CYCLING(3, ActivityKind.CYCLING),
MOUNTAIN_HIKE(4, ActivityKind.MOUNTAIN_HIKE),
INDOOR_RUN(5, ActivityKind.INDOOR_RUNNING),
POOL_SWIM(6, ActivityKind.POOL_SWIM),
INDOOR_CYCLE(7, ActivityKind.INDOOR_CYCLING),
@ -485,7 +490,36 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
int sumAltitudeUp = 0;
int sumAltitudeDown = 0;
//NOTE: The method of retrieving HR zones from the Huawei watch is not discovered. It may not return zones.
// So they are calculated based on config. Enabled only for running and walking activities for testing.
// Currently only calculated zones based on MHR.
// TODO: Use other methods after the configuration will be implemented. Use calculateMethod on HeartRateZonesConfig class.
// TODO: Enable for other workout types
HeartRateZonesConfig HRZonesCfg = null;
if( type == ActivityKind.WALKING || type == ActivityKind.RUNNING) {
ActivityUser activityUser = new ActivityUser();
HuaweiSportHRZones hrSportZones = new HuaweiSportHRZones(activityUser.getAge());
HRZonesCfg = hrSportZones.getHRZonesConfigByType(HeartRateZonesConfig.TYPE_UPRIGHT);
}
int dataDelta = 5;
if (dataSamples.size() >= 2 && dataSamples.get(1).getTimestamp() - dataSamples.get(0).getTimestamp() >= 40) {
dataDelta = 60;
}
int[] HRZones = new int[5];
int dataIdx = 0;
for (HuaweiWorkoutDataSample dataSample : dataSamples) {
if(HRZonesCfg != null) {
int zoneIdx = HRZonesCfg.getMHRZone(dataSample.getHeartRate() & 0xFF);
if (zoneIdx != -1 && dataIdx < (dataSamples.size() - 1)) {
HRZones[zoneIdx] += dataDelta;
}
dataIdx++;
}
if (dataSample.getSpeed() != -1) {
speed += dataSample.getSpeed();
speedCount += 1;
@ -588,6 +622,25 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
unknownData = true;
}
if(HRZonesCfg != null) {
final double totalTime = Arrays.stream(HRZones).sum();
final List<String> zoneOrder = Arrays.asList(ActivitySummaryEntries.HR_ZONE_WARM_UP, ActivitySummaryEntries.HR_ZONE_FAT_BURN, ActivitySummaryEntries.HR_ZONE_AEROBIC, ActivitySummaryEntries.HR_ZONE_ANAEROBIC, ActivitySummaryEntries.HR_ZONE_EXTREME);
for (int i = 0; i < zoneOrder.size(); i++) {
double timeInZone = HRZones[i];
LOG.info("Zone: {} {}", zoneOrder.get(i), timeInZone);
summaryData.add(
zoneOrder.get(i),
new ActivitySummaryProgressEntry(
timeInZone,
ActivitySummaryEntries.UNIT_SECONDS,
(int) (100 * timeInZone / totalTime)
)
);
}
}
// Average the things that should be averaged
if (speedCount > 0)
speed = speed / speedCount;
@ -748,6 +801,7 @@ public class HuaweiWorkoutGbParser implements ActivitySummaryParser {
summaryData.add(ActivitySummaryEntries.ELEVATION_LOSS, elevationLoss / 10.0f, ActivitySummaryEntries.UNIT_METERS);
}
final LinkedHashMap<String, ActivitySummaryTableRowEntry> pacesTable = new LinkedHashMap<>();
pacesTable.put("paces_table",

View File

@ -63,6 +63,36 @@ public class DashboardUtils {
return totalSteps;
}
public static int getActiveCaloriesTotal(DashboardFragment.DashboardData dashboardData) {
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
int totalActiveCalories = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActivityTracking()) {
totalActiveCalories += (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getActiveCalories();
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of active calories: ", e);
}
return totalActiveCalories;
}
public static int getRestingCaloriesTotal(DashboardFragment.DashboardData dashboardData) {
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
int totalRestingCalories = 0;
try (DBHandler dbHandler = GBApplication.acquireDB()) {
for (GBDevice dev : devices) {
if ((dashboardData.showAllDevices || dashboardData.showDeviceList.contains(dev.getAddress())) && dev.getDeviceCoordinator().supportsActivityTracking()) {
totalRestingCalories += (int) getDailyTotals(dev, dbHandler, dashboardData.timeTo).getRestingCalories();
}
}
} catch (Exception e) {
LOG.warn("Could not calculate total amount of resting calories: ", e);
}
return totalRestingCalories;
}
public static float getStepsGoalFactor(DashboardFragment.DashboardData dashboardData) {
ActivityUser activityUser = new ActivityUser();
float stepsGoal = activityUser.getStepsGoal();
@ -134,6 +164,24 @@ public class DashboardUtils {
return goalFactor;
}
public static float getActiveCaloriesGoalFactor(DashboardFragment.DashboardData dashboardData) {
ActivityUser activityUser = new ActivityUser();
int caloriesGoal = activityUser.getActiveCaloriesBurntGoal();
float goalFactor = (float) getActiveCaloriesTotal(dashboardData) / caloriesGoal;
if (goalFactor > 1) goalFactor = 1;
return goalFactor;
}
public static float getCaloriesGoalFactor(DashboardFragment.DashboardData dashboardData) {
ActivityUser activityUser = new ActivityUser();
int caloriesGoal = activityUser.getCaloriesBurntGoal();
float goalFactor = (float) (getRestingCaloriesTotal(dashboardData) + getActiveCaloriesTotal(dashboardData)) / caloriesGoal;
if (goalFactor > 1) goalFactor = 1;
return goalFactor;
}
public static long getActiveMinutesTotal(DashboardFragment.DashboardData dashboardData) {
List<GBDevice> devices = GBApplication.app().getDeviceManager().getDevices();
long totalActiveMinutes = 0;

View File

@ -0,0 +1,125 @@
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<TextView
android:id="@+id/date_view"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="15dp"
android:layout_marginBottom="20dp"
android:gravity="center"
android:textSize="20sp" />
<ImageView
android:layout_width="180dp"
android:layout_height="180dp"
android:layout_gravity="center"
android:scaleType="fitStart"
android:id="@+id/calories_gauge" />
<GridLayout
android:id="@+id/calories_types_wrapper"
android:background="@color/gauge_line_color"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:columnCount="2"
android:layout_marginTop="15dp"
>
<LinearLayout
android:id="@+id/calories_active_wrapper"
style="@style/GridTile"
android:layout_marginEnd="1dp"
android:layout_marginTop="2dp"
>
<TextView
android:id="@+id/calories_active"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_empty_value"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/active"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/calories_active_goal_wrapper"
style="@style/GridTile"
android:layout_marginStart="1dp"
android:layout_marginTop="2dp"
>
<TextView
android:id="@+id/calories_active_goal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_empty_value"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/active_goal"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/calories_resting_wrapper"
style="@style/GridTile"
android:layout_marginEnd="1dp"
>
<TextView
android:id="@+id/calories_resting"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_empty_value"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/hr_resting"
android:textSize="12sp" />
</LinearLayout>
<LinearLayout
android:id="@+id/calories_total_goal_wrapper"
style="@style/GridTile"
android:layout_marginStart="1dp"
>
<TextView
android:id="@+id/calories_total_goal"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/stats_empty_value"
android:textSize="20sp" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@string/total_goal"
android:textSize="12sp" />
</LinearLayout>
</GridLayout>
<TextView
android:id="@+id/steps_chart_title"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="left"
android:paddingLeft="20dip"
android:text=""
android:textSize="20sp" />
</LinearLayout>
</ScrollView>

View File

@ -473,7 +473,7 @@
<string name="calories">السعرات</string>
<string name="distance">المسافة</string>
<string name="fwinstaller_firmware_not_compatible_to_device">هذا البرنامج الثابت غير متوافق مع الجهاز</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">هل تريد الكتابة فوق البيانات الحالية حقا؟ سيتم الكتابة فوق جميع بيانات نشاطك الحالية (إن وجدت) وتفضيلاتك.</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">هل تريد حقًا الكتابة فوق البيانات الحالية ؟ سيتم استبدال جميع بيانات نشاطك الحالية (إن وجدت) والأجهزة والتفضيلات.</string>
<string name="activity_error_no_app_for_png">لمشاركة لقطة الشاشة هذه ، قم بتثبيت تطبيق يمكنه التعامل مع ملفات الصور.</string>
<string name="activity_error_no_app_for_gpx">لعرض تتبع النشاط ، قم بتثبيت التطبيق الذي يمكنه التعامل مع ملفات GPX.</string>
<string name="permission_notification_listener">يحتاج %1$s إلى الوصول إلى الإشعارات لعرضها على ساعتك عندما تكون شاشة هاتفك مغلقة.
@ -512,7 +512,7 @@
<string name="activity_type_swimming">السباحه</string>
<string name="share">مشاركة</string>
<string name="error_no_location_access">يجب منح الوصول إلى الموقع وتمكينه للمسح ليعمل بشكل صحيح</string>
<string name="error_background_service_reason">فشل بدء تشغيل خدمة الخلفية لوجود استثناء. خطأ:</string>
<string name="error_background_service_reason">فشل بدء تشغيل خدمة الخلفية بسبب استثناء - انقر هنا لمزيد من المعلومات.\n\nخطأ:</string>
<string name="pref_summary_pebble_enable_applogs">سيؤدي إلى تسجيل السجلات من تطبيقات الساعة بواسطة Gadgetbridge (يتطلب إعادة الاتصال)</string>
<string name="test">الاختبار</string>
<string name="mi2_prefs_goal_notification_summary">سيهتز السوار عند الوصول إلى هدف الخطوات اليومية</string>
@ -700,7 +700,7 @@
<string name="heartrate_bpm_145">145 نبضة في الدقيقة</string>
<string name="heartrate_bpm_150">150 نبضة في الدقيقة</string>
<string name="prefs_find_phone_summary">استخدم سوارك لتشغيل نغمة رنين هاتفك.</string>
<string name="mi2_enable_text_notifications_summary">يحتاج إلى تثبيت البرنامج الثابت &gt; = 1.0.1.28 و Mili_pro.ft*.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Needs firmware >= 1.0.1.28 and Mili_pro.ft* installed.]]></string>
<string name="warning">تحذير!</string>
<string name="pref_chart_heartrate_color_red">أحمر</string>
<string name="pref_charts_range_on">تم تعيين نطاق الرسوم البيانية إلى شهر</string>
@ -1497,7 +1497,7 @@
<string name="live_activity_current_steps_per_minute">الخطوات الحالية / دقيقة</string>
<string name="device_not_connected">غير متصل.</string>
<string name="prefs_find_phone_duration">مدة الرنين بالثواني</string>
<string name="dateformat_date_time">الوقت والتاريخ</string>
<string name="dateformat_date_time"><![CDATA[Time & date]]></string>
<string name="prefs_disconnect_notification">إشعار قطع الاتصال</string>
<string name="mi2_prefs_button_press_count">عدد مرات الضغط على الزر</string>
<string name="mi2_prefs_button_action">تمكين إجراء الزر</string>
@ -2960,7 +2960,7 @@
<string name="pref_wearing_tone_summary">يصدر نغمة عند تركيب سماعة الأذن</string>
<string name="devicetype_soundcore_liberty3_pro">Soundcore Liberty 3 Pro</string>
<string name="devicetype_huawei_watchfit3">Huawei Watch Fit 3</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 Pro</string>
<string name="devicetype_huawei_watch4pro">(Huawei Watch 4 (Pro</string>
<string name="preferences_qhybrid_settings_summary">الإعدادات القديمة لساعات Q الهجينة</string>
<string name="pref_adaptive_noise_cancelling_title">عزل الصوت المتكيف</string>
<string name="pref_adaptive_noise_cancelling_summary">اضبط قوة عزل الصوت تلقائيًا على مستوى الصوت المحيط</string>
@ -3231,4 +3231,291 @@
<string name="minutes_120">120 دقيقة</string>
<string name="minutes_90">90 دقيقة</string>
<string name="minutes_150">150 دقيقة</string>
<string name="idasen_pref_value_warning">ويجب أن تتراوح القيمة بين 62 و126 سم</string>
<string name="prefs_hrv_monitoring_description">راقب تقلب معدل ضربات القلب تلقائيًا على مدار اليوم</string>
<string name="pref_continuous_skin_temperature_measurement_description">استرداد درجة الحرارة غير مدعوم حاليًا. يتيح هذا الإعداد القياس المستمر على الجهاز فقط</string>
<string name="backup_restore_do_not_exit">%s يرجى إبقاء هذه الشاشة مفتوحة حتى تنتهي العملية.</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="activity_type_ice_skating">التزلج على الثلج</string>
<string name="prefs_title_gatt_client_notification_intents">إذاعة نوايا إخطار الغات من خلال واجهة برمجة تطبيقات نوايا BLE</string>
<string name="cannot_upload_watchface_too_many_watchfaces_installed">لا يمكن تحميل واجهة الساعة، تم تثبيت العديد من واجهات الساعة</string>
<string name="prefs_summary_gatt_client_allow_gatt_interactions">السماح بإرسال أوامر القراءة/الكتابة الخاصة بـ BLE وتوصيلها</string>
<string name="pref_title_sync_birthdays">مزامنة ايام الميلاد</string>
<string name="activity_type_sky_diving">القفز في السماء</string>
<string name="activity_type_snowshoe">حذاء جليدي</string>
<string name="busy_task_fetch_hrv_data">جلب بيانات الـ HRV</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="miscale_small_objects_summary">قم بتخزين وزن الأشياء التي يقل وزنها عن 10 كجم</string>
<string name="prefs_summary_gatt_client_api_package">تقييد اتصال واجهة برمجة التطبيقات نية BLE بهذه الحزمة</string>
<string name="inactivity_warnings_minimum_steps_summary">الحد الأدنى من الخطوات التي يجب اتخاذها خلال دقائق العتبة</string>
<string name="pref_summary_sync_birthdays">مزامنة ايام الميلاد لجهات الاتصال مع أحداث التقويم</string>
<string name="activity_db_management_backup_restore_explanation">تسمح لك عمليات الاستيراد/التصدير بترحيل أو نسخ جميع إعدادات Gadgetbridge والأجهزة والبيانات من وإلى ملف مضغوط.\n\nسيؤدي استيراد ملف إلى إزالة جميع البيانات والأجهزة والتفضيلات الموجودة، واستبدالها بالكامل بالنسخة الاحتياطية.</string>
<string name="pref_dnd_follow_phone_summary">عند تمكين وضع عدم الإزعاج أو تعطيله على الهاتف، قم بتبديله تلقائيًا على الجهاز أيضًا</string>
<string name="pref_title_calendar_lookahead">عدد الأيام المقبلة</string>
<string name="pref_summary_calendar_lookahead">مزامنة ما يصل إلى %1s أيام من أحداث التقويم</string>
<string name="pref_crash_notification_summary">عند تعطل التطبيق، اعرض إشعارًا يحتوي على الخطأ</string>
<string name="devicetype_mijia_xmwsdj04">مستشعر درجة الحرارة والرطوبة Mijia 2 (الحبر الإلكتروني)</string>
<string name="miscale_weight_unit_summary">تعيين وحدة الوزن للقياسات المعروضة</string>
<string name="pref_header_deprecated_functionalities_warning">تم إهمال الوظائف التالية وسيتم إزالتها قريبًا من البرنامج.\nإذا كنت بحاجة إلى تمكين أحد الإعدادات التالية، فتأكد من التواصل مع فريق المشروع.</string>
<string name="mijia_lywsd_comfort_level_summary">تكوين حدود درجة الحرارة والرطوبة للرموز التعبيرية المعروضة</string>
<string name="backup_restore_abort_import_confirmation">هل تريد إلغاء الاستيراد ؟ قد يؤدي ذلك إلى تلف قاعدة البيانات أو عدم اتساقها.</string>
<string name="backup_restore_abort_export_confirmation">هل تريد إلغاء التصدير ؟ سيتم حذف الملف المضغوط الجزئي.</string>
<string name="pref_dashboard_widget_today_time_indicator_summary">عرض مؤشر في الوقت الحالي، لفصل البيانات بصريًا عن الأمس واليوم</string>
<string name="pref_dashboard_widget_today_yesterday_data_summary">عرض البيانات من الأمس خافتة بين الوقت الحالي ومنتصف الليل</string>
<string name="smart_ring_measurement_error_worn_incorrectly">خطأ في القياس. هل مستشعرات الحلقة موجهة بشكل صحيح ؟</string>
<string name="choose_device">اختر جهازا</string>
<string name="no_supported_devices_found">لم يتم العثور على الأجهزة المدعومة</string>
<string name="search">بحث</string>
<string name="pref_deprecated_media_control_summary">إرسال أوامر التحكم في الوسائط كأحداث رئيسية بدلاً من وحدة التحكم في الوسائط.</string>
<string name="smart_ring_measurement_error_unknown">خطأ قياس غير معروف %d تم استلامه من الحلقة</string>
<string name="hr_resting">الراحة</string>
<string name="hr_maximum">أقصى</string>
<string name="hr_minimum">أدنى</string>
<string name="hr_average">المتوسط</string>
<string name="pref_title_nagivation_apps">تطبيقات الملاحة</string>
<string name="pref_header_external_integrations">الدمج الخارجي</string>
<string name="pref_header_automations">الاتمته</string>
<string name="pref_description_general">البداية، اللغة، المنطقة، الموقع</string>
<string name="pref_description_about_you">تاريخ الميلاد ونوع الجنس والطول والوزن والأهداف</string>
<string name="pref_description_notifications">إشعارات التطبيق، القائمة البيضاء/القائمة السوداء</string>
<string name="pref_description_user_interface">السمة، الشاشة الرئيسية</string>
<string name="pref_description_dashboard">الأدوات والأجهزة المراد تضمينها</string>
<string name="pref_description_automations">تصدير تلقائي، جلب تلقائي</string>
<string name="pref_description_developer_options">السجلات، واجهة برمجة تطبيقات النوايا</string>
<string name="pref_description_deprecated_functionalities">الإعدادات التي ستتم إزالتها في إصدار مستقبلي</string>
<string name="pref_header_main_screen">الشاشة الرئيسية</string>
<string name="pref_title_user_interface">واجهة المستخدم</string>
<string name="activity_prefs_date_birth">تاريخ الميلاد</string>
<string name="devicetype_redmi_watch_5_active">Redmi Watch 5 Active</string>
<string name="max_respiration_rate">معدل التنفس الأقصى</string>
<string name="min_respiration_rate">معدل التنفس الأدنى</string>
<string name="average_respiration_rate">معدل التنفس</string>
<string name="hrv_sdrr">HRV SDRR</string>
<string name="hrZoneMaximum">الحد الأقصى</string>
<string name="activity_type_plaza_dancing">رقص البلازا</string>
<string name="miscale_weight_unit_imperial">الامبراطورية (الطن)</string>
<string name="miscale_weight_unit_metric">متري (كغ)</string>
<string name="backup_restore_importing_database">استيراد قاعدة البيانات…</string>
<string name="devicetype_sony_wf_c500">Sony WF-C500</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="activity_type_orienteering">سباق موجه</string>
<string name="idasen_control_button_stand">وقوف</string>
<string name="activity_detail_share_json_details">مشاركة تفاصيل JSON</string>
<string name="devicetype_miband9">Xiaomi Smart Band 9</string>
<string name="devicetype_amazfit_trex_3">Amazfit T-Rex 3</string>
<string name="devicetype_idasen">IKEA Idasen Desk</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="menuitem_heart_rate_push">معدل نبضات القلب</string>
<string name="hrv_rmssd">HRV RMSSD</string>
<string name="workout_set_reps">التكرار</string>
<string name="breaths_per_min">انفاس/دقيقة</string>
<string name="milliseconds_ms">م ث</string>
<string name="idasen_control_button_mid">MID</string>
<string name="idasen_control_button_sit">SIT</string>
<string name="idasen_pref_mid_height">ارتفاع الموضع الأوسط (بالسنتيمتر)</string>
<string name="idasen_pref_sit_height">ارتفاع موضع الجلوس (بالسنتيمتر)</string>
<string name="activity_db_management_import_from_zip">استيراد الملف المضغوط</string>
<string name="prefs_title_ble_intent_api">BLE النوايا API</string>
<string name="backup_restore_exporting_preferences">تفضيلات التصدير…</string>
<string name="backup_restore_importing_preferences">أفضليات الاستيراد…</string>
<string name="prefs_hrv_monitoring_title">HRV مراقبة</string>
<string name="backup_restore_error_import">فشل الاستيراد من الملف المضغوط</string>
<string name="pref_dnd_follow_phone_title">اتبع إعداد وضع عدم الإزعاج (DND) للهاتف</string>
<string name="label_distance_total_mph">الإجمالي: %.1f ميل</string>
<string name="menuitem_stress_segmented">الإجهاد (المجزأ)</string>
<string name="insufficient_space_for_upload">مساحة غير كافية للتحميل</string>
<string name="backup_restore_exporting">التصدير إلى ملف مضغوط…</string>
<string name="mijia_lywsd_comfort_lower">الحد الأدنى</string>
<string name="activity_type_bocce">بوتشي</string>
<string name="activity_type_sail_expedition">رحلة استكشافية</string>
<string name="activity_type_aerobics">الملاحة الجوية</string>
<string name="activity_type_spinning">الدوران</string>
<string name="activity_type_free_sparring">ملاكمة حرة</string>
<string name="devicetype_garmin_forerunner_955">Garmin Forerunner 955</string>
<string name="prefs_summary_gatt_client_notification_intents">تلقي التغييرات المميزة لـ BLE من خلال النوايا</string>
<string name="prefs_title_gatt_client_allow_gatt_interactions">السماح بتفاعل GATT من خلال واجهة برمجة التطبيقات BLE Intent API</string>
<string name="label_distance_total">الإجمالي: %.1f كم</string>
<string name="activity_type_water_skiing">التزلج على المياه</string>
<string name="activity_type_kayaking">تجديف بالكاياك</string>
<string name="activity_type_racket">التنس</string>
<string name="activity_type_meditation">التأمل</string>
<string name="activity_type_para_sport">رياضة بارا</string>
<string name="activity_type_board_game">لعبة لوح</string>
<string name="activity_type_finswimming">السباحة بالزعنفة</string>
<string name="activity_type_flowriding">سيرًا على الأقدام</string>
<string name="activity_type_hip_hop">هيب-هوب</string>
<string name="activity_type_modern_dance">الرقص الحديث</string>
<string name="activity_type_sledding">التزلج</string>
<string name="activity_type_laser_tag">علامات الليزر</string>
<string name="bpm_value_unit">%1$d نبضة في الدقيقة</string>
<string name="menuitem_stress_simple">الإجهاد (بسيط)</string>
<string name="devicetype_sony_wf_c700n">Sony WF-C700N</string>
<string name="devicetype_huawei_watchgt5">Huawei Watch GT 5 (Pro)</string>
<string name="menuitem_stress_breakdown">الإجهاد (الكسر)</string>
<string name="estimatedSweatLoss">الخسارة المقدرة للعرق</string>
<string name="activity_type_marine">البحرية</string>
<string name="activity_type_indoor_push_walk_speed">دفع داخلي - سرعة المشي</string>
<string name="activity_type_indoor_push_run_speed">دفع داخلي - سرعة الجري</string>
<string name="activity_type_push_run_speed">دفع - سرعة الجري</string>
<string name="activity_type_disc_golf">قولف القرص</string>
<string name="activity_type_pole_dance">رقصة العمود</string>
<string name="activity_type_ballroom_dance">رقصة قاعة الرقص</string>
<string name="activity_type_race_walking">سباق المشي</string>
<string name="activity_type_somatosensory_game">لعبة حسية جسدية</string>
<string name="activity_type_square_dance">ساحة الرقص</string>
<string name="activity_type_shuffleboard">شافلبورد (لعبة دفع الأقراص)</string>
<string name="steps_distance_unit">%1$,.2f كم</string>
<string name="activity_type_weiqi">ويتشي</string>
<string name="devicetype_garmin_venu">Garmin Venu</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="devicetype_garmin_forerunner_165">Garmin Forerunner 165</string>
<string name="devicetype_garmin_forerunner_245_music">Garmin Forerunner 245 Music</string>
<string name="hrZoneThreshold">الحد الأدنى</string>
<string name="miscale_small_objects_title">الأجسام الصغيرة</string>
<string name="mijia_lywsd_comfort_humidity_title">الرطوبة (%)</string>
<string name="backup_restore_exporting_database">تصدير قاعدة البيانات…</string>
<string name="backup_restore_exporting_finishing">الانتهاء من التصدير…</string>
<string name="backup_restore_exporting_files_i_of_n">تصدير الملفات... %1d من %2d</string>
<string name="activity_type_stand_up_paddleboarding">التجديف على الألواح في وضع الوقوف</string>
<string name="activity_type_jumpmaster">القفز</string>
<string name="activity_type_wakesurfing">ركوب الأمواج</string>
<string name="activity_type_aerobic_combo">المركب الأيروبي</string>
<string name="activity_type_mixed_martial_arts">فنون القتال المختلطة</string>
<string name="activity_type_artistic_swimming">السباحة الفنية</string>
<string name="activity_type_breaking">كسر</string>
<string name="activity_type_futsal">كرة الصالات</string>
<string name="activity_type_frisbee">صحن طائر</string>
<string name="activity_type_jai_alai">جاي عللاي</string>
<string name="activity_type_parallel_bars">جهاز المتوازي</string>
<string name="app_crash_share_stacktrace">خطأ في المشاركة</string>
<string name="contact_birthday">%1s يوم ميلاد</string>
<string name="backup_restore_importing_loading">تحميل الملف…</string>
<string name="backup_restore_importing_validating">التحقق من الملف …</string>
<string name="backup_restore_importing_files_i_of_n">استيراد الملفات... %1d من %2d</string>
<string name="fmtPaceAverage">معدل الخطى</string>
<string name="backup_restore_abort_title">تجاهل</string>
<string name="mijia_lywsd_comfort_upper">الحد الأقصى</string>
<string name="label_distance_trip_mph">الرحلة: %.1f ميل</string>
<string name="backup_restore_restart_summary">سيتم الآن إعادة تشغيل %1s.</string>
<string name="label_distance_trip">الرحلة: %.1f كم</string>
<string name="inactivity_warnings_minimum_steps_title">الحد الأدنى للخطوات</string>
<string name="pref_dashboard_widget_today_yesterday_data_title">بيانات أمس</string>
<string name="activity_type_esports">رياضة إلكترونية</string>
<string name="activity_type_checkers">الشيكات</string>
<string name="activity_type_chess">شطرنج</string>
<string name="activity_type_dragon_boat">قارب التنين</string>
<string name="activity_type_muay_thai">مو تاي</string>
<string name="activity_type_snorkeling">الغوص</string>
<string name="activity_type_mass_gymnastics">جمباز جماعي</string>
<string name="devicetype_garmin_forerunner_265s">Garmin Forerunner 265S</string>
<string name="pref_crash_notification_title">الإخطار عند التحطم</string>
<string name="birthdays">أيام الميلاد</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="devicetype_soundcore_liberty4_nc">Soundcore Liberty 4 NC</string>
<string name="vo2max_running">تشغيل VO₂ Max</string>
<string name="vo2max_cycling">قيادة الدراجة VO₂ الحد الاقصى</string>
<string name="thirty_days_timeline">الجدول الزمني لمدة 30 يومًا</string>
<string name="target">الهدف</string>
<string name="miscale_weight_unit_title">وحدة الوزن</string>
<string name="error_no_cycling_sensor_found">لم يتم العثور على مستشعر للدراجات</string>
<string name="hrZoneEasy">سهل</string>
<string name="mijia_lywsd_comfort_level_title">مستوى الراحة</string>
<string name="mijia_lywsd_comfort_temperature_title">درجة الحرارة (درجة مئوية)</string>
<string name="mijia_lywsd_comfort_temperature_summary">النطاق الموصى به: 19 - 27</string>
<string name="mijia_lywsd_comfort_humidity_summary">النطاق الموصى به: 20 - 85</string>
<string name="activity_db_management_backup_restore_label">النسخ الاحتياطي والاستعادة</string>
<string name="activity_db_management_export_to_zip">تصدير الملف المضغوط</string>
<string name="backup_restore_exporting_files">تصدير الملفات…</string>
<string name="backup_restore_export_complete">تم التصدير</string>
<string name="backup_restore_import_complete">تم الاستيراد</string>
<string name="backup_restore_warning_files">‏‫فشلت استعادة %1d من الملفات: \n%2s</string>
<string name="backup_restore_error_export">فشل التصدير للملف المضغوط</string>
<string name="backup_restore_restart_title">إعادة تشغيل</string>
<string name="devicetype_garmin_venu_2s">Garmin Venu 2S</string>
<string name="prefs_title_gatt_client_api_package">حزمة BLE API</string>
<string name="activity_type_wall_ball">الكرة الجدارية</string>
<string name="activity_type_water_polo">كرة الماء</string>
<string name="activity_type_body_combat">القتال الجسدي</string>
<string name="activity_type_obstacle_race">سباق العقبات</string>
<string name="activity_type_water_scooter">سكوتر المياه</string>
<string name="activity_type_bungee_jumping">القفز بالحبال</string>
<string name="activity_type_billiard_pool">حمام السباحة</string>
<string name="activity_type_canoeing">زورق</string>
<string name="activity_type_bobsleigh">بوبسلي</string>
<string name="activity_type_biathlon">بياثلون</string>
<string name="activity_type_tug_of_war">شد الحبل</string>
<string name="prefs_summary_gatt_client_device_state_updates">تلقي تغييرات حالة اتصال BLE عبر النوايا</string>
<string name="activity_type_racquetball">كرة الراح</string>
<string name="activity_type_push_walk_speed">دفع - سرعة المشي</string>
<string name="activity_type_lacrosse">لكروس</string>
<string name="activity_type_ultimate_disc">ألتيميت ديسك</string>
<string name="activity_type_team_sport">رياضة الفريق</string>
<string name="activity_type_water_tubing">أنابيب المياه</string>
<string name="activity_type_grinding">الصقل</string>
<string name="activity_type_shooting">إطلاق النار</string>
<string name="activity_type_padel">بادل</string>
<string name="activity_type_bridge">الجسر</string>
<string name="activity_type_softball_slow_pitch">الكرة اللينة رميه بطيئة</string>
<string name="activity_type_floor_climbing">تسلق الأرضيات</string>
<string name="activity_type_winter_sport">الرياضة الشتوية</string>
<string name="activity_type_health_snapshot">لمحة عن الصحة</string>
<string name="activity_type_air_walker">مشاية هوائية</string>
<string name="activity_type_cardio_combat">مكافحة أمراض القلب</string>
<string name="devicetype_colmi_r02">Colmi R02</string>
<string name="steps_avg">متوسط الخطوات</string>
<string name="devicetype_colmi_r06">Colmi R06</string>
<string name="devicetype_huawei_watchgtcyber">Huawei Watch GT Cyber</string>
<string name="menuitem_weight">الوزن</string>
<string name="app_crash_notification_title">تعطل %1s</string>
<string name="prefs_light_duration_longer">مدة إضاءة أطول</string>
<string name="pref_dashboard_widget_today_time_indicator_title">مؤشر الوقت الحالي</string>
<string name="paceCorrection">تصحيح</string>
<string name="activity_type_wakeboarding">ركوب مياه البحيره</string>
<string name="devicetype_colmi_r03">Colmi R03</string>
<string name="steps_total">اجمالي الخطوات</string>
<string name="pref_app_connection_duration">مدة اتصال التطبيق</string>
<string name="weight_kg">%1$.2f كغ</string>
<string name="activity_type_snowmobiling">التزحلق على الجليد</string>
<string name="activity_type_rafting">التجديف النهري</string>
<string name="activity_type_tactical">تكتيكية</string>
<string name="idasen_pref_stand_height">ارتفاع موضع الوقوف (بالسنتيمتر)</string>
<string name="backup_restore_importing">استيراد من ملف مضغوط…</string>
<string name="activity_type_video_gaming">ألعاب الفيديو</string>
<string name="activity_type_bmx">الدراجة</string>
<string name="activity_type_judo">الجودو</string>
<string name="activity_type_folk_dance">رقصة الناس</string>
<string name="activity_type_hacky_sack">كيس هاكي</string>
<string name="activity_type_hula_hoop">طوق هولا هوب</string>
<string name="activity_type_jujitsu">جوجوتسو</string>
<string name="activity_type_stair_climber">متسلق السلالم</string>
<string name="activity_type_table_football">كرة قدم الطاولة</string>
<string name="devicetype_micompositionscale">Mi Body Composition Scale 2</string>
<string name="pref_continuous_skin_temperature_measurement_title">قياس مستمر لدرجة حرارة الجلد</string>
<string name="number_selected_items">تم تحديد %1d</string>
<string name="pref_header_deprecated_functionalities">الوظائف المهملة</string>
<string name="devicetype_garmin_fenix_5x_plus">Garmin Fenix 5X Plus</string>
<string name="devicetype_garmin_enduro_3">Garmin Enduro 3</string>
<string name="devicetype_mismartscale">Mi Smart Scale 2</string>
<string name="devicetype_honor_watchgspro">Honor Watch GS Pro</string>
<string name="devicetype_honor_watchgs3">Honor Watch GS 3</string>
<string name="menuitem_map">خريطة</string>
<string name="menuitem_night_display">الشاشة اليلية</string>
<string name="distance_avg">متوسط المسافة</string>
<string name="distance_total">اجمالي المدى</string>
<string name="lactateThresholdHeartRate">معدل ضربات قلب عتبة اللاكتات</string>
<string name="recoveryTime">مدة الشفاء</string>
<string name="workoutSets">المجموعة</string>
<string name="workout_set_repetitions_weight_kg">%1d x %2$.2f kg</string>
<string name="workout_set_repetitions_weight_lbs">%1d x %2$.2f lbs</string>
<string name="workout_set_i">المجموعة %1d</string>
<string name="workout_set_repetitions">%1d x</string>
<string name="weight_lbs">%1$.2f طن</string>
<string name="pref_deprecated_media_control_title">الميزة المهملة للتحكم في الوسائط</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="miscale_weight_unit_chinese">الصينية (جين)</string>
<string name="devicetype_ble_gatt_client">عميل عام لـ BLE GATT</string>
<string name="music_upload_info">أنت على وشك تحميل ملف الموسيقى التالي:\n\n%1$s\nعنوان الأغنية: %2$s\nالألبوم: %3$s\n</string>
<string name="file_already_exists">الملف موجود بالفعل</string>
<string name="devicetype_garmin_fenix_7">Garmin Fenix 7</string>
</resources>

View File

@ -296,7 +296,7 @@
<string name="miband_prefs_device_time_offset_hours">Časový posun zařízení v hodinách (pro zjišťování spánku směnařů)</string>
<string name="miband2_prefs_dateformat">Formát data</string>
<string name="dateformat_time">Čas</string>
<string name="dateformat_date_time">Čas a datum</string>
<string name="dateformat_date_time"><![CDATA[Čas a datum]]></string>
<string name="mi2_prefs_activate_display_on_lift">Zapnout displej při zvednutí</string>
<string name="FetchActivityOperation_about_to_transfer_since">Přenáším data od %1$s</string>
<string name="waiting_for_reconnect">Čekání na znovupřipojení</string>
@ -398,7 +398,7 @@
<string name="dbmanagementactivity_error_importing_shared">Chyba při importu preferencí: %1$s</string>
<string name="mi2_fw_installhandler_fw53_hint">Před instalací tohoto firmwaru musíte nainstalovat verzi %1$s!</string>
<string name="mi2_enable_text_notifications">Textové upozornění</string>
<string name="mi2_enable_text_notifications_summary">Vyžaduje aby byl nainstalován font &gt;= 1.0.1.28 and Mili_pro.ft*.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Vyžaduje nainstalovaný firmware >= 1.0.1.28 and Mili_pro.ft*]]></string>
<string name="off">Vypnuto</string>
<string name="mi2_dnd_off">Vypnuto</string>
<string name="mi2_dnd_automatic">Automaticky (detekce spánku)</string>
@ -441,7 +441,7 @@
\nPOKRAČUJTE NA VLASTNÍ NEBEZPEČÍ!</string>
<string name="pref_title_charts_swipe">Zapnout možnost potažení mezi grafy aktivit</string>
<string name="pref_title_weather">Počasí</string>
<string name="pref_title_weather_location">Poloha pro počasí (LineageOS poskytovatel)</string>
<string name="pref_title_weather_location">Poloha pro počasí (poskytovatel v LineageOS)</string>
<string name="pref_title_pebble_enable_bgjs">Zapnout JS na pozadí</string>
<string name="pref_summary_pebble_enable_bgjs">Pokud je zapnuto, umožňuje hodinám zobrazovat počasí, údaje o baterii atd.</string>
<string name="pref_header_auto_export">Automatický export</string>
@ -967,7 +967,7 @@
<string name="error_exporting_device_preferences">Při exportu předvoleb specifických pro zařízení došlo k chybě</string>
<string name="pref_check_permission_status_summary">Kontroluje chybějící oprávnění a žádá o ně, i když nemusí být okamžitě potřeba. Tuto funkci zakažte pouze v případě, že vaše zařízení některou z těchto funkcí skutečně nepodporuje. Neudělení oprávnění může způsobit problémy!</string>
<string name="pref_check_permission_status">Kontrolovat stav oprávnění</string>
<string name="error_background_service_reason">Spuštění služby na pozadí selhalo z důvodu výjimky. Chyba:</string>
<string name="error_background_service_reason">Spuštění služby na pozadí selhalo z důvodu chyby klepněte sem pro více informací.\n\nChyba:</string>
<string name="device_requires_key">VYŽADOVÁN KLÍČ, ZADEJTE PODRŽENÍM</string>
<string name="device_is_currently_bonded">JIŽ SPÁROVÁNO</string>
<string name="error_background_service_reason_truncated">Službu na pozadí se nepodařilo spustit z důvodu…</string>
@ -1474,8 +1474,8 @@
<string name="maxCadence">Max rytmus</string>
<string name="spm">kroky/min</string>
<string name="mi2_prefs_do_not_disturb_lift_wrist">Zapnout displej při zvednutí během režimu Nerušit</string>
<string name="minHR">Min Tepová frekvence</string>
<string name="maxHR">Max Tepová frekvence</string>
<string name="minHR">Min. tepová frekvence</string>
<string name="maxHR">Max. tepová frekvence</string>
<string name="minCadence">Min rytmus</string>
<string name="pref_header_sony_equalizer_bands">Rozsahy</string>
<string name="sony_audio_upsampling">Převzorkování zvuku</string>
@ -3482,4 +3482,47 @@
<string name="paceCorrection">Oprava</string>
<string name="activity_detail_share_json_details">Sdílet podrobnosti v JSON</string>
<string name="number_selected_items">Vybráno %1d</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="mijia_lywsd_comfort_temperature_title">Teplota (°C)</string>
<string name="mijia_lywsd_comfort_temperature_summary">Doporučený rozsah: 19 - 27</string>
<string name="mijia_lywsd_comfort_humidity_title">Vlhkost (%)</string>
<string name="mijia_lywsd_comfort_humidity_summary">Doporučený rozsah: 20 - 85</string>
<string name="mijia_lywsd_comfort_lower">Spodní limit</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="mijia_lywsd_comfort_level_title">Úroveň pohodlí</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="mijia_lywsd_comfort_level_summary">Nastavte si omezení teploty a vlhkosti pro nastavené emotikony</string>
<string name="mijia_lywsd_comfort_upper">Horní limit</string>
<string name="busy_task_fetch_hrv_data">Získávání dat HRV</string>
<string name="pref_dnd_follow_phone_title">Podle nastavení režimu Nerušit telefonu</string>
<string name="pref_dnd_follow_phone_summary">Pokud je na telefonu povolen nebo zakázán režim Nerušit, automaticky jej přepnout i na zařízení</string>
<string name="inactivity_warnings_minimum_steps_title">Minimální počet kroků</string>
<string name="min_respiration_rate">Min. rychlost dýchání</string>
<string name="breaths_per_min">nádechů/min</string>
<string name="fmtPaceAverage">Průměrné tempo</string>
<string name="milliseconds_ms">ms</string>
<string name="average_respiration_rate">Rychlost dýchání</string>
<string name="max_respiration_rate">Max. rychlost dýchání</string>
<string name="hrv_sdrr">HRV SDRR</string>
<string name="hrv_rmssd">HRV RMSSD</string>
<string name="inactivity_warnings_minimum_steps_summary">Minimální počet kroků, které je třeba udělat během prahových minut</string>
<string name="prefs_hrv_monitoring_title">Sledování HRV</string>
<string name="prefs_hrv_monitoring_description">Automaticky sledovat variabilitu srdeční frekvence během dne</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="idasen_control_button_mid">MID</string>
<string name="devicetype_idasen">Stůl IKEA Idasen</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="idasen_pref_stand_height">Výška stojící pozice (v centimetrech)</string>
<string name="idasen_control_button_sit">SIT</string>
<string name="idasen_control_button_stand">STAND</string>
<string name="idasen_pref_sit_height">Výška sedící pozice (v centimetrech)</string>
<string name="idasen_pref_value_warning">Hodnota musí být mezi 62 a 126 cm</string>
<string name="idasen_pref_mid_height">Výška prostřední pozice (v centimetrech)</string>
<string name="music_upload_info">Chystáte se nahrát následující hudební soubor:\n\n%1$s\nNázev skladby: %2$s\nAlbum: %3$s\n</string>
<string name="devicetype_garmin_fenix_7">Garmin Fenix 7</string>
<string name="file_already_exists">Soubor již existuje</string>
<string name="devicetype_sony_wi_c100">Sony WI-C100</string>
</resources>

View File

@ -3208,11 +3208,11 @@
<string name="activity_type_bouldering">Bouldern</string>
<string name="activity_type_water_skiing">Wasserskifahren</string>
<string name="activity_type_kayaking">Kajakfahren</string>
<string name="activity_type_rafting"/>
<string name="activity_type_rafting">Rafting</string>
<string name="activity_type_navigate">Navigieren</string>
<string name="activity_type_indoor_track">Indoor Strecke</string>
<string name="activity_type_handcycling">Handbikefahren</string>
<string name="activity_type_e_bike"/>
<string name="activity_type_e_bike">E-Bike</string>
<string name="activity_type_bike_commute">Pendeln zur Arbeit mit dem Fahrrad</string>
<string name="activity_type_platform_tennis">Plattformtennis</string>
<string name="activity_type_training">Training</string>
@ -3275,4 +3275,74 @@
<string name="hrv">HFV</string>
<string name="activity_type_winter_sport">Wintersport</string>
<string name="activity_type_video_gaming">Videospiel</string>
<string name="devicetype_miband9">Xiaomi Smart Band 9</string>
<string name="pref_header_deprecated_functionalities">Veraltete Funktionalitäten</string>
<string name="mijia_lywsd_comfort_temperature_title">Temperatur (°C)</string>
<string name="activity_type_breaking">Breaking</string>
<string name="target">Ziel</string>
<string name="pref_title_sync_birthdays">Geburtstage synchronisieren</string>
<string name="activity_type_spinning">Spinning</string>
<string name="devicetype_huawei_watchgt5">Huawei Watch GT 5 (Pro)</string>
<string name="busy_task_fetch_hrv_data">Abrufen von HRV-Daten</string>
<string name="activity_type_softball_slow_pitch">Slowpitch-Softball</string>
<string name="activity_type_disc_golf">Discgolf</string>
<string name="activity_type_snorkeling">Schnorcheln</string>
<string name="activity_type_ultimate_disc">Ultimate Frisbee</string>
<string name="activity_type_bmx">BMX</string>
<string name="activity_type_bocce">Boccia</string>
<string name="activity_type_esports">E-Sport</string>
<string name="activity_type_checkers">Dame (Brettspiel)</string>
<string name="mijia_lywsd_comfort_level_title">Komfort-Level</string>
<string name="mijia_lywsd_comfort_humidity_title">Luftfeuchtigkeit (%)</string>
<string name="average_respiration_rate">Atemfrequenz durchschnittlich</string>
<string name="breaths_per_min">Atemzüge/min</string>
<string name="fmtPaceAverage">Durchschnittliches Tempo</string>
<string name="milliseconds_ms">ms</string>
<string name="pref_summary_sync_birthdays">Geburtstage von Kontakten zusammen mit Kalender-Events synchronisieren</string>
<string name="activity_type_board_game">Brettspiel</string>
<string name="menuitem_weight">Gewicht</string>
<string name="pref_crash_notification_title">Absturzbenachrichtigung</string>
<string name="pref_crash_notification_summary">Zeige eine Benachrichtigung mit dem Fehler, wenn die App abstürzt</string>
<string name="steps_avg">Schritte durchschnittlich</string>
<string name="miscale_small_objects_title">Leichte Gegenstände</string>
<string name="pref_continuous_skin_temperature_measurement_title">Kontinuierliche Messung der Hauttemperatur</string>
<string name="activity_type_mixed_martial_arts">Mixed Martial Arts</string>
<string name="activity_type_chess">Schach</string>
<string name="miscale_weight_unit_metric">Metrisch (kg)</string>
<string name="miscale_weight_unit_title">Gewichtseinheit</string>
<string name="miscale_weight_unit_summary">Gewichtseinheit für angezeigte Messungen festlegen</string>
<string name="insufficient_space_for_upload">Zu geringer Speicherplatz für Upload</string>
<string name="cannot_upload_watchface_too_many_watchfaces_installed">Zu viele Zifferblätter installiert. Upload nicht möglich</string>
<string name="miscale_small_objects_summary">Gewicht von Gegenständen unter 10 kg speichern</string>
<string name="miscale_weight_unit_chinese">Chinesisch (jin)</string>
<string name="mijia_lywsd_comfort_level_summary">Stelle die Temperatur- und Luftfeuchtigkeitsgrenzen für das angezeigte Emoji ein</string>
<string name="mijia_lywsd_comfort_lower">Untergrenze</string>
<string name="mijia_lywsd_comfort_upper">Obergrenze</string>
<string name="activity_type_laser_tag">Laser Tag</string>
<string name="activity_type_billiard_pool">Poolbillard</string>
<string name="activity_type_biathlon">Biathlon</string>
<string name="activity_type_bungee_jumping">Bungeejumping</string>
<string name="activity_type_wakeboarding">Wakeboarden</string>
<string name="activity_type_meditation">Meditation</string>
<string name="activity_type_lacrosse">Lacrosse</string>
<string name="activity_type_aerobics">Aerobic</string>
<string name="activity_type_american_football">American Football</string>
<string name="pref_continuous_skin_temperature_measurement_description">Temperaturabfrage derzeit nicht unterstützt. Diese Einstellung ermöglicht nur die kontinuierliche Messung auf dem Gerät</string>
<string name="paceCorrection">Korrektur</string>
<string name="miscale_weight_unit_imperial">Imperial (lbs)</string>
<string name="min_respiration_rate">Atemfrequenz min</string>
<string name="recoveryTime">Erholungszeit</string>
<string name="activity_type_frisbee">Frisbee</string>
<string name="activity_type_judo">Judo</string>
<string name="activity_type_table_football">Tischfußball</string>
<string name="distance_avg">Strecke durchschnittlich</string>
<string name="distance_total">Strecke insgesamt</string>
<string name="estimatedSweatLoss">Geschätzter Schweißverlust</string>
<string name="workout_set_reps">Wiederholungen</string>
<string name="activity_detail_share_json_details">JSON-Details teilen</string>
<string name="max_respiration_rate">Atemfrequenz max</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="pref_title_calendar_lookahead">Anzahl der Tage voraus</string>
<string name="pref_summary_calendar_lookahead">Kalenderereignisse bis zu %1s Tagen synchronisieren</string>
</resources>

View File

@ -405,7 +405,7 @@
<string name="miband2_prefs_timeformat">Mi2: formato de hora</string>
<string name="mi2_fw_installhandler_fw53_hint">¡Debes instalar la versión %1$s antes de instalar este firmware!</string>
<string name="mi2_enable_text_notifications">Notificaciones de texto</string>
<string name="mi2_enable_text_notifications_summary">Requiere firmware &gt;= 1.0.1.28 y tener Mili_pro.ft* instalado.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Needs firmware >= 1.0.1.28 y Mili_pro.ft* instalados.]]></string>
<string name="off">Apagado</string>
<string name="mi2_dnd_off">Apagado</string>
<string name="mi2_dnd_automatic">Automático (detección de sueño)</string>
@ -1070,7 +1070,7 @@
<string name="error_exporting_device_preferences">Error al exportar las preferencias específicas del dispositivo</string>
<string name="pref_check_permission_status_summary">Comprueba y pide los permisos que faltan, incluso cuando pueden no ser necesarios al instante. Desactiva esto solo si tus dispositivos no soportan ninguna de estas características. ¡No conceder un permiso puede causar problemas!</string>
<string name="pref_check_permission_status">Comprobar el estado de los permisos</string>
<string name="error_background_service_reason">El inicio del servicio en segundo plano ha fallado debido a una excepción. Error:</string>
<string name="error_background_service_reason">El inicio del servicio en segundo plano falló debido a una excepción - haga clic aquí para obtener más información.\n\nError:</string>
<string name="device_requires_key">CLAVE REQUERIDA, PULSACIÓN LARGA PARA ENTRAR</string>
<string name="device_is_currently_bonded">YA SE HA HECHO EL ENLACE</string>
<string name="error_background_service_reason_truncated">El inicio del servicio en segundo plano falló porque…</string>
@ -3486,4 +3486,43 @@
<string name="devicetype_huawei_watchgtcyber">Huawei Watch GT Cyber</string>
<string name="activity_detail_share_json_details">Compartir detalles en JSON</string>
<string name="number_selected_items">%1d seleccionado</string>
<string name="mijia_lywsd_comfort_level_summary">Configura los límites de temperatura y humedad para el emoji mostrado</string>
<string name="mijia_lywsd_comfort_temperature_title">Temperatura (°C)</string>
<string name="mijia_lywsd_comfort_humidity_title">Humedad (%)</string>
<string name="mijia_lywsd_comfort_lower">Límite inferior</string>
<string name="mijia_lywsd_comfort_upper">Límite superior</string>
<string name="mijia_lywsd_comfort_level_title">Nivel de comodidad</string>
<string name="mijia_lywsd_comfort_temperature_summary">Rango recomendado: 19 - 27</string>
<string name="mijia_lywsd_comfort_humidity_summary">Rango recomendado: 20 - 85</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="pref_dnd_follow_phone_title">Siga la configuración DND del teléfono</string>
<string name="inactivity_warnings_minimum_steps_title">Cantidad mínima de pasos</string>
<string name="inactivity_warnings_minimum_steps_summary">Cantidad mínima de pasos que se deben realizar durante los minutos límite</string>
<string name="prefs_hrv_monitoring_title">Monitoreo del ritmo cardíaco</string>
<string name="busy_task_fetch_hrv_data">Obtención datos HRV</string>
<string name="pref_dnd_follow_phone_summary">Cuando DND está habilitado o deshabilitado en el teléfono, también se activa automáticamente en el dispositivo</string>
<string name="prefs_hrv_monitoring_description">Monitoriza automáticamente la frecuencia cardíaca a lo largo del día</string>
<string name="fmtPaceAverage">Ritmo promedio</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="average_respiration_rate">Frecuencia de la respiración</string>
<string name="breaths_per_min">Respiraciones por minuto</string>
<string name="devicetype_idasen">Escritorios de trabajo IDÅSEN de IKEA</string>
<string name="min_respiration_rate">Frecuencia mínima de la respiración</string>
<string name="hrv_sdrr">VFC SDRR</string>
<string name="idasen_control_button_sit">SENTADO</string>
<string name="idasen_control_button_stand">DE PIE</string>
<string name="idasen_pref_value_warning">El valor debe estar comprendido entre 62 y 126 cm</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="idasen_control_button_mid">MEDIO</string>
<string name="max_respiration_rate">Frecuencia máxima de la respiración</string>
<string name="hrv_rmssd">RMSSD de la variación del ritmo cardíaco</string>
<string name="idasen_pref_sit_height">Altura de la posición sentado (en centímetros)</string>
<string name="idasen_pref_mid_height">Altura de posición media (en centímetros)</string>
<string name="idasen_pref_stand_height">Altura de la posición de pie (en centímetros)</string>
<string name="milliseconds_ms">ms</string>
</resources>

View File

@ -3464,4 +3464,62 @@ Temps de sommeil préféré en heures</string>
<string name="vo2max_running">VO₂ Max en course</string>
<string name="vo2max_cycling">VO₂ Max en cyclisme</string>
<string name="thirty_days_timeline">Timeline 30 jours</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="max_respiration_rate">Fréquence respiratoire max</string>
<string name="devicetype_idasen">IKEA Idasen Desk</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="average_respiration_rate">Fréquence respiratoire</string>
<string name="min_respiration_rate">Fréquence respiratoire min</string>
<string name="hrv_sdrr">VFC SDRR</string>
<string name="milliseconds_ms">ms</string>
<string name="idasen_pref_mid_height">Hauteur de la position moyenne (en centimètres)</string>
<string name="idasen_pref_sit_height">Hauteur de la position assise (en centimètres)</string>
<string name="idasen_pref_stand_height">Hauteur de la position du support (en centimètres)</string>
<string name="idasen_pref_value_warning">La valeur doit être comprise entre 62 - 126 cm</string>
<string name="pref_dashboard_widget_today_time_indicator_summary">Afficher un indicateur à lheure actuelle, pour séparer visuellement les données dhier et daujourdhui</string>
<string name="pref_dnd_follow_phone_title">Suivre le réglage NPD du téléphone</string>
<string name="pref_dnd_follow_phone_summary">Lorsque le mode NPD est activé ou désactivé sur le téléphone, il bascule automatiquement sur lappareil également</string>
<string name="inactivity_warnings_minimum_steps_title">Nombre minimal de pas</string>
<string name="prefs_hrv_monitoring_title">Surveillance de la VFC</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="mijia_lywsd_comfort_temperature_title">Temperature (°C)</string>
<string name="mijia_lywsd_comfort_temperature_summary">Plage recommandée : 19 - 27</string>
<string name="mijia_lywsd_comfort_level_title">Niveau confort</string>
<string name="mijia_lywsd_comfort_humidity_title">Humidité (%)</string>
<string name="mijia_lywsd_comfort_level_summary">Configurer les limites de température et dhumidité pour laffihage d\'emoji</string>
<string name="mijia_lywsd_comfort_lower">limite inférieure</string>
<string name="mijia_lywsd_comfort_upper">Limite supérieure</string>
<string name="mijia_lywsd_comfort_humidity_summary">Plage recommandée : 20 - 85</string>
<string name="pref_summary_sync_birthdays">Synchroniser les anniversaires de contact avec les événements du calendrier</string>
<string name="pref_title_sync_birthdays">Synchroniser les anniversaires</string>
<string name="devicetype_sony_wf_c700n">Sony WF-C700N</string>
<string name="birthdays">Anniversaires</string>
<string name="busy_task_fetch_hrv_data">Récupération des données VFC</string>
<string name="pref_crash_notification_title">Notifier en cas d\'erreur</string>
<string name="pref_crash_notification_summary">Quand l\'application plante, afficher une notification avec l\'erreur</string>
<string name="fmtPaceAverage">Rythme moyen</string>
<string name="hrv_rmssd">VFC RMSSD</string>
<string name="breaths_per_min">inspirations/min</string>
<string name="prefs_hrv_monitoring_description">Surveiller automatiquement la variabilité de la fréquence cardiaque tout au long de la journée</string>
<string name="pref_dashboard_widget_today_yesterday_data_summary">Afficher les données dhier qui sont entre lheure actuelle et minuit</string>
<string name="pref_title_calendar_lookahead">Nombre de jours à venir</string>
<string name="pref_summary_calendar_lookahead">Synchroniser jusquà %1s jours dévénements du calendrier</string>
<string name="app_crash_notification_title">%1s a planté</string>
<string name="app_crash_share_stacktrace">Partager l\'erreur</string>
<string name="hrZoneMaximum">Maximum</string>
<string name="hrZoneThreshold">Seuil</string>
<string name="workout_set_reps">Répétitions</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="devicetype_huawei_watchgtcyber">Huawei Watch GT Cyber</string>
<string name="pref_dashboard_widget_today_time_indicator_title">indicateur d\'instant présent</string>
<string name="pref_dashboard_widget_today_yesterday_data_title">Données d\'hier</string>
<string name="activity_detail_share_json_details">Partager les détails JSON</string>
<string name="number_selected_items">%1d sélectionné</string>
<string name="contact_birthday">Anniversaire de %1s</string>
<string name="paceCorrection">Correction</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="hrZoneEasy">Facile</string>
</resources>

View File

@ -23,9 +23,9 @@
<string name="appmananger_app_reinstall">התקנה מחדש</string>
<string name="appmanager_app_openinstore">חיפוש בחנות היישומונים של Pebble</string>
<string name="appmanager_health_activate">הפעלה</string>
<string name="appmanager_health_deactivate">נטרול</string>
<string name="appmanager_health_deactivate">כיבוי</string>
<string name="appmanager_hrm_activate">הפעלת מעקב דופק</string>
<string name="appmanager_hrm_deactivate">נטרול מעקב דופק</string>
<string name="appmanager_hrm_deactivate">השבתת מעקב דופק</string>
<string name="appmanager_weather_activate">הפעלת יישומון מזג האוויר של המערכת</string>
<string name="appmanager_weather_deactivate">השבתת יישומון מזג האוויר של המערכת</string>
<string name="appmanager_weather_install_provider">התקנת יישומון דיווח מזג האוויר</string>
@ -92,7 +92,7 @@
<string name="pref_title_pebble_sync_misfit">סנכרון Misfit</string>
<string name="pref_title_pebble_sync_morpheuz">סנכרון Morpheuz</string>
<string name="pref_title_enable_outgoing_call">תמיכה בשיחות יוצאות</string>
<string name="pref_summary_enable_outgoing_call">נטרול אפשרות זו גם תנטרל את הרטט לשיחות יוצאות ב־Pebble 2/LE</string>
<string name="pref_summary_enable_outgoing_call">השבתת אפשרות זו גם תשבית את הרטט לשיחות יוצאות ב־Pebble 2/LE</string>
<string name="pref_title_enable_pebblekit">לאפשר גישה ליישומוני צד שלישי באנדרואיד</string>
<string name="pref_summary_enable_pebblekit">הפעלת תמיכה ניסיונית ביישומוני Android באמצעות PebbleKit</string>
<string name="pref_title_sunrise_sunset">זריחה ושקיעה</string>
@ -138,7 +138,7 @@
<string name="test_notification">התראה לבדיקה</string>
<string name="this_is_a_test_notification_from_gadgetbridge">זוהי התראה לבדיקה מ־Gadgetbridge</string>
<string name="bluetooth_is_not_supported_">אין תמיכה ב־Bluetooth.</string>
<string name="bluetooth_is_disabled_">ה־Bluetooth מנוטרל.</string>
<string name="bluetooth_is_disabled_">ה־Bluetooth מושבת.</string>
<string name="tap_connected_device_for_app_mananger">נקישה על ההתקן המחובר למנהל היישומים</string>
<string name="tap_connected_device_for_activity">נקישה על ההתקן המחובר לפעילות</string>
<string name="tap_connected_device_for_vibration">נקישה על ההתקן המחובר לרטט</string>
@ -181,7 +181,7 @@
<string name="miband_pairing_using_dummy_userdata">לא ניתנו נתוני משתמש, נעשה שימוש בנתוני דמה לבינתיים.</string>
<string name="miband_pairing_tap_hint">כאשר ה־Mi Band שלך רוטט ומהבהב, יש לגעת בו מספר פעמים ברצף.</string>
<string name="appinstaller_install">התקנה</string>
<string name="discovery_connected_devices_hint">יש להפעיל את האפשרות לאיתור ההתקן שלך. התקנים שכבר מחוברים כעת לא יתגלו. יש להפעיל מיקום (GPS) באנדרואיד 6+. יש לנטרל את שומר הפרטיות עבור Gadgetbridge כיוון שתכונה זו עשויה להקריס ולהפעיל מחדש את הטלפון שלך. אם לא נמצא אף התקן לאחר מספר דקות יש לנסות שוב לאחר הפעלת הטלפון הנייד שלך מחדש. </string>
<string name="discovery_connected_devices_hint">יש להפעיל את האפשרות לאיתור ההתקן שלך. התקנים שכבר מחוברים כעת לא יתגלו. יש להפעיל מיקום (GPS) באנדרואיד 6+. יש לכבות את שומר הפרטיות עבור Gadgetbridge כיוון שתכונה זו עשויה להקריס ולהפעיל מחדש את הטלפון שלך. אם לא נמצא אף התקן לאחר מספר דקות יש לנסות שוב לאחר הפעלת הטלפון הנייד שלך מחדש.</string>
<string name="discovery_note">לתשומת לבך:</string>
<string name="candidate_item_device_image">תמונת ההתקן</string>
<string name="miband_prefs_alias">שם/כינוי</string>
@ -278,7 +278,7 @@
<string name="abstract_chart_fragment_kind_deep_sleep">שינה עמוקה</string>
<string name="abstract_chart_fragment_kind_not_worn">לא נענד</string>
<string name="device_not_connected">לא מחובר.</string>
<string name="user_feedback_all_alarms_disabled">כל ההתראות מנוטרלות</string>
<string name="user_feedback_all_alarms_disabled">כל ההתראות מושבתות</string>
<string name="pref_title_keep_data_on_device">להשאיר את נתוני הפעילות בהתקן</string>
<string name="miband_fwinstaller_incompatible_version">קושחה בלתי נתמכת</string>
<string name="fwinstaller_firmware_not_compatible_to_device">קושחה זו אינה נתמכת בהתקן</string>
@ -348,7 +348,7 @@
<string name="pebble_pairing_hint">במסך של התקן האנדרואיד שלך אמורה לקפוץ חלונית צימוד. אם החלונית לא מופיעה, יש לחפש במגירת הדיווחים ולאשר את בקשת הצימוד. לאחר מכן יש לאשר את בקשת הצימוד ב־Pebble שלך.</string>
<string name="weather_notification_label">נא לוודא שערכת עיצוב זו מופעלת ביישומון דיווח מזג האוויר כדי לקבל נתוני מזג אוויר ל־Pebble שלך.\n\nלא נדרשות כאן הגדרות.\n\nניתן להפעיל את יישומון מזג האוויר המערכתי של ה־Pebble שלך ממנהל היישומונים.\n\nמסיכות השעון התומכות יציגו את מזג האוויר אוטומטית.</string>
<string name="pref_title_setup_bt_pairing">הפעלת צימוד Bluetooth</string>
<string name="pref_summary_setup_bt_pairing">יש לנטרל זאת אם עולות תקלות בחיבור</string>
<string name="pref_summary_setup_bt_pairing">יש להשבית את זה אם קורות תקלות בחיבור</string>
<string name="unit_metric">מטרית</string>
<string name="unit_imperial">אימפריאלית</string>
<string name="timeformat_24h">24ש׳</string>
@ -909,7 +909,7 @@
<string name="menuitem_worldclock">שעון עולמי</string>
<string name="permission_granting_mandatory">כל ההרשאות האלו נדרשות ואם לא תוענקנה היציבות תתערער</string>
<string name="error_version_check_extreme_caution">אזהרה: בדיקת פרטי הגרסה נתקלה בשגיאה! עדיף שלא להמשיך! הגרסה שנצפתה היא „%s”</string>
<string name="error_background_service_reason">התחלת שירות הרקע נכשלה עקב חריגה. שגיאה:</string>
<string name="error_background_service_reason">התחלת שירות הרקע נכשלה עקב חריגה - נא ללחוץ כאן לפרטים נוספים. \n\nשגיאה:</string>
<string name="error_background_service_reason_truncated">התחלת שירות הרקע נכשל עקב…</string>
<string name="error_background_service">התחלת שירות הרקע נכשלה</string>
<string name="fw_upgrade_notice_miband5">פעולה זו תתקין את הקושחה %s במקום הנוכחית שעל ה־Mi Band 5 שלך.
@ -3015,4 +3015,17 @@
<string name="pref_header_deprecated_functionalities">יכולות עבר</string>
<string name="pref_header_deprecated_functionalities_warning">היכולות הבאות יצאו מכלל שימוש והן תוסרנה בקרוב מהתוכנה.
\nאם צריך להפעיל את אחת מההגדרות הבאות כדאי ליצור קשר עם צוות המיזם.</string>
<string name="pref_summary_sync_birthdays">לסנכרן את ימי ההולדת של אנשי הקשר לצד אירועי לוח שנה</string>
<string name="pref_title_sync_birthdays">סנכרון ימי הולדת</string>
<string name="busy_task_fetch_hrv_data">נתוני שונות קצב לב מעודכנים</string>
<string name="milliseconds_ms">מ״ש</string>
<string name="prefs_hrv_monitoring_description">למדוד שונות קצב לב במהלך היום</string>
<string name="pref_summary_calendar_lookahead">לסנכרן עד %1s ימים של אירועי לוח שנה</string>
<string name="pref_title_calendar_lookahead">מספר הימים מראש</string>
<string name="notif_battery_full">הסוללה של %1$s מלאה</string>
<string name="gps_glonass">GPS + GLONASS</string>
<string name="hr_resting">מנוחה</string>
<string name="hr_maximum">מרבי</string>
<string name="hr_minimum">מזערי</string>
<string name="hr_average">ממוצע</string>
</resources>

View File

@ -550,7 +550,7 @@
<string name="user_feedback_miband_set_alarms_ok">Alarm dikirim ke perangkat.</string>
<string name="live_activity_current_steps_per_minute">Langkah/mnt saat ini</string>
<string name="lefun_prefs_antilost_summary">Gelang akan bergetar ketika ponsel Anda terputus dari gelang</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Benar-benar timpa data saat ini? Semua data aktivitas dan preferensi saat ini (jika ada) akan ditimpa.</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Benar-benar timpa data saat ini? Semua data aktivitas, perangkat, dan preferensi saat ini (jika ada) akan ditimpa.</string>
<string name="dbmanagementactivity_old_activity_db_successfully_deleted">Data aktivitas lawas dihapus.</string>
<string name="StringUtils_sender">(%1$s)</string>
<string name="activity_type_biking">Bersepeda</string>
@ -687,7 +687,7 @@
<string name="pref_enable_unsupported_settings_summary">Ini akan mengaktifkan akses ke semua pengaturan yang tersedia, bahkan jika tidak didukung oleh perangkat. Ini bisa menjadi tidak stabil dan mogok pada perangkat.</string>
<string name="abstract_chart_fragment_kind_rem_sleep">Tidur REM</string>
<string name="user_feedback_all_alarms_disabled">Semua alarm dinonaktifkan</string>
<string name="you_slept">Anda tidur dari %1$s ke %2$s</string>
<string name="you_slept">%1$s - %2$s</string>
<string name="prefs_find_phone_summary">Gunakan gelang Anda untuk memainkan bunyi ponsel Anda.</string>
<string name="mi2_prefs_display_items_summary">Pilih item untuk ditampilkan pada layar gelang</string>
<string name="prefs_password_6_digits_0_to_9_summary">Kata sandi harus memiliki 6 digit, dengan hanya nomor</string>
@ -2949,7 +2949,7 @@
<string name="cyclingPowerAverage">Daya bersepeda rata-rata</string>
<string name="cyclingPowerMin">Daya bersepeda minimum</string>
<string name="cyclingPowerMax">Daya bersepeda maksimum</string>
<string name="huawei_trusleep_warning">Peringatan: mengaktifkan ini akan menghentikan kemunculan tidur di Gadgetbridge! Klik di sini jika Anda menerima hal ini.</string>
<string name="huawei_trusleep_warning">Peringatan: mengaktifkan ini akan membuat semua tidur sebagai tidur ringan di Gadgetbridge! Klik di sini jika Anda menerima hal ini.</string>
<string name="battery_percentage_str">%1$s%%</string>
<string name="toggle_debug_mode">Saklar mode pengawakutuan</string>
<string name="toast_setting_requires_reconnect">Pengaturan ini akan diterapkan setelah penghubungan ulang</string>
@ -2977,7 +2977,7 @@
<string name="moondrop_touch_action_play_pause">Putar/Jeda</string>
<string name="devicetype_garmin_fenix_6_sapphire">Garmin Fenix 6 Sapphire</string>
<string name="devicetype_huawei_band9">Huawei Band 9</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 Pro</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 (Pro)</string>
<string name="garmin_agps_url_i">URL %1$d AGPS</string>
<string name="devicetype_huawei_watchfit3">Huawei Watch Fit 3</string>
<string name="devicetype_garmin_instinct">Garmin Instinct</string>
@ -3078,4 +3078,82 @@
<string name="pref_speak_notifications_focus_exclusive_summary_off">Volume pemutaran aplikasi lain akan direndahkan ketika notifikasi ini diucapkan</string>
<string name="devicetype_garmin_venu_2">Garmin Venu 2</string>
<string name="devicetype_garmin_forerunner_245">Garmin Forerunner 245</string>
<string name="devicetype_miband9">Xiaomi Smart Band 9</string>
<string name="devicetype_amazfit_trex_3">Amazfit T-Rex 3</string>
<string name="devicetype_garmin_forerunner_255_music">Garmin Forerunner 255 Music</string>
<string name="pref_title_notification_times_enabled">Waktu notifikasi</string>
<string name="pref_summary_notification_times_enabled">Hanya kirim notifikasi pada waktu tertentu</string>
<string name="devicetype_redmi_watch_5_active">Redmi Watch 5 Active</string>
<string name="devicetype_colmi_r02">Colmi R02</string>
<string name="devicetype_colmi_r06">Colmi R06</string>
<string name="devicetype_colmi_r03">Colmi R03</string>
<string name="minutes_20">20 menit</string>
<string name="minutes_240">240 menit</string>
<string name="devicetype_garmin_venu_2s">Garmin Venu 2S</string>
<string name="devicetype_micompositionscale">Mi Body Composition Scale 2</string>
<string name="devicetype_mijia_xmwsdj04">Mijia Temperature and Humidity Sensor 2 (E-ink)</string>
<string name="devicetype_honor_watchgs3">Honor Watch GS 3</string>
<string name="devicetype_nothing_cmf_buds_pro_2">CMF Buds Pro 2</string>
<string name="devicetype_nothing_cmf_watch_pro_2">CMF Watch Pro 2</string>
<string name="devicetype_sony_wf_c700n">Sony WF-C700N</string>
<string name="devicetype_soundcore_motion300">Soundcore Motion 300</string>
<string name="devicetype_huawei_watch3">Huawei Watch 3 (Pro)</string>
<string name="devicetype_garmin_fenix_5_plus">Garmin Fenix 5 Plus</string>
<string name="pref_title_calendar_lookahead">Jumlah hari berikut</string>
<string name="pref_summary_calendar_lookahead">Sinkronkan sampai dengan %1s hari dari acara kalender</string>
<string name="minutes_255">255 menit</string>
<string name="devicetype_garmin_fenix_5x_plus">Garmin Fenix 5X Plus</string>
<string name="devicetype_garmin_forerunner_245_music">Garmin Forerunner 245 Music</string>
<string name="devicetype_vivitar_hr_bp_monitor_activity_tracker">Vivitar HR &amp; BP Monitor Activity Tracker</string>
<string name="devicetype_huawei_watchgtrunner">Huawei Watch GT Runner</string>
<string name="pref_time_sync">Sinkronisasi waktu otomatis</string>
<string name="minutes_7">7 menit</string>
<string name="minutes_8">8 menit</string>
<string name="minutes_2">2 menit</string>
<string name="minutes_3">3 menit</string>
<string name="minutes_4">4 menit</string>
<string name="minutes_6">6 menit</string>
<string name="devicetype_huawei_watchgtcyber">Huawei Watch GT Cyber</string>
<string name="minutes_150">150 menit</string>
<string name="devicetype_garmin_venu">Garmin Venu</string>
<string name="devicetype_garmin_forerunner_265s">Garmin Forerunner 265S</string>
<string name="devicetype_garmin_forerunner_965">Garmin Forerunner 965</string>
<string name="devicetype_mismartscale">Mi Smart Scale 2</string>
<string name="devicetype_soundcore_liberty4_nc">Soundcore Liberty 4 NC</string>
<string name="devicetype_honor_watchgspro">Honor Watch GS Pro</string>
<string name="search">Cari</string>
<string name="minutes_9">9 menit</string>
<string name="minutes_15">15 menit</string>
<string name="minutes_45">45 menit</string>
<string name="minutes_60">60 menit</string>
<string name="minutes_75">75 menit</string>
<string name="minutes_90">90 menit</string>
<string name="minutes_120">120 menit</string>
<string name="minutes_180">180 menit</string>
<string name="minutes_210">210 menit</string>
<string name="devicetype_garmin_forerunner_955">Garmin Forerunner 955</string>
<string name="devicetype_garmin_vivosport">Garmin Vívosport</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="devicetype_sony_wf_c500">Sony WF-C500</string>
<string name="devicetype_huawei_watchgt5">Huawei Watch GT 5 (Pro)</string>
<string name="devicetype_ble_gatt_client">Klien Generik BLE GATT</string>
<string name="pref_title_nagivation_apps">Aplikasi navigasi</string>
<string name="pref_header_external_integrations">Integrasi Eksternal</string>
<string name="pref_header_automations">Otomatisasi</string>
<string name="pref_description_general">Pemulaian, bahasa, wilayah, lokasi</string>
<string name="pref_description_about_you">Tanggal lahir, kelamin, tinggi, berat, goal</string>
<string name="pref_description_notifications">Notifikasi aplikasi, daftar putih/hitam</string>
<string name="pref_description_dashboard">Widget, perangkat yang disertakan</string>
<string name="pref_description_automations">Ekspor otomatis, pendapatan data otomatis</string>
<string name="pref_description_developer_options">Log, API intent</string>
<string name="pref_header_main_screen">Layar utama</string>
<string name="pref_title_user_interface">Antarmuka pengguna</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="devicetype_garmin_enduro_3">Garmin Enduro 3</string>
<string name="devicetype_garmin_forerunner_165">Garmin Forerunner 165</string>
<string name="devicetype_garmin_forerunner_255s_music">Garmin Forerunner 255S Music</string>
<string name="pref_description_deprecated_functionalities">Pengaturan yang akan dihapus dalam versi depan</string>
<string name="pref_header_sound">Suara</string>
<string name="pref_description_user_interface">Tema, layar utama</string>
<string name="gps_glonass">GPS + GLONASS</string>
</resources>

View File

@ -309,7 +309,7 @@
<string name="miband_prefs_device_time_offset_hours">Sfasamento dell\'orario per il device (per consentire il rilevamento del sonno per chi lavora a turni)</string>
<string name="miband2_prefs_dateformat">Formato Data</string>
<string name="dateformat_time">Ora</string>
<string name="dateformat_date_time">Ora e data</string>
<string name="dateformat_date_time"><![CDATA[Ora e data]]></string>
<string name="mi2_prefs_goal_notification">Notifica raggiungimento obbiettivi</string>
<string name="mi2_prefs_goal_notification_summary">La band vibrerà una volta raggiunto l\'obbiettivo passi giornalieri</string>
<string name="mi2_prefs_display_items">Elementi mostrati</string>
@ -363,7 +363,7 @@
<string name="dbmanagementactivity_error_exporting_db">Errore esportando il DB: %1$s</string>
<string name="dbmanagementactivity_error_exporting_shared">"Errore nell\'esportazione delle preferenze: %1$s"</string>
<string name="dbmanagementactivity_import_data_title">Importare i dati?</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Vuoi davvero sovrascrivere i dati attuali? Tutti i dati delle tue attività e delle preferenze saranno sovrascritti.</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Vuoi davvero sovrascrivere i dati attuali? Tutti i dati delle tue attività (se presenti), dei dispositivi e delle preferenze saranno sovrascritti.</string>
<string name="dbmanagementactivity_import_successful">Importazione avvenuta con successo.</string>
<string name="dbmanagementactivity_error_importing_db">Errore importando il DB: %1$s</string>
<string name="dbmanagementactivity_error_importing_shared">"Errore nell\'importazione della preferenza: %1$s"</string>
@ -396,7 +396,7 @@
<string name="miband2_prefs_timeformat">Mi2: Formato dell\'orario</string>
<string name="mi2_fw_installhandler_fw53_hint">È necessario installare la verione %1$s prima di installare questo firmware!</string>
<string name="mi2_enable_text_notifications">Notifiche</string>
<string name="mi2_enable_text_notifications_summary">Richiede firmware versione minima 1.9.1.28 e Mili_pro.ft* installati.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Richiede versione firmware >= 1.0.1.28 e Mili_pro.ft* installati.]]></string>
<string name="off">spento</string>
<string name="mi2_dnd_off">Spento</string>
<string name="mi2_dnd_automatic">Automatico (rilevamento del sonno)</string>
@ -512,7 +512,7 @@
<string name="activity_type_activity">Attività</string>
<string name="activity_type_light_sleep">Sonno leggero</string>
<string name="activity_type_deep_sleep">Sonno profondo</string>
<string name="activity_type_not_worn">Device non indossato</string>
<string name="activity_type_not_worn">Dispositivo non indossato</string>
<string name="activity_type_running">Corsa</string>
<string name="activity_type_walking">Camminata</string>
<string name="activity_type_swimming">Nuoto</string>
@ -865,7 +865,7 @@
<string name="pref_header_notifications_and_calls">Notifiche e chiamate</string>
<string name="pref_theme_system">Sistema</string>
<string name="pref_summary_relax_firmware_checks">Allenta i controlli del firmware</string>
<string name="error_background_service_reason">L\'avvio del servizio in background non è riuscito a causa di un\'eccezione. Errore:</string>
<string name="error_background_service_reason">L\'avvio del servizio in background non è riuscito a causa di un\'eccezione - clicca qui per maggiori informazioni.\n\nErrore:</string>
<string name="error_background_service_reason_truncated">L\'avvio del servizio in background non è riuscito perché…</string>
<string name="error_background_service">Impossibile avviare il servizio in background</string>
<string name="error_version_check_extreme_caution">ATTENZIONE: Errore durante la verifica delle informazioni sulla versione! Non dovresti continuare! Visto il nome della versione \"%s\"</string>
@ -1038,7 +1038,7 @@
<string name="activity_type_rowing_machine">Remoergometro</string>
<string name="activity_type_soccer">Calcio</string>
<string name="activity_type_jump_roping">Salti alla corda</string>
<string name="activity_type_indoor_cycling">Spinning</string>
<string name="activity_type_indoor_cycling">Bicicletta su Rulli</string>
<string name="activity_type_swimming_openwater">Nuoto (all\'aperto)</string>
<string name="no">No</string>
<string name="km">km</string>
@ -2410,7 +2410,7 @@
<string name="prefs_wena3_home_icon_name_calories">Calorie</string>
<string name="prefs_wena3_vibration_smart_item">Vibrazione Intelligente</string>
<string name="pref_message_privacy_mode_bodyonly">Nascondi solo il corpo</string>
<string name="prefs_wena3_hint_background_sync">Consenti a Wena di chiedere periodicamente a Gadgetbridge di scaricare i dati di attività dal dispositivo.</string>
<string name="prefs_wena3_hint_background_sync">Consenti a Wena di chiedere periodicamente a Gadgetbridge di scaricare i dati di attività dal dispositivo</string>
<string name="prefs_wena3_vibration_strength_item_medium">Media</string>
<string name="error_invalid_menu_structure">Struttura menu JSON invalida</string>
<string name="prefs_wena3_home_icon_name_pedometer">Contapassi</string>
@ -2695,7 +2695,7 @@
<string name="preferences_qhybrid_settings_summary">Impostazioni obsolete per gli orologi Q Hybrid</string>
<string name="devicetype_huawei_band9">Huawei Band 9</string>
<string name="devicetype_huawei_watchfit3">Huawei Watch Fit 3</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 Pro</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 (Pro)</string>
<string name="impactMax">Impatto massimo</string>
<string name="pref_force_options">Forza le opzioni</string>
<string name="pref_spo_automatic_enable">Abilita la misurazione automatica della SpO2</string>
@ -2810,7 +2810,7 @@
<string name="prefs_wena3_vibration_siren">Sirena</string>
<string name="serial_number">Numero di serie</string>
<string name="pref_navigation_app_osmand">OsmAnd(+)</string>
<string name="huawei_trusleep_warning">Attenzione: attivando questa opzione, le informazioni sul sonno non appariranno in Gadgetbridge! Cliccare qui se accetti.</string>
<string name="huawei_trusleep_warning">Attenzione: attivando questa opzione, tutti i sonni verranno visualizzati come sonni leggeri in Gadgetbridge! Clicca qui se accetti.</string>
<string name="pref_enable_call_accept_summary">Abilita l\'accettazione delle chiamate dal dispositivo</string>
<string name="prefs_wena3_home_icon_name_edy">Saldo Edy</string>
<string name="prefs_wena3_day_start_hour_item">Il giorno inizia alle</string>
@ -2917,4 +2917,595 @@
<string name="sleep_colored_stats_rem">REM</string>
<string name="sleep_colored_stats_deep">Profondo</string>
<string name="gps_glonass">GPS + GLONASS</string>
<string name="milliseconds_ms">ms</string>
<string name="activity_type_tae_bo">Tae Bo</string>
<string name="activity_type_beach_soccer">Calcio da spiaggia</string>
<string name="devicetype_idasen">IKEA Idasen Desk</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="breaths_per_min">Respiri/min</string>
<string name="devicetype_huawei_watchgtrunner">Huawei Watch GT Runner</string>
<string name="devicetype_vivitar_hr_bp_monitor_activity_tracker">Monitor Attività HR &amp; BP Vivitar</string>
<string name="workoutSets">Serie</string>
<string name="thirty_days_timeline">Cronologia 30 giorni</string>
<string name="moondrop_touch_action_anc_mode">Commuta Modalità Cancellazione Attiva Rumore</string>
<string name="moondrop_touch_trigger_long_press_3s">Pressione Prolungata (3s)</string>
<string name="devicetype_huawei_watchgt5">Huawei Watch GT 5 (Pro)</string>
<string name="sleep_colored_stats_rem_avg">AVG REM</string>
<string name="devicetype_garmin_fenix_7">Garmin Fenix 7</string>
<string name="devicetype_garmin_vivosport">Garmin Vívosport</string>
<string name="lactateThresholdHeartRate">Soglia Frequenza Cardiaca del Lattato</string>
<string name="activity_type_navigate">Navigazione</string>
<string name="activity_type_flying">Volo</string>
<string name="activity_type_climb_indoor">Arrampicata al coperto</string>
<string name="activity_type_sky_diving">paracadutismo</string>
<string name="activity_type_tactical">Sport tattico</string>
<string name="activity_type_video_gaming">Video Ludica</string>
<string name="activity_type_mixed_martial_arts">Arti Marziali Miste</string>
<string name="activity_type_aerobic_combo">Aerobica combinata</string>
<string name="activity_type_chess">Scacchi</string>
<string name="activity_type_dragon_boat">Dragon boat</string>
<string name="activity_type_mass_gymnastics">Ginnastica in massa</string>
<string name="activity_type_modern_dance">Danza moderna</string>
<string name="activity_type_pole_dance">Pole dance</string>
<string name="activity_type_shuffleboard">Shuffleboard</string>
<string name="activity_type_stair_climber">Salita su scale</string>
<string name="activity_type_weiqi">Gioco del go</string>
<string name="activity_type_laser_tag">Laser tag</string>
<string name="hrv_status_baseline_label">Linea guida</string>
<string name="devicetype_miband9">Xiaomi Smart Band 9</string>
<string name="devicetype_garmin_forerunner_255s_music">Garmin Forerunner 255S Music</string>
<string name="devicetype_redmi_watch_5_active">Redmi Watch 5 Active</string>
<string name="steps_avg">AVG Passi</string>
<string name="activity_detail_share_json_details">Condividi Dettagli JSON</string>
<string name="moondrop_touch_action_play_pause">Riproduci/Pausa</string>
<string name="moondrop_touch_action_call_pick_hang">Rispondi/Rifiuta Chiamata</string>
<string name="stats_highest_hr">HR massimo</string>
<string name="activity_type_meditation">Meditazione</string>
<string name="activity_type_wakesurfing">Wakesurf</string>
<string name="activity_type_breaking">Breaking</string>
<string name="activity_type_sledding">Pattino</string>
<string name="body_energy_gained">Acquisita</string>
<string name="body_energy_lost">Persa</string>
<string name="devicetype_garmin_forerunner_245_music">Garmin Forerunner 245 Music</string>
<string name="devicetype_sony_wf_c500">Sony WF-C500</string>
<string name="devicetype_honor_watchgs3">Honor Watch GS 3</string>
<string name="menuitem_stress_breakdown">Stress (rottura)</string>
<string name="menuitem_stress_segmented">Stress (segmentato)</string>
<string name="recoveryTime">Tempo di Recupero</string>
<string name="workout_set_i">Serie %1d</string>
<string name="activity_type_mountaineering">Alpinismo</string>
<string name="activity_type_sail_race">Gara di vela</string>
<string name="activity_type_rafting">Rafting</string>
<string name="activity_type_health_snapshot">Panoramica sulla salute</string>
<string name="activity_type_marine">Marittima</string>
<string name="activity_type_finswimming">Finswimming</string>
<string name="activity_type_esports">Sport elettronici</string>
<string name="activity_type_flowriding">Simulatore di surf</string>
<string name="busy_task_fetch_hrv_data">Recupero dati HRV</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="activity_type_stand_up_paddleboarding">Stand Up Paddle</string>
<string name="activity_type_jumpmaster">Jumpmaster</string>
<string name="activity_type_multisport">Sport multipli</string>
<string name="activity_type_floor_climbing">Arrampicata a terra</string>
<string name="activity_type_push_walk_speed">Push - Walk Speed</string>
<string name="activity_type_softball_slow_pitch">Softball a passo lento</string>
<string name="activity_type_indoor_push_walk_speed">Indoor Push - Walk Speed</string>
<string name="activity_type_snorkeling">Snorkeling</string>
<string name="activity_type_somatosensory_game">Gioco somatosensoriale</string>
<string name="activity_type_spinning">Spinning</string>
<string name="activity_type_wall_ball">Wall ball</string>
<string name="devicetype_amazfit_trex_3">Amazfit T-Rex 3</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="devicetype_garmin_venu_2s">Garmin Venu 2S</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="devicetype_soundcore_motion300">Soundcore Motion 300</string>
<string name="pref_title_nagivation_apps">App di navigazione</string>
<string name="pref_header_automations">Automazioni</string>
<string name="pref_description_about_you">Data di nascita, sesso, altezza, peso, obiettivi</string>
<string name="pref_description_developer_options">Registri, API degli intenti</string>
<string name="pref_description_automations">Esportazione automatica, recupero automatico</string>
<string name="pref_header_main_screen">Schermata principale</string>
<string name="pref_title_user_interface">Interfaccia utente</string>
<string name="pref_summary_sync_birthdays">Sincronizza i compleanni dei contatti con gli eventi del calendario</string>
<string name="pref_title_sync_birthdays">Sincronizza i compleanni</string>
<string name="find_my_phone_companion_warning">L\'accoppiamento con il companion è necessario per trovare il telefono. Per ulteriori informazioni, fare clic qui.</string>
<string name="music_upload_info">Si sta per caricare il seguente file musicale:\n\n%1$s\nTitolo della canzone: %2$s\nAlbum: %3$s\n</string>
<string name="authentication_failed_negotiation">Negoziazione della chiave di autenticazione fallita</string>
<string name="activity_type_rem_sleep">Sonno REM</string>
<string name="activity_type_indoor_track">Percorso indoor</string>
<string name="activity_type_kayaking">Kayak</string>
<string name="vo2max_cycling">Massima VO₂ in Ciclismo</string>
<string name="target">Obiettivo</string>
<string name="activity_type_push_run_speed">Push - Run Speed</string>
<string name="activity_type_indoor_push_run_speed">Indoor Push - Run Speed</string>
<string name="activity_type_lacrosse">Lacrosse</string>
<string name="activity_type_water_tubing">Water Tubing</string>
<string name="activity_type_para_sport">Para Sport</string>
<string name="activity_type_ultimate_disc">Ultimate</string>
<string name="activity_type_aerobics">Aerobica</string>
<string name="activity_type_plaza_dancing">Ballo di piazza</string>
<string name="hrv_status_day_avg">Media giornaliera</string>
<string name="activity_type_body_combat">Combattimento corpo a corpo</string>
<string name="hrv_status_day_avg_legend">Media giornalista (ms)</string>
<string name="activity_type_table_football">Biliardino</string>
<string name="activity_type_water_polo">Pallanuoto</string>
<string name="activity_type_biathlon">Biathlon</string>
<string name="devicetype_sony_wf_c700n">Sony WF-C700N</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="devicetype_colmi_r06">Colmi R06</string>
<string name="distance_total">Distanza Totale</string>
<string name="pref_header_hrv_status">Stato HRV</string>
<string name="body_energy">Energia Corporea</string>
<string name="moondrop_touch_trigger">Attivazione</string>
<string name="pref_wide_area_tap_title">Selezione area ampia</string>
<string name="min_respiration_rate">Frequenza Minima Respiro</string>
<string name="average_respiration_rate">Frequenza Respiro</string>
<string name="max_respiration_rate">Frequenza Massima Respiro</string>
<string name="hrv_sdrr">HRV SDRR</string>
<string name="hrv_rmssd">HRV RMSSD</string>
<string name="fmtPaceAverage">Media del ritmo</string>
<string name="activity_type_bike_commute">Bici Pendolari</string>
<string name="activity_type_handcycling_indoor">Handcycling al coperto</string>
<string name="activity_type_fitness_equipment">Attrezzature fitness</string>
<string name="activity_type_platform_tennis">Piattaforma Tennis</string>
<string name="activity_type_racket">Racchetta</string>
<string name="activity_type_grinding">Grind</string>
<string name="activity_type_padel">Padel</string>
<string name="activity_type_racquetball">Racquetball</string>
<string name="activity_type_disc_golf">Golf a disco</string>
<string name="activity_type_bridge">Bridge</string>
<string name="activity_type_ballroom_dance">Ballo da sala</string>
<string name="activity_type_board_game">Giochi da tavola</string>
<string name="activity_type_bocce">Bocce</string>
<string name="activity_type_cardio_combat">Cardio combat</string>
<string name="activity_type_muay_thai">Muay thai</string>
<string name="activity_type_race_walking">Gara podistica</string>
<string name="activity_type_square_dance">Quadriglia</string>
<string name="activity_type_tug_of_war">Tiro alla fune</string>
<string name="activity_type_free_sparring">Free sparring</string>
<string name="activity_type_obstacle_race">Corsa a ostacoli</string>
<string name="activity_type_billiard_pool">Biliardo</string>
<string name="activity_type_canoeing">Canoa</string>
<string name="activity_type_water_scooter">Moto d\'acqua</string>
<string name="activity_type_bobsleigh">Guidoslitta</string>
<string name="activity_type_bungee_jumping">Bungee jumping</string>
<string name="activity_type_orienteering">Orienteering</string>
<string name="hrv_status_seven_days_avg">Media a 7 giorni</string>
<string name="hrv_status_balanced">Bilanciato</string>
<string name="hrv_status_unbalanced">Sbilanciato</string>
<string name="hrv_status_low">Basso</string>
<string name="hrv_status_baseline">%1$d-%2$d ms</string>
<string name="bpm_value_unit">%1$d bpm</string>
<string name="hrv_status_poor">Scarso</string>
<string name="hrv_status_unit">%1$d ms</string>
<string name="steps_distance_unit">%1$,.2f km</string>
<string name="body_energy_legend_level">Livello Energia del Corpo</string>
<string name="devicetype_garmin_forerunner_255_music">Garmin Forerunner 255 Music</string>
<string name="devicetype_garmin_forerunner_265s">Garmin Forerunner 265S</string>
<string name="devicetype_mismartscale">Mi Smart Scale 2</string>
<string name="pref_title_calendar_lookahead">Numero di giorni di anticipo</string>
<string name="pref_summary_calendar_lookahead">Sincronizza fino a %1s giorni di eventi del calendario</string>
<string name="sleep_colored_stats_deep_avg">AVG Profonda</string>
<string name="sleep_colored_stats_light_avg">AVG Leggera</string>
<string name="transition">Transizione</string>
<string name="app_crash_share_stacktrace">Condividi errore</string>
<string name="steps_total">Passi totali</string>
<string name="distance_avg">Distanza media</string>
<string name="workout_set_repetitions">%1d x</string>
<string name="RunningForm">Forma nella Corsa</string>
<string name="hrZoneEasy">Facile</string>
<string name="activity_type_bmx">BMX</string>
<string name="devicetype_huawei_watch3">Huawei Watch 3 (Pro)</string>
<string name="devicetype_colmi_r02">Colmi R02</string>
<string name="devicetype_colmi_r03">Colmi R03</string>
<string name="workout_set_repetitions_weight_kg">%1d x %2$.2f kg</string>
<string name="workout_set_repetitions_weight_lbs">%1d x %2$.2f lbs</string>
<string name="devicetype_nothing_cmf_buds_pro_2">CMF Buds Pro 2</string>
<string name="devicetype_nothing_cmf_watch_pro_2">CMF Watch Pro 2</string>
<string name="moondrop_touch_action_assistant">Attiva Assistente Vocale</string>
<string name="moondrop_touch_action_call_start">Inizia Chiamata</string>
<string name="activity_type_worn">Indossato</string>
<string name="estimatedSweatLoss">Perdita di sudore stimata</string>
<string name="hrv">HRV</string>
<string name="activity_type_bouldering">Sassismo</string>
<string name="activity_type_winter_sport">Sport Invernale</string>
<string name="activity_type_air_walker">Air walker</string>
<string name="activity_type_artistic_swimming">Nuoto sincronizzato</string>
<string name="activity_type_team_sport">Sport di Squadra</string>
<string name="activity_type_parallel_bars">Parallele</string>
<string name="activity_type_hip_hop">Hip-hop</string>
<string name="activity_type_hula_hoop">Hula hoop</string>
<string name="activity_type_jai_alai">Jai alai</string>
<string name="activity_type_judo">Judo</string>
<string name="activity_type_jujitsu">Jujitsu</string>
<string name="activity_type_cross_trainer">Cyclette ellittica</string>
<string name="pref_time_sync">Sincronizzazione automatica orario</string>
<string name="minutes_2">2 minuti</string>
<string name="dateformat_day_month">Giorno, Mese</string>
<string name="dateformat_month_day">Mese, Giorno</string>
<string name="activity_type_snowshoe">Ciaspolata</string>
<string name="activity_type_hacky_sack">Hacky sack</string>
<string name="busy_task_fetch_sleep_data">Recupero dati del sonno</string>
<string name="user_feedback_set_settings_ok">Impostazioni inviate al dispositivo.</string>
<string name="minutes_15">15 minuti</string>
<string name="devicetype_huawei_watchgtcyber">Huawei Watch GT Cyber</string>
<string name="menuitem_map">Mappa</string>
<string name="pref_crash_notification_title">Notifica arresto anomalo</string>
<string name="pref_crash_notification_summary">Quando l\'applicazione si blocca, mostra una notifica con l\'errore</string>
<string name="app_crash_notification_title">%1s si è arrestato</string>
<string name="vo2max_running">Massima VO₂ in Corsa</string>
<string name="weight_lbs">%1$.2f lbs</string>
<string name="paceCorrection">Correzione</string>
<string name="workout_set_reps">Ripetizioni</string>
<string name="sleep_colored_stats_awake_avg">AVG Sveglio</string>
<string name="activity_type_transition">Transizione</string>
<string name="activity_type_breathwork">Lavoro sul respiro</string>
<string name="activity_type_xc_classic_ski">Sci XC Classico</string>
<string name="activity_type_sail_expedition">Spedizione in barca a vela</string>
<string name="activity_type_wakeboarding">Wakeboard</string>
<string name="activity_type_shooting">Sport di tiro</string>
<string name="activity_type_folk_dance">Danza popolare</string>
<string name="activity_type_frisbee">Frisbee</string>
<string name="activity_type_futsal">Futsal</string>
<string name="weight_kg">%1$.2f kg</string>
<string name="abstract_chart_fragment_kind_awake_sleep">Sveglio</string>
<string name="stats_lowest_hr">HR minimo</string>
<string name="pref_header_sound">Audio</string>
<string name="activity_type_sepak_takraw">Sepak Takraw</string>
<string name="activity_type_snowmobiling">Motoslitta</string>
<string name="activity_type_water_skiing">Sci Nautico</string>
<string name="devicetype_garmin_fenix_5_plus">Garmin Fenix 5 Plus</string>
<string name="hrZoneThreshold">Soglia</string>
<string name="hrZoneMaximum">Massimo</string>
<string name="prefs_light_duration_longer">Durata maggiore della luce</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">Il numero di minuti in cui il grafico mostra \'indossato\' dopo ogni misurazione corretta della frequenza cardiaca</string>
<string name="choose_device">Scegli un dispositivo</string>
<string name="no_supported_devices_found">Non sono stati trovati dispositivi supportati</string>
<string name="menuitem_stress_simple">Stress (semplice)</string>
<string name="search">Cerca</string>
<string name="devicetype_garmin_enduro_3">Garmin Enduro 3</string>
<string name="devicetype_garmin_fenix_5x_plus">Garmin Fenix 5X Plus</string>
<string name="hr_resting">A riposo</string>
<string name="hr_maximum">Massimo</string>
<string name="hr_minimum">Minimo</string>
<string name="hr_average">Media</string>
<string name="minutes_3">3 minuti</string>
<string name="minutes_45">45 minuti</string>
<string name="minutes_75">75 minuti</string>
<string name="minutes_90">90 minuti</string>
<string name="minutes_180">180 minuti</string>
<string name="minutes_210">210 minuti</string>
<string name="minutes_240">240 minuti</string>
<string name="minutes_255">255 minuti</string>
<string name="stress_average">Media</string>
<string name="activity_type_hang_gliding">Deltaplano</string>
<string name="activity_type_inline_skating">Pattinaggio in linea</string>
<string name="activity_type_checkers">Dama</string>
<string name="devicetype_garmin_venu">Garmin Venu</string>
<string name="devicetype_garmin_forerunner_955">Garmin Forerunner 955</string>
<string name="devicetype_soundcore_liberty4_nc">Soundcore Liberty 4 NC</string>
<string name="menuitem_heart_rate_push">Frequenza Cardiaca Push</string>
<string name="menuitem_night_display">Visualizzazione notturna</string>
<string name="moondrop_equalizer_preset_monitor">Controllo</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="devicetype_garmin_forerunner_165">Garmin Forerunner 165</string>
<string name="devicetype_garmin_forerunner_965">Garmin Forerunner 965</string>
<string name="devicetype_mijia_xmwsdj04">Sensore Temperatura e Umidità Mijia 2 (E-ink)</string>
<string name="devicetype_micompositionscale">Mi Body Composition Scale 2</string>
<string name="menuitem_weight">Peso</string>
<string name="hrv_status_seven_days_avg_status">Stato</string>
<string name="hrv_status_last_night">Ultima notte</string>
<string name="hrv_status_last_night_highest_5">Ultima notte max media 5 min</string>
<string name="hrv_status_seven_days_avg_long">Media 7 giorni</string>
<string name="pref_header_external_integrations">Integrazioni Esterne</string>
<string name="pref_description_general">Avvio, lingua, zona, posizione</string>
<string name="pref_description_notifications">Notifiche delle app, whitelist/blacklist</string>
<string name="pref_description_user_interface">Tema, schermata principale</string>
<string name="pref_description_dashboard">Widget, dispositivi da includere</string>
<string name="pref_description_deprecated_functionalities">Impostazioni che saranno rimosse in una versione futura</string>
<string name="minutes_4">4 minuti</string>
<string name="minutes_6">6 minuti</string>
<string name="minutes_7">7 minuti</string>
<string name="minutes_8">8 minuti</string>
<string name="minutes_9">9 minuti</string>
<string name="minutes_120">120 minuti</string>
<string name="minutes_150">150 minuti</string>
<string name="activity_prefs_date_birth">Data di nascita</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="devicetype_honor_watchgspro">Honor Watch GS Pro</string>
<string name="moondrop_equalizer_preset_basshead">A Testa Bassa</string>
<string name="soundcore_voice_prompts">Prompt Vocali</string>
<string name="moondrop_touch_trigger_long_press_1s">Pressione Prolungata (1s)</string>
<string name="mijia_lywsd_comfort_humidity_title">Umidità (%)</string>
<string name="mijia_lywsd_comfort_lower">Limite Inferiore</string>
<string name="mijia_lywsd_comfort_upper">Limite Superiore</string>
<string name="idasen_control_button_mid">MED</string>
<string name="idasen_control_button_sit">SED</string>
<string name="idasen_pref_mid_height">Altezza della posizione centrale (in centimetri)</string>
<string name="idasen_control_button_stand">ALTO</string>
<string name="idasen_pref_value_warning">Il valore deve essere compreso tra 62 e 126 cm</string>
<string name="soundcore_ldac_mode_title">Modalità LDAC</string>
<string name="soundcore_ldac_mode_summary">L\'attivazione di LDAC riduce la durata della batteria e potrebbe causare l\'instabilità della connessione</string>
<string name="soundcore_adaptive_direction_title">Direzione Adattiva</string>
<string name="notification_channel_connection_status_name">Stato Connessione</string>
<string name="uploading_watchface">Caricamento quadrante…</string>
<string name="pref_force_connection_type_ble">Bluetooth LE</string>
<string name="widget_move_down">Muovi giù</string>
<string name="warning_missing_notification_permission">Impossibile pubblicare una notifica in corso a causa di un\'autorizzazione mancante</string>
<string name="pref_test_features_title">Funzioni</string>
<string name="widget_move_up">Muovi su</string>
<string name="pref_test_features_summary">Funzioni abilitate per questo dispositivo di test</string>
<string name="miscale_weight_unit_metric">Metrica (kg)</string>
<string name="miscale_weight_unit_imperial">Imperiale (lb)</string>
<string name="miscale_weight_unit_chinese">Cinese (jin)</string>
<string name="mijia_lywsd_comfort_level_title">Livello Comfort</string>
<string name="wake_up_time">Sveglia</string>
<string name="widget_name_untitled">Widget senza titolo (%1$s)</string>
<string name="pref_title_fossil_hr_navigation_instructions">Istruzioni Navigazione</string>
<string name="pref_summary_fossil_hr_navigation_instructions">Configurare il comportamento dell\'app di navigazione nell\'orologio</string>
<string name="activity_info">Info attività</string>
<string name="soundcore_button_brightness">Luminosità dei pulsanti</string>
<string name="soundcore_button_brightness_low">Bassa</string>
<string name="soundcore_button_brightness_high">Alta</string>
<string name="soundcore_button_brightness_medium">Media</string>
<string name="button_open_menu_companion">Apri menu della app del companion</string>
<string name="widget_name_colored_tile">%1$s (tessera colorata)</string>
<string name="scan_scanning_multiple_devices">Scansione di %d dispositivi</string>
<string name="pref_app_connection_duration">Durata connessione app</string>
<string name="widget_missing_parts">Seleziona tutti i widget</string>
<string name="pref_title_fossil_hr_nav_vibrate">Vibra con nuove istruzioni</string>
<string name="uploadwatchfaceoperation_in_progress">Caricamento quadrante</string>
<string name="uploadwatchfaceoperation_complete">Installazione quadrante completata</string>
<string name="uploadwatchfaceoperation_failed">Installazione quadrante fallita</string>
<string name="pref_force_connection_type_bt_classic">Bluetooth Classica</string>
<string name="mijia_lywsd_comfort_temperature_title">Temperatura (°C)</string>
<string name="widget_layout">Aspetto widget</string>
<string name="auto_reconnect_ble_scan_summary">Attendere la scansione del dispositivo invece di tentare la connessione alla cieca</string>
<string name="widget_unknown_workout">Esercizio sconosciuto - %s</string>
<string name="scan_not_scanning">Non scansionando</string>
<string name="unbind_before_pair_message">Questo dispositivo è già collegato nelle impostazioni di Android, il che può far fallire l\'associazione per alcuni dispositivi.\n\nSe l\'aggiunta del dispositivo non riesce, rimuoverlo dalle impostazioni di Android e riprovare.</string>
<string name="unbind_before_pair_title">Già collegato</string>
<string name="companion_pairing_request_title">Dispositivo companion</string>
<string name="mijia_lywsd_comfort_level_summary">Configurare i limiti di temperatura e umidità per le emoji visualizzate</string>
<string name="idasen_pref_sit_height">Altezza della posizione seduta (in centimetri)</string>
<string name="idasen_pref_stand_height">Altezza della posizione in piedi (in centimetri)</string>
<string name="mijia_lywsd_comfort_temperature_summary">Intervallo consigliato: 19 - 27</string>
<string name="mijia_lywsd_comfort_humidity_summary">Intervallo consigliato: 20 - 85</string>
<string name="widget_subtype">Sottotipo Widget</string>
<string name="error_scan_failed">Scansione fallita: %d</string>
<string name="auto_reconnect_ble_scan_title">Riconnessione tramite scansione BLE</string>
<string name="pref_summary_fossil_hr_nav_foreground">Se la app di navigazione deve passare automaticamente in primo piano quando riceve un\'istruzione di navigazione</string>
<string name="prompt_restart_gadgetbridge">Riavviare GB affinché abbia effetto.</string>
<string name="soundcore_equalizer_direction">Direzione Dispositivo</string>
<string name="soundcore_adaptive_direction_summary">Regola automaticamente la preimpostazione dell\'equalizzatore in base alla direzione del dispositivo</string>
<string name="pref_summary_fossil_hr_nav_vibrate">Se l\'orologio deve vibrare ad ogni istruzione di navigazione nuova o modificata (solo quando l\'applicazione è in primo piano)</string>
<string name="pref_force_connection_type_title">Forza tipo di connessione</string>
<string name="pref_force_connection_type_description">Si può provare a forzare il tipo di connessione nel caso in cui il dispositivo non risponda a Gadgetbridge</string>
<string name="pref_force_connection_type_auto">Automatica</string>
<string name="device_state_waiting_scan">In attesa della scansione del dispositivo</string>
<string name="pref_continuous_skin_temperature_measurement_description">Il recupero della temperatura non è attualmente supportato. Questa impostazione abilita solo la misurazione continua sul dispositivo</string>
<string name="pref_continuous_skin_temperature_measurement_title">Misurazione continua temperatura della pelle</string>
<string name="pref_title_fossil_hr_nav_foreground">Porta in primo piano</string>
<string name="soundcore_equalizer_direction_lying">Sdraiato</string>
<string name="waiting_for_bluetooth">Attesa del bluetooth…</string>
<string name="notification_channel_scan_service_name">Servizio di scansione</string>
<string name="pref_sleep_mode_schedule_summary">Invia un promemoria e attiva la modalità di riposo al momento di coricarsi. All\'ora di sveglia programmata, la sveglia suonerà.</string>
<string name="scan_scanning_all_devices">Scansione di tutti i dispositivi</string>
<string name="scan_scanning_single_device">Scansione di 1 dispositivo</string>
<string name="soundcore_equalizer_band7">Banda 7</string>
<string name="soundcore_equalizer_band8">Banda 8</string>
<string name="soundcore_equalizer_band9">Banda 9</string>
<string name="soundcore_equalizer_frequency">Frequenza</string>
<string name="soundcore_equalizer_value">Valore</string>
<string name="miscale_weight_unit_title">Unità di Peso</string>
<string name="miscale_weight_unit_summary">Imposta l\'unità di peso per le misure visualizzate</string>
<string name="soundcore_equalizer_band1">Banda 1</string>
<string name="soundcore_equalizer_band2">Banda 2</string>
<string name="soundcore_equalizer_band3">Banda 3</string>
<string name="soundcore_equalizer_band4">Banda 4</string>
<string name="soundcore_equalizer_band5">Banda 5</string>
<string name="soundcore_equalizer_band6">Banda 6</string>
<string name="soundcore_equalizer_preset">Predisposizione</string>
<string name="soundcore_equalizer_preset_signature">Firma soundcore</string>
<string name="soundcore_equalizer_preset_xtra_bass">Bass eXtra</string>
<string name="soundcore_equalizer_direction_standing">In piedi</string>
<string name="soundcore_equalizer_reset_summary">Riporta tutte le bande dell\'equalizzatore alle impostazioni predefinite</string>
<string name="soundcore_equalizer_direction_hanging">Appeso</string>
<string name="miscale_small_objects_summary">Memorizzare il peso di oggetti più leggeri di 10 kg</string>
<string name="miscale_small_objects_title">Piccoli Oggetti</string>
<string name="error_menu_companion_not_installed">\'HR Menu Companion\' probabilmente non installata</string>
<string name="soundcore_equalizer_preset_voice">Voce</string>
<string name="soundcore_equalizer_preset_balanced">Bilanciato</string>
<string name="soundcore_equalizer_custom_title">Personalizza…</string>
<string name="soundcore_equalizer_custom_summary">Configura impostazioni equalizzatore parametrico</string>
<string name="soundcore_equalizer_reset_title">Ripristina predefinito</string>
<string name="menuitem_focus">Focus</string>
<string name="bedtime">Sonno</string>
<string name="pref_sleep_mode_schedule_title">Programma Modalità A Riposo</string>
<string name="prefs_wena3_status_page_title">Ordinamento Pagina di Stato</string>
<string name="devicesetting_scannable_minimum_unseen_summary">Dopo la scansione, il dispositivo deve rimanere non visibile per questo periodo di tempo prima di essere nuovamente registrato</string>
<string name="devicesetting_scannable_rssi_summary">La soglia RSSI minima per il rilevamento</string>
<string name="state_scanned">Scansionato</string>
<string name="devicesetting_scannable_debounce">Timeout di smorzamento scansionabilità (secondi)</string>
<string name="devicesetting_scannable_minimum_unseen">Tempo minimo non visibile (secondi)</string>
<string name="companion_pairing_request_description">Accoppiare questo dispositivo come companion?\n\nQuesta opzione è consigliata per alcune funzioni, come la ricerca del dispositivo, e garantisce una connessione migliore.</string>
<string name="devicesetting_scannable_rssi">Soglia RSSI minima</string>
<string name="devicesetting_scannable_debounce_summary">Dopo la scansione, il dispositivo viene mantenuto come scansionato e ignorato per il periodo di tempo specificato</string>
<string name="devicetype_scannable">Dispositivi scansionabili</string>
<string name="error_showing_changelog">Errore di visualizzazione del registro modifiche</string>
<string name="bottom_nav_devices">Dispositivi</string>
<string name="bottom_nav_dashboard">Cruscotto</string>
<string name="pref_dashboard_first_title">Mostra prima il cruscotto</string>
<string name="dashboard_settings">Impostazioni Dashboard</string>
<string name="pref_dashboard_cards_summary">Disegnare tessere intorno ai widget del cruscotto</string>
<string name="pref_dashboard_first_summary">Mostra il cruscotto all\'avvio di Gadgetbridge, invece della schermata dei dispositivi</string>
<string name="pref_auto_reply_calls_title">Rispondi automaticamente alle chiamate telefoniche</string>
<string name="pref_auto_reply_calls_summary">Il telefono risponde automaticamente alle chiamate in arrivo</string>
<string name="pref_summary_bottom_navigation_bar_off">Passa da una schermata principale all\'altra solo con lo swipe orizzontale</string>
<string name="pref_dashboard_all_devices_title">Tutti i dispositivi</string>
<string name="pref_dashboard_widget_goals_chart_title">Grafico obiettivi</string>
<string name="pref_title_garmin_default_reply_suffix">Utilizza un suffisso di risposta predefinito</string>
<string name="pref_dashboard_widget_today_upside_down_title">Mezzanotte in basso</string>
<string name="pref_dashboard_devices_to_include">Dispositivi da includere</string>
<string name="pref_dashboard_widget_show_legend_title">Mostra legenda</string>
<string name="pref_summary_garmin_default_reply_suffix">Appendice in aggiunta al suffisso impostato in Gadgetbridge</string>
<string name="pref_dashboard_select_devices_summary">Combina i dati di attività da dispositivi specifici per i totali sul cruscotto</string>
<string name="pref_dashboard_widget_today_24h_summary">Mostra l\'attività in un singolo cerchio di 24 ore invece che in un due cerchi concentrici di 12 ore</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Intervallo frequenza cardiaca</string>
<string name="pref_auto_reply_calls_delay_title">Ritardo Risposta Automatica</string>
<string name="pref_speak_notifications_aloud_summary">Le notifiche saranno lette ad alta voce attraverso le cuffie</string>
<string name="pref_speak_notifications_aloud_title">Leggi Notifiche ad Alta Voce</string>
<string name="pref_auto_reply_calls_delay_summary">Numero di secondi dopo i quali si risponde automaticamente alla chiamata</string>
<string name="pref_dashboard_select_devices_title">Seleziona dispositivi...</string>
<string name="dashboard_calendar_month_goals_reached_title">% dei passi raggiunti</string>
<plurals name="amount_of_days">
<item quantity="one">%d giorno</item>
<item quantity="many">%d di giorni</item>
<item quantity="other">%d giorni</item>
</plurals>
<string name="pref_dashboard_widget_double_size_title">Dimensione raddoppiata</string>
<string name="pref_dashboard_widget_today_upside_down_summary">In modalità 24 ore, disegna la mezzanotte in basso e il mezzogiorno in alto nel grafico</string>
<string name="pref_dashboard_widgets_order_summary">Seleziona quali widget sono abilitati e in quale ordine vengono visualizzati sul cruscotto</string>
<string name="pref_dashboard_widget_settings">Impostazioni widget</string>
<string name="pref_dashboard_widget_today_title">Grafico attività</string>
<string name="pref_dashboard_widget_today_24h_title">Modalità 24 ore</string>
<string name="pref_speak_notifications_focus_exclusive_title">Metti in pausa l\'audio di altre applicazioni</string>
<string name="pref_speak_notifications_focus_exclusive_summary_on">La riproduzione di altre applicazioni viene messa in pausa durante l\'ascolto della notifica</string>
<string name="pref_dashboard_cards_title">Mostra i widget sulle tessere</string>
<string name="pref_speak_notifications_focus_exclusive_summary_off">Il volume di riproduzione delle altre applicazioni verrà abbassato durante la notifica</string>
<string name="pref_header_calls_and_notifications">Chiamate e notifiche</string>
<string name="pref_title_bottom_navigation_bar">Barra di navigazione inferiore</string>
<string name="pref_summary_bottom_navigation_bar_on">Passa da una schermata principale all\'altra utilizzando la barra di navigazione o lo scorrimento orizzontale</string>
<string name="pref_dashboard_widget_double_size_summary">Consenti al widget di occupare due colonne sul cruscotto</string>
<string name="pref_dashboard_widget_show_legend_summary">Mostra una legenda sotto il widget che spieghi il significato dei colori</string>
<string name="pref_dashboard_all_devices_summary">Somma i dati delle attività di tutti i dispositivi aggiunti per i totali sul cruscotto</string>
<string name="pref_sleepasandroid_slot_title">Registri sveglie</string>
<string name="chart_cycling_point_label_distance">Oggi: %.1f km\nTotale: %.1f km</string>
<string name="copied_to_clipboard">Copiato negli appunti</string>
<string name="pref_sleepasandroid_enable_summary">Attiva l\'integrazione di Sleep As Android</string>
<string name="pref_sleepasandroid_device_title">Dispositivo fornitore</string>
<string name="pref_sleepasandroid_features_title">Caratteristiche</string>
<string name="pref_sleepasandroid_feat_spo2">SpO2</string>
<string name="pref_title_huawei_account">Account Huawei</string>
<string name="open_camera">Apri Fotocamera</string>
<string name="toast_camera_permission_required">Per questa funzione è necessaria l\'autorizzazione della fotocamera.</string>
<string name="toast_camera_support_required">Per questa funzione è necessario il supporto della fotocamera.</string>
<string name="toast_camera_photo_taken">La foto è stata scattata e salvata in: %s</string>
<string name="toggle_debug_mode">Imposta modalità debug</string>
<string name="battery_full_threshold">Soglia batteria ricaricata</string>
<string name="cannot_upload_watchface_too_many_watchfaces_installed">Impossibile caricare il quadrante, troppi quadranti installati</string>
<string name="alarm_slot_reset">Il registro della sveglia è stato reimpostato</string>
<string name="garmin_agps_local_file">Documenti locali</string>
<string name="battery_percentage_str">%1$s%%</string>
<string name="pref_fetch_unknown_files_title">Recuperare file sconosciuti</string>
<string name="device_name_bicycle_sensor">Sensore Bici</string>
<string name="pref_sleepasandroid_device_summary">Seleziona il dispositivo come fornitore di dati Sleep As Android</string>
<string name="folder_is_empty">La cartella è vuota</string>
<string name="sleepasandroid_settings">Sleep As Android</string>
<string name="insufficient_space_for_upload">Spazio insufficiente per il caricamento</string>
<string name="pref_summary_cycling_persistence_interval">Intervallo in secondi per la scrittura dei dati ciclistici correnti nel database</string>
<string name="pref_summary_huawei_account">Un account Huawei utilizzato nel processo di associazione. L\'impostazione consente l\'accoppiamento senza reset di fabbrica.</string>
<string name="watchface_resolution_doesnt_match">La risoluzione del quadrante non corrisponde allo schermo del dispositivo. La superficie dell\'orologio è %1$s lo schermo del dispositivo è %2$s</string>
<string name="pref_battery_polling_configuration">Configurazione controllo batteria</string>
<string name="url">URL</string>
<string name="pref_garmin_agps_help">L\'elenco seguente contiene tutti gli URL richiesti dall\'orologio per gli aggiornamenti AGPS. È possibile selezionare un file dalla memoria del telefono che verrà inviato all\'orologio quando richiede un aggiornamento.</string>
<string name="max_val">Massimo: %d</string>
<string name="folder">Cartella</string>
<string name="show_in_notification">Mostra nella notifica</string>
<string name="share_debug_info">Condividi le informazioni di debug</string>
<string name="battery_low_notify_enabled">Notifica batteria scarica</string>
<string name="realtime_settings">Impostazioni in tempo reale</string>
<string name="unsupported">Non supportato</string>
<string name="no_folder_selected">Nessuna cartella selezionata</string>
<string name="default_percentage">Predefinito (%1$d%%)</string>
<string name="battery_low_threshold">Soglia batteria scarica</string>
<string name="battery_full_notify_enabled">Notifica batteria ricaricata</string>
<string name="min_val">Minimo: %d</string>
<string name="pref_sleepasandroid_feat_oximetry">Ossimetria</string>
<string name="pref_summary_wheel_diameter">Diametro della ruota in pollici. In genere 29, 27,5 o 26.</string>
<string name="pref_sleepasandroid_feat_heartrate">Battito cardiaco</string>
<string name="pref_battery_polling_interval_format">Ogni %1$s minuti</string>
<string name="pref_title_cycling_persistence_interval">Intervallo di persistenza</string>
<string name="pref_sleepasandroid_feat_notifications">Notifiche</string>
<string name="pref_sleepasandroid_feat_movement">Accelerometro</string>
<string name="garmin_agps_url_i">URL AGPS %1$d</string>
<string name="pref_sleepasandroid_feat_alarms">Sveglie</string>
<string name="pref_sleepasandroid_slot_summary">Quale registro delle sveglia utilizzare quando se ne imposta una</string>
<string name="battery_polling_failed_start">Impossibile avviare il controllo della batteria</string>
<string name="title_cycling">Ciclismo</string>
<string name="chart_cycling_point_label_speed">%.1f km/h</string>
<string name="toast_setting_requires_reconnect">Questa impostazione avrà effetto dopo una nuova connessione</string>
<string name="pref_battery_polling_enable">Abilita controllo batteria</string>
<string name="pref_battery_polling_interval">Intervallo controllo batteria</string>
<string name="none">Nessuno</string>
<string name="pref_battery_polling_summary">Si tratta di un grosso sforzo, che potrebbe essere rimandato per diverse ragioni</string>
<string name="pref_sleepasandroid_features_summary">Il supporto varia da dispositivo a dispositivo</string>
<string name="device_name_cycling_sensor">Sensore di pedalata</string>
<string name="devicetype_cycling_sensor">Sensore di velocità ciclistica</string>
<string name="number_selected_items">%1d selezionati</string>
<string name="pref_fetch_unknown_files_summary">Recupera i file di attività sconosciuti dall\'orologio. Non verranno elaborati, ma saranno salvati nel telefono.</string>
<string name="pref_title_wheel_diameter">Diametro ruota</string>
<string name="loading">Caricamento…</string>
<string name="backup_restore_exporting_preferences">Esportazione preferenze…</string>
<string name="inactivity_warnings_minimum_steps_summary">Quantità minima di passi che devono essere compiuti durante i minuti di soglia</string>
<string name="backup_restore_exporting_database">Esportazione banca dati.…</string>
<string name="smart_ring_measurement_error_worn_incorrectly">Errore di misurazione. I sensori dell\'anello sono orientati correttamente?</string>
<string name="prefs_summary_gatt_client_allow_gatt_interactions">Consente di inviare comandi di lettura/scrittura e di connessione della caratteristica BLE</string>
<string name="prefs_summary_gatt_client_device_state_updates">Ricevere le modifiche allo stato della connessione BLE tramite gli Intenti</string>
<string name="activity_db_management_backup_restore_explanation">Le operazioni di importazione/esportazione consentono di migrare o eseguire il backup di tutte le impostazioni, i dispositivi e i dati di Gadgetbridge da e verso un file zip.\n\nL\'importazione di un file rimuove tutti i dati, i dispositivi e le preferenze esistenti, sostituendoli completamente con il backup.</string>
<string name="backup_restore_exporting_finishing">Conclusione esportazione…</string>
<string name="backup_restore_importing">Importazione da zip…</string>
<string name="label_distance_trip">Parziale: %.1f km</string>
<string name="backup_restore_restart_title">Riavvia</string>
<string name="devicetype_ble_gatt_client">Client generico BLE GATT</string>
<string name="pref_deprecated_media_control_summary">Invia i comandi di controllo dei media come eventi chiave invece che come controller dei media.</string>
<string name="backup_restore_exporting_files_i_of_n">Esportazione file... %1d di %2d</string>
<string name="backup_restore_importing_loading">Caricamento file…</string>
<string name="backup_restore_exporting_files">Esportazione file…</string>
<string name="backup_restore_restart_summary">%1s verrà riavviato.</string>
<string name="label_distance_total_mph">Totale: %.1f mi</string>
<string name="file_already_exists">File già esistente</string>
<string name="prefs_title_gatt_client_notification_intents">Trasmissione di Intenti di notifica GATT tramite API Intenti BLE</string>
<string name="backup_restore_error_export">Esportazione in zip fallita</string>
<string name="error_no_cycling_sensor_found">Non è stato trovato alcun sensore di ciclismo</string>
<string name="pref_dnd_follow_phone_title">Segui l\'impostazione ND del telefono</string>
<string name="prefs_hrv_monitoring_title">Monitoraggio HRV</string>
<string name="prefs_hrv_monitoring_description">Monitoraggio automatico della variabilità della frequenza cardiaca durante la giornata</string>
<string name="pref_header_deprecated_functionalities_warning">Le seguenti funzionalità sono state deprecate e saranno presto rimosse dal software.\nSe avete bisogno di attivare una delle seguenti impostazioni, contattate il team del progetto.</string>
<string name="pref_deprecated_media_control_title">Controllo multimediale deprecato</string>
<string name="prefs_title_gatt_client_api_package">Pacchetto API BLE</string>
<string name="prefs_title_ble_intent_api">API Intenti BLE</string>
<string name="prefs_summary_gatt_client_api_package">Limita la comunicazione dell\'API Intenti BLE a questo pacchetto</string>
<string name="contact_birthday">Compleanno di %1s</string>
<string name="birthdays">Compleanni</string>
<string name="pref_header_deprecated_functionalities">Funzionalità deprecate</string>
<string name="backup_restore_importing_files_i_of_n">Importazione file... %1d di %2d</string>
<string name="backup_restore_error_import">Importazione da zip fallita</string>
<string name="backup_restore_abort_import_confirmation">Annullare l\'importazione? Ciò potrebbe comportare una banca dati corrotta o inconsistente.</string>
<string name="inactivity_warnings_minimum_steps_title">Numero minimo di passi</string>
<string name="activity_db_management_backup_restore_label">Salvataggio e Ripristino</string>
<string name="backup_restore_importing_database">Importazione banca dati…</string>
<string name="backup_restore_importing_preferences">Importazione preferenze…</string>
<string name="backup_restore_export_complete">Esportazione completata</string>
<string name="activity_db_management_import_from_zip">Importa zip</string>
<string name="backup_restore_import_complete">Importazione completata</string>
<string name="backup_restore_do_not_exit">%s tieni aperta questa schermata fino al termine dell\'operazione.</string>
<string name="pref_dashboard_widget_today_yesterday_data_title">Dati di ieri</string>
<string name="pref_dashboard_widget_today_time_indicator_title">Indicatore dell\'ora attuale</string>
<string name="backup_restore_abort_title">Interrompi</string>
<string name="backup_restore_abort_export_confirmation">Annullare l\'esportazione? Il zip parziale sarà cancellato.</string>
<string name="prefs_summary_gatt_client_notification_intents">Ricevere le modifiche alle caratteristiche BLE tramite gli Intenti</string>
<string name="activity_db_management_export_to_zip">Esporta zip</string>
<string name="backup_restore_importing_validating">Validazione file…</string>
<string name="pref_dashboard_widget_today_yesterday_data_summary">Mostra i dati di ieri oscurati tra l\'ora attuale e la mezzanotte</string>
<string name="pref_dnd_follow_phone_summary">Quando la funzione ND è attivata o disattivata sul telefono, viene attivata automaticamente anche sul dispositivo</string>
<string name="label_distance_total">Totale: %.1f km</string>
<string name="label_distance_trip_mph">Parziale: %.1f mi</string>
<string name="smart_ring_measurement_error_unknown">Errore di misura sconosciuto %d ricevuto dall\'anello</string>
<string name="prefs_title_gatt_client_allow_gatt_interactions">Consentire l\'interazione con il GATT attraverso l\'API Intenti BLE</string>
<string name="backup_restore_warning_files">%1d file non ripristinati: \n%2s</string>
<string name="pref_dashboard_widget_today_time_indicator_summary">Mostra un indicatore all\'ora corrente, per separare visivamente i dati di ieri e di oggi</string>
<string name="backup_restore_exporting">Esportazione in formato zip…</string>
<string name="devicetype_sony_wi_c100">Sony WI-C100</string>
</resources>

View File

@ -343,7 +343,7 @@
<string name="miband_prefs_device_time_offset_hours">Apparaat-tijdsverschuiving in uren (voor het detecteren van slaap van werknemers in ploegendienst)</string>
<string name="miband2_prefs_dateformat">Datumformaat</string>
<string name="dateformat_time">Tijd</string>
<string name="dateformat_date_time">Tijd &amp; datum</string>
<string name="dateformat_date_time"><![CDATA[Tijd & datum]]></string>
<string name="mi2_prefs_button_actions">Knoppen acties</string>
<string name="mi2_prefs_button_actions_summary">Specificeer actie voor knop druk</string>
<string name="mi2_prefs_button_press_count">Aantal knopdrukken</string>
@ -451,7 +451,7 @@
<string name="miband2_prefs_timeformat">Mi2: Tijdsformaat</string>
<string name="mi2_fw_installhandler_fw53_hint">U moet versie %1$s installeren voordat u deze firmware installeert!</string>
<string name="mi2_enable_text_notifications">Tekst meldingen</string>
<string name="mi2_enable_text_notifications_summary">Vereist dat firmware &gt;= 1.0.1.28 en Mili_pro.ft* geïnstalleerd is.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Vereist dat firmware >= 1.0.1.28 en Mili_pro.ft* geïnstalleerd is.]]></string>
<string name="off">Uit</string>
<string name="mi2_dnd_off">Uit</string>
<string name="mi2_dnd_automatic">Automatisch (slaap detectie)</string>
@ -910,7 +910,7 @@
<string name="pref_title_weather_summary">Gebruikt voor de LineageOS-weeraanbieder, andere Android versies moeten een app zoals \"Weather notification\" gebruiken. Meer informatie is te vinden in de Gadgetbridge wiki.</string>
<string name="menuitem_worldclock">Wereld Klok</string>
<string name="error_background_service_reason_truncated">Het starten van de achtergrondservice is mislukt omdat…</string>
<string name="error_background_service_reason">Het starten van de achtergronddienst is mislukt vanwege een uitzondering. Fout:</string>
<string name="error_background_service_reason">Het starten van de achtergrondservice is mislukt door een probleem. Klik hier voor meer informatie.\n\nFout:</string>
<string name="error_background_service">Kan de achtergrondservice niet starten</string>
<string name="error_version_check_extreme_caution">LET OP: Fout bij het controleren van versie-informatie! Je moet niet doorgaan! Zag versienaam \"%s\"</string>
<string name="permission_granting_mandatory">Al deze toestemmingen zijn vereist en er kan instabiliteit ontstaan als ze niet worden verleend</string>
@ -3482,4 +3482,46 @@
<string name="activity_detail_share_json_details">Deel JSON-details</string>
<string name="number_selected_items">%1d geselecteerd</string>
<string name="paceCorrection">Correctie</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="mijia_lywsd_comfort_upper">Maximum</string>
<string name="mijia_lywsd_comfort_lower">Minimum</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="mijia_lywsd_comfort_level_summary">Stel de temperatuur- en luchtvochtigheidslimieten in voor de weergegeven emoji</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="mijia_lywsd_comfort_level_title">Comfortniveau</string>
<string name="mijia_lywsd_comfort_temperature_title">Temperatuur (°C)</string>
<string name="mijia_lywsd_comfort_temperature_summary">Aangeraden bereik: 19 - 27</string>
<string name="mijia_lywsd_comfort_humidity_title">Luchtvochtigheid (%)</string>
<string name="mijia_lywsd_comfort_humidity_summary">Aangeraden bereik: 20 - 85</string>
<string name="busy_task_fetch_hrv_data">HRV-gegevens ophalen</string>
<string name="pref_dnd_follow_phone_title">Volg niet-storenstand</string>
<string name="pref_dnd_follow_phone_summary">Wanneer \"niet storen\" wordt in- of uitgeschakeld op de telefoon, verander de instelling op het apparaat mee</string>
<string name="inactivity_warnings_minimum_steps_title">Minimum aantal stappen</string>
<string name="inactivity_warnings_minimum_steps_summary">Minimaal aantal stappen dat gezet moet worden binnen de minutendrempel</string>
<string name="prefs_hrv_monitoring_title">HRV-monitoring</string>
<string name="prefs_hrv_monitoring_description">Automatisch de hele dag de variabiliteit van hartslag in de gaten houden</string>
<string name="average_respiration_rate">Ademhalingsfrequentie</string>
<string name="max_respiration_rate">Maximale ademhalingsfrequentie</string>
<string name="min_respiration_rate">Minimale ademhalingsfrequentie</string>
<string name="hrv_sdrr">HRV SDRR</string>
<string name="hrv_rmssd">HRV RMSSD</string>
<string name="breaths_per_min">ademhaling/min</string>
<string name="fmtPaceAverage">Tempo gemiddeld</string>
<string name="milliseconds_ms">ms</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="devicetype_idasen">IKEA Idasen bureau</string>
<string name="idasen_control_button_mid">Midden</string>
<string name="idasen_control_button_sit">Zitten</string>
<string name="idasen_control_button_stand">Staan</string>
<string name="idasen_pref_mid_height">Middenpositie (in centimeters)</string>
<string name="idasen_pref_value_warning">De waarde moet tussen 62 en 126 cm zijn</string>
<string name="idasen_pref_sit_height">Zitpositie (in centimeters)</string>
<string name="idasen_pref_stand_height">Stapositie (in centimeters)</string>
<string name="music_upload_info">U staat op het punt om het volgende muziekbestand te uploaden:\n\n%1$s\nTitel: %2$s\nAlbum: %3$s\n</string>
<string name="devicetype_garmin_fenix_7">Garmin Fenix 7</string>
<string name="file_already_exists">Bestand bestaat al</string>
</resources>

View File

@ -192,7 +192,7 @@
<string name="pbw_install_handler_unable_to_install">Nie można zainstalować podanego pliku : %1$s</string>
<string name="pbw_install_handler_hw_revision_mismatch">Instalacja tego oprogramowania jest niemożliwa, ponieważ nie pasuje do wersji sprzętowej twojego Pebble.</string>
<string name="installer_activity_wait_while_determining_status">Proszę czekać na określanie statusu instalacji…</string>
<string name="notif_battery_low_title">Bateria gadżetu prawie rozładowana!</string>
<string name="notif_battery_low_title">Gadżet prawie rozładowany!</string>
<string name="notif_battery_low_percent">%1$s pozostało baterii: %2$s%%</string>
<string name="notif_battery_low_bigtext_last_charge_time">Ostatnie ładowanie: %s
\n</string>
@ -318,7 +318,7 @@
<string name="clock">Zegar</string>
<string name="heart_rate">Tętno</string>
<string name="battery">Bateria</string>
<string name="dateformat_date_time">Data i czas</string>
<string name="dateformat_date_time"><![CDATA[Data i czas]]></string>
<string name="mi2_prefs_button_actions">Akcje przycisku</string>
<string name="mi2_prefs_button_actions_summary">Wybierz akcję po przyciśnięciu przycisku</string>
<string name="mi2_prefs_button_press_count">Licznik wciśnięć przycisku</string>
@ -2800,9 +2800,9 @@
<string name="minutes_20">20 minut</string>
<string name="sleep_colored_stats_deep">Głęboki</string>
<string name="sleep_colored_stats_light">Płytki</string>
<string name="sleep_colored_stats_deep_avg">Głęboki średni</string>
<string name="sleep_colored_stats_light_avg">Płytki średni</string>
<string name="sleep_colored_stats_rem_avg">REM średni</string>
<string name="sleep_colored_stats_deep_avg">Średnia głębokiegio</string>
<string name="sleep_colored_stats_light_avg">Średnia płytkiego</string>
<string name="sleep_colored_stats_rem_avg">Średnia REM</string>
<string name="stats_empty_value">-</string>
<string name="pref_header_audio">Audio</string>
<string name="minutes_60">60 minut</string>
@ -2862,7 +2862,7 @@
<string name="armenian">Ormiański</string>
<string name="devicetype_garmin_vivomove_trend">Garmin Vívomove Trend</string>
<string name="swolfMin">Minimalny swolf</string>
<string name="notif_battery_full_title">Bateria gadżetu naładowana!</string>
<string name="notif_battery_full_title">Gadżet naładowany!</string>
<string name="url">URL</string>
<string name="authentication_failed_check_key">Uwierzytelnienie nie powiodło się, proszę sprawdź klucz autoryzacji</string>
<string name="battery_full_notify_enabled">Powiadom o pełnym naładowaniu baterii</string>
@ -3431,4 +3431,10 @@
<string name="pref_title_sync_birthdays">Synchronizuj urodziny</string>
<string name="contact_birthday">Urodziny: %1s</string>
<string name="birthdays">Urodziny</string>
<string name="pref_dnd_follow_phone_summary">Gdy tryb „bie przeszkadzać” jest włączany, lub wyłączany w telefonie, automatycznie przełącz go również na urządzeniu</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="pref_dnd_follow_phone_title">Śledź ustawienia trybu „nie przeszkadzać” w telefonie</string>
<string name="pref_title_calendar_lookahead">Liczba kolejnych dni</string>
<string name="pref_summary_calendar_lookahead">Synchronizuj wydarzenia z kalendarza do %1s dni</string>
</resources>

View File

@ -3233,4 +3233,8 @@
<string name="hrv_status_balanced">Сбалансированное</string>
<string name="hrv_status_unbalanced">Несбалансированное</string>
<string name="devicetype_soundcore_motion300">Soundcore Motion 300</string>
<string name="activity_type_table_football">Настольный футбол</string>
<string name="idasen_control_button_stand">СТОЯ</string>
<string name="idasen_control_button_sit">СИДЯ</string>
<string name="idasen_pref_value_warning">Значение должно быть в пределах 62-126 см</string>
</resources>

View File

@ -152,7 +152,7 @@
<string name="controlcenter_start_activitymonitor">Etkinliğiniz</string>
<string name="controlcenter_start_configure_alarms">Alarmları yapılandır</string>
<string name="controlcenter_take_screenshot">Ekran Görüntüsü Al</string>
<string name="dateformat_date_time">Saat ve tarih</string>
<string name="dateformat_date_time"><![CDATA[Saat ve tarih]]></string>
<string name="dateformat_time">Saat</string>
<string name="dbaccess_error_executing">\'%1$s\' çalıştırılırken hata oluştu</string>
<string name="dbmanagementactivity_database_successfully_deleted">Veriler silindi.</string>
@ -389,7 +389,7 @@
<string name="mi2_dnd_off">Kapalı</string>
<string name="mi2_dnd_scheduled">Zamanlandı (zaman aralığı)</string>
<string name="mi2_enable_text_notifications">Metin bildirimleri</string>
<string name="mi2_enable_text_notifications_summary">1.0.1.28 veya üstü bir ürün yazılımı ve Mili_pro.ft* kurulu olması gerekiyor.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[1.0.1.28 veya üstü bir ürün yazılımı ve Mili_pro.ft* kurulu olması gerekiyor.]]></string>
<string name="mi2_fw_installhandler_fw53_hint">Bu ürün yazılımını kurmadan önce %1$s sürümünü kurmalısınız!</string>
<string name="mi2_prefs_activate_display_on_lift">Kaldırma anında ekranı etkinleştir</string>
<string name="mi2_prefs_button_action">Düğme eylemini etkinleştir</string>
@ -3495,4 +3495,43 @@
<string name="paceCorrection">Düzeltme</string>
<string name="activity_detail_share_json_details">JSON Ayrıntılarını Paylaş</string>
<string name="number_selected_items">%1d seçildi</string>
<string name="devicetype_garmin_fenix_8">Garmin Fenix 8</string>
<string name="devicetype_garmin_venu_sq">Garmin Venu Sq</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="mijia_lywsd_comfort_temperature_summary">Tavsiye edilen aralık: 19 - 27</string>
<string name="mijia_lywsd_comfort_level_title">Rahatlık Seviyesi</string>
<string name="mijia_lywsd_comfort_level_summary">Görüntülenen emoji için sıcaklık ve nem sınırlarını yapılandırın</string>
<string name="mijia_lywsd_comfort_humidity_title">Nem (%)</string>
<string name="date_placeholders__date__time">%1s, %1s</string>
<string name="mijia_lywsd_comfort_temperature_title">Sıcaklık (°C)</string>
<string name="mijia_lywsd_comfort_humidity_summary">Tavsiye edilen aralık: 20 - 85</string>
<string name="mijia_lywsd_comfort_lower">Alt Sınır</string>
<string name="mijia_lywsd_comfort_upper">Üst Sınır</string>
<string name="devicetype_garmin_venu_sq_2">Garmin Venu Sq 2</string>
<string name="devicetype_garmin_fenix_6s_sapphire">Garmin Fenix 6S Sapphire</string>
<string name="inactivity_warnings_minimum_steps_title">Asgari adım sayısı</string>
<string name="inactivity_warnings_minimum_steps_summary">Eşik dakikaları boyunca atılması gereken asgari adım sayısı</string>
<string name="prefs_hrv_monitoring_title">Kalp Ritmi Değişkenliği izleme</string>
<string name="prefs_hrv_monitoring_description">Gün boyunca kalp ritmi değişkenliğini otomatik olarak izle</string>
<string name="busy_task_fetch_hrv_data">Kalp Ritmi Değişkenliği verileri alınıyor</string>
<string name="pref_dnd_follow_phone_title">Telefon Rahatsız Etme ayarını takip et</string>
<string name="pref_dnd_follow_phone_summary">Telefonda Rahatsız Etme etkinleştirildiğinde veya devre dışı bırakıldığında, aygıtta da otomatik olarak geçiş yap</string>
<string name="average_respiration_rate">Solunum Hızı</string>
<string name="hrv_rmssd">Kalp Ritmi Değişkenliği RMSSD</string>
<string name="milliseconds_ms">ms</string>
<string name="max_respiration_rate">En Yüksek Solunum Hızı</string>
<string name="min_respiration_rate">En Düşük Solunum Hızı</string>
<string name="hrv_sdrr">Kalp Ritmi Değişkenliği SDDR</string>
<string name="breaths_per_min">nefes/dak</string>
<string name="fmtPaceAverage">Hız ortalaması</string>
<string name="devicetype_huawei_watchd2">Huawei Watch D2</string>
<string name="devicetype_idasen">IKEA Idasen Desk</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="idasen_control_button_mid">ORTA</string>
<string name="idasen_control_button_sit">OTUR</string>
<string name="idasen_control_button_stand">AYAKTA</string>
<string name="idasen_pref_mid_height">Orta konum yüksekliği (santimetre cinsinden)</string>
<string name="idasen_pref_stand_height">Ayakta konumu yüksekliği (santimetre cinsinden)</string>
<string name="idasen_pref_value_warning">Değer 62 - 126 cm arasında olmalıdır</string>
<string name="idasen_pref_sit_height">Otur konumu yüksekliği (santimetre cinsinden)</string>
</resources>

View File

@ -355,7 +355,7 @@
<string name="miband_prefs_reserve_alarm_calendar">Будильники для резервування майбутніх подій</string>
<string name="miband_prefs_hr_sleep_detection">Використовувати датчик пульсу для поліпшення виявлення сну</string>
<string name="dateformat_time">Час</string>
<string name="dateformat_date_time">Дата й час</string>
<string name="dateformat_date_time"><![CDATA[Дата й час]]></string>
<string name="pref_title_unit_system">Одиниці вимірювання</string>
<string name="tap_connected_device_for_vibration">Торкніться під\'єднаного пристрою для вібрації</string>
<string name="pairing">Створення пари з %s…</string>
@ -645,7 +645,7 @@
\n*.log — файли журналів
\nЕкспортовані файли (або помістіть сюди файли для імпорту) розміщено тут:</string>
<string name="dbmanagementactivvity_cannot_access_export_path">Неможливо отримати доступ до теки для експорту. Будь ласка, зверніться до розробників.</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Дійсно перезаписати поточні дані? Всі поточні дані про діяльність (якщо вони є) та налаштування будуть перезаписані.</string>
<string name="dbmanagementactivity_overwrite_database_confirmation">Дійсно перезаписати поточні дані? Усі поточні дані про діяльність (якщо вони є) пристрої та налаштування будуть перезаписані.</string>
<string name="dbmanagementactivity_really_delete_entire_db">Дійсно видалити всю базу даних? Всі ваші дані про діяльність та дані про ваші пристрої будуть втрачені.</string>
<string name="dbmanagementactivity_delete_old_activity_db">Видалити стару базу даних?</string>
<string name="dbmanagementactivity_delete_old_activitydb_confirmation">Дійсно видалити стару базу даних діяльностей? Дані, які не були імпортовані, будуть втрачені.</string>
@ -663,7 +663,7 @@
<string name="pref_title_setup_bt_pairing">Увімкніть створення пари через Bluetooth</string>
<string name="pref_summary_setup_bt_pairing">Вимкніть це, якщо у вас виникають проблеми з під\'єднанням</string>
<string name="mi2_fw_installhandler_fw53_hint">Перед встановленням цієї мікропрограми спочатку потрібно встановити версію %1$s!</string>
<string name="mi2_enable_text_notifications_summary">Потрібна мікропрограма &gt;= 1.0.1.28 та встановлений Mili_pro.ft*.</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[Потрібна мікропрограма >= 1.0.1.28 та встановлений Mili_pro.ft*.]]></string>
<string name="off">Вимкнути</string>
<string name="mi2_dnd_off">Вимкнути</string>
<string name="discovery_attempting_to_pair">Спроба створення пари з %1$s</string>
@ -2839,7 +2839,7 @@
<string name="devicetype_huawei_watchfit">Huawei Watch Fit</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="devicetype_honor_magicwatch2">Honor MagicWatch 2</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 Pro</string>
<string name="devicetype_huawei_watch4pro">Huawei Watch 4 (Pro)</string>
<string name="devicetype_huawei_band9">Huawei Band 9</string>
<string name="devicetype_huawei_watchgt2">Huawei Watch GT 2 (Pro)</string>
<string name="devicetype_mijia_mho_c303">Mijia MHO-C303</string>

View File

@ -320,7 +320,7 @@
<string name="miband_prefs_device_time_offset_hours">设备时间偏移 (用于检测倒班工作人员的睡眠)</string>
<string name="miband2_prefs_dateformat">日期格式</string>
<string name="dateformat_time">仅时间</string>
<string name="dateformat_date_time">时间和日期</string>
<string name="dateformat_date_time"><![CDATA[时间和日期]]></string>
<string name="mi2_prefs_button_actions">按钮操作</string>
<string name="mi2_prefs_button_actions_summary">指定按钮按下时的操作</string>
<string name="mi2_prefs_button_press_count">按钮按下计数</string>
@ -424,7 +424,7 @@
<string name="miband2_prefs_timeformat">小米手环2时间格式</string>
<string name="mi2_fw_installhandler_fw53_hint">您需要安装版本号为%1$s的固件在安装此固件前</string>
<string name="mi2_enable_text_notifications">文本通知</string>
<string name="mi2_enable_text_notifications_summary">需要已安装固件1.0.1.28 和 Mili_pro. ft * 。</string>
<string name="mi2_enable_text_notifications_summary"><![CDATA[ 需要已安装固件版大于或等于 1.0.1.28 和 Mili_pro. ft * 。]]></string>
<string name="off"></string>
<string name="mi2_dnd_off"></string>
<string name="mi2_dnd_automatic">自动 (睡眠检测)</string>
@ -909,7 +909,7 @@
<string name="pref_title_weather_summary">由LineageOS天气服务提供其他版本的Android系统需要使用诸如“Weather notification”。更多信息请访问 Gadgetbridge 的Wiki。</string>
<string name="menuitem_worldclock">世界时钟</string>
<string name="permission_granting_mandatory">所有权限都是必须的,若未授予这些权限,可能会导致不稳定</string>
<string name="error_background_service_reason">由于意外错误,启动后台服务失败:</string>
<string name="error_background_service_reason">由于意外错误,启动后台服务失败。 - 点击此处查看更多详情。\n\n错误</string>
<string name="error_background_service_reason_truncated">无法启动后台服务是由于…</string>
<string name="error_background_service">启动后台服务失败</string>
<string name="error_version_check_extreme_caution">注意:检查版本信息时发生错误!您不应该继续下去,已知版本名“%s”</string>
@ -3482,4 +3482,46 @@
<string name="paceCorrection">修正</string>
<string name="number_selected_items">已选择 %1d</string>
<string name="activity_detail_share_json_details">分享 JSON 详情</string>
<string name="devicetype_garmin_fenix_8">佳明 Fenix 8</string>
<string name="devicetype_garmin_venu_sq">佳明 Venu Sq</string>
<string name="mijia_lywsd_comfort_upper">上限</string>
<string name="date_placeholders__date__time">%1s%1s</string>
<string name="date_placeholders__start_time__end_time">%1s - %2s</string>
<string name="mijia_lywsd_comfort_level_title">舒适度</string>
<string name="mijia_lywsd_comfort_level_summary">配置显示表情符号的温度和湿度限制</string>
<string name="mijia_lywsd_comfort_temperature_title">摄氏度</string>
<string name="mijia_lywsd_comfort_temperature_summary">推荐范围19 - 27</string>
<string name="mijia_lywsd_comfort_humidity_title">湿度</string>
<string name="mijia_lywsd_comfort_humidity_summary">推荐范围: 20 - 85</string>
<string name="mijia_lywsd_comfort_lower">下限</string>
<string name="devicetype_garmin_venu_sq_2">佳明 Venu Sq 2</string>
<string name="devicetype_garmin_fenix_6s_sapphire">佳明 Fenix 6S Sapphire</string>
<string name="busy_task_fetch_hrv_data">获取心率变异性数据</string>
<string name="hrv_sdrr">心跳间隔时间的标准偏差</string>
<string name="hrv_rmssd">HRV典型时域指标</string>
<string name="inactivity_warnings_minimum_steps_title">最少步数</string>
<string name="average_respiration_rate">呼吸频率</string>
<string name="max_respiration_rate">最大呼吸率</string>
<string name="min_respiration_rate">最低呼吸频率</string>
<string name="fmtPaceAverage">平均配速</string>
<string name="pref_dnd_follow_phone_title">遵循电话免打扰设置</string>
<string name="pref_dnd_follow_phone_summary">当手机上启用或禁用免打扰时,也会在设备上自动切换</string>
<string name="breaths_per_min">呼吸/分钟</string>
<string name="milliseconds_ms">毫秒</string>
<string name="inactivity_warnings_minimum_steps_summary">在阈值分钟内需要采取的最少步数</string>
<string name="prefs_hrv_monitoring_title">心率监控</string>
<string name="prefs_hrv_monitoring_description">自动监测全天心率变异性</string>
<string name="devicetype_huawei_watchd2">华为 Watch D2</string>
<string name="idasen_control_button_sit"></string>
<string name="idasen_control_button_mid"></string>
<string name="idasen_control_button_stand"></string>
<string name="idasen_pref_mid_height">中间位置高度(厘米)</string>
<string name="idasen_pref_sit_height">坐姿高度(厘米)</string>
<string name="idasen_pref_stand_height">站立高度(厘米)</string>
<string name="idasen_pref_value_warning">该值必须在 62 - 126 厘米之间</string>
<string name="devicetype_idasen">宜家伊朵森书桌</string>
<string name="devicetype_colmi_r10">Colmi R10</string>
<string name="file_already_exists">文件已存在</string>
<string name="music_upload_info">您将要上传以下音乐文件:\n\n%1$s\n音乐标题%2$s\n专辑%3$s\n</string>
<string name="devicetype_garmin_fenix_7">佳明 Fenix 7</string>
</resources>

View File

@ -3113,6 +3113,7 @@
<item>@string/pref_header_spo2</item>
<item>@string/menuitem_temperature</item>
<item>@string/menuitem_weight</item>
<item>@string/menuitem_calories</item>
</string-array>
<string-array name="pref_charts_tabs_values">
@ -3131,6 +3132,7 @@
<item>@string/p_spo2</item>
<item>@string/p_temperature</item>
<item>@string/p_weight</item>
<item>@string/p_calories</item>
</string-array>
<string-array name="pref_charts_tabs_items_default">
@ -3150,6 +3152,7 @@
<item>@string/p_spo2</item>
<item>@string/p_temperature</item>
<item>@string/p_weight</item>
<item>@string/p_calories</item>
</string-array>
@ -4250,6 +4253,9 @@
<item>@string/menuitem_vo2_max</item>
<item>@string/vo2max_running</item>
<item>@string/vo2max_cycling</item>
<item>@string/menuitem_calories_goal</item>
<item>@string/menuitem_calories_active_goal</item>
<item>@string/menuitem_calories_segmented</item>
</string-array>
<string-array name="pref_dashboard_widgets_order_values">
@ -4267,6 +4273,9 @@
<item>vo2max</item>
<item>vo2max_running</item>
<item>vo2max_cycling</item>
<item>calories</item>
<item>calories_active</item>
<item>calories_segmented</item>
</string-array>
<string-array name="pref_dashboard_widgets_order_default">
@ -4280,5 +4289,8 @@
<item>stress_segmented</item>
<item>hrv</item>
<item>vo2max</item>
<item>calories</item>
<item>calories_active</item>
<item>calories_segmented</item>
</string-array>
</resources>

View File

@ -61,6 +61,8 @@
<color name="body_energy_level_color" type="color">#5ac234</color>
<color name="body_energy_lost_color" type="color">#ff6c43</color>
<color name="steps_color" type="color">#00c9bf</color>
<color name="calories_color" type="color">#fa4502</color>
<color name="calories_resting_color" type="color">#1f49f2</color>
<color name="value_line_color" type="color">#858585</color>
<color name="row_separator_light" type="color">#ffe2e2e5</color>

View File

@ -926,6 +926,7 @@
<string name="updatefirmwareoperation_failed_low_mtu">Current MTU of %1$d is too low, please enable high MTU in the device settings and disconnect/re-connect the device.</string>
<string name="chart_steps">Steps</string>
<string name="calories">Calories</string>
<string name="active_calories">Active calories</string>
<string name="distance">Distance</string>
<string name="clock">Clock</string>
<string name="heart_rate">Heart rate</string>
@ -933,6 +934,11 @@
<string name="hr_maximum">Maximum</string>
<string name="hr_minimum">Minimum</string>
<string name="hr_average">Average</string>
<string name="active">Active</string>
<string name="active_goal">Active goal</string>
<string name="total_goal">Total goal</string>
<string name="total_burnt">Total burnt</string>
<string name="goal">Goal</string>
<string name="blood_pressure">Blood pressure</string>
<string name="getting_heart_rate">Measuring</string>
<string name="heart_rate_result">Measurement results</string>
@ -1228,6 +1234,7 @@
<string name="activity_prefs_activetime_minutes">Daily target: active time in minutes</string>
<string name="activity_prefs_goal_standing_time_minutes">Daily target: standing time in minutes</string>
<string name="activity_prefs_goal_fat_burn_time_minutes">Daily target: fat burn time in minutes</string>
<string name="activity_prefs_goal_active_calories_burnt">Daily target: active calories burnt</string>
<string name="active_time">Active time</string>
<string name="standing_time">Standing time</string>
<string name="pref_title_pebble_health_store_raw">Store raw record in the database</string>
@ -1751,6 +1758,7 @@
<string name="devicetype_garmin_instinct_2_soltac">Garmin Instinct 2 SolTac</string>
<string name="devicetype_garmin_instinct_crossover">Garmin Instinct Crossover</string>
<string name="devicetype_garmin_forerunner_165">Garmin Forerunner 165</string>
<string name="devicetype_garmin_forerunner_235">Garmin Forerunner 235</string>
<string name="devicetype_garmin_forerunner_245">Garmin Forerunner 245</string>
<string name="devicetype_garmin_forerunner_245_music">Garmin Forerunner 245 Music</string>
<string name="devicetype_garmin_forerunner_255">Garmin Forerunner 255</string>
@ -1821,6 +1829,7 @@
<string name="devicetype_sony_wf_1000xm5">Sony WF-1000XM5</string>
<string name="devicetype_sony_wf_c500">Sony WF-C500</string>
<string name="devicetype_sony_wf_c700n">Sony WF-C700N</string>
<string name="devicetype_sony_wi_c100">Sony WI-C100</string>
<string name="devicetype_sony_wi_sp600n">Sony WI-SP600N</string>
<string name="devicetype_sony_linkbuds">Sony LinkBuds</string>
<string name="devicetype_sony_linkbuds_s">Sony LinkBuds S</string>
@ -1929,6 +1938,9 @@
<string name="menuitem_stress_simple">Stress (simple)</string>
<string name="menuitem_stress_segmented">Stress (segmented)</string>
<string name="menuitem_stress_breakdown">Stress (breakdown)</string>
<string name="menuitem_calories_segmented">Calories(segmented)</string>
<string name="menuitem_calories_active_goal">Calories goal(active)</string>
<string name="menuitem_calories_goal">Calories goal(total)</string>
<string name="menuitem_pai">PAI</string>
<string name="menuitem_hr">Heart Rate</string>
<string name="menuitem_spo2">SpO2</string>
@ -1949,6 +1961,7 @@
<string name="menuitem_widgets">Widgets</string>
<string name="menuitem_temperature">Temperature</string>
<string name="menuitem_weight">Weight</string>
<string name="menuitem_calories">Calories</string>
<string name="menuitem_barometer">Barometer</string>
<string name="menuitem_flashlight">Flashlight</string>
<string name='menuitem_email'>E-mail</string>

View File

@ -93,6 +93,15 @@
android:title="@string/activity_prefs_calories_burnt"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:iconSpaceReserved="false"
android:defaultValue="350"
android:inputType="number"
android:key="activity_user_goal_active_calories_burnt"
android:maxLength="3"
android:title="@string/activity_prefs_goal_active_calories_burnt"
app:useSimpleSummaryProvider="true" />
<EditTextPreference
app:iconSpaceReserved="false"
android:defaultValue="5000"

File diff suppressed because it is too large Load Diff

View File

@ -1,117 +0,0 @@
#!/bin/bash
#This script needs bash for the read command
#Takes screenshots of Gadgetbridge for the fastlane.
#Live Activity screenshot not taken, as it needs more inputs.
VERSION="0407"
#Version sets clock in Android demo mode to version
#to indicate when screenshots have been taken
DIR="metadata/android/en-US/images/phoneScreenshots/"
#enable demo mode
adb shell settings put global sysui_demo_allowed 1
adb shell am broadcast -a com.android.systemui.demo -e command enter
adb shell am broadcast -a com.android.systemui.demo -e command clock -e hhmm $VERSION
adb shell am broadcast -a com.android.systemui.demo -e command notifications -e visible false
adb shell am broadcast -a com.android.systemui.demo -e command battery -e level 100
adb shell am broadcast -a com.android.systemui.demo -e command network -e wifi show -e level 4
adb shell am broadcast -a com.android.systemui.demo -e command network -e mobile show -e datatype none -e level 4
#launch Gadgetbridge
adb shell monkey -p nodomain.freeyourgadget.gadgetbridge -c android.intent.category.LAUNCHER 1
sleep 3
#Start taking screenshots:
adb shell screencap -p > $DIR"10-MainScreen.png"
adb shell input tap 455 355
read -p "Select a day and press Enter"
adb shell screencap -p > $DIR"20-ActivityAndSleep.png"
adb shell input tap 240 210
read -p "slightly adjust label on chart and press Enter"
adb shell screencap -p > $DIR"30-Sleep.png"
adb shell input tap 420 210
read -p "slightly adjust label on chart and press Enter"
adb shell screencap -p > $DIR"40-SleepPerWeek.png"
#switch to month
adb shell input tap 670 100
sleep 0.5
adb shell input tap 670 1080
sleep 0.5
adb shell input keyevent 111
read -p "slightly adjust label on chart and press Enter"
adb shell screencap -p > $DIR"41-SleepPerMonth.png"
adb shell input tap 590 210
sleep 0.5
adb shell screencap -p > $DIR"51-StepsPerMonth.png"
#switch back to week
adb shell input tap 670 100
sleep 0.5
adb shell input tap 670 1080
sleep 0.5
adb shell input keyevent 111
read -p "Select a day and press Enter"
adb shell screencap -p > $DIR"50-StepsPerWeek.png"
adb shell input tap 590 210
sleep 0.5
adb shell screencap -p > $DIR"60-SpeedZones.png"
#Go back to main screen
adb shell input keyevent 111
#sports activities
adb shell input tap 540 355
read -p "Slide the activities and press Enter"
adb shell screencap -p > $DIR"70-SportActivities.png"
adb shell input tap 490 100
read -p "Set the filter and press Enter"
adb shell screencap -p > $DIR"71-SportActivitiesFilter.png"
adb shell input tap 315 1100
sleep 0.5
adb shell input tap 585 110
sleep 0.5
adb shell screencap -p > $DIR"72-SportActivitiesSummary.png"
#dark mode. Here, we re-use old pictures, which due to a bug in f.droid, keep being cached on the server.
#so we at least use them for dark mode, but do not add new ones
read -p "Set dark mode and press Enter"
adb shell screencap -p > $DIR"1-MainScreen.png"
adb shell input tap 455 355
read -p "Select a day and press Enter"
adb shell screencap -p > $DIR"2-ActivityAndSleep.png"
adb shell input tap 420 210
read -p "slightly adjust label on chart and press Enter"
adb shell screencap -p > $DIR"3-SleepPerWeek.png"
adb shell screencap -p > $DIR"4-StepsPerWeek.png"
adb shell input tap 590 210
sleep 0.5
adb shell input tap 590 210
sleep 0.5
adb shell screencap -p > $DIR"5-SpeedZones.png"
#Go back to main screen
adb shell input keyevent 111
#disable demo mode
adb shell am broadcast -a com.android.systemui.demo -e command exit
adb shell settings put global sysui_demo_allowed 0

View File

@ -0,0 +1,138 @@
* Initial support for Anker Soundcore Liberty 4 NC
* Initial support for CMF Buds Pro 2 / Watch Pro 2
* Initial support for Colmi R02/R03/R06/R10 smart rings
* Initial support for Garmin Enduro 3, Fenix 5/5 Plus/5X Plus/6/6S Sapphire/7/8, Forerunner 165/255/255S Music/245 Music/265S/955/965, Venu/Venu Sq/Venu Sq 2/Venu 2S, Vivoactive 3, Vivomove Trend, Vivosport
* Initial support for Huawei Watch 3 / 3 Pro / 4 Pro / D2 / GT 3 SE / GT 5 / GT 5 Pro / GT Cyber / GT Runner
* Initial support for Honor Watch GS 3 / Watch GS Pro
* Initial support for IKEA desk controller
* Initial support for Moondrop Space Travel
* Initial support for Mijia XMWSDJ04MMC
* Initial support for Mi Smart Scale 2
* Initial support for Sony WF-C500 / WF-C700N / WI-C100
* Initial support for Soundcore Motion 300
* Initial support for Vivitar HR & BP Monitor Activity Tracker
* Experimental support for Amazfit T-Rex 3
* Experimental support for Redmi Watch 5 Active
* Experimental support for Xiaomi Smart Band 9
* Experimental support for Xiaomi Watch S3
* Add all languages supported in weblate
* Add BLE intent API
* Add configuration for calendar lookahead
* Add month and day to date of birth
* Add more activity types (CMF, Garmin, Huawei, Zepp OS)
* Allow configuration of notification times
* Allow syncing birthdays with calendar events
* Amazfit GTR 2: Enable PAI support
* AsteroidOS: Fix missing weather day and set-time on connection
* Bangle.js: Add canned responses
* Bangle.js: Fix calendar sync setting
* Bangle.js: Fix distance in activity details
* Bluetooth Intent API: Add disconnect action
* Casio GW-B5600: Alarms, find phone, reminders, watch settings
* Casio: Fix notifications on long messages
* Change device icons to use theme colors
* Charts: Add button to pick date
* Charts: Add charts for HRV, body energy, heart rate, steps, VO2 max, weight
* Charts: Fix heart rate charts when min is set to 0
* Charts: Re-design sleep, stress, PAI, workout details
* Charts: Use HR from workout track file if available
* CMF Watch Pro 2: Negotiate authentication key
* CMF Watch Pro: Fix activity transfer
* Cycling sensor: added live data view
* Cycling sensor: Improve cycling data display
* Dashboard: Add new widgets for stress, HRV, body energy
* Dashboard: Add option to show yesterday's data in Today widget
* Dashboard: Improve widget gauge resolution
* Data Management: Add file manager
* Data Management: Allow browse folders, open and share files
* Data Management: Allow full backup/restore from a zip file
* Data Management: Fix import of some preference from a backup
* Fix activity charts generation for devices that do not report intensity
* Fix crash when companion pairing
* Fix discovery of connected devices
* Fix emoji when some connected device does not support them
* Fix language not being respected in some situations
* Fix media controls not working for some apps
* Fix notification text not being sent for some apps
* Fix reconnection when device connects back during BLE scan
* Fossil HR: Fix crash on disconnection
* Fossil HR: Minor watchface fixes
* Garmin: Display awake time during sleep
* Garmin: Display HRV and body energy
* Garmin: Display resting heart rate
* Garmin: Fetch SKIP_TEMP files
* Garmin: Fix agps upload for some URLs
* Garmin: Fix all-day events
* Garmin: Fix auto-activity fetch on some devices
* Garmin: Fix canned replies reset to defaults
* Garmin: Fix crash on call with privacy mode on
* Garmin: Fix crash on timezones without DST
* Garmin: Fix daily weather missing current day
* Garmin: Fix weather temperature and speed units
* Garmin: Improve activity, sleep and workout parsing
* Garmin: Infer sleep time for devices that do not send sleep stages
* Garmin: Manual HR measurements and live activity
* Garmin: Map some unknown realtime settings
* Garmin: Parse workout physiological metrics, strength training workout sets
* Garmin: Re-parse workout summary when opening details page
* Garmin: Upload gpx and workout fit files to watch
* Garmin: Use distance and calories provided by the watch
* Garmin: View and share gpx files
* Huami: Fetch workouts during normal sync
* Huami: Migrate all device settings to sub-screens
* Huawei Band 9: Improved support
* Huawei: Add battery polling
* Huawei: Basic support for the installation of the applications
* Huawei: Calendar sync support
* Huawei: Contacts uploading support
* Huawei: Continuous skin temperature measurement switch
* Huawei: Enable emoji for HarmonyOS watches
* Huawei: Fix crash when notification has no text
* Huawei: Fix initialization issues on some watches
* Huawei: Fix notifications for Huawei Band 4e
* Huawei: Fix some reconnection issues
* Huawei: Fix watchface upload, activity sync, event alarms, weather for some devices
* Huawei: Fix workout altitude, pace, workout re-parsing
* Huawei: Improve device initialization
* Huawei: Improve watchface install support
* Huawei: Improve weather support
* Huawei: Initial ephemeris update support
* Huawei: Map more workout types
* Huawei: Music upload support
* Huawei: Provide an activity sample every minute
* Huawei: Re-parse workout details when opening details
* Huawei: Send default HR zones
* Huawei: Workout GPS synchronization
* Huawei: Simple TruSleep support
* Huawei: Use distance and calories provided by the watch
* Improve calendar change detection
* Mi Band: Migrate global preferences to device-specific
* Mi Composition Scale: Add alternative bluetooth name
* Mi Composition Scale: Persist and display weight samples
* Mijia LYWSD/XMWSDJ: Add comfort level preference
* Pebble: Migrate global preferences to device-specific
* Redmi Smart Band Pro: Fix crash on connection and activity sync issues
* Sony Headphones: Enable read aloud incoming notifications and auto call pickup
* UI: Add new activity icons
* UI: Fix changelog on device rotation
* UI: Fix HR samples displayed on wrong device
* UI: Fix light navbar buttons on light themes for Android 8+
* UI: Fix pull-down to refresh for some devices
* UI: Improvements for large screen resolutions, font sizes, landscape
* UI: Reduce stutters on device changes / data fetch / scrolling
* UI: Refactor preferences screen
* UM25C: Fix some disconnection issues
* Use default system TTS language
* Xiaomi Protobuf: Allow re-parse activity from storage
* Xiaomi Protobuf: Enable watchface upload for all devices
* Xiaomi Protobuf: Show watchface preview
* Xiaomi Protobuf: Fix watchface install on some watches
* Xiaomi Protobuf: Fix deleting first widget screen
* Xiaomi Protobuf: Fix naps
* Xiaomi Protobuf: Improve workout parsing for some devices
* Zepp OS 3: Fix file transfer (notification icons, gpx upload, agps updates)
* Zepp OS 3.5 / 4: Fix shortcuts, shortcut cards, menu items
* Zepp OS: Add VO2 Max support
* Zepp OS: Display resting heart rate
* Zepp OS: Fix reminder creation in some cases
* ZeTime: Migrate global preferences to device-specific

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 86 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 49 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 88 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 98 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 99 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 100 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 43 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 140 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 81 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 114 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 41 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 46 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 42 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 138 KiB

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 47 KiB

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 131 KiB

After

Width:  |  Height:  |  Size: 50 KiB

View File

@ -0,0 +1,646 @@
#!/usr/bin/env bash
set -euo pipefail
#
# Copyright (C) 2024 ysfchn
#
# 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/>.
#
# Path of the ADB binary to use for ADB commands. If not set, "adb" will
# be used as the binary, meaning it will search from the PATH. Alternatively,
# if "ANDROID_HOME" variable exists, it will be used as fallback to search
# for the ADB binary.
ADB_BINARY="${ADB_BINARY:-"adb"}"
# Package name of Gadgetbridge. Wildcards are also allowed, in this
# case, will look for a matching package names. If there are more than
# 1 result, the script will not continue since we can't determine which
# Gadgetbridge flavor on the device should be used for screenshots.
#
# If there is only one Gadgetbridge flavor installed on the device, this
# variable can be kept this way, so it can launch whetever it is a Nightly
# or not.
PACKAGE_NAME="${PACKAGE_NAME:-"nodomain.freeyourgadget.gadgetbridge.*"}"
# Additional commands that will be executed after disabling demo UI to revert
# the device in its original state (as in before running this script.)
REVERT_COMMANDS=""
# Where to save screenshots, relative to the folder
# where this script is located. Don't prefix with "./".
OUTPUT_DIR="metadata/android/en-US/images/phoneScreenshots"
# Where to look for pngquant to optimize the taken screenshots,
# if pngquant is not available in given path, it will be ignored, so this is
# optional.
PNGQUANT_BIN="${PNGQUANT_BIN:-"pngquant"}"
# Displayed time on the screenshots in HH:MM format. It will be applied inside
# Android Demo Mode, so it won't change the actual Android system time.
#
# Set this value to "version" to automatically construct a time by reading
# the current Gadgetbridge version code and converting it to minutes.
#
# SYSTEM_CLOCK="version"
SYSTEM_CLOCK="10:00"
# Set to 1 for debugging input actions, if set to "1", it won't run any
# commands that causes any modifications (such as changing the theme,
# enabling demo UI etc.) to the system.
DEBUG="${DEBUG:-0}"
# ---------------------------------------------------------------------
# Utility
# ---------------------------------------------------------------------
# Prefix output directory with current file path
OUTPUT_DIR="$(dirname $(realpath -s $0))/${OUTPUT_DIR}"
# Append semicolon for seperating new commands
if [ -n "${REVERT_COMMANDS}" ]; then
REVERT_COMMANDS+=";"
fi
# Read the version code of Gagdetbridge and convert it to HHMM format,
# which will be set as the Android demo UI clock,
# so it can hint which version of Gadgetbridge is being used
# while taking screenshots.
#
# In some cases when the version code couldn't be read
# or the constructed clock is invalid, it will fallback to 10:00.
get_clock() {
if [ "${SYSTEM_CLOCK}" = "version" ]
then
# As how it is in build.gradle file.
version_code=$(git rev-list HEAD --count)
date --date "@${version_code}" -u +%M%S 2>/dev/null || echo "1000"
else
echo "${SYSTEM_CLOCK}" | sed "s/[^0-9]//g"
fi
}
# Try to find the "adb" binary. First, look for "adb" specified in "ADB_BINARY"
# variable. If variable is not specified, it will look for "adb" in PATH,
# otherwise, check for "ANDROID_HOME" variable.
#
# It will print the path of the ADB binary to stdout if ADB is found, otherwise
# write to stderr and exit, since we can't continue without ADB.
locate_adb() {
if [ ! -x "$(command -v ${ADB_BINARY})" ]
then
# Also try Android SDK environment variable.
# https://developer.android.com/tools/variables#envar
if [ -n "${ANDROID_HOME:-}" ]
then
if [ -x "${ANDROID_HOME}/platform-tools/adb" ]
then
echo "ADB found at: ${ANDROID_HOME}/platform-tools/adb" >&2
echo "${ANDROID_HOME}/platform-tools/adb"
return 0
fi
fi
echo "ADB couldn't be found in '${ADB_BINARY}', exiting..." >&2
exit 1
else
echo "ADB found at: ${ADB_BINARY}" >&2
echo "${ADB_BINARY}"
return 0
fi
}
# Check if required packages are installed, and fail if its not.
check_deps() {
if [ ! -x "$(command -v xmlstarlet)" ]
then
echo "'xmlstarlet' is an additional package that is required"
echo "by this script. It may be available in your system package"
echo "manager. Exiting..."
exit 1
fi
}
# Locate the ADB (see above function) and check for connected devices. If device
# count is 1, print the ADB path with a "-s DEVICE_SERIAL" suffix to stdout, so
# we can make sure that ADB commands throughout the script will be executed only
# for the specified device, serving as a safeguard.
# (e.g. "adb -s DEVICE_SERIAL shell echo Hello!")
#
# If deivce count is not equal to 1, exit and tell the reason to stderr.
get_adb_command() {
adb_path=$(locate_adb)
device_list="$("${adb_path}" devices | sed -n "s/^\([0-9a-zA-Z]*\)\s*device$/\1/p")"
device_count="$(echo -n "${device_list}" | grep -c '^')"
# Make sure there is an only single device connected.
if [ $device_count != 1 ]
then
echo "" >&2
echo "There must be an exactly only one device that connected to the ADB," >&2
echo "but found $device_count devices instead! Exiting..." >&2
exit 1
fi
# Construct a command line to be used in next commands.
echo "${adb_path} -s ${device_list}"
}
# ---------------------------------------------------------------------
# ADB Commands
# ---------------------------------------------------------------------
# Changes the system theme programmatically.
# First it applies the light mode, and second, (if API level is >= 33),
# changes system colors.
set_system_theme() {
adb_prefix="${1}"
if [ "${DEBUG}" -eq "1" ]; then
echo "Theme: Skipped because of debug"
return
fi
# Read the existing night mode value on the system, save the original
# value for reverting it later. And change system theme to light mode.
# Run "adb shell cmd uimode night help" for reference.
current_night_mode="$(${adb_prefix} shell cmd uimode night | sed "s/Night mode: //")"
case "${current_night_mode}" in
"no")
echo "Theme: Already set to light, skipped"
;;
"yes" | "auto" | "custom_bedtime" | "custom_schedule")
REVERT_COMMANDS+="${adb_prefix} shell cmd uimode night ${current_night_mode} 1>/dev/null;"
echo "Theme: Switching to light from dark"
${adb_prefix} shell cmd uimode night no 1>/dev/null
;;
*)
echo "Theme: Unsupported theme value, skipped"
esac
# For Android 13 and above, change the system colors programmatically to
# a red-ish color to better match with Gadgetbridge branding.
if [ "$(${adb_prefix} shell getprop ro.build.version.sdk)" -ge "33" ]; then
echo "Theme: Setting Dynamic color"
# Reference for color properties:
# https://source.android.com/docs/core/display/dynamic-color
theme_properties='{
"android.theme.customization.system_palette":"FFB2B5",
"android.theme.customization.accent_color":"FFB2B5",
"android.theme.customization.theme_style":"RAINBOW"
}'
original_theme="$(${adb_prefix} shell settings get secure theme_customization_overlay_packages | tr -d "[:space:]" | tr "\"" "\\\"")"
echo "${original_theme}"
# TODO: Reverting the colors currently doesn't work beause of the characters getting escaped somehow in ADB
# REVERT_COMMANDS+="${adb_prefix} shell settings put secure theme_customization_overlay_packages ""'"${original_theme}"'"
${adb_prefix} shell settings put secure theme_customization_overlay_packages "'"$(echo "${theme_properties}" | tr -d "[:space:]" | tr "\"" "\\\"")"'"
fi
}
# Enables Android Demo Mode and mock status bar icons.
#
# See the reference for list of properties used below:
# https://android.googlesource.com/platform/frameworks/base/+/master/packages/SystemUI/docs/demo_mode.md
#
# Note that the demo UI may a little bit problematic, e.g. when network
# signal level is faked to 4, the signal level might be changed still
# if the actual signal level has changed even if demo UI is shown at the
# moment, so better to take screenshots quickly as possible before status
# icons are changed.
set_status_bar() {
adb_prefix="${1}"
if [ "${DEBUG}" -eq "1" ]; then
echo "Demo mode: Skipped because of debug"
return
fi
echo "Demo mode: Enabling"
${adb_prefix} shell settings put global sysui_demo_allowed 1
echo "Demo mode: Setting status icons"
# Enter the demo mode
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command enter 1>/dev/null
# Wi-Fi and mobile data for each SIM slot
# (couldn't manage to turn off the second slot for dual SIM)
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command network \
--es wifi show --es level 4 1>/dev/null
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command network \
--es mobile show --es level 4 1>/dev/null
# Battery
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command battery \
--es level 100 --es plugged false --es powersave false 1>/dev/null
# Explictly disable status icons
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command status \
--es volume hide \
--es bluetooth hide \
--es location hide \
--es alarm hide \
--es sync hide \
--es tty hide \
--es eri hide \
--es mute hide \
--es speakerphone hide 1>/dev/null
# No notification icons
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command notifications \
--es visible false 1>/dev/null
# Set system clock
${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command clock \
--es hhmm $(get_clock) 1>/dev/null
# Also disable demo UI itself when reverting the preferences.
REVERT_COMMANDS+="${adb_prefix} shell am broadcast -a com.android.systemui.demo --es command exit 1>/dev/null;"
REVERT_COMMANDS+="${adb_prefix} shell settings put global sysui_demo_allowed 0;"
}
# In addition to the Android Demo Mode (as above), we can mock more system
# status icons with LineageOS (or ROMs that based on LineageOS) specific
# settings, so we can keep the AOSP-like look for screenshots.
#
# This function will be executed for all devices regardless of their ROM,
# since this function already checks if running under LineageOS, and if it
# is not, it is a no-op.
set_status_bar_lineage_os() {
adb_prefix="${1}"
if [ "${DEBUG}" -eq "1" ]; then
echo "LineageOS: Skipped because of debug"
return
fi
# As its name implies, "ro.lineage.device" property is found on
# LineageOS (or based on it) ROMs, so we check for its existence.
if [ -n "$(${adb_prefix} shell getprop ro.lineage.device)" ]
then
echo "LineageOS: Setting ROM-specific icons"
# LineageOS allows changing the battery icon style, so we set it
# to portrait and hide the battery percent temporarily. Note the
# "--lineage" flag here, since it is a LineageOS addition, not
# Android's, so it won't work without that flag.
#
# See also for all system properties:
# https://lineageos.github.io/android_lineage-sdk/reference/lineageos/providers/LineageSettings.System.html
battery_style="$(${adb_prefix} shell settings get --lineage system status_bar_battery_style)"
battery_percent="$(${adb_prefix} shell settings get --lineage system status_bar_show_battery_percent)"
# Save the original values to a variable, so we can execute these commands after
# screenshots are taken to revert the changed system preferences to its original state.
REVERT_COMMANDS+="${adb_prefix} shell settings put --lineage system status_bar_battery_style ${battery_style};"
REVERT_COMMANDS+="${adb_prefix} shell settings put --lineage system status_bar_show_battery_percent ${battery_percent};"
${adb_prefix} shell settings put --lineage system status_bar_battery_style 0
${adb_prefix} shell settings put --lineage system status_bar_show_battery_percent 0
else
echo "LineageOS: Not a LineageOS ROM, skipped"
fi
}
# Filters the installed packages on the device and prints the matched
# Gadgetbridge package name that specified in "PACKAGE_NAME" variable.
get_gadgetbridge_app() {
adb_prefix="${1}"
# Convert the "PACKAGE_NAME" variable to a valid regex format, change periods to
# literal periods, and change wildcards to a valid wildcards.
package_filter="$(echo "${PACKAGE_NAME}" | tr "." "\\." | tr "*" ".*")"
# List installed & enabled ("-e" flag) packages, and find the packages that
# matches with the pattern.
packages="$(${adb_prefix} shell cmd package list packages -e | sed -rn "s/^package:(${package_filter})/\1/p")"
package_count="$(echo -n "${packages}" | grep -c '^')"
# There can be multiple Gadgetbridge flavors installed on the device, since we
# can't determine which one should be launched, we exit.
if [ $package_count != 1 ]
then
echo "" >&2
echo "There are none or more than one Gadgetbridge flavors found on the device," >&2
echo "since it can't be determined which Gadgetbridge flavor should be used, " >&2
echo "you will need to specifically set the preferred flavor with PACKAGE_NAME" >&2
echo "variable to continue!" >&2
exit 1
fi
echo "Chosen app: ${packages}" >&2
echo "${packages}"
}
# ---------------------------------------------------------------------
# Functions
# ---------------------------------------------------------------------
optimize_screenshots() {
if [ -x "$(command -v ${PNGQUANT_BIN})" ]
then
echo "Optimize: Running pngquant"
"$(command -v ${PNGQUANT_BIN})" --strip --force --ext .png $(find "${OUTPUT_DIR}" -name "*.png")
echo "Optimize: Done"
else
echo "Optimize: Couldn't find pngquant at '${PNGQUANT_BIN}', skipped"
fi
}
# Takes a screenshot of the screen and saves to a given name. Optionally,
# it also can be prompted to pressing a key before taking a screenshot.
grab_screenshot() {
adb_prefix="${1}"
file_name="${2}"
wait_for_key_prompt="${3:-}"
if [ -n "${wait_for_key_prompt}" ]; then
read -s -r -N 1 -p "[screenshot]: Waiting for '${file_name}' - ${wait_for_key_prompt} ** [Press any key to continue]"
echo ""
fi
${adb_prefix} shell screencap -p > "${OUTPUT_DIR}/${file_name}"
# Play a bell sound to indicate the screenshot has been saved.
echo -en '\a'
echo "[screenshot]: Took '${file_name}'."
}
# Gets the XY touch positions of a UI element that hinted by a specific
# name by filtering from the layout data. The layout can be obtained by
# "dump_screen_layout" function.
get_position() {
dump_output="${1}"
name="${2}"
# There can be multiple elements that matching the same "name", so
# we limit to printing one line only by specifying which n-th element
# to return. If not given, will print the coordinates of the first
# matching (1st) element.
index="${3:-1}"
echo "${dump_output}" | sed -rn "s/name:${name},position:([0-9]+):([0-9]+)/\1 \2/p" | sed -n ${index}p
}
launch_gadgetbridge() {
adb_prefix="${1}"
package_name="${2}"
# Check if Gadgetbridge is launched already, and warn the user to close
# Gadgetbridge, so we can start in the home screen when we launch
# Gadgetbridge.
status=$(${adb_prefix} shell dumpsys window windows \
| grep -E 'mCurrentFocus|mFocusedApp|mInputMethodTarget|mSurface' \
| grep -qs "${package_name}" || echo $?)
if [ -z $status ]; then
echo "[!] Gadgetbridge is currently shown on the device. Close it " >&2
echo "(and delete it from the recents) and press any key to continue." >&2
read -s -r -N 1
launch_gadgetbridge "${adb_prefix}" "${package_name}"
else
echo "Launching Gadgetbridge..."
# Launch Gadgetbridge with monkey command, since it doesn't require us
# to specify the activity class name along with the package name.
${adb_prefix} shell monkey -p "${package_name}" 1 1 1>/dev/null 2>&1
# Give it some time before continuing.
sleep 2
fi
}
# Creates a dump of the current layout that is shown on the device screen.
# So this allow us to programmatically get touch positions of UI elements.
#
# It will output a string that contains element descriptions and their
# X/Y positions, for each valid element:
# "name:Open navigation drawer,position:70:159"
dump_screen_layout() {
adb_prefix="${1}"
# "uiautomator" service prints a XML document, but it also prints a
# "UI hierchary dumped to..." message in the end, so we strip this
# message from the string to make it a valid XML text.
char_count=$(echo "UI hierchary dumped to: /dev/tty" | wc -c)
xml_document="$(${adb_prefix} exec-out uiautomator dump /dev/tty | head -c -${char_count})"
# XPath to list UI nodes listed in the current screen (we specifically
# only list nodes in the Gadgetbridge app to be explicit), and print
# their bound positions ("bounds") and UI names ("content-desc"), so we
# can filter elements by their names.
package_name="$(echo "${PACKAGE_NAME}" | sed "s/*$//")"
xml_path="./hierarchy/node[contains(@package, \"${package_name}\") and @class=\"android.widget.FrameLayout\"]//node/@*[name() = \"bounds\" or name() = \"content-desc\"]"
index=0
previous_ui_name=""
while IFS="" read -r line || [ -n "$line" ]
do
# The output from XPath query, we will have attribute values printed
# one by one, so since we look for both "bounds" and "content-desc" attribute,
# it will print:
# - bounds
# - content-desc
# - bounds
# - content-desc
#
# So to group each node, we check if it is divisible by 2, the count of the
# attributes that we are listing.
if [ "$(( $index % 2 ))" -eq 0 ]; then
# This will be the "content-desc", so we pass it as-is.
previous_ui_name="${line}"
else
# This will be the "bounds", so we convert this value to a X/Y positions.
# Each bound value will contain 4 points, START_X, START_Y, END_X and END_Y,
# and is formatted as: "[0,0][1080,2219]", since we only need a single position
# to touch it, we calculate the center of both X and Y here.
#
# To read the values, we need to convert these bounds to a Bash array,
# so remove all comma and square bracket characters to only leave the numbers.
# "[0,0][1080,2219]" -> array of 4: "0 0 1080 2219"
bounds=($(echo "${line}" | sed "s/^\[//; s/\[/ /g; s/\]//g; s/,/ /g"))
# Now we can calculate the center position of the element.
# X_CENTER = X_START + ((X_END - X_START) / 2)
# Y_CENTER = Y_START + ((Y_END - Y_START) / 2)
center_x=$((( ${bounds[0]} + ((${bounds[2]} - ${bounds[0]}) / 2) )))
center_y=$((( ${bounds[1]} + ((${bounds[3]} - ${bounds[1]}) / 2) )))
# Only output if there is a UI name for the element.
if [ -n "${previous_ui_name}" ]
then
echo "name:${previous_ui_name},position:${center_x}:${center_y}"
fi
fi
index=$(( index + 1 ))
done < <(echo "${xml_document}" | xmlstarlet sel --template --value-of "${xml_path}")
if [ $index -eq 0 ]
then
echo "[!] Couldn't find valid elements on the screen, is Gadgetbridge currently shown on the screen?" >&2
fi
}
perform_input() {
adb_prefix="${1}"
input_type="${2}"
case "${input_type}" in
# Swipe for a specific direction.
"swipe_left" | "swipe_right")
# Get screen dimensions.
dimensions="$(${adb_prefix} shell wm size | rev | cut -d " " -f 1 | rev)"
screen_x=$(echo "$dimensions" | cut -d "x" -f 1)
screen_y=$(echo "$dimensions" | cut -d "x" -f 2)
# If swiping to the left, swipe to the left edge of the screen.
swipe_x=0
# Or if swiping to the right, swipe to the right edge of the screen.
if [ "${input_type}" = "swipe_right" ]; then
swipe_x=$screen_x
fi
# Perform the swipe (starting form the center of the screen)
# to given direction in 100 milliseconds.
${adb_prefix} shell input swipe $((screen_x / 2)) $((screen_y / 2)) $swipe_x $((screen_y / 2)) 100
sleep 1
;;
# Send "back" button key.
"go_back")
# 111 = KEYCODE_ESCAPE
# 4 = KEYCODE_BACK
${adb_prefix} shell input keyevent 4
sleep 0.5
;;
# Touch to a UI element which hinted with a given element name.
"touch_element")
element_name="${3}"
xml_layout="$(dump_screen_layout "${adb_prefix}")"
element_index="${4:-1}"
# Get the X/Y position of given element name, and touch it.
${adb_prefix} shell input tap $(get_position "${xml_layout}" "${element_name}" "${element_index}")
sleep 0.5
;;
*)
echo "[!] Unsupported input type!"
exit 1
esac
}
# Open Gadgetbridge and start taking screenshots of different screens.
# To find out the touch positions;
# Developer Options > Under "Input" category > Enable "Pointer location"
#
# TODO: Calculate the exact position from screen density and dimensions to make X/Y positions adaptive with other screens.
take_screenshots() {
adb_prefix="${1}"
echo; echo "! - If system preferences are not reverted automatically after exiting, you can manually run these commands:"
echo "${REVERT_COMMANDS}"
echo; echo "Taking screenshots, it might take some time;"
# Dashboard
perform_input "${adb_prefix}" "swipe_right"
grab_screenshot "${adb_prefix}" "10-Dashboard.png" "Change the day or keep today"
# Calendar
perform_input "${adb_prefix}" "touch_element" "Calendar"
grab_screenshot "${adb_prefix}" "30-Calendar.png" "Change the month of keep as-is"
perform_input "${adb_prefix}" "go_back"
# Devices
perform_input "${adb_prefix}" "swipe_left"
grab_screenshot "${adb_prefix}" "11-Devices.png"
# Activity chart
perform_input "${adb_prefix}" "touch_element" "Your activity"
grab_screenshot "${adb_prefix}" "20-Activity.png" "Adjust the chart"
# Sleep chart (Day)
perform_input "${adb_prefix}" "touch_element" "Sleep"
perform_input "${adb_prefix}" "touch_element" "Day"
grab_screenshot "${adb_prefix}" "40-SleepPerDay.png" "Change the day or keep today"
# Sleep chart (Week)
perform_input "${adb_prefix}" "touch_element" "Week"
grab_screenshot "${adb_prefix}" "41-SleepPerWeek.png" "Change the day or keep today"
# Steps chart (Day)
perform_input "${adb_prefix}" "touch_element" "Steps"
perform_input "${adb_prefix}" "touch_element" "Day"
grab_screenshot "${adb_prefix}" "50-StepsPerDay.png" "Change the day or keep today"
# Steps chart (Week)
perform_input "${adb_prefix}" "touch_element" "Week"
grab_screenshot "${adb_prefix}" "51-StepsPerWeek.png" "Change the day or keep today"
# Steps chart (Month)
perform_input "${adb_prefix}" "touch_element" "Month"
grab_screenshot "${adb_prefix}" "52-StepsPerMonth.png" "Change the day or keep today"
# Stress
perform_input "${adb_prefix}" "touch_element" "Stress"
grab_screenshot "${adb_prefix}" "60-Stress.png" "Change the day or keep today"
# Live activity
perform_input "${adb_prefix}" "touch_element" "Live activity"
grab_screenshot "${adb_prefix}" "70-LiveActivity.png" "Start your activity on the watch"
# Back to the home screen
perform_input "${adb_prefix}" "go_back"
# Sport activities
perform_input "${adb_prefix}" "touch_element" "Your activity tracks"
grab_screenshot "${adb_prefix}" "70-SportActivities.png"
# Sport activity filter
perform_input "${adb_prefix}" "touch_element" "Sports Activities Filter"
grab_screenshot "${adb_prefix}" "71-SportActivitiesFilter.png"
# Back to the sport activities screen
perform_input "${adb_prefix}" "go_back"
# Sport activity summary
perform_input "${adb_prefix}" "touch_element" "Device image" 10
grab_screenshot "${adb_prefix}" "72-SportActivitiesSummary.png"
}
# Disable demo UI, and revert all applied settings by eval-ing all
# revert commands that is saved before.
revert() {
if [ -n "${REVERT_COMMANDS}" ]; then
echo; echo "[*] Reverting modifications..."
fi
eval "${REVERT_COMMANDS}"
exit 0
}
start() {
check_deps
echo "[*] Searching for devices..."
adb_command=$(get_adb_command)
use_package=$(get_gadgetbridge_app "${adb_command}")
echo; echo "[*] Applying preferences..."
set_system_theme "${adb_command}"
set_status_bar_lineage_os "${adb_command}"
set_status_bar "${adb_command}"
launch_gadgetbridge "${adb_command}" "${use_package}"
echo; echo "[*] Taking screenshots..."
take_screenshots "${adb_command}"
optimize_screenshots
}
# Run "revert" function to revert everything if received an SIGINT or SIGTERM signal.
# Also with "EXIT" signal, run this function whenever the script exits.
trap revert SIGINT SIGTERM EXIT
start