1
0
mirror of https://codeberg.org/Freeyourgadget/Gadgetbridge synced 2024-06-01 19:06:06 +02:00

Compare commits

..

99 Commits

Author SHA1 Message Date
Daniele Gobbetti
226277bcdc Garmin: enable AGPS update for all Instinct 2 devices 2024-05-03 20:28:12 +02:00
kuhy
60066014e0 Garmin protocol: show AGPS data status in settings 2024-05-03 20:28:12 +02:00
kuhy
eeb80d712b Garmin protocol: add AGPS data checks 2024-05-03 20:28:12 +02:00
kuhy
ad44459fc4 Garmin protocol: install AGPS data as firmware 2024-05-03 20:28:12 +02:00
kuhy
c9cb7d788e Garmin protocol: improve detection of successfully sent files (DataTransferHandler) 2024-05-03 20:28:12 +02:00
kuhy
5841058863 Garmin protocol: add support for AGPS data retrieval 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
f3b07694b2 Fixup: Introduce device specific writable directory (MAC address)
Add logic to not fetch again files which had the previously defined name
2024-05-03 20:28:12 +02:00
Daniele Gobbetti
4d06eb7339 Introduce device specific writable directory (MAC address)
Also adds temporary method to move the fetched files from the legacy path to the new one which does not include the device name.
Also moves the FileIndex to the end of the cached files to allow for easier sorting.

Cherry-picked from 525b395c01 and adapted
2024-05-03 20:28:12 +02:00
José Rebelo
6c79b42130 Garmin: Make fit header crc optional 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
fee3b9188c Garmin: enable unicode Emoji for all devices
This seems to be widely supported by garmin devices, hence enable it in the base coordinator. Specific devices not supporting Unicode Emojis can override this method and return false.
2024-05-03 20:28:12 +02:00
Daniele Gobbetti
4eabf87e18 Garmin: harmonize device names
All device name strings start with manufacturer name.
Normalized the usage of accented i.
2024-05-03 20:28:12 +02:00
Andreas Schneider
d0f0db833c Garmin: add coordinator for Instinct Crossover 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
36781e6958 Garmin: fix regression in call handling
Add a fictitious action to the notification to enable reply/hangup/reject from the watch.
Also fixes the behavior on sms reply, which should also reject the incoming call.

Change the log level in case some of the canned messages types are left as default to info, as this is a supported scenario.
2024-05-03 20:28:12 +02:00
Daniele Gobbetti
4faf95a417 Garmin: encode unknown weather codes as invalid 2024-05-03 20:28:12 +02:00
meskio
709544e6bd Initial support for Garmin Instinct Solar 2024-05-03 20:28:12 +02:00
José Rebelo
1328ce13e1 Garmin: Improve fit parsing
* Remove the dependency on PredefinedLocalMessage from generic fit parsing code
* Standardize toString methods, omit types for known fields
* Return null on unknown field number or names, instead of crashing
* Map more Global FIT messages (device info, monitoring, sleep stages, sleep stats, stress level)
* Prioritize "timestamp" over "253_timestamp" if specified explicitly in the global message definition
* Introduce RecordData wrappers for each global message, allowing us to have proper types when getting data. If missing or unknown, the getter returns null. All classes are auto-generated by the FitCodeGen.
* Persist a list of RecordData, instead of a Map from RecordDefinition
* Fix parsing of compressed timestamps - keep them in computedTimestamp on each data record
* Use timestamp16 if available in Monitoring records
2024-05-03 20:28:12 +02:00
Daniele Gobbetti
d240597bfe Garmin: add coordinator for Instinct 2 Solar Tactical
confirmed working in https://codeberg.org/Freeyourgadget/Gadgetbridge/issues/3063#issuecomment-1787762
2024-05-03 20:28:12 +02:00
José Rebelo
eec88c3dd5 Garmin: Send location to watch 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
7700154b16 Garmin: calendar integration improvements
use the protobuf fields described in the documentation[0]
build the message according to the requested fields

[0] https://gadgetbridge.org/internals/specifics/garmin-protocol/#calendarevent
2024-05-03 20:28:12 +02:00
a0z
1dec34afea Garmin: Initial support of Instinct 2 Solar 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
eba72bd40f Garmin: fix notification crashes and handle SMS correctly
It looks like (some) watches really don't like having an empty list of actions, hence enable the legacy "refuse" action in every case, leaving it empty and inactive.
Further display the SMS sender in the notification and enable the correct code path for the reply action to work.
2024-05-03 20:28:12 +02:00
José Rebelo
915d059c1c Garmin: Auto-detect canned messages support 2024-05-03 20:28:12 +02:00
José Rebelo
de9e087e2d Garmin: Fix reply to sms 2024-05-03 20:28:12 +02:00
José Rebelo
27b0a5ce49 Garmin: Add setting to disable notifications 2024-05-03 20:28:12 +02:00
José Rebelo
36c52e1900 Garmin Venu 3: Enable canned replies 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
b75ecae454 Garmin: use developer device setting for keeping data on device
Make use of the previously added preference to toggle file archival (deletion) on the watch.

Default is true (keep data on device) until we are sure of the consequences.
2024-05-03 20:28:12 +02:00
José Rebelo
bcb8f7504d Garmin: Map all known files types 2024-05-03 20:28:12 +02:00
José Rebelo
46ea7d87b1 Garmin: Add support for http weather requests 2024-05-03 20:28:12 +02:00
Daniele Gobbetti
77e64b149b Garmin: Rename LocalMessage to PredefinedLocalMessage and clarify its usage
PredefinedLocalMessage are only useful for FIT messages and should not interfere with FIT files. The only impact of using the local message in fit files was in the textual output, but it was confusing.

Add an explicit constructor to RecordHeader if PredefinedLocalMessage should be taken into account, and use this only in fit messages leaving the default constructor for fit files.

Also adjusts the test case as textual output comparison needs to be fixed.
2024-05-03 20:28:11 +02:00
kuhy
f46929c080 Initial support for Garmin Vivoactive 4S 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
a7d4f3df93 Garmin: Add support for custom replies (notifications and calls)
To enable custom replies an override must be defined in the devices coordinator that actually support custom replies.

The custom preferences allow to:
- enable / disable the default message suffix (Instinct 2 appends "sent from my $vendor device" to each reply by default)
- define custom messages to reply to calls and incoming messages (leaving those lists empty will enable the default messages to be used)

Also adds a new protobuf definition file of mostly unknown values that enable toggling the message suffix on Instinct 2.
2024-05-03 20:28:11 +02:00
myxor
d72113c0cb Initial support for Garmin Vivoactive 5 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
bdfab59a81 Garmin: Add support for replying to notifications
This uses the (assumed) new method of passing multiple actions, instead of the (assumed) legacy accept/decline approach.
At the moment the preset messages stored on the watch firmware are used for replying, the code supports using custom messages already but those have to be updated to the watch somehow (probably by protobuf) and this is not supported yet. Using custom messages if they are not set will just do nothing.
The NotificationActionIconPosition values have been determined on a vívomove Style and might not work properly on other watches.
The evaluation of GBDeviceEvent have been moved in GarminSupport since the notification actions handling uses device events.

Also adds a method to read null terminated strings to GarminByteBufferReader.
Also adds a warning in NotificationListener if the wrong handle is used for replying to a notification.
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
ce968e1ea8 Garmin: Add FileDownloadedDeviceEvent and (disabled) file deletion
Also adds (disabled) file deletion in case of already downloaded files
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
e6f78bbba4 Garmin: Add DST/Timezone support 2024-05-03 20:28:11 +02:00
hrdl
2673edf05b Add Garmin Forerunner 245 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
9d2a42b173 Garmin: Support file archival (deletion) on watch
Also add original timestamp to local cache filename as the file identifier are reused
Also fix imports of Test class
2024-05-03 20:28:11 +02:00
José Rebelo
a21ceb606c Garmin: Fetch activity on demand 2024-05-03 20:28:11 +02:00
José Rebelo
b0932d0f17 Garmin: Fix proguard rules for release builds 2024-05-03 20:28:11 +02:00
José Rebelo
3dab968805 Garmin: Allow high MTU 2024-05-03 20:28:11 +02:00
José Rebelo
9c7aa8c22b Garmin protocol: Simplify FILE_TYPE 2024-05-03 20:28:11 +02:00
José Rebelo
207ab89448 Garmin protocol: Fix linter warnings 2024-05-03 20:28:11 +02:00
José Rebelo
4c3092089e Garmin protocol: Introduce GarminCoordinator 2024-05-03 20:28:11 +02:00
José Rebelo
993765b3c6 Garmin protocol: fix crash when stopping find phone 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
554e33adaa Garmin protocol: basic file transfer and notification handling
adds synchronization of supported files from watch to external directory
adds support for Activity and Monitoring files (workouts and activity samples), but those are not integrated yet
adds upload functionality (not used ATM and not tested)
adds notification support without actions
introduces centralized processing of "messageHandlers" (protobuf, file transfer, notifications)

also properly dispose of the music timer when disconnecting
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
951f550b87 Garmin protocol: enable media volume control from watch 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
ed0f8077e7 Garmin protocol: store max packet size from DeviceInformationMessage
also adds messageType to the warnifleftover log message
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
f90b544dc9 Garmin protocol: various changes
- add FitFile class that deals with parsing and generating outgoing files
- consider all field definitions with number 253 as Timestamps [0]
- add support for "compressed timestamps" in fit file parsing. Those are not returned among the other normal fields but are available through a method of RecordData
- adjust the test cases

[0]48b6554d8a/fitdecode/reader.py (L719)
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
a5bf32b9f1 Garmin protocol: change naming and logic of several FIT classes
- refactor the logic of Global and Local messages
- add some Global messages with naming taken from [1]
- Global messages are not enum because there are too many
- introduce the concept of FieldDefinitionPrimitive
- add new Field Definitions
- add support for developer fields and array fields
- add test case for FIT files taken from [0]

[0] https://github.com/polyvertex/fitdecode/
[1] https://www.fitfileviewer.com/
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
e18d7df513 Garmin protocol: create helper class GarminByteBufferReader
separate the logic specific for GFDI messages from the generally useful logic.
Also centralize the logging in case of leftover bytes while parsing GFDI messages.
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
e1bfd05523 Garmin protocol: create custom GBDeviceEvent for weather request 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
3ea737d89c Garmin protocol: use message enum instead of id in GFDI Messages 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
6b7db3d92d Garmin protocol: refactoring and fixes of BaseTypes
The boundaries are enforced on the stored value when decoding, before applying the adjustments for scale and offset.
Also add some tests for the BaseTypes
Introduce new FieldDefinition for Temperature and WeatherCondition (removing the static class)
Add accessors for field data in the containing RecordData, thus keeping the FieldData private
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
74facd4505 Garmin protocol: create specific field definition for day of week 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
9152a5c3da Garmin protocol: move field encode/decode interface to the FieldDefinition
This allows for semantic subclassing the FieldDefinition.
A FieldDefinitionTimestamp subclass is introduced as example
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
07d4dd9dcb Garmin protocol: fix invalid signed int base type value 2024-05-03 20:28:11 +02:00
Daniele Gobbetti
ae347bed98 Garmin protocol: add initial support for FIT messages
note: only weather message definition and data tested so far
also enable weather support for Instinct 2S and vivomove style
also cleanup some unused constants that have been migrated to new enums in GFDIMessage
additionally switch to new local implementation of GarminTimeUtils with needed methods
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
4a38b7aee8 Garmin protocol: fixes
- fix DEVICE_SETTINGS message ID
- put all status messages in own package
- allow protobuf handler to change the returned status message to signal unsupported requests
- fix various bugs
2024-05-03 20:28:11 +02:00
Daniele Gobbetti
135073585e Garmin protocol: initial refactoring and basic functionalities
This commit takes aims to bring many new garmin devices up to a working status, with basic functionalities such as:
- garmin protocol initialization
- basic message exchange
- support for some messages in Garmin own format
- support for some messages in protobuf format
2024-05-03 20:28:11 +02:00
Martin.JM
4c93647aaf [Huawei] Add TruSleep warning 2024-05-02 20:59:08 +02:00
José Rebelo
881e8e36e8 Update changelog 2024-05-01 23:35:04 +01:00
José Rebelo
0ff8774fce DebugActivity: Omit manufacturer for test devices if name contains it 2024-05-01 23:34:14 +01:00
rymut
7a50df61b8 [Huawei] refactor: removed isExperimental override 2024-05-01 22:35:12 +02:00
rymut
8860b4b678 [Huawei] fix: use correct coordinator for watch fit 2 2024-05-01 22:24:36 +02:00
Nyatsuki
b8852379f9
Translated using Weblate (Japanese)
Currently translated at 54.7% (1500 of 2739 strings)

Co-authored-by: Nyatsuki <Odamaki@yandex.ru>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ja/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:34:03 +02:00
Baka Gaijin
07a11addb9
Translated using Weblate (Japanese)
Currently translated at 54.6% (1494 of 2735 strings)

Co-authored-by: Baka Gaijin <lewdwarrior@waifu.club>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ja/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:34:02 +02:00
あぽろあぽろ
4dde33c342
Translated using Weblate (Japanese)
Currently translated at 54.6% (1494 of 2735 strings)

Co-authored-by: あぽろあぽろ <aporotilyoko0000@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ja/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:34:00 +02:00
Deleted User
294adf6da5
Translated using Weblate (Portuguese (Brazil))
Currently translated at 52.3% (1432 of 2735 strings)

Co-authored-by: Deleted User <Resume7202@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/pt_BR/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:59 +02:00
José Rebelo
5c7ea9131e
Translated using Weblate (Russian)
Currently translated at 94.8% (2589 of 2731 strings)

Co-authored-by: José Rebelo <joserebelo@outlook.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:57 +02:00
0que
27fa1a94fe
Translated using Weblate (Russian)
Currently translated at 94.8% (2592 of 2734 strings)

Translated using Weblate (Russian)

Currently translated at 94.8% (2589 of 2731 strings)

Co-authored-by: 0que <0que@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:56 +02:00
summoner001
80857758b4
Translated using Weblate (Hungarian)
Currently translated at 84.2% (2287 of 2716 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/hu/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:54 +02:00
Balage
153199b3b4
Translated using Weblate (Hungarian)
Currently translated at 83.1% (2258 of 2714 strings)

Co-authored-by: Balage <222855@buas.nl>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/hu/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:52 +02:00
Sergey Ponomarev
c7a29e4499
Translated using Weblate (Russian)
Currently translated at 95.1% (2580 of 2711 strings)

Co-authored-by: Sergey Ponomarev <stokito@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:51 +02:00
Nyatsuki
7b05853b7d
Translated using Weblate (Japanese)
Currently translated at 54.6% (1494 of 2735 strings)

Translated using Weblate (Japanese)

Currently translated at 45.8% (1255 of 2735 strings)

Translated using Weblate (Japanese)

Currently translated at 44.3% (1213 of 2735 strings)

Translated using Weblate (Japanese)

Currently translated at 42.3% (1157 of 2734 strings)

Translated using Weblate (Japanese)

Currently translated at 41.5% (1136 of 2734 strings)

Translated using Weblate (Japanese)

Currently translated at 41.5% (1135 of 2734 strings)

Translated using Weblate (Japanese)

Currently translated at 41.5% (1134 of 2731 strings)

Translated using Weblate (Japanese)

Currently translated at 41.4% (1131 of 2731 strings)

Translated using Weblate (Japanese)

Currently translated at 41.1% (1124 of 2731 strings)

Translated using Weblate (Japanese)

Currently translated at 39.3% (1069 of 2716 strings)

Translated using Weblate (Japanese)

Currently translated at 38.3% (1042 of 2714 strings)

Translated using Weblate (Japanese)

Currently translated at 36.8% (1000 of 2711 strings)

Co-authored-by: Nyatsuki <Odamaki@yandex.ru>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ja/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:49 +02:00
summoner001
d543dcdd80
Translated using Weblate (Hungarian)
Currently translated at 81.0% (2198 of 2711 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/hu/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:47 +02:00
0que
58c4242ba5
Translated using Weblate (Russian)
Currently translated at 95.0% (2578 of 2711 strings)

Co-authored-by: 0que <0que@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:44 +02:00
Hikaru
1d53259988
Translated using Weblate (Japanese)
Currently translated at 30.4% (826 of 2711 strings)

Co-authored-by: Hikaru <Hikali-47041@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ja/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:41 +02:00
Nyatsuki
f596c3b83c
Translated using Weblate (Japanese)
Currently translated at 30.4% (826 of 2711 strings)

Co-authored-by: Nyatsuki <Odamaki@yandex.ru>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ja/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:40 +02:00
ritchierope
2ed0be0bcd
Translated using Weblate (Hungarian)
Currently translated at 80.2% (2175 of 2711 strings)

Co-authored-by: ritchierope <zdg.acc@mailbox.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/hu/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:37 +02:00
summoner001
a94e1eb573
Translated using Weblate (Hungarian)
Currently translated at 80.2% (2175 of 2711 strings)

Co-authored-by: summoner001 <summoner@vivaldi.net>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/hu/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:35 +02:00
Stepan
6fd9414d37
Translated using Weblate (Russian)
Currently translated at 95.2% (2572 of 2700 strings)

Co-authored-by: Stepan <stepan.miroshnikov@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:33 +02:00
glemco
05ffd79815
Translated using Weblate (Italian)
Currently translated at 90.8% (2482 of 2731 strings)

Translated using Weblate (Italian)

Currently translated at 89.1% (2435 of 2731 strings)

Translated using Weblate (Italian)

Currently translated at 85.3% (2299 of 2694 strings)

Co-authored-by: glemco <glemco@posteo.net>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/it/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:31 +02:00
Yaron Shahrabani
82dfbce231
Translated using Weblate (Hebrew)
Currently translated at 98.1% (2681 of 2731 strings)

Translated using Weblate (Hebrew)

Currently translated at 98.5% (2673 of 2711 strings)

Translated using Weblate (Hebrew)

Currently translated at 97.4% (2642 of 2711 strings)

Translated using Weblate (Hebrew)

Currently translated at 95.5% (2590 of 2711 strings)

Translated using Weblate (Hebrew)

Currently translated at 95.7% (2587 of 2702 strings)

Translated using Weblate (Hebrew)

Currently translated at 95.5% (2581 of 2700 strings)

Translated using Weblate (Hebrew)

Currently translated at 95.3% (2575 of 2700 strings)

Translated using Weblate (Hebrew)

Currently translated at 95.4% (2574 of 2698 strings)

Translated using Weblate (Hebrew)

Currently translated at 96.2% (2569 of 2668 strings)

Co-authored-by: Yaron Shahrabani <sh.yaron@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/he/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:29 +02:00
0que
3d35e322e9
Translated using Weblate (Russian)
Currently translated at 95.1% (2568 of 2698 strings)

Translated using Weblate (Russian)

Currently translated at 95.1% (2563 of 2694 strings)

Translated using Weblate (Russian)

Currently translated at 96.0% (2562 of 2668 strings)

Co-authored-by: 0que <0que@users.noreply.hosted.weblate.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ru/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:28 +02:00
bowornsin
f2002fc9a9
Translated using Weblate (Thai)
Currently translated at 4.0% (110 of 2710 strings)

Translated using Weblate (Thai)

Currently translated at 3.2% (89 of 2702 strings)

Translated using Weblate (Thai)

Currently translated at 3.0% (82 of 2702 strings)

Translated using Weblate (Thai)

Currently translated at 3.3% (90 of 2664 strings)

Co-authored-by: bowornsin <bowornsin@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/th/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:25 +02:00
Linerly
9caf07657d
Translated using Weblate (Indonesian)
Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (Indonesian)

Currently translated at 99.3% (2712 of 2731 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2711 of 2711 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2710 of 2710 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2702 of 2702 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2700 of 2700 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2698 of 2698 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2694 of 2694 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2668 of 2668 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2664 of 2664 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (Indonesian)

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: Linerly <linerly@proton.me>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/id/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:23 +02:00
Rex_sa
1c7c7ff4d6
Translated using Weblate (Arabic)
Currently translated at 100.0% (2738 of 2738 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2731 of 2731 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2716 of 2716 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2711 of 2711 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2710 of 2710 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2709 of 2709 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2702 of 2702 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2700 of 2700 strings)

Translated using Weblate (Arabic)

Currently translated at 99.7% (2691 of 2698 strings)

Translated using Weblate (Arabic)

Currently translated at 99.0% (2672 of 2698 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2668 of 2668 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2664 of 2664 strings)

Translated using Weblate (Arabic)

Currently translated at 99.3% (2646 of 2664 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (Arabic)

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: Rex_sa <rex.sa@pm.me>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/ar/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:21 +02:00
陈少举
a8dbb30139
Translated using Weblate (Chinese (Simplified))
Currently translated at 100.0% (2739 of 2739 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2738 of 2738 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.9% (2730 of 2731 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2716 of 2716 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2714 of 2714 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2710 of 2710 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 99.8% (2706 of 2709 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2702 of 2702 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2700 of 2700 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2698 of 2698 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2694 of 2694 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2668 of 2668 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2664 of 2664 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (Chinese (Simplified))

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: 陈少举 <oshirisu.red@gmail.com>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/zh_Hans/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:19 +02:00
arjan-s
59e9d01605
Translated using Weblate (Dutch)
Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (2731 of 2731 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (2710 of 2710 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (2698 of 2698 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (Dutch)

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: arjan-s <a_gitlab@anymore.nl>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:17 +02:00
Mikachu
e99a7654af
Translated using Weblate (Dutch)
Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: Mikachu <micah.sh@proton.me>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/nl/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:16 +02:00
Oğuz Ersen
30de0cda70
Translated using Weblate (Turkish)
Currently translated at 100.0% (2739 of 2739 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2738 of 2738 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2733 of 2733 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2731 of 2731 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2716 of 2716 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2714 of 2714 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2711 of 2711 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2710 of 2710 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2709 of 2709 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2704 of 2704 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2702 of 2702 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2700 of 2700 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2698 of 2698 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2694 of 2694 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2668 of 2668 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2664 of 2664 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (Turkish)

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: Oğuz Ersen <oguz@ersen.moe>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/tr/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:14 +02:00
gallegonovato
ccbfeb11d0
Translated using Weblate (Spanish)
Currently translated at 100.0% (2739 of 2739 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2733 of 2733 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2731 of 2731 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2714 of 2714 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2702 of 2702 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2700 of 2700 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2698 of 2698 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2668 of 2668 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2664 of 2664 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (Spanish)

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: gallegonovato <fran-carro@hotmail.es>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/es/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:12 +02:00
skdubg
e6e87f9ff7
Translated using Weblate (German)
Currently translated at 100.0% (2739 of 2739 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2738 of 2738 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2735 of 2735 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2734 of 2734 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2733 of 2733 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2731 of 2731 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2716 of 2716 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2714 of 2714 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2711 of 2711 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2702 of 2702 strings)

Translated using Weblate (German)

Currently translated at 99.8% (2695 of 2700 strings)

Translated using Weblate (German)

Currently translated at 99.8% (2693 of 2698 strings)

Translated using Weblate (German)

Currently translated at 99.7% (2691 of 2698 strings)

Translated using Weblate (German)

Currently translated at 99.7% (2687 of 2694 strings)

Translated using Weblate (German)

Currently translated at 99.7% (2661 of 2668 strings)

Translated using Weblate (German)

Currently translated at 99.7% (2657 of 2664 strings)

Translated using Weblate (German)

Currently translated at 99.5% (2652 of 2664 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2639 of 2639 strings)

Translated using Weblate (German)

Currently translated at 100.0% (2631 of 2631 strings)

Co-authored-by: skdubg <skdubg@autistici.org>
Translate-URL: https://hosted.weblate.org/projects/freeyourgadget/gadgetbridge/de/
Translation: Freeyourgadget/Gadgetbridge
2024-05-01 18:33:10 +02:00
Martin.JM
83fd09939f [Huawei] Fix PR #3742, add workout frequency and altitude 2024-05-01 16:32:27 +00:00
Damien 'Psolyca' Gaignon
2d32822ff8
[Huawei] Add Huawei Watch Fit 2 gadget 2024-05-01 12:03:59 +02:00
José Rebelo
772ec05049 Update changelog 2024-04-30 20:57:40 +01:00
José Rebelo
18e08d13da Fix tests and linter 2024-04-30 20:43:23 +01:00
Martin.JM
1c2c1f710e [Huawei] Add support for workout calories and cycling power 2024-04-30 21:08:23 +02:00
José Rebelo
013ffe5559 Format pace as mm:ss 2024-04-29 19:50:57 +01:00
54 changed files with 4345 additions and 624 deletions

View File

@ -2,21 +2,61 @@
#### Next release (WIP)
* Experimental support for Redmi Watch 4
* Initial support for Huawei Watch Fit 2
* Introduce new Dashboard view
* AsteroidOS: Added icons to the notifications
* Bangle.js: Add screenshot support
* Bangle.js: Add setting to disable notifications
* Bangle.js: Allow wake phone when opening notification response from watch
* Bangle.js: Fix activity intensity normalization
* Bangle.js: Fix message reply
* Fossil/Skagen Hybrids: Update device settings to new structure
* Galaxy Buds Live: Update device settings to new structure
* HPlus: Migrate global preferences to device-specific
* Huawei: Add cycling workout type
* Huawei: Add enable HeartRate and SpO2 force option
* Huawei: Add huawei account support (pair without resetting watch)
* Huawei: Add support for workout calories and cycling power
* Huawei: Ask pincode only on first connection
* Huawei: Enable sleep detection
* Huawei: File upload and watchface management
* Huawei: Fix force DND support
* Huawei: Fix long notification
* Huawei: Fix TimeZone offset calculation
* Huawei: Improve connection and reconnection
* Huawei: Improve notification icons
* Huawei: Improve workout parsing
* Huawei: Rework settings menu with sub-screens
* Huawei: Support sending GPS to band
* Huawei Watch GT4: Add HR and SpO support
* Huawei Watch Ultimate: Add HR and SpO support
* Intent API: Added debug end call
* Mi Band 6: Add menu items for NFC shortcuts
* Nothing CMF Watch Pro: Add weather support
* Nothing Earbuds: Add adjustable delay for auto-pick-up of calls
* Nothing Earbuds: Add option to auto-reply to incoming phone calls
* Nothing Earbuds: Add option to read aloud incoming notifications
* Xiaomi Smart Band 8 Active: Fix discovery
* Xiaomi: Fix some crashes
* Xiaomi: Improve reconnection
* Xiaomi: Improve weather support, add multiple locations
* Set navbar color to match theme
* Xiaomi: Sync calendar event reminders
* Zepp OS: Add support for Sleep as Android
* Zepp OS: Sync calendar event reminders
* Add Armenian and Serbian transliterators
* Add GENERIC_PHONE and GENERIC_CALENDAR NotificationType handling
* Add support for scannable-only devices
* Fix crash when connecting on some phones
* Fix crash when enabling bluetooth
* Fix receiving shared gpx files
* Format pace as mm:ss
* Set navbar color to match theme
* Simplify pairing of bonded and companion devices
* Prevent text cutoff on all checkbox preferences
* Recognize "Delta Chat" as generic chat
* Remove deprecated general auto-reconnect preference
* Refactor location service
* Fix text cutoff on all checkbox preferences
#### 0.80.0
* Initial support for Amazfit Bip 3

View File

@ -45,7 +45,7 @@ public class GBDaoGenerator {
public static void main(String[] args) throws Exception {
final Schema schema = new Schema(71, MAIN_PACKAGE + ".entities");
final Schema schema = new Schema(73, MAIN_PACKAGE + ".entities");
Entity userAttributes = addUserAttributes(schema);
Entity user = addUserInfo(schema, userAttributes);
@ -1167,6 +1167,12 @@ public class GBDaoGenerator {
workoutDataSample.addByteArrayProperty("dataErrorHex");
workoutDataSample.addShortProperty("calories").notNull();
workoutDataSample.addShortProperty("cyclingPower").notNull();
workoutDataSample.addShortProperty("frequency").notNull();
workoutDataSample.addIntProperty("altitude");
return workoutDataSample;
}

View File

@ -178,10 +178,6 @@
android:name=".devices.pebble.PebbleSettingsActivity"
android:label="@string/pref_title_pebble_settings"
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".devices.hplus.HPlusSettingsActivity"
android:label="@string/preferences_hplus_settings"
android:parentActivityName=".activities.SettingsActivity" />
<activity
android:name=".devices.zetime.ZeTimePreferenceActivity"
android:label="@string/zetime_title_settings"

View File

@ -71,6 +71,7 @@ import java.util.Comparator;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Locale;
import java.util.concurrent.TimeUnit;
import nodomain.freeyourgadget.gadgetbridge.GBApplication;
@ -518,6 +519,14 @@ public class ActivitySummaryDetail extends AbstractGBActivity {
if (unit.equals("seconds") && !show_raw_data) { //rather then plain seconds, show formatted duration
value_field.setText(DateTimeUtils.formatDurationHoursMinutes((long) value, TimeUnit.SECONDS));
} else if (unit.equals("minutes_km") || unit.equals("minutes_mi")) {
// Format pace
value_field.setText(String.format(
Locale.getDefault(),
"%d:%02d %s",
(int) Math.floor(value), (int) Math.round(60 * (value - (int) Math.floor(value))),
getStringResourceByName(unit)
));
} else {
value_field.setText(String.format("%s %s", df.format(value), getStringResourceByName(unit)));
}

View File

@ -1190,7 +1190,10 @@ public class DebugActivity extends AbstractGBActivity {
for (DeviceType deviceType : DeviceType.values()) {
DeviceCoordinator coordinator = deviceType.getDeviceCoordinator();
int icon = coordinator.getDefaultIconResource();
String name = app.getString(coordinator.getDeviceNameResource()) + " (" + coordinator.getManufacturer() + ")";
String name = app.getString(coordinator.getDeviceNameResource());
if (!name.startsWith(coordinator.getManufacturer())) {
name += " (" + coordinator.getManufacturer() + ")";
}
long deviceId = deviceType.ordinal();
newMap.put(name, new Pair(deviceId, icon));
}

View File

@ -231,6 +231,7 @@ public class DeviceSettingsPreferenceConst {
public static final String PREF_AGPS_EXPIRY_REMINDER_TIME = "pref_agps_expiry_reminder_time";
public static final String PREF_AGPS_UPDATE_TIME = "pref_agps_update_time";
public static final String PREF_AGPS_EXPIRE_TIME = "pref_agps_expire_time";
public static final String PREF_AGPS_STATUS = "pref_agps_status";
public static final String PREF_FIND_PHONE = "prefs_find_phone";
public static final String PREF_FIND_PHONE_DURATION = "prefs_find_phone_duration";

View File

@ -0,0 +1,43 @@
/* Copyright (C) 2024 Martin.JM
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.database.schema;
import android.database.sqlite.SQLiteDatabase;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
public class GadgetbridgeUpdate_72 implements DBUpdateScript {
@Override
public void upgradeSchema(final SQLiteDatabase db) {
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Calories.columnName, db)) {
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
+ HuaweiWorkoutDataSampleDao.Properties.Calories.columnName + "\" INTEGER NOT NULL DEFAULT -1";
db.execSQL(statement);
}
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.CyclingPower.columnName, db)) {
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
+ HuaweiWorkoutDataSampleDao.Properties.CyclingPower.columnName + "\" INTEGER NOT NULL DEFAULT -1";
db.execSQL(statement);
}
}
@Override
public void downgradeSchema(final SQLiteDatabase db) {
}
}

View File

@ -0,0 +1,43 @@
/* Copyright (C) 2024 Martin.JM
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.database.schema;
import android.database.sqlite.SQLiteDatabase;
import nodomain.freeyourgadget.gadgetbridge.database.DBHelper;
import nodomain.freeyourgadget.gadgetbridge.database.DBUpdateScript;
import nodomain.freeyourgadget.gadgetbridge.entities.HuaweiWorkoutDataSampleDao;
public class GadgetbridgeUpdate_73 implements DBUpdateScript {
@Override
public void upgradeSchema(final SQLiteDatabase db) {
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Frequency.columnName, db)) {
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
+ HuaweiWorkoutDataSampleDao.Properties.Frequency.columnName + "\" INTEGER NOT NULL DEFAULT -1";
db.execSQL(statement);
}
if (!DBHelper.existsColumn(HuaweiWorkoutDataSampleDao.TABLENAME, HuaweiWorkoutDataSampleDao.Properties.Altitude.columnName, db)) {
final String statement = "ALTER TABLE " + HuaweiWorkoutDataSampleDao.TABLENAME + " ADD COLUMN \""
+ HuaweiWorkoutDataSampleDao.Properties.Altitude.columnName + "\" INTEGER DEFAULT NULL";
db.execSQL(statement);
}
}
@Override
public void downgradeSchema(final SQLiteDatabase db) {
}
}

View File

@ -0,0 +1,122 @@
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
import android.content.Context;
import android.net.Uri;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.BufferedInputStream;
import java.io.IOException;
import java.io.InputStream;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.InstallActivity;
import nodomain.freeyourgadget.gadgetbridge.devices.DeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
import nodomain.freeyourgadget.gadgetbridge.model.GenericItem;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps.GarminAgpsFile;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.UriHelper;
public class GarminAgpsInstallHandler implements InstallHandler {
private static final Logger LOG = LoggerFactory.getLogger(GarminAgpsInstallHandler.class);
protected final Context mContext;
private GarminAgpsFile file;
public GarminAgpsInstallHandler(final Uri uri, final Context context) {
this.mContext = context;
final UriHelper uriHelper;
try {
uriHelper = UriHelper.get(uri, context);
} catch (final IOException e) {
LOG.error("Failed to get uri", e);
return;
}
try (InputStream in = new BufferedInputStream(uriHelper.openInputStream())) {
final byte[] rawBytes = FileUtils.readAll(in, 1024 * 1024); // 1MB, they're usually ~60KB
final GarminAgpsFile agpsFile = new GarminAgpsFile(rawBytes);
if (agpsFile.isValid()) {
this.file = agpsFile;
}
} catch (final Exception e) {
LOG.error("Failed to read file", e);
}
}
@Override
public boolean isValid() {
return file != null;
}
@Override
public void validateInstallation(final InstallActivity installActivity, final GBDevice device) {
if (device.isBusy()) {
installActivity.setInfoText(device.getBusyTask());
installActivity.setInstallEnabled(false);
return;
}
final DeviceCoordinator coordinator = device.getDeviceCoordinator();
if (!(coordinator instanceof GarminCoordinator)) {
LOG.warn("Coordinator is not a GarminCoordinator: {}", coordinator.getClass());
installActivity.setInfoText(mContext.getString(R.string.fwapp_install_device_not_supported));
installActivity.setInstallEnabled(false);
return;
}
final GarminCoordinator garminCoordinator = (GarminCoordinator) coordinator;
if (!garminCoordinator.supportsAgpsUpdates()) {
installActivity.setInfoText(mContext.getString(R.string.fwapp_install_device_not_supported));
installActivity.setInstallEnabled(false);
return;
}
if (!device.isInitialized()) {
installActivity.setInfoText(mContext.getString(R.string.fwapp_install_device_not_ready));
installActivity.setInstallEnabled(false);
return;
}
final GenericItem fwItem = createInstallItem(device);
fwItem.setIcon(coordinator.getDefaultIconResource());
if (file == null) {
fwItem.setDetails(mContext.getString(R.string.miband_fwinstaller_incompatible_version));
installActivity.setInfoText(mContext.getString(R.string.fwinstaller_firmware_not_compatible_to_device));
installActivity.setInstallEnabled(false);
return;
}
final StringBuilder builder = new StringBuilder();
final String agpsBundle = mContext.getString(R.string.kind_agps_bundle);
builder.append(mContext.getString(R.string.fw_upgrade_notice, agpsBundle));
builder.append("\n\n").append(mContext.getString(R.string.miband_firmware_unknown_warning));
fwItem.setDetails(mContext.getString(R.string.miband_fwinstaller_untested_version));
installActivity.setInfoText(builder.toString());
installActivity.setInstallItem(fwItem);
installActivity.setInstallEnabled(true);
}
@Override
public void onStartInstall(final GBDevice device) {
}
public GarminAgpsFile getFile() {
return file;
}
private GenericItem createInstallItem(final GBDevice device) {
DeviceCoordinator coordinator = device.getDeviceCoordinator();
final String firmwareName = mContext.getString(
R.string.installhandler_firmware_name,
mContext.getString(coordinator.getDeviceNameResource()),
mContext.getString(R.string.kind_agps_bundle),
""
);
return new GenericItem(firmwareName);
}
}

View File

@ -1,5 +1,8 @@
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
import android.content.Context;
import android.net.Uri;
import androidx.annotation.NonNull;
import java.util.List;
@ -8,8 +11,10 @@ import nodomain.freeyourgadget.gadgetbridge.GBApplication;
import nodomain.freeyourgadget.gadgetbridge.GBException;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettings;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsScreen;
import nodomain.freeyourgadget.gadgetbridge.devices.AbstractBLEDeviceCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.InstallHandler;
import nodomain.freeyourgadget.gadgetbridge.entities.DaoSession;
import nodomain.freeyourgadget.gadgetbridge.entities.Device;
import nodomain.freeyourgadget.gadgetbridge.impl.GBDevice;
@ -50,6 +55,9 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
final List<Integer> location = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.LOCATION);
location.add(R.xml.devicesettings_workout_send_gps_to_band);
if (supportsAgpsUpdates()) {
location.add(R.xml.devicesettings_garmin_agps);
}
final List<Integer> connection = deviceSpecificSettings.addRootScreen(DeviceSpecificSettingsScreen.CONNECTION);
connection.add(R.xml.devicesettings_high_mtu);
@ -60,6 +68,11 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
return deviceSpecificSettings;
}
@Override
public DeviceSpecificSettingsCustomizer getDeviceSpecificSettingsCustomizer(GBDevice device) {
return new GarminSettingsCustomizer();
}
@Override
public boolean supportsActivityDataFetching() {
return true;
@ -92,4 +105,20 @@ public abstract class GarminCoordinator extends AbstractBLEDeviceCoordinator {
public boolean supportsUnicodeEmojis() {
return true;
}
@Override
public InstallHandler findInstallHandler(final Uri uri, final Context context) {
if (supportsAgpsUpdates()) {
final GarminAgpsInstallHandler agpsInstallHandler = new GarminAgpsInstallHandler(uri, context);
if (agpsInstallHandler.isValid()) {
return agpsInstallHandler;
}
}
return null;
}
public boolean supportsAgpsUpdates() {
return false;
}
}

View File

@ -0,0 +1,72 @@
package nodomain.freeyourgadget.gadgetbridge.devices.garmin;
import android.os.Parcel;
import androidx.annotation.NonNull;
import androidx.preference.Preference;
import java.text.SimpleDateFormat;
import java.util.Collections;
import java.util.Date;
import java.util.Locale;
import java.util.Set;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsCustomizer;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSpecificSettingsHandler;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps.GarminAgpsStatus;
import nodomain.freeyourgadget.gadgetbridge.util.Prefs;
public class GarminSettingsCustomizer implements DeviceSpecificSettingsCustomizer {
@Override
public void onPreferenceChange(Preference preference, DeviceSpecificSettingsHandler handler) {
}
@Override
public void customizeSettings(DeviceSpecificSettingsHandler handler, Prefs prefs) {
final SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss", Locale.getDefault());
final Preference prefAgpsUpdateTime = handler.findPreference(DeviceSettingsPreferenceConst.PREF_AGPS_UPDATE_TIME);
if (prefAgpsUpdateTime != null) {
final long ts = prefs.getLong(DeviceSettingsPreferenceConst.PREF_AGPS_UPDATE_TIME, 0L);
if (ts > 0) {
prefAgpsUpdateTime.setSummary(sdf.format(new Date(ts)));
} else {
prefAgpsUpdateTime.setSummary(handler.getContext().getString(R.string.unknown));
}
}
final Preference prefAgpsStatus = handler.findPreference(DeviceSettingsPreferenceConst.PREF_AGPS_STATUS);
if (prefAgpsStatus != null) {
final GarminAgpsStatus agpsStatus = GarminAgpsStatus.valueOf(prefs.getString(DeviceSettingsPreferenceConst.PREF_AGPS_STATUS, GarminAgpsStatus.MISSING.name()));
prefAgpsStatus.setSummary(handler.getContext().getString(agpsStatus.getText()));
}
}
@Override
public Set<String> getPreferenceKeysWithSummary() {
return Collections.emptySet();
}
public static final Creator<GarminSettingsCustomizer> CREATOR = new Creator<GarminSettingsCustomizer>() {
@Override
public GarminSettingsCustomizer createFromParcel(final Parcel in) {
return new GarminSettingsCustomizer();
}
@Override
public GarminSettingsCustomizer[] newArray(final int size) {
return new GarminSettingsCustomizer[size];
}
};
@Override
public int describeContents() {
return 0;
}
@Override
public void writeToParcel(@NonNull Parcel dest, int flags) {
}
}

View File

@ -15,4 +15,14 @@ public class GarminInstinct2SCoordinator extends GarminCoordinator {
public int getDeviceNameResource() {
return R.string.devicetype_garmin_instinct_2s;
}
@Override
public boolean supportsFlashing() {
return true;
}
@Override
public boolean supportsAgpsUpdates() {
return true;
}
}

View File

@ -16,4 +16,14 @@ public class GarminInstinct2SolarCoordinator extends GarminCoordinator {
public int getDeviceNameResource() {
return R.string.devicetype_garmin_instinct_2_solar;
}
@Override
public boolean supportsFlashing() {
return true;
}
@Override
public boolean supportsAgpsUpdates() {
return true;
}
}

View File

@ -15,4 +15,14 @@ public class GarminInstinct2SolTacCoordinator extends GarminCoordinator {
public int getDeviceNameResource() {
return R.string.devicetype_garmin_instinct_2_soltac;
}
@Override
public boolean supportsFlashing() {
return true;
}
@Override
public boolean supportsAgpsUpdates() {
return true;
}
}

View File

@ -6,13 +6,23 @@ import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminCoordinator;
public class GarminVivoActive4SCoordinator extends GarminCoordinator {
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile("vívoactive 4S");
}
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile("vívoactive 4S");
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_garmin_vivoactive_4s;
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_garmin_vivoactive_4s;
}
@Override
public boolean supportsFlashing() {
return true;
}
@Override
public boolean supportsAgpsUpdates() {
return true;
}
}

View File

@ -66,6 +66,7 @@ public final class HuaweiConstants {
public static final String HU_WATCHGT3PRO_NAME = "huawei watch gt 3 pro-";
public static final String HU_WATCHGT4_NAME = "huawei watch gt 4-";
public static final String HU_WATCHFIT_NAME = "huawei watch fit-";
public static final String HU_WATCHFIT2_NAME = "huawei watch fit 2-";
public static final String HU_WATCHULTIMATE_NAME = "huawei watch ultimate-";
public static final String PREF_HUAWEI_ADDRESS = "huawei_address";

View File

@ -0,0 +1,51 @@
/* Copyright (C) 2024 Damien Gaignon
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.huawei.huaweiwatchfit2;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.regex.Pattern;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiBRCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.HuaweiConstants;
import nodomain.freeyourgadget.gadgetbridge.model.DeviceType;
public class HuaweiWatchFit2Coordinator extends HuaweiBRCoordinator {
private static final Logger LOG = LoggerFactory.getLogger(HuaweiWatchFit2Coordinator.class);
public HuaweiWatchFit2Coordinator() {
super();
getHuaweiCoordinator().setTransactionCrypted(true);
}
@Override
public DeviceType getDeviceType() {
return DeviceType.HUAWEIWATCHFIT2;
}
@Override
protected Pattern getSupportedDeviceName() {
return Pattern.compile("(" + HuaweiConstants.HU_WATCHFIT2_NAME + ").*", Pattern.CASE_INSENSITIVE);
}
@Override
public int getDeviceNameResource() {
return R.string.devicetype_huawei_watchfit2;
}
}

View File

@ -239,12 +239,17 @@ public class Workout {
public byte swolf = -1;
public short strokeRate = -1;
public short calories = -1;
public short cyclingPower = -1;
public short frequency = -1;
public Integer altitude = null;
public int timestamp = -1; // Calculated timestamp for this data point
@Override
public String toString() {
return "Data{" +
"unknownData=" + unknownData +
"unknownData=" + Arrays.toString(unknownData) +
", heartRate=" + heartRate +
", speed=" + speed +
", stepRate=" + stepRate +
@ -259,13 +264,17 @@ public class Workout {
", eversionAngle=" + eversionAngle +
", swolf=" + swolf +
", strokeRate=" + strokeRate +
", calories=" + calories +
", cyclingPower=" + cyclingPower +
", frequency=" + frequency +
", altitude=" + altitude +
", timestamp=" + timestamp +
'}';
}
}
// I'm not sure about the lengths, but we haven't gotten any complaints so they probably are fine
private final byte[] bitmapLengths = {1, 2, 1, 2, 2, 4, -1, 2, 2, 1, 1, 1, 1, 1, 1, 1};
private final byte[] bitmapLengths = {1, 2, 1, 2, 2, 4, -1, 2, 2, 2, 1, 1, 1, 1, 1, 1};
private final byte[] innerBitmapLengths = {2, 2, 2, 1, 2, 1, 1, 1, 1, 2, 2, 1, 1, 1, 1, 1};
public short workoutNumber;
@ -367,6 +376,9 @@ public class Workout {
case 4:
data.strokeRate = buf.getShort();
break;
case 5:
data.altitude = buf.getInt();
break;
case 6:
// Inner data, parsing into data
// TODO: function for readability?
@ -410,6 +422,15 @@ public class Workout {
}
}
break;
case 7:
data.calories = buf.getShort();
break;
case 8:
data.frequency = buf.getShort();
break;
case 9:
data.cyclingPower = buf.getShort();
break;
default:
data.unknownData = this.tlv.serialize();
// Fix alignment

View File

@ -106,6 +106,10 @@ public class ActivitySummaryEntries {
public static final String MAXIMUM_OXYGEN_UPTAKE = "maximumOxygenUptake";
public static final String RECOVERY_TIME = "recoveryTime";
public static final String CYCLING_POWER_AVERAGE = "cyclingPowerAverage";
public static final String CYCLING_POWER_MIN = "cyclingPowerMin";
public static final String CYCLING_POWER_MAX = "cyclingPowerMax";
public static final String UNIT_BPM = "bpm";
public static final String UNIT_CM = "cm";
public static final String UNIT_UNIX_EPOCH_SECONDS = "unix_epoch_seconds";

View File

@ -129,6 +129,7 @@ import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiband8.HuaweiBan
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweibandaw70.HuaweiBandAw70Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweitalkbandb6.HuaweiTalkBandB6Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchfit.HuaweiWatchFitCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchfit2.HuaweiWatchFit2Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchgt.HuaweiWatchGTCoordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchgt2.HuaweiWatchGT2Coordinator;
import nodomain.freeyourgadget.gadgetbridge.devices.huawei.huaweiwatchgt2e.HuaweiWatchGT2eCoordinator;
@ -386,6 +387,7 @@ public enum DeviceType {
HUAWEIWATCHGT4(HuaweiWatchGT4Coordinator.class),
HUAWEIBAND8(HuaweiBand8Coordinator.class),
HUAWEIWATCHFIT(HuaweiWatchFitCoordinator.class),
HUAWEIWATCHFIT2(HuaweiWatchFit2Coordinator.class),
HUAWEIWATCHULTIMATE(HuaweiWatchUltimateCoordinator.class),
VESC(VescCoordinator.class),
BINARY_SENSOR(BinarySensorCoordinator.class),

View File

@ -18,6 +18,7 @@
package nodomain.freeyourgadget.gadgetbridge.service.btle;
import android.Manifest;
import android.annotation.SuppressLint;
import android.app.Notification;
import android.app.NotificationManager;
import android.app.Service;
@ -326,8 +327,8 @@ public class BLEScanService extends Service {
unregisterReceiver(bluetoothStateChangedReceiver);
}
private boolean hasBluetoothPermission(){
if(Build.VERSION.SDK_INT <= Build.VERSION_CODES.R){
private boolean hasBluetoothPermission() {
if (Build.VERSION.SDK_INT <= Build.VERSION_CODES.R) {
// workaround. Cannot give bluetooth permission on Android O
LOG.warn("Running on android 11, skipping bluetooth permission check");
return ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.ACCESS_COARSE_LOCATION) == PackageManager.PERMISSION_GRANTED;
@ -335,6 +336,7 @@ public class BLEScanService extends Service {
return ActivityCompat.checkSelfPermission(getApplicationContext(), Manifest.permission.BLUETOOTH_SCAN) == PackageManager.PERMISSION_GRANTED;
}
@SuppressLint("MissingPermission") // linter does not recognize the usage of hasBluetoothPermission
private void restartScan(boolean applyFilters) {
if (!hasBluetoothPermission()) {
// this should never happen
@ -357,7 +359,9 @@ public class BLEScanService extends Service {
return;
}
if (currentState.isDoingAnyScan()) {
scanner.stopScan(scanCallback);
if (hasBluetoothPermission()) {
scanner.stopScan(scanCallback);
}
}
ArrayList<ScanFilter> scanFilters = null;
@ -375,7 +379,7 @@ public class BLEScanService extends Service {
}
}
if (scanFilters.size() == 0) {
if (scanFilters.isEmpty()) {
// no need to start scanning
LOG.debug("restartScan: stopping BLE scan, no devices");
currentState = ScanningState.NOT_SCANNING;

View File

@ -3,11 +3,14 @@ package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin;
import android.bluetooth.BluetoothGatt;
import android.bluetooth.BluetoothGattCharacteristic;
import android.location.Location;
import android.net.Uri;
import android.widget.Toast;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.DecimalFormat;
import java.util.ArrayList;
@ -24,7 +27,10 @@ import java.util.TimerTask;
import java.util.UUID;
import nodomain.freeyourgadget.gadgetbridge.R;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEvent;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminAgpsInstallHandler;
import nodomain.freeyourgadget.gadgetbridge.devices.garmin.GarminPreferences;
import nodomain.freeyourgadget.gadgetbridge.devices.vivomovehr.GarminCapability;
import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService;
@ -44,6 +50,7 @@ import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiSmartProto;
import nodomain.freeyourgadget.gadgetbridge.service.btle.AbstractBTLEDeviceSupport;
import nodomain.freeyourgadget.gadgetbridge.service.btle.TransactionBuilder;
import nodomain.freeyourgadget.gadgetbridge.service.btle.actions.SetDeviceStateAction;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps.GarminAgpsStatus;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.ICommunicator;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.v1.CommunicatorV1;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.communicator.v2.CommunicatorV2;
@ -616,6 +623,28 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
}
}
@Override
public void onInstallApp(final Uri uri) {
final GarminAgpsInstallHandler agpsHandler = new GarminAgpsInstallHandler(uri, getContext());
if (agpsHandler.isValid()) {
try {
// Write the AGPS update to a temporary file in cache, so we can load it when requested
final File agpsFile = getAgpsFile();
try (FileOutputStream outputStream = new FileOutputStream(agpsFile)) {
outputStream.write(agpsHandler.getFile().getBytes());
evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(
DeviceSettingsPreferenceConst.PREF_AGPS_STATUS, GarminAgpsStatus.PENDING.name()
));
LOG.info("AGPS file successfully written to the cache directory.");
} catch (final IOException e) {
LOG.error("Failed to write AGPS bytes to temporary directory", e);
}
} catch (final Exception e) {
GB.toast(getContext(), "AGPS install error: " + e.getMessage(), Toast.LENGTH_LONG, GB.ERROR, e);
}
}
}
private boolean checkFileExists(String fileName) {
File dir;
try {
@ -647,4 +676,20 @@ public class GarminSupport extends AbstractBTLEDeviceSupport implements ICommuni
);
sendOutgoingMessage(locationUpdatedNotificationRequest);
}
public File getAgpsFile() throws IOException {
return new File(getAgpsCacheDirectory(), "CPE.BIN");
}
private File getAgpsCacheDirectory() throws IOException {
final File cacheDir = getContext().getCacheDir();
final File agpsCacheDir = new File(cacheDir, "garmin-agps");
if (agpsCacheDir.mkdir()) {
LOG.info("AGPS cache directory for Garmin devices successfully created.");
} else if (!agpsCacheDir.exists() || !agpsCacheDir.isDirectory()) {
throw new IOException("Cannot create/locate AGPS directory for Garmin devices.");
}
return agpsCacheDir;
}
}

View File

@ -24,11 +24,13 @@ import nodomain.freeyourgadget.gadgetbridge.externalevents.gps.GBLocationService
import nodomain.freeyourgadget.gadgetbridge.model.CannedMessagesSpec;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiCalendarService;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiCore;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiDataTransferService;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiDeviceStatus;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiFindMyWatch;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiHttpService;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiSmartProto;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiSmsNotification;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http.DataTransferHandler;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http.HttpHandler;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.GFDIMessage;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.messages.ProtobufMessage;
@ -45,12 +47,16 @@ public class ProtocolBufferHandler implements MessageHandler {
private final Map<Integer, ProtobufFragment> chunkedFragmentsMap;
private final int maxChunkSize = 375; //tested on Vívomove Style
private int lastProtobufRequestId;
private final HttpHandler httpHandler;
private final DataTransferHandler dataTransferHandler;
private final Map<GdiSmsNotification.SmsNotificationService.CannedListType, String[]> cannedListTypeMap = new HashMap<>();
public ProtocolBufferHandler(GarminSupport deviceSupport) {
this.deviceSupport = deviceSupport;
chunkedFragmentsMap = new HashMap<>();
httpHandler = new HttpHandler(deviceSupport);
dataTransferHandler = new DataTransferHandler();
}
private int getNextProtobufRequestId() {
@ -91,12 +97,19 @@ public class ProtocolBufferHandler implements MessageHandler {
return prepareProtobufResponse(processProtobufSmsNotificationMessage(smart.getSmsNotificationService()), message.getRequestId());
}
if (smart.hasHttpService()) {
final GdiHttpService.HttpService response = HttpHandler.handle(smart.getHttpService());
final GdiHttpService.HttpService response = httpHandler.handle(smart.getHttpService());
if (response == null) {
return null;
}
return prepareProtobufResponse(GdiSmartProto.Smart.newBuilder().setHttpService(response).build(), message.getRequestId());
}
if (smart.hasDataTransferService()) {
final GdiDataTransferService.DataTransferService response = dataTransferHandler.handle(smart.getDataTransferService(), message.getRequestId());
if (response == null) {
return null;
}
return prepareProtobufResponse(GdiSmartProto.Smart.newBuilder().setDataTransferService(response).build(), message.getRequestId());
}
if (smart.hasDeviceStatusService()) {
processed = true;
processProtobufDeviceStatusResponse(smart.getDeviceStatusService());
@ -116,6 +129,9 @@ public class ProtocolBufferHandler implements MessageHandler {
private ProtobufMessage processIncoming(ProtobufStatusMessage statusMessage) {
LOG.info("Processing protobuf status message #{}@{}: status={}, error={}", statusMessage.getRequestId(), statusMessage.getDataOffset(), statusMessage.getProtobufChunkStatus(), statusMessage.getProtobufStatusCode());
//TODO: check status and react accordingly, right now we blindly proceed to next chunk
if (statusMessage.isOK()) {
DataTransferHandler.onDataChunkSuccessfullyReceived(statusMessage.getRequestId());
}
if (chunkedFragmentsMap.containsKey(statusMessage.getRequestId()) && statusMessage.isOK()) {
final ProtobufFragment protobufFragment = chunkedFragmentsMap.get(statusMessage.getRequestId());
LOG.debug("Protobuf message #{} found in queue: {}", statusMessage.getRequestId(), GB.hexdump(protobufFragment.fragmentBytes));

View File

@ -0,0 +1,90 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.threeten.bp.Instant;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Map;
import java.util.Objects;
import java.util.concurrent.Callable;
import nodomain.freeyourgadget.gadgetbridge.activities.devicesettings.DeviceSettingsPreferenceConst;
import nodomain.freeyourgadget.gadgetbridge.deviceevents.GBDeviceEventUpdatePreferences;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminSupport;
import nodomain.freeyourgadget.gadgetbridge.util.FileUtils;
import nodomain.freeyourgadget.gadgetbridge.util.GBTarFile;
public class AgpsHandler {
private static final Logger LOG = LoggerFactory.getLogger(AgpsHandler.class);
private static final String QUERY_CONSTELLATIONS = "constellations";
private final GarminSupport deviceSupport;
public AgpsHandler(GarminSupport deviceSupport) {
this.deviceSupport = deviceSupport;
}
public byte[] handleAgpsRequest(final String path, final Map<String, String> query) {
try {
if (!query.containsKey(QUERY_CONSTELLATIONS)) {
LOG.debug("Query does not contain information about constellations; skipping request.");
return null;
}
final File agpsFile = deviceSupport.getAgpsFile();
if (!agpsFile.exists() || !agpsFile.isFile()) {
LOG.info("File with AGPS data does not exist.");
return null;
}
try(InputStream agpsIn = new FileInputStream(agpsFile)) {
final byte[] rawBytes = FileUtils.readAll(agpsIn, 1024 * 1024); // 1MB, they're usually ~60KB
final GBTarFile tarFile = new GBTarFile(rawBytes);
final String[] requestedConstellations = Objects.requireNonNull(query.get(QUERY_CONSTELLATIONS)).split(",");
for (final String constellation: requestedConstellations) {
try {
final GarminAgpsDataType garminAgpsDataType = GarminAgpsDataType.valueOf(constellation);
if (!tarFile.containsFile(garminAgpsDataType.getFileName())) {
LOG.error("AGPS archive is missing requested file: {}", garminAgpsDataType.getFileName());
deviceSupport.evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(
DeviceSettingsPreferenceConst.PREF_AGPS_STATUS, GarminAgpsStatus.ERROR.name()
));
return null;
}
} catch (IllegalArgumentException e) {
LOG.error("Device requested unsupported AGPS data type: {}", constellation);
deviceSupport.evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(
DeviceSettingsPreferenceConst.PREF_AGPS_STATUS, GarminAgpsStatus.ERROR.name()
));
return null;
}
}
LOG.info("Sending new AGPS data to the device.");
return rawBytes;
}
} catch (IOException e) {
LOG.error("Unable to obtain AGPS data.", e);
deviceSupport.evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(
DeviceSettingsPreferenceConst.PREF_AGPS_STATUS, GarminAgpsStatus.ERROR.name()
));
return null;
}
}
public Callable<Void> getOnDataSuccessfullySentListener() {
return () -> {
LOG.info("AGPS data successfully sent to the device.");
deviceSupport.evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(
DeviceSettingsPreferenceConst.PREF_AGPS_UPDATE_TIME, Instant.now().toEpochMilli()
));
deviceSupport.evaluateGBDeviceEvent(new GBDeviceEventUpdatePreferences(
DeviceSettingsPreferenceConst.PREF_AGPS_STATUS, GarminAgpsStatus.CURRENT.name()
));
if (deviceSupport.getAgpsFile().delete()) {
LOG.info("AGPS data was deleted from the cache folder.");
}
return null;
};
}
}

View File

@ -0,0 +1,25 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps;
public enum GarminAgpsDataType {
GLONASS("CPE_GLO.BIN"), QZSS("CPE_QZSS.BIN"), GPS("CPE_GPS.BIN"),
GALILEO("CPE_GAL.BIN");
private final String fileName;
GarminAgpsDataType(String fileName) {
this.fileName = fileName;
}
public String getFileName() {
return fileName;
}
public static boolean isValidAgpsDataFileName(String fileName) {
for (GarminAgpsDataType type: GarminAgpsDataType.values()) {
if (fileName.equals(type.fileName)) {
return true;
}
}
return false;
}
}

View File

@ -0,0 +1,37 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import nodomain.freeyourgadget.gadgetbridge.util.GBTarFile;
public class GarminAgpsFile {
private static final Logger LOG = LoggerFactory.getLogger(GarminAgpsFile.class);
private final byte[] tarBytes;
public GarminAgpsFile(final byte[] tarBytes) {
this.tarBytes = tarBytes;
}
public boolean isValid() {
if (!GBTarFile.isTarFile(tarBytes)) {
LOG.debug("Is not TAR file!");
return false;
}
final GBTarFile tarFile = new GBTarFile(tarBytes);
for (final String fileName: tarFile.listFileNames()) {
if (!GarminAgpsDataType.isValidAgpsDataFileName(fileName)) {
LOG.error("Unknown file in TAR archive: {}", fileName);
return false;
}
}
return true;
}
public byte[] getBytes() {
return tarBytes.clone();
}
}

View File

@ -0,0 +1,23 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps;
import androidx.annotation.StringRes;
import nodomain.freeyourgadget.gadgetbridge.R;
public enum GarminAgpsStatus {
MISSING(R.string.agps_status_missing), // AGPS data file was not yet installed
PENDING(R.string.agps_status_pending), // AGPS data file is waiting for installation
CURRENT(R.string.agps_status_current), // AGPS data was successfully installed
ERROR(R.string.agps_status_error); // Unable to install AGPS data file
private final @StringRes int text;
GarminAgpsStatus(@StringRes int text) {
this.text = text;
}
public @StringRes int getText() {
return text;
}
}

View File

@ -0,0 +1,178 @@
package nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.http;
import com.google.protobuf.ByteString;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;
import java.util.Random;
import java.util.TreeMap;
import java.util.concurrent.Callable;
import java.util.concurrent.atomic.AtomicInteger;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiDataTransferService;
public class DataTransferHandler {
private static final Logger LOG = LoggerFactory.getLogger(DataTransferHandler.class);
private static final AtomicInteger idCounter = new AtomicInteger((new Random()).nextInt(Integer.MAX_VALUE / 2));
private static final Map<Integer, Data> dataById = new HashMap<>();
private static final Map<Integer, ChunkInfo> unprocessedChunksByRequestId = new HashMap<>();
public GdiDataTransferService.DataTransferService handle(
final GdiDataTransferService.DataTransferService dataTransferService,
final int requestId
) {
if (dataTransferService.hasDataDownloadRequest()) {
final GdiDataTransferService.DataTransferService.DataDownloadResponse dataDownloadResponse
= handleDataDownloadRequest(dataTransferService.getDataDownloadRequest(), requestId);
if (dataDownloadResponse != null) {
return GdiDataTransferService.DataTransferService.newBuilder()
.setDataDownloadResponse(dataDownloadResponse)
.build();
}
return null;
}
LOG.warn("Unsupported data transfer service request: {}", dataTransferService);
return null;
}
public GdiDataTransferService.DataTransferService.DataDownloadResponse handleDataDownloadRequest(
final GdiDataTransferService.DataTransferService.DataDownloadRequest dataDownloadRequest,
final int requestId
) {
final int dataId = dataDownloadRequest.getId();
final int offset = dataDownloadRequest.getOffset();
LOG.debug("Received data download request (id: {}, offset: {})", dataId, offset);
final Data data = dataById.get(dataId);
if (data == null) {
LOG.error("Device requested data with invalid id: {}", dataId);
return GdiDataTransferService.DataTransferService.DataDownloadResponse.newBuilder()
.setStatus(GdiDataTransferService.DataTransferService.Status.INVALID_ID)
.setId(dataId)
.setOffset(offset)
.build();
}
final int maxChunkSize = dataDownloadRequest.hasMaxChunkSize() ? dataDownloadRequest.getMaxChunkSize() : Integer.MAX_VALUE;
final byte[] chunk = data.getDataChunk(offset, maxChunkSize);
if (chunk == null) {
LOG.error("Device requested data with invalid offset: {}", offset);
return GdiDataTransferService.DataTransferService.DataDownloadResponse.newBuilder()
.setStatus(GdiDataTransferService.DataTransferService.Status.INVALID_OFFSET)
.setId(dataId)
.setOffset(offset)
.build();
}
unprocessedChunksByRequestId.put(requestId, new ChunkInfo(dataId, offset, offset + chunk.length));
return GdiDataTransferService.DataTransferService.DataDownloadResponse.newBuilder()
.setStatus(GdiDataTransferService.DataTransferService.Status.SUCCESS)
.setId(dataId)
.setOffset(offset)
.setPayload(ByteString.copyFrom(chunk))
.build();
}
public static int registerData(final byte[] data) {
int id = idCounter.getAndIncrement();
LOG.info("New data will be sent to the device (id: {}, size: {})", id, data.length);
dataById.put(id, new Data(data));
return id;
}
public static void onDataChunkSuccessfullyReceived(final int requestId) {
final ChunkInfo chunkInfo = unprocessedChunksByRequestId.get(requestId);
if (chunkInfo == null) {
return;
}
unprocessedChunksByRequestId.remove(requestId);
final Data data = dataById.get(chunkInfo.dataId);
if (data == null) {
return;
}
data.onDataChunkSuccessfullyReceived(chunkInfo);
if (data.isDataSuccessfullySent()) {
LOG.info("Data successfully sent to the device (id: {}, size: {})", chunkInfo.dataId, data.data.length);
for (Callable<Void> listener : data.onDataSuccessfullySentListeners) {
try {
listener.call();
} catch (Exception e) {
LOG.error("Data listener failed.", e);
}
}
dataById.remove(chunkInfo.dataId);
} else {
LOG.debug(
"Data chunk successfully sent to the device (dataId: {}, requestId: {}): {}-{}/{}",
chunkInfo.dataId, requestId, chunkInfo.start, chunkInfo.end, data.data.length
);
}
}
public static void addOnDataSuccessfullySentListener(final int dataId, final Callable<Void> listener) {
Objects.requireNonNull(dataById.get(dataId)).onDataSuccessfullySentListeners.add(listener);
}
private static class ChunkInfo {
private final int dataId;
private final int start;
private final int end;
private ChunkInfo(int dataId, int start, int end) {
this.dataId = dataId;
this.start = start;
this.end = end;
}
}
private static class Data {
// TODO Wouldn't it be better to store data as streams?
// Because now we have to store the whole data in RAM.
private final byte[] data;
private final TreeMap<Integer, ChunkInfo> chunksReceivedByDevice;
private final List<Callable<Void>> onDataSuccessfullySentListeners;
private Data(byte[] data) {
this.data = data;
chunksReceivedByDevice = new TreeMap<>();
onDataSuccessfullySentListeners = new ArrayList<>();
}
private byte[] getDataChunk(final int offset, final int maxChunkSize) {
if (offset < 0 || offset >= data.length) {
return null;
}
return Arrays.copyOfRange(data, offset, Math.min(offset + maxChunkSize, data.length));
}
private void onDataChunkSuccessfullyReceived(ChunkInfo newlyReceivedChunk) {
final ChunkInfo alreadyReceivedChunk = chunksReceivedByDevice.get(newlyReceivedChunk.start);
if (alreadyReceivedChunk == null || alreadyReceivedChunk.end < newlyReceivedChunk.end) {
chunksReceivedByDevice.put(newlyReceivedChunk.start, newlyReceivedChunk);
}
}
private boolean isDataSuccessfullySent() {
Integer previousChunkEnd = null;
for (Map.Entry<Integer, ChunkInfo> chunkEntry : chunksReceivedByDevice.entrySet()) {
if (previousChunkEnd == null && chunkEntry.getKey() != 0) {
// The head of the data wasn't received by the device.
return false;
}
if (previousChunkEnd != null && chunkEntry.getKey() > previousChunkEnd) {
// There is some gap between received chunks.
return false;
}
previousChunkEnd = chunkEntry.getValue().end;
}
// Check if the end of the last chunk matches the data size.
return previousChunkEnd != null && data.length == previousChunkEnd;
}
}
}

View File

@ -16,9 +16,12 @@ import java.util.HashMap;
import java.util.List;
import java.util.Locale;
import java.util.Map;
import java.util.concurrent.Callable;
import java.util.zip.GZIPOutputStream;
import nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr.GdiHttpService;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.GarminSupport;
import nodomain.freeyourgadget.gadgetbridge.service.devices.garmin.agps.AgpsHandler;
import nodomain.freeyourgadget.gadgetbridge.util.HttpUtils;
public class HttpHandler {
@ -28,7 +31,13 @@ public class HttpHandler {
//.serializeNulls()
.create();
public static GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) {
private final AgpsHandler agpsHandler;
public HttpHandler(GarminSupport deviceSupport) {
agpsHandler = new AgpsHandler(deviceSupport);
}
public GdiHttpService.HttpService handle(final GdiHttpService.HttpService httpService) {
if (httpService.hasRawRequest()) {
final GdiHttpService.HttpService.RawResponse rawResponse = handleRawRequest(httpService.getRawRequest());
if (rawResponse != null) {
@ -44,7 +53,8 @@ public class HttpHandler {
return null;
}
public static GdiHttpService.HttpService.RawResponse handleRawRequest(final GdiHttpService.HttpService.RawRequest rawRequest) {
public GdiHttpService.HttpService.RawResponse handleRawRequest(final GdiHttpService.HttpService.RawRequest rawRequest) {
// TODO Return status code 304 (Not Modified) when we don't have newer data and "if-none-match" is set.
final String urlString = rawRequest.getUrl();
LOG.debug("Got rawRequest: {} - {}", rawRequest.getMethod(), urlString);
@ -58,53 +68,85 @@ public class HttpHandler {
final String path = url.getPath();
final Map<String, String> query = HttpUtils.urlQueryParameters(url);
final Map<String, String> requestHeaders = headersToMap(rawRequest.getHeaderList());
final byte[] responseBody;
final List<GdiHttpService.HttpService.Header> responseHeaders = new ArrayList<>();
if (path.startsWith("/weather/")) {
LOG.debug("Got weather request for {}", path);
final Object obj = WeatherHandler.handleWeatherRequest(path, query);
if (obj == null) {
LOG.info("Got weather request for {}", path);
final Object weatherData = WeatherHandler.handleWeatherRequest(path, query);
if (weatherData == null) {
return null;
}
final String json = GSON.toJson(obj);
final String json = GSON.toJson(weatherData);
LOG.debug("Weather response: {}", json);
final byte[] stringBytes = json.getBytes(StandardCharsets.UTF_8);
if ("gzip".equals(requestHeaders.get("accept-encoding"))) {
responseHeaders.add(
GdiHttpService.HttpService.Header.newBuilder()
.setKey("Content-Encoding")
.setValue("gzip")
.build()
);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
gzos.write(stringBytes);
gzos.finish();
gzos.flush();
responseBody = baos.toByteArray();
} catch (final Exception e) {
LOG.error("Failed to compress response", e);
return null;
}
} else {
responseBody = stringBytes;
return createRawResponse(rawRequest, json.getBytes(StandardCharsets.UTF_8), "application/json", null);
} else if (path.startsWith("/ephemeris/")) {
LOG.info("Got AGPS request for {}", path);
final byte[] agpsData = agpsHandler.handleAgpsRequest(path, query);
if (agpsData == null) {
return null;
}
responseHeaders.add(
GdiHttpService.HttpService.Header.newBuilder()
.setKey("Content-Type")
.setValue("application/json")
.build()
);
LOG.debug("Successfully obtained AGPS data (length: {})", agpsData.length);
return createRawResponse(rawRequest, agpsData, "application/x-tar", agpsHandler.getOnDataSuccessfullySentListener());
} else {
LOG.warn("Unhandled path {}", urlString);
return null;
}
}
private static GdiHttpService.HttpService.RawResponse createRawResponse(
final GdiHttpService.HttpService.RawRequest rawRequest,
final byte[] data,
final String contentType,
final Callable<Void> onDataSuccessfullySentListener
) {
if (rawRequest.hasUseDataXfer() && rawRequest.getUseDataXfer()) {
LOG.debug("Data will be returned using data_xfer");
int id = DataTransferHandler.registerData(data);
if (onDataSuccessfullySentListener != null) {
DataTransferHandler.addOnDataSuccessfullySentListener(id, onDataSuccessfullySentListener);
}
return GdiHttpService.HttpService.RawResponse.newBuilder()
.setStatus(GdiHttpService.HttpService.Status.OK)
.setHttpStatus(200)
.setXferData(
GdiHttpService.HttpService.DataTransferItem.newBuilder()
.setId(id)
.setSize(data.length)
.build()
)
.build();
}
final Map<String, String> requestHeaders = headersToMap(rawRequest.getHeaderList());
final List<GdiHttpService.HttpService.Header> responseHeaders = new ArrayList<>();
final byte[] responseBody;
if ("gzip".equals(requestHeaders.get("accept-encoding"))) {
responseHeaders.add(
GdiHttpService.HttpService.Header.newBuilder()
.setKey("Content-Encoding")
.setValue("gzip")
.build()
);
final ByteArrayOutputStream baos = new ByteArrayOutputStream();
try (GZIPOutputStream gzos = new GZIPOutputStream(baos)) {
gzos.write(data);
gzos.finish();
gzos.flush();
responseBody = baos.toByteArray();
} catch (final Exception e) {
LOG.error("Failed to compress response", e);
return null;
}
} else {
responseBody = data;
}
responseHeaders.add(
GdiHttpService.HttpService.Header.newBuilder()
.setKey("Content-Type")
.setValue(contentType)
.build()
);
return GdiHttpService.HttpService.RawResponse.newBuilder()
.setStatus(GdiHttpService.HttpService.Status.OK)

View File

@ -1513,7 +1513,11 @@ public class HuaweiSupportProvider {
data.eversionAngle,
data.swolf,
data.strokeRate,
unknown
unknown,
data.calories,
data.cyclingPower,
data.frequency,
data.altitude
);
dao.insertOrReplace(dataSample);
}

View File

@ -106,7 +106,11 @@ public class HuaweiWorkoutGbParser {
responseData.eversionAngle,
responseData.swolf,
responseData.strokeRate,
dataErrorHex
dataErrorHex,
responseData.calories,
responseData.cyclingPower,
responseData.frequency,
responseData.altitude
);
dbHandler.getDaoSession().getHuaweiWorkoutDataSampleDao().insertOrReplace(dataSample);
@ -301,6 +305,18 @@ public class HuaweiWorkoutGbParser {
int heartRateCount = 0;
int maxHeartRate = 0;
int minHeartRate = Integer.MAX_VALUE;
int sumCalories = 0;
int minCyclingPower = Integer.MAX_VALUE;
int maxCyclingPower = 0;
int cyclingPower = 0;
int cyclingPowerCount = 0;
int avgAltitude = 0;
int altitudeCount = 0;
int minAltitude = 0;
int maxAltitude = 0;
Integer previousAlt = null;
int sumAltitudeUp = 0;
int sumAltitudeDown = 0;
for (HuaweiWorkoutDataSample dataSample : dataSamples) {
if (dataSample.getSpeed() != -1) {
speed += dataSample.getSpeed();
@ -373,6 +389,33 @@ public class HuaweiWorkoutGbParser {
if (hr < minHeartRate)
minHeartRate = hr;
}
if (dataSample.getCalories() != -1)
sumCalories += dataSample.getCalories();
if (dataSample.getCyclingPower() != -1) {
int cp = dataSample.getCyclingPower();
cyclingPower += cp;
cyclingPowerCount += 1;
if (cp > maxCyclingPower)
maxCyclingPower = cp;
if (cp < minCyclingPower)
minCyclingPower = cp;
}
if (dataSample.getAltitude() != null) {
int alt = dataSample.getAltitude();
avgAltitude += alt;
altitudeCount += 1;
if (alt > maxAltitude)
maxAltitude = alt;
if (alt < minAltitude)
minAltitude = alt;
if (previousAlt != null) {
if (alt > previousAlt)
sumAltitudeUp += alt - previousAlt;
else if (alt < previousAlt)
sumAltitudeDown += previousAlt - alt;
}
previousAlt = alt;
}
if (dataSample.getDataErrorHex() != null)
unknownData = true;
}
@ -400,6 +443,10 @@ public class HuaweiWorkoutGbParser {
strokeRate = strokeRate / strokeRateCount;
if (heartRateCount > 0)
heartRate = heartRate / heartRateCount;
if (cyclingPowerCount > 0)
cyclingPower = cyclingPower / cyclingPowerCount;
if (altitudeCount > 0)
avgAltitude = avgAltitude / altitudeCount;
if (speedCount > 0) {
JSONObject speedJson = new JSONObject();
@ -534,6 +581,57 @@ public class HuaweiWorkoutGbParser {
minHeartRateJson.put("unit", ActivitySummaryEntries.UNIT_BPM);
jsonObject.put(ActivitySummaryEntries.HR_MIN, minHeartRateJson);
}
if (sumCalories > 0) {
JSONObject caloriesSumJson = new JSONObject();
caloriesSumJson.put("value", sumCalories);
caloriesSumJson.put("unit", ActivitySummaryEntries.UNIT_KCAL);
jsonObject.put(ActivitySummaryEntries.CALORIES_BURNT, caloriesSumJson);
}
if (cyclingPowerCount > 0) {
JSONObject cyclingPowerJson = new JSONObject();
cyclingPowerJson.put("value", cyclingPower);
cyclingPowerJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.CYCLING_POWER_AVERAGE, cyclingPowerJson);
JSONObject minCyclingPowerJson = new JSONObject();
minCyclingPowerJson.put("value", minCyclingPower);
minCyclingPowerJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.CYCLING_POWER_MIN, minCyclingPowerJson);
JSONObject maxCyclingPowerJson = new JSONObject();
maxCyclingPowerJson.put("value", maxCyclingPower);
maxCyclingPowerJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.CYCLING_POWER_MAX, maxCyclingPowerJson);
}
if (altitudeCount > 0) {
JSONObject avgAltitudeJson = new JSONObject();
avgAltitudeJson.put("value", avgAltitude);
avgAltitudeJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.ALTITUDE_AVG, avgAltitudeJson);
JSONObject minAltitudeJson = new JSONObject();
minAltitudeJson.put("value", minAltitude);
minAltitudeJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.ALTITUDE_MIN, minAltitudeJson);
JSONObject maxAltitudeJson = new JSONObject();
maxAltitudeJson.put("value", maxAltitude);
maxAltitudeJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.ALTITUDE_MAX, maxAltitudeJson);
JSONObject sumUpAltitudeJson = new JSONObject();
sumUpAltitudeJson.put("value", sumAltitudeUp);
sumUpAltitudeJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.ELEVATION_GAIN, sumUpAltitudeJson);
JSONObject sumDownAltitudeJson = new JSONObject();
sumDownAltitudeJson.put("value", sumAltitudeDown);
sumDownAltitudeJson.put("unit", "");
jsonObject.put(ActivitySummaryEntries.ELEVATION_LOSS, sumDownAltitudeJson);
}
}
try (CloseableListIterator<HuaweiWorkoutPaceSample> it = qbPace.build().listIterator()) {

View File

@ -0,0 +1,79 @@
package nodomain.freeyourgadget.gadgetbridge.util;
import org.bouncycastle.shaded.util.Arrays;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.List;
public class GBTarFile {
private static final Logger LOG = LoggerFactory.getLogger(GBTarFile.class);
private final byte[] tarBytes;
public static final int TAR_MAGIC_BYTES_OFFSET = 257;
public static final byte[] TAR_MAGIC_BYTES = new byte[]{
'u', 's', 't', 'a', 'r', '\0'
};
public static final int TAR_BLOCK_SIZE = 512;
public static final int TAR_HEADER_FILE_NAME_OFFSET = 0;
public static final int TAR_HEADER_FILE_NAME_LENGTH = 100;
public static final int TAR_HEADER_FILE_SIZE_OFFSET = 124;
public static final int TAR_HEADER_FILE_SIZE_LENGTH = 12;
public GBTarFile(byte[] tarBytes) {
this.tarBytes = tarBytes;
}
public static boolean isTarFile(byte[] data) {
return ArrayUtils.equals(data, TAR_MAGIC_BYTES, TAR_MAGIC_BYTES_OFFSET);
}
public List<String> listFileNames() {
final List<String> fileNames = new ArrayList<>();
for (TarHeader header: listHeaders()) {
fileNames.add(header.fileName);
}
return fileNames;
}
public boolean containsFile(String fileName) {
for (TarHeader header: listHeaders()) {
if (fileName.equals(header.fileName)) {
return true;
}
}
return false;
}
private List<TarHeader> listHeaders() {
final List<TarHeader> headers = new ArrayList<>();
int offset = 0;
while (ArrayUtils.equals(tarBytes, TAR_MAGIC_BYTES, offset + TAR_MAGIC_BYTES_OFFSET)) {
final TarHeader tarHeader = new TarHeader(Arrays.copyOfRange(tarBytes, offset, offset + TAR_BLOCK_SIZE));
headers.add(tarHeader);
offset += (((tarHeader.fileSize + TAR_BLOCK_SIZE - 1) / TAR_BLOCK_SIZE) + 1) * TAR_BLOCK_SIZE;
}
return headers;
}
private static class TarHeader {
final String fileName;
final int fileSize;
public TarHeader(byte[] header) {
fileName = parseString(header, TAR_HEADER_FILE_NAME_OFFSET, TAR_HEADER_FILE_NAME_LENGTH);
fileSize = Integer.parseInt(parseString(header, TAR_HEADER_FILE_SIZE_OFFSET, TAR_HEADER_FILE_SIZE_LENGTH).trim(), 8);
}
private static String parseString(final byte[] data, final int offset, final int maxLength) {
int length = 0;
while (length < maxLength && offset + length < data.length && data[offset + length] != 0) {
length++;
}
return new String(data, offset, length, StandardCharsets.US_ASCII);
}
}
}

View File

@ -0,0 +1,30 @@
syntax = "proto2";
package garmin_vivomovehr;
option java_package = "nodomain.freeyourgadget.gadgetbridge.proto.vivomovehr";
message DataTransferService {
enum Status {
UNKNOWN = 0;
SUCCESS = 1;
INVALID_ID = 2;
INVALID_OFFSET = 3;
}
optional DataDownloadRequest dataDownloadRequest = 1;
optional DataDownloadResponse dataDownloadResponse = 2;
message DataDownloadRequest {
required uint32 id = 1;
required uint32 offset = 2;
optional uint32 maxChunkSize = 3;
}
message DataDownloadResponse {
required Status status = 1;
required uint32 id = 2;
required uint32 offset = 3;
optional bytes payload = 4;
}
}

View File

@ -30,15 +30,22 @@ message HttpService {
required string url = 1;
optional Method method = 3;
repeated Header header = 5;
optional bool useDataXfer = 6;
}
message RawResponse {
optional Status status = 1;
optional uint32 httpStatus = 2;
optional bytes body = 3;
optional DataTransferItem xferData = 4;
repeated Header header = 5;
}
message DataTransferItem {
required uint32 id = 1;
required uint32 size = 2;
}
message Header {
required string key = 1;
required string value = 2;

View File

@ -8,6 +8,7 @@ import "garmin_vivomovehr/gdi_device_status.proto";
import "garmin_vivomovehr/gdi_find_my_watch.proto";
import "garmin_vivomovehr/gdi_core.proto";
import "garmin_vivomovehr/gdi_http_service.proto";
import "garmin_vivomovehr/gdi_data_transfer_service.proto";
import "garmin_vivomovehr/gdi_sms_notification.proto";
import "garmin_vivomovehr/gdi_calendar_service.proto";
import "garmin_vivomovehr/gdi_settings_service.proto";
@ -15,6 +16,7 @@ import "garmin_vivomovehr/gdi_settings_service.proto";
message Smart {
optional CalendarService calendar_service = 1;
optional HttpService http_service = 2;
optional DataTransferService data_transfer_service = 7;
optional DeviceStatusService device_status_service = 8;
optional FindMyWatchService find_my_watch_service = 12;
optional CoreService core_service = 13;

View File

@ -2835,4 +2835,121 @@
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="busy_task_fetch_sports_details_interrupted">تمت مقاطعة جلب التفاصيل الرياضية</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="unbind_before_pair_title">مرتبط بالفعل</string>
<string name="companion_pairing_request_description">إقران هذا الجهاز كمرافق؟.
\n
\nيوصى بهذا لبعض الوظائف مثل البحث عن الجهاز، ويوفر اتصالاً أفضل.</string>
<string name="companion_pairing_request_title">جهاز مرافق</string>
<string name="unbind_before_pair_message">هذا الجهاز مرتبط بالفعل بإعدادات Android، مما قد يؤدي إلى فشل الاقتران لبعض الأجهزة.
\n
\nإذا فشلت إضافة الجهاز، فيرجى إزالته في إعدادات Android والمحاولة مرة أخرى.</string>
<string name="devicetype_scannable">جهاز قابل للمسح الضوئي</string>
<string name="state_scanned">تم مسحها</string>
<string name="devicesetting_scannable_debounce">مهلة الارتداد القابلة للمسح (ثواني)</string>
<string name="devicesetting_scannable_rssi_summary">الحد الأدنى لعتبة RSSI للكشف</string>
<string name="devicesetting_scannable_minimum_unseen">الحد الأدنى للوقت غير المرئي (ثواني)</string>
<string name="devicesetting_scannable_debounce_summary">بعد أن يتم فحصه، سيظل الجهاز ممسوحًا ضوئيًا ويتم تجاهله لفترة زمنية محددة</string>
<string name="devicesetting_scannable_minimum_unseen_summary">بعد أن يتم فحصه، يجب أن يكون الجهاز غير مرئي لهذه الفترة من الوقت قبل أن يتم تسجيله مرة أخرى</string>
<string name="devicesetting_scannable_rssi">الحد الأدنى لعتبة RSSI</string>
<string name="stepRateSum">مجموع معدل الخطوة</string>
<string name="stepRateAvg">متوسط معدل الخطوة</string>
<string name="stepLengthAvg">متوسط طول الخطوة</string>
<string name="groundContactTimeAvg">متوسط وقت التلامس بالأرض</string>
<string name="impactAvg">متوسط الأثر</string>
<string name="impactMax">اقصى أثر</string>
<string name="swingAngleAvg">متوسط زاوية التأرجح</string>
<string name="swolfAvg">متوسط المذؤوب</string>
<string name="swolfMax">الحد الأقصى للمذؤوب</string>
<string name="swolfMin">الحد الأدنى للمذؤوبين</string>
<string name="foreFootLandings">الهبوط الأمامي</string>
<string name="midFootLandings">هبوط منتصف القدم</string>
<string name="backFootLandings">هبوط القدم الخلفية</string>
<string name="eversionAngleAvg">متوسط زاوية الانقلاب</string>
<string name="eversionAngleMax">أقصى زاوية للانقلاب</string>
<string name="fmtPaceDistance">مسافة الوتيرة %d</string>
<string name="fmtPaceType">نوع الوتيرة %d</string>
<string name="fmtPacePace">وتيرة %d الوتيرة</string>
<string name="fmtPaceCorrection">تصحيح الوتيرة %d</string>
<string name="fmtPaceTypeAverage">نوع متوسط السرعة %d</string>
<string name="unknownDataEncountered">تمت مواجهة بيانات غير معروفة</string>
<string name="milliseconds">ميلي ثانية</string>
<string name="degrees">درجة</string>
<string name="Pace">وتيره</string>
<string name="RunningForm">نموذج الجري</string>
<string name="pref_force_enable_spo2_support">دعم قوة SpO2</string>
<string name="pref_force_enable_heartrate_support">دعم قوة معدل ضربات القلب</string>
<string name="pref_force_enable_heartrate_support_summary">قوة تمكين دعم معدل ضربات القلب.
\nاستخدام على مسؤوليتك الخاصة</string>
<string name="pref_force_enable_spo2_support_summary">فرض تمكين دعم SpO2.
\nاستخدام على مسؤوليتك الخاصة</string>
<string name="dashboard_settings">إعدادات لوحة القيادة</string>
<string name="error_showing_changelog">حدث خطأ أثناء عرض سجل التغيير</string>
<string name="activity_type_worn">تم لبسها</string>
<string name="bottom_nav_devices">الأجهزة</string>
<string name="bottom_nav_dashboard">اللوحة</string>
<string name="pref_dashboard_first_title">اظهر اللوحة أولا</string>
<string name="pref_dashboard_first_summary">إظهار لوحة المعلومات عند بدء تشغيل Gadgetbridge، بدلاً من شاشة الأجهزة</string>
<string name="pref_dashboard_cards_title">عرض الأدوات على البطاقات</string>
<string name="pref_dashboard_cards_summary">ارسم بطاقات حول الأدوات على لوحة المعلومات</string>
<string name="pref_dashboard_widget_settings">إعدادات الويدجيت</string>
<string name="pref_dashboard_widget_today_title">خريطة الأنشطة</string>
<string name="pref_dashboard_widget_today_24h_title">وضع 24 ساعة</string>
<string name="pref_dashboard_widget_double_size_title">حجم مزدوج</string>
<string name="pref_dashboard_widget_show_legend_title">عرض الأسطورة</string>
<string name="pref_dashboard_widget_goals_chart_title">خريطة الأهداف</string>
<string name="pref_dashboard_all_devices_title">جميع الأجهزة</string>
<string name="pref_dashboard_select_devices_title">تحديد الأجهزة...</string>
<string name="pref_dashboard_widgets_order_summary">حدد الأدوات التي تم تمكينها وبأي ترتيب يتم عرضها على لوحة المعلومات</string>
<string name="pref_dashboard_widget_today_24h_summary">اعرض النشاط في دائرة واحدة مدتها 24 ساعة بدلاً من دائرة مزدوجة مدتها 12 ساعة</string>
<string name="pref_dashboard_widget_double_size_summary">اسمح للأداة بشغل عمودين على لوحة المعلومات</string>
<string name="pref_dashboard_all_devices_summary">قم بدمج بيانات النشاط من كافة الأجهزة المضافة للحصول على الإجماليات على لوحة المعلومات</string>
<string name="pref_dashboard_devices_to_include">الأجهزة التي تشمل</string>
<string name="pref_dashboard_widget_show_legend_summary">إظهار وسيلة إيضاح أسفل الأداة تشرح الألوان</string>
<string name="pref_dashboard_select_devices_summary">قم بدمج بيانات النشاط من أجهزة محددة للحصول على الإجماليات على لوحة المعلومات</string>
<string name="pref_dashboard_widget_today_hr_interval_title">الفاصل الزمني لمعدل ضربات القلب</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">مقدار الدقائق التي يظهرها الرسم البياني \"مستهلكة\" بعد كل قياس ناجح لمعدل ضربات القلب</string>
<string name="pref_header_generic">نوعي</string>
<string name="pref_header_audio">صوت</string>
<string name="pref_auto_reply_calls_summary">سوف يقوم الهاتف تلقائيًا باستقبال المكالمات الهاتفية الواردة</string>
<string name="pref_auto_reply_calls_title">الرد على المكالمات الهاتفية تلقائيا</string>
<string name="pref_auto_reply_calls_delay_summary">عدد الثواني التي يتم بعدها الرد على المكالمة تلقائيًا</string>
<string name="pref_auto_reply_calls_delay_title">تأخير الرد التلقائي</string>
<string name="pref_title_notification_wake_on_open">التنبيه التلقائي وفتح القفل</string>
<string name="pref_summary_notification_wake_on_open">قم بتنبيه جهاز Android وإلغاء قفله عندما ترسل الأداة ردًا مفتوحًا. يجب أن تكون في حالة موثوقة.</string>
<string name="devicetype_redmi_watch_4">ساعة ريدمي ٤</string>
<string name="widget_name_colored_tile">%1$s (إطار ملون)</string>
<string name="pref_speak_notifications_aloud_summary">سيتم قراءة الإخطارات بصوت عال من خلال سماعات الرأس</string>
<string name="pref_speak_notifications_aloud_title">نطق الإخطارات بصوت عال</string>
<string name="widget_layout_top_wide_bot_large">عريضة من الأعلى، كبيرة من الأسفل</string>
<string name="widget_layout_top_large_bot_wide">كبير من الاعلى، عريضة من الاسفل</string>
<string name="widget_name_untitled">عنصر واجهة المستخدم بدون عنوان (%1$s)</string>
<string name="pref_header_calls_and_notifications">المكالمات والإخطارات</string>
<string name="armenian">اﻷرمينية</string>
<string name="pref_summary_bottom_navigation_bar_off">قم بالتبديل بين الشاشات الرئيسية فقط باستخدام السحب الأفقي</string>
<string name="pref_dashboard_widget_today_upside_down_summary">في وضع 24 ساعة، ارسم منتصف الليل في الأسفل، ومنتصف النهار في الجزء العلوي من الرسم البياني</string>
<string name="pref_dashboard_widget_today_upside_down_title">منتصف الليل في الأسفل</string>
<string name="pref_title_bottom_navigation_bar">شريط التنقل السفلي</string>
<string name="pref_summary_bottom_navigation_bar_on">قم بالتبديل بين الشاشات الرئيسية باستخدام شريط التنقل أو التمرير الأفقي</string>
<string name="sleepasandroid_settings">نم كالأندرويد</string>
<string name="pref_sleepasandroid_enable_summary">تمكين تكامل Sleep As Android</string>
<string name="alarm_slot_reset">تم ضبط فتحة التنبيه على الوضع الافتراضي</string>
<string name="pref_sleepasandroid_feat_heartrate">معدل ضربات القلب</string>
<string name="pref_sleepasandroid_device_title">جهاز المزود</string>
<string name="pref_sleepasandroid_device_summary">حدد الجهاز كمزود بيانات Sleep As Android</string>
<string name="pref_sleepasandroid_features_title">المميزات</string>
<string name="pref_sleepasandroid_features_summary">يختلف الدعم من جهاز إلى جهاز</string>
<string name="pref_sleepasandroid_feat_alarms">إنذار</string>
<string name="pref_sleepasandroid_slot_title">فتحة الإشعارات</string>
<string name="pref_sleepasandroid_slot_summary">ما هي فتحة التنبيه التي يجب استخدامها عند ضبط الإشعارات</string>
<string name="pref_sleepasandroid_feat_notifications">الإشعارات</string>
<string name="pref_sleepasandroid_feat_movement">مقياس التسارع</string>
<string name="pref_sleepasandroid_feat_oximetry">المقاييس</string>
<string name="pref_sleepasandroid_feat_spo2">SPO2</string>
<string name="pref_title_huawei_account">حساب هواوي</string>
<string name="pref_summary_huawei_account">حساب هواوي المستخدم في عملية الاقتران. يسمح إعداده بالاقتران دون إعادة ضبط المصنع.</string>
<string name="serbian">الصربية</string>
<string name="watchface_resolution_doesnt_match">دقة وجه الساعة لا تتطابق مع شاشة الجهاز. واجهة الساعة هي %1$s شاشة الجهاز هي %2$s</string>
<string name="cyclingPowerMax">أقصى قوة ركوب الدراجة</string>
<string name="cyclingPowerAverage">متوسط قوة ركوب الدراجة</string>
<string name="cyclingPowerMin">الحد الأدنى من قوة ركوب الدراجة</string>
</resources>

View File

@ -768,7 +768,7 @@
<string name="prefs_find_phone_summary">Verwende dein Band, um den Klingelton deines Telefons wiederzugeben.</string>
<string name="prefs_find_phone_duration">Klingeldauer in Sekunden</string>
<string name="maximum_duration">Dauer</string>
<string name="discovery_need_to_enter_authkey">Dieses Gerät benötigt einen geheimen Authentifikationsschlüssel, den du durch langes Drücken auf den Gerätnamen eingeben kannst. Genaueres im Wiki.</string>
<string name="discovery_need_to_enter_authkey">Dieses Gerät benötigt einen geheimen Authentifikationsschlüssel, den du durch langes Drücken auf den Gerätnamen eingeben kannst. Mehr Informationen gibt es auf der Gadgetbride-Webseite.</string>
<string name="fw_upgrade_notice_amazfitbip_lite">Du bist dabei, die Firmware %s auf deine Amazfit Bip Lite zu installieren.
\n
\nBitte stelle sicher, dass du die .fw Datei und danach die .res Datei installierst. Deine Uhr wird nach der Installation der .fw Datei neu gestartet.
@ -915,7 +915,7 @@
<string name="about_description_generic">Cloudloser freier Ersatz für proprietäre Android-Gadget-Apps der Hersteller.</string>
<string name="about_activity_title_generic">Über Gadgetbridge</string>
<string name="about_title">Über</string>
<string name="pref_title_weather_summary">Wird für den LineageOS Wetterdienst genutzt, andere Android-Versionen müssen eine Anwendung wie Weather notification nutzen. Mehr Informationen gibt es im Gadgetbride-Wiki.</string>
<string name="pref_title_weather_summary">Wird für den LineageOS Wetterdienst genutzt, andere Android-Versionen müssen eine Anwendung (wie Breezy Weather) nutzen. Mehr Informationen gibt es auf der Gadgetbride-Webseite.</string>
<string name="menuitem_worldclock">Weltzeituhr</string>
<string name="error_version_check_extreme_caution">ACHTUNG: Fehler beim Prüfen der Information zur Version! Du solltest nicht fortfahren! Versionsname \"%s\" gefunden</string>
<string name="permission_granting_mandatory">Alle Berechtigungen sind notwendig und es kann zu Problemen führen, wenn sie nicht genehmigt werden</string>
@ -1221,7 +1221,7 @@
\nHinweis: Du musst .res nicht installieren, wenn es genau die gleiche ist, wie die zuvor installierte.
\n
\nINSTALLATION AUF EIGENE GEFAHR!</string>
<string name="fossil_hr_commute_actions_explanation">Die hier konfigurierten Aktionen werden in der Commute-App auf deiner Uhr angezeigt. Lies das Wiki, um Informationen zum Umgang mit den durch diese Aktionen erzeugten Vorgaben zu erhalten.</string>
<string name="fossil_hr_commute_actions_explanation">Die hier konfigurierten Aktionen werden in der Commute-App auf deiner Uhr angezeigt. Mehr Informationen gibt es auf der Gadgetbride-Webseite.</string>
<string name="kind_agps_bundle">AGPS-Bundle</string>
<string name="qhybrid_calibration_100_steps">100 Schritte</string>
<string name="qhybrid_calibration_10_steps">10 Schritte</string>
@ -1727,7 +1727,7 @@
<string name="controlcenter_toggle_details">Details anzeigen</string>
<string name="controlcenter_connected_fraction">Verbunden: %d/%d</string>
<string name="ukranian">Ukrainisch</string>
<string name="info_no_devices_connected">keine Geräte verbunden</string>
<string name="info_no_devices_connected">Keine Geräte verbunden</string>
<string name="info_connected_count">%d Geräte verbunden</string>
<string name="estonian">Estnisch</string>
<string name="extended_ascii">Erweitertes ASCII</string>
@ -1775,7 +1775,7 @@
<string name="open_fw_installer_connect_minimum_one_device">Bitte verbinde MINDESTENS EIN Gerät, an das du die Datei senden möchtest.</string>
<string name="open_fw_installer_connect_maximum_one_device">Bitte verbinde NUR EIN Gerät, an das du die Datei senden möchtest.</string>
<string name="open_fw_installer_ensure_device_connected">Stelle sicher, dass das Gerät %s angeschlossen ist</string>
<string name="open_fw_installer_info_text">Mit dem Firmware/Watchface/App/File Installer kannst du unterstützte Dateien (Firmware, Zifferblätter, Anwendungen, GPS, Ressourcen, Schriftarten...) auf das Gerät hochladen/installieren. Weitere Informationen findest du im Wiki: https://codeberg.org/Freeyourgadget/Gadgetbridge/wiki/Firmware-Update</string>
<string name="open_fw_installer_info_text">Mit dem Firmware/Watchface/App/File Installer kannst du unterstützte Dateien (Firmware, Zifferblätter, Anwendungen, GPS, Ressourcen, Schriftarten...) auf das Gerät hochladen/installieren. Mehr Informationen gibt es auf der Gadgetbride-Webseite.</string>
<string name="open_fw_installer_getting_files_text">Da wir die Firmware-Dateien nicht verteilen dürfen, musst du dir die Dateien selbst beschaffen. Das bedeutet, dass du nach den Dateien in apk-Dateien, online, in Foren, auf Amazfitwatchfaces (für Miband/Amazfit-Geräte) und so weiter suchen musst.</string>
<string name="appmanager_item_outdated">(veraltet)</string>
<string name="pref_title_banglejs_txt_bitmap_size">Größe der Text-Bitmaps</string>
@ -2119,13 +2119,13 @@
<string name="devicetype_galaxybuds_2_pro">Galaxy Buds2 Pro</string>
<string name="devicetype_soflow_s06">SoFlow SO6</string>
<string name="pref_title_lock_unlock">Sperren</string>
<string name="pref_header_intent_api">Intent API</string>
<string name="pref_header_intent_api">Intent-API</string>
<string name="pref_agps_update_time">AGPS Aktualisierungszeit</string>
<string name="pref_agps_expire_time">AGPS Ablaufzeit</string>
<string name="intent_api_allow_activity_sync_summary">Auslösen der Aktivitätssynchronisierung über die Intent API erlauben</string>
<string name="intent_api_allow_activity_sync_summary">Auslösen der Aktivitätssynchronisierung über die Intent-API erlauben</string>
<string name="intent_api_allow_activity_sync_title">Aktivitätssynchronisierungsauslöser zulassen</string>
<string name="sony_ambient_sound_control_button_modes">Tastenmodi für die Steuerung von Umgebungsgeräuschen</string>
<string name="intent_api_allow_trigger_export_summary">Datenbankexport über die Intent API erlauben</string>
<string name="intent_api_allow_trigger_export_summary">Datenbankexport über die Intent-API erlauben</string>
<string name="intent_api_broadcast_export_summary">Einen Intent via Broadcast verschicken, wenn der Datenbankexport abgeschlossen ist</string>
<string name="pref_workout_keep_screen_on_title">Bildschirm während des Trainings eingeschaltet lassen</string>
<string name="pref_workout_keep_screen_on_summary">Der Bildschirm bleibt während des Trainings eingeschaltet und die Helligkeit wird angepasst, um die Trainingsdaten in Echtzeit anzuzeigen</string>
@ -2849,4 +2849,122 @@
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="busy_task_fetch_sports_details_interrupted">Das Abrufen von Sportdaten wurde unterbrochen</string>
<string name="companion_pairing_request_title">Begleitendes Gerät</string>
<string name="unbind_before_pair_title">Bereits gebunden</string>
<string name="companion_pairing_request_description">Koppelst du dieses Gerät als Begleiter?
\n
\nDies wird für einige Funktionen empfohlen, z. B. für die Gerätesuche, und bietet eine bessere Verbindung.</string>
<string name="unbind_before_pair_message">Dieses Gerät ist bereits in den Android-Einstellungen gebunden, was dazu führen kann, dass die Kopplung bei einigen Geräten fehlschlägt.
\n
\nWenn das Hinzufügen des Geräts fehlschlägt, entferne es bitte in den Android-Einstellungen und versuche es erneut.</string>
<string name="devicetype_scannable">Scannbares Gerät</string>
<string name="state_scanned">Gescannt</string>
<string name="devicesetting_scannable_minimum_unseen">Minimale ungesehene Zeit (Sekunden)</string>
<string name="devicesetting_scannable_rssi">Minimaler RSSI-Schwellenwert</string>
<string name="devicesetting_scannable_debounce_summary">Nach dem Scannen bleibt das Gerät als gescannt und wird für die angegebene Zeitspanne ignoriert</string>
<string name="devicesetting_scannable_minimum_unseen_summary">Nach dem Scannen muss das Gerät für diese Zeitspanne unsichtbar sein, bevor es erneut registriert wird</string>
<string name="devicesetting_scannable_rssi_summary">Der minimale RSSI-Schwellenwert für die Erkennung</string>
<string name="devicesetting_scannable_debounce">Zeitüberschreitung der abtastbaren Entprellung (Sekunden)</string>
<string name="stepRateSum">Summe der Schrittgeschwindigkeit</string>
<string name="stepRateAvg">Durchschnittliche Schrittfrequenz</string>
<string name="stepLengthAvg">Durchschnittliche Schrittlänge</string>
<string name="groundContactTimeAvg">Durchschnittliche Bodenkontaktzeit</string>
<string name="impactAvg">Durchschnittliche Auswirkungen</string>
<string name="impactMax">Maximale Wirkung</string>
<string name="swingAngleAvg">Durchschnittlicher Schwenkwinkel</string>
<string name="foreFootLandings">Landungen mit dem Vorderfuß</string>
<string name="eversionAngleAvg">Durchschnittlicher Eversionswinkel</string>
<string name="eversionAngleMax">Maximaler Eversionswinkel</string>
<string name="unknownDataEncountered">Unbekannte Daten gefunden</string>
<string name="milliseconds">Millisekunden</string>
<string name="degrees">Grad</string>
<string name="swolfAvg">Mittlerer Swolf</string>
<string name="swolfMax">Maximaler Swolf</string>
<string name="swolfMin">Minimaler Swolf</string>
<string name="backFootLandings">Landungen mit dem Fußrücken</string>
<string name="midFootLandings">Landungen mit dem Mittelfuß</string>
<string name="pref_force_enable_spo2_support">SpO2-Unterstützung erzwingen</string>
<string name="pref_force_enable_heartrate_support">Unterstützung der Herzfrequenz erzwingen</string>
<string name="pref_force_enable_spo2_support_summary">Erzwinge die Aktivierung der SpO2-Unterstützung.
\nVERWENDUNG AUF EIGENE GEFAHR</string>
<string name="pref_force_enable_heartrate_support_summary">Erzwinge die Herzfrequenzunterstützung.
\nVERWENDUNG AUF EIGENE GEFAHR</string>
<string name="error_showing_changelog">Fehler bei der Anzeige des Changelogs</string>
<string name="pref_dashboard_widget_goals_chart_title">Zieltabelle</string>
<string name="pref_dashboard_all_devices_title">Alle Geräte</string>
<string name="pref_dashboard_widgets_order_summary">Wähle, welche Widgets aktiviert sind und in welcher Reihenfolge sie auf dem Dashboard angezeigt werden</string>
<string name="pref_dashboard_widget_today_24h_summary">Zeige die Aktivität in einem einzelnen 24-Stunden-Kreis anstelle eines doppelten 12-Stunden-Kreis</string>
<string name="pref_dashboard_widget_double_size_summary">Erlaube dem Widget, zwei Spalten auf dem Dashboard einzunehmen</string>
<string name="pref_dashboard_widget_show_legend_summary">Eine Legende unterhalb des Widgets anzeigen, welche die Farben erklärt</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Herzfrequenz-Intervall</string>
<string name="activity_type_worn">Getragen</string>
<string name="dashboard_settings">Dashboard-Einstellungen</string>
<string name="bottom_nav_dashboard">Dashboard</string>
<string name="bottom_nav_devices">Geräte</string>
<string name="pref_dashboard_first_title">Dashboard zuerst anzeigen</string>
<string name="pref_dashboard_first_summary">Zeige beim Start von Gadgetbridge das Dashboard anstelle des Gerätebildschirms an</string>
<string name="pref_dashboard_cards_title">Widgets auf Karten anzeigen</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">Die Anzahl der Minuten, die das Diagramm nach jeder erfolgreichen Herzfrequenzmessung \"Getragen\" anzeigt</string>
<string name="pref_dashboard_cards_summary">Zeichne Karten um die Widgets auf dem Dashboard</string>
<string name="pref_dashboard_widget_settings">Widget-Einstellungen</string>
<string name="pref_dashboard_widget_today_title">Tätigkeitstabelle</string>
<string name="pref_dashboard_widget_today_24h_title">24h-Modus</string>
<string name="pref_dashboard_widget_double_size_title">Doppelte Größe</string>
<string name="pref_dashboard_widget_show_legend_title">Legende anzeigen</string>
<string name="pref_dashboard_select_devices_title">Geräte auswählen...</string>
<string name="pref_dashboard_all_devices_summary">Kombiniere Aktivitätsdaten von allen hinzugefügten Geräten für die Gesamtzahlen auf dem Dashboard</string>
<string name="pref_dashboard_select_devices_summary">Kombiniere Aktivitätsdaten von bestimmten Geräten für die Gesamtzahlen auf dem Dashboard</string>
<string name="fmtPaceDistance">Tempo %d Entfernung</string>
<string name="pref_auto_reply_calls_delay_title">Automatische Antwortverzögerung</string>
<string name="pref_auto_reply_calls_delay_summary">Anzahl der Sekunden, nach denen der Anruf automatisch entgegengenommen wird</string>
<string name="pref_auto_reply_calls_title">Telefonanrufe automatisch annehmen</string>
<string name="pref_auto_reply_calls_summary">Das Telefon nimmt eingehende Telefonanrufe automatisch entgegen</string>
<string name="pref_dashboard_devices_to_include">Einzubeziehende Geräte</string>
<string name="RunningForm">Art der Durchführung</string>
<string name="pref_header_audio">Audio</string>
<string name="pref_header_generic">Allgemein</string>
<string name="pref_title_notification_wake_on_open">Automatisches Aufwachen und Entsperren</string>
<string name="pref_summary_notification_wake_on_open">Wecken und Entsperren des Android-Geräts, wenn das Gadget eine OPEN-Antwort zurücksendet. Es muss sich in einem vertrauenswürdigen Zustand befinden.</string>
<string name="fmtPaceType">Tempo %d Typ</string>
<string name="fmtPacePace">Tempo %d Tempo</string>
<string name="fmtPaceCorrection">Tempo %d Korrektur</string>
<string name="fmtPaceTypeAverage">Tempo-Typ %d Durchschnitt</string>
<string name="Pace">Tempo</string>
<string name="widget_name_colored_tile">%1$s (farbige Kachel)</string>
<string name="armenian">Armenisch</string>
<string name="widget_layout_top_wide_bot_large">Oben weit, unten groß</string>
<string name="widget_name_untitled">Unbenanntes Widget (%1$s)</string>
<string name="pref_speak_notifications_aloud_summary">Benachrichtigungen werden über die Kopfhörer vorgelesen</string>
<string name="pref_speak_notifications_aloud_title">Lautes Sprechen von Benachrichtigungen</string>
<string name="pref_header_calls_and_notifications">Anrufe und Benachrichtigungen</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="widget_layout_top_large_bot_wide">Oben groß, unten weit</string>
<string name="pref_summary_bottom_navigation_bar_off">Wechseln zwischen den Hauptbildschirmen nur durch horizontales Wischen</string>
<string name="pref_title_bottom_navigation_bar">Untere Navigationsleiste</string>
<string name="pref_summary_bottom_navigation_bar_on">Wechsle zwischen den Hauptbildschirmen mit der Navigationsleiste oder durch horizontales Wischen</string>
<string name="pref_dashboard_widget_today_upside_down_title">Mitternacht ist unten</string>
<string name="pref_dashboard_widget_today_upside_down_summary">Im 24-Stunden-Modus zeichne Mitternacht unten und Mittag oben im Diagramm</string>
<string name="pref_sleepasandroid_device_title">Auszuwählendes Gerät</string>
<string name="pref_sleepasandroid_device_summary">Gerät als Sleep as Android-Datenanbieter auswählen</string>
<string name="pref_sleepasandroid_features_summary">Die Unterstützung ist von Gerät zu Gerät unterschiedlich</string>
<string name="pref_sleepasandroid_feat_alarms">Alarme</string>
<string name="alarm_slot_reset">Der Alarm-Platz wurde auf Standard eingestellt</string>
<string name="pref_sleepasandroid_feat_notifications">Benachrichtigungen</string>
<string name="pref_sleepasandroid_feat_movement">Beschleunigungssensor</string>
<string name="pref_sleepasandroid_feat_heartrate">Herzfrequenz</string>
<string name="pref_sleepasandroid_feat_spo2">SpO2</string>
<string name="sleepasandroid_settings">Sleep as Android</string>
<string name="pref_sleepasandroid_enable_summary">Aktiviere die Integration von Sleep as Android</string>
<string name="pref_sleepasandroid_features_title">Eigenschaften</string>
<string name="pref_sleepasandroid_slot_title">Alarm-Platz</string>
<string name="pref_sleepasandroid_slot_summary">Welcher Alarm-Platz beim Einstellen von Alarmen zu verwenden ist</string>
<string name="pref_sleepasandroid_feat_oximetry">Oximetrie</string>
<string name="pref_title_huawei_account">Huawei Account</string>
<string name="pref_summary_huawei_account">Huawei-Account, welcher für den Kopplungsprozess verwendet wird. Die Einstellung ermöglicht die Kopplung ohne Werksreset.</string>
<string name="serbian">Serbisch</string>
<string name="watchface_resolution_doesnt_match">Die Auflösung des Watchface stimmt nicht mit dem Bildschirm des Geräts überein. Watchface ist %1$s Gerätebildschirm ist %2$s</string>
<string name="cyclingPowerMin">Minimale Leistung beim Radfahren</string>
<string name="cyclingPowerMax">Maximale Leistung beim Radfahren</string>
<string name="cyclingPowerAverage">Durchschnittliche Leistung beim Radfahren</string>
<string name="devicetype_huawei_watchfit2">Huawei Watch Fit 2</string>
</resources>

View File

@ -1766,7 +1766,7 @@
<string name="sony_ambient_sound_control_button_modes">Modos del botón de control de sonido ambiente</string>
<string name="sony_ambient_sound_control_button_mode_nc_as_off">Cancelación de ruido, sonido ambiente, apagado</string>
<string name="sony_ambient_sound_control_button_mode_as_off">Sonido ambiente, apagado</string>
<string name="info_no_devices_connected">no hay dispositivos conectados</string>
<string name="info_no_devices_connected">Ningún dispositivo conectado</string>
<string name="controlcenter_set_folder_title">Establecer o crear una nueva carpeta</string>
<string name="autoconnect_from_device_summary">Establecer una conexión cuando ésta es iniciada por un dispositivo, como los auriculares</string>
<string name="activity_prefs_allow_bluetooth_intent_api">API Intent de Bluetooth</string>
@ -2844,4 +2844,122 @@
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="busy_task_fetch_sports_details_interrupted">Se interrumpió la búsqueda de los detalles deportivos</string>
<string name="unbind_before_pair_message">Este dispositivo ya está vinculado en los ajustes de Android, lo que puede hacer que el emparejamiento falle en algunos dispositivos.
\n
\nSi no se puede añadir el dispositivo, elimínelo de los ajustes de Android y vuelva a intentarlo.</string>
<string name="companion_pairing_request_title">Dispositivo complementario</string>
<string name="companion_pairing_request_description">¿Empareje este dispositivo como complementario?
\n
\nSe recomienda para algunas funciones, como buscar dispositivo, y proporciona una mejor conexión.</string>
<string name="unbind_before_pair_title">Ya vinculado</string>
<string name="devicesetting_scannable_rssi">Umbral mínimo de RSSI</string>
<string name="devicesetting_scannable_minimum_unseen_summary">Después de ser escaneado, el dispositivo debe permanecer oculto durante este tiempo antes de ser registrado de nuevo</string>
<string name="devicesetting_scannable_rssi_summary">El umbral RSSI mínimo para la detección</string>
<string name="devicesetting_scannable_debounce">Tiempo de espera para volver a escanear (segundos)</string>
<string name="devicetype_scannable">Dispositivo escaneable</string>
<string name="state_scanned">Escaneado</string>
<string name="devicesetting_scannable_debounce_summary">Después de ser escaneado, el dispositivo permanecerá como escaneado e ignorado durante el tiempo especificado</string>
<string name="devicesetting_scannable_minimum_unseen">Tiempo mínimo sin ser escaneado (segundos)</string>
<string name="swolfAvg">Promedio swolf</string>
<string name="swolfMax">Swolf máximo</string>
<string name="swolfMin">Swolf mínimo</string>
<string name="stepRateSum">Velocidad total de pasos</string>
<string name="stepRateAvg">Frecuencia media del paso</string>
<string name="stepLengthAvg">Longitud media de los pasos</string>
<string name="groundContactTimeAvg">Tiempo medio de la pisada</string>
<string name="impactAvg">Promedio de la pisada</string>
<string name="impactMax">Pisada máxima</string>
<string name="swingAngleAvg">Ángulo promedio de giro</string>
<string name="foreFootLandings">Pisadas con el antepié</string>
<string name="midFootLandings">Pisadas con el mediopié</string>
<string name="backFootLandings">Pisadas con el retropié</string>
<string name="eversionAngleAvg">Angulo medio de la eversión</string>
<string name="eversionAngleMax">Angulo máximo de la eversión</string>
<string name="fmtPaceDistance">Ritmo %d distancia</string>
<string name="fmtPaceType">Tipo %d ritmo</string>
<string name="fmtPacePace">Ritmo %d</string>
<string name="fmtPaceCorrection">Corrección del ritmo %d</string>
<string name="fmtPaceTypeAverage">Tipo de ritmo %d medio</string>
<string name="unknownDataEncountered">Se encontraron datos desconocidos</string>
<string name="milliseconds">milisegundos</string>
<string name="degrees">grados</string>
<string name="RunningForm">Forma de ejecución</string>
<string name="Pace">Ritmo</string>
<string name="pref_force_enable_heartrate_support">Forzar soporte de frecuencia cardíaca</string>
<string name="pref_force_enable_heartrate_support_summary">Forzar habilitar el soporte de frecuencia cardíaca.
\nÚSELO BAJO SU PROPIO RIESGO</string>
<string name="pref_force_enable_spo2_support">Forzar el soporte de SpO2</string>
<string name="pref_force_enable_spo2_support_summary">Forzar la habilitación del soporte de SpO2.
\nÚSELO BAJO SU PROPIO RIESGO</string>
<string name="error_showing_changelog">Error al mostrar el registro de cambios</string>
<string name="dashboard_settings">Ajustes del panel de control</string>
<string name="bottom_nav_dashboard">Panel de control</string>
<string name="bottom_nav_devices">Dispositivos</string>
<string name="pref_dashboard_first_title">Mostrar primero el panel de control</string>
<string name="pref_dashboard_first_summary">Mostrar el panel de control cuando se inicia Gadgetbridge, en lugar de la pantalla de dispositivos</string>
<string name="pref_dashboard_cards_title">Mostrar widgets en las tarjetas</string>
<string name="pref_dashboard_cards_summary">Dibujar tarjetas alrededor de los widgets del panel de control</string>
<string name="pref_dashboard_widget_settings">Ajustes del widget</string>
<string name="pref_dashboard_widget_today_title">Gráfico de actividad</string>
<string name="pref_dashboard_widget_today_24h_title">Modo 24h</string>
<string name="pref_dashboard_widget_double_size_title">Tamaño doble</string>
<string name="pref_dashboard_widget_show_legend_title">Mostrar leyenda</string>
<string name="pref_dashboard_widget_goals_chart_title">Gráfico de objetivos</string>
<string name="pref_dashboard_devices_to_include">Dispositivos a incluir</string>
<string name="pref_dashboard_all_devices_title">Todos los dispositivos</string>
<string name="pref_dashboard_select_devices_title">Selecciona los dispositivos...</string>
<string name="pref_dashboard_widgets_order_summary">Seleccione qué widgets están activados y en qué orden se muestran en el panel de control</string>
<string name="pref_dashboard_widget_today_24h_summary">Mostrar la actividad en un único círculo de 24h en lugar de un círculo doble de 12h</string>
<string name="pref_dashboard_widget_double_size_summary">Permitir que el widget ocupe dos columnas en el panel de control</string>
<string name="pref_dashboard_widget_show_legend_summary">Mostrar una leyenda debajo del widget explicando los colores</string>
<string name="pref_dashboard_all_devices_summary">Combinar los datos de la actividad de todos los dispositivos añadidos para los totales del panel de control</string>
<string name="pref_dashboard_select_devices_summary">Combinar los datos de actividad de dispositivos específicos para los totales del panel de control</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Intervalo de frecuencia cardíaca</string>
<string name="activity_type_worn">Usada</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">La cantidad de minutos que el gráfico muestra \"usado\" después de cada medición correcta de la frecuencia cardíaca</string>
<string name="pref_auto_reply_calls_summary">El teléfono descolgará automáticamente las llamadas entrantes</string>
<string name="pref_auto_reply_calls_delay_summary">Número de segundos tras los cuales se descuelga automáticamente la llamada</string>
<string name="pref_auto_reply_calls_title">Responder automáticamente a las llamadas</string>
<string name="pref_auto_reply_calls_delay_title">Retraso automático en la respuesta</string>
<string name="pref_header_audio">Audio</string>
<string name="pref_header_generic">Genérico</string>
<string name="pref_summary_notification_wake_on_open">Despierta y desbloquea el dispositivo Android cuando el gadget envía una respuesta ABIERTO de vuelta. Debe estar en un estado de confianza.</string>
<string name="pref_title_notification_wake_on_open">Despertador y desbloqueo automáticos</string>
<string name="armenian">armenio</string>
<string name="widget_layout_top_wide_bot_large">Ancho arriba, grande abajo</string>
<string name="widget_layout_top_large_bot_wide">Grande arriba, ancho abajo</string>
<string name="pref_speak_notifications_aloud_summary">Las notificaciones se leerán en voz alta a través de los auriculares</string>
<string name="pref_speak_notifications_aloud_title">Decir las notificaciones con volumen alto</string>
<string name="pref_header_calls_and_notifications">llamadas y notificaciones</string>
<string name="pref_title_bottom_navigation_bar">Barra de navegación inferior</string>
<string name="pref_summary_bottom_navigation_bar_off">Cambiar entre pantallas principales solo deslizando el dedo horizontalmente</string>
<string name="widget_name_colored_tile">%1$s (mosaico de color)</string>
<string name="widget_name_untitled">Widget sin título ( %1$s )</string>
<string name="pref_summary_bottom_navigation_bar_on">Cambiar entre pantallas principales usando la barra de navegación o deslizando el dedo horizontalmente</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="pref_dashboard_widget_today_upside_down_title">Medianoche en el fondo</string>
<string name="pref_dashboard_widget_today_upside_down_summary">En el modo 24h, dibuje la medianoche en la parte inferior y el mediodía en la parte superior del gráfico</string>
<string name="sleepasandroid_settings">Dormir como Android</string>
<string name="pref_sleepasandroid_enable_summary">Habilitar la integración de Sleep As Android</string>
<string name="pref_sleepasandroid_device_summary">Seleccione el dispositivo como proveedor de datos de Sleep As Android</string>
<string name="pref_sleepasandroid_slot_summary">¿Qué espacio para la alarma se debe utilizar al configurar las alarmas?</string>
<string name="pref_sleepasandroid_feat_oximetry">oximetria</string>
<string name="pref_sleepasandroid_device_title">Dispositivo del proveedor</string>
<string name="pref_sleepasandroid_features_title">Características</string>
<string name="pref_sleepasandroid_features_summary">La compatibilidad varía de un dispositivo a otro</string>
<string name="pref_sleepasandroid_feat_alarms">Alarmas</string>
<string name="alarm_slot_reset">El espacio de la alarma se ha ajustado por defecto</string>
<string name="pref_sleepasandroid_slot_title">Espacio de alarmas</string>
<string name="pref_sleepasandroid_feat_notifications">Notificaciones</string>
<string name="pref_sleepasandroid_feat_movement">Acelerómetro</string>
<string name="pref_sleepasandroid_feat_heartrate">Frecuencia cardíaca</string>
<string name="pref_sleepasandroid_feat_spo2">SPO2</string>
<string name="pref_title_huawei_account">Cuenta Huawei</string>
<string name="pref_summary_huawei_account">Cuenta de Huawei utilizada en el proceso de emparejamiento. Configurarlo permite el emparejamiento sin restablecimiento de fábrica.</string>
<string name="serbian">Serbio</string>
<string name="watchface_resolution_doesnt_match">La resolución de Watchface no coincide con la pantalla del dispositivo. Watchface es %1$s la pantalla del dispositivo es %2$s</string>
<string name="cyclingPowerMin">Potencia mínima del ciclo</string>
<string name="devicetype_huawei_watchfit2">Huawei Watch Fit 2</string>
<string name="cyclingPowerAverage">Potencia media de ciclo</string>
<string name="cyclingPowerMax">Potencia máxima del ciclo</string>
</resources>

View File

@ -2764,4 +2764,134 @@
<string name="pref_enable_call_accept">הפעלת קבלת שיחות</string>
<string name="pref_heartrate_automatic_enable">הפעלת מדידת דופק אוטומטית</string>
<string name="activity_type_roller_skating">החלקה על גלגיליות</string>
<string name="devicetype_nothing_cmf_watch_pro">CMF Watch Pro</string>
<string name="devicetype_nothingear2">Nothing Ear (2)</string>
<string name="pref_header_sony_sound_control">בקרת שמע</string>
<string name="pref_wide_area_tap_title">טפיחה באזור רחב</string>
<string name="devicetype_nothingearstick">Nothing Ear (Stick)</string>
<string name="prefs_active_noise_cancelling_transparency">שקיפות</string>
<string name="degrees">מעלות</string>
<string name="Pace">צעד</string>
<string name="RunningForm">צורת ריצה</string>
<string name="pref_wide_area_tap_summary">זיהוי טפיחות בין הלחיים והאוזניים</string>
<string name="pref_force_enable_heartrate_support_summary">אילוץ הפעלת תמיכה בדופק.
\nעל אחריותך בלבד</string>
<string name="pref_force_enable_spo2_support">אילוץ תמיכה במדידת חמצן</string>
<string name="unbind_before_pair_title">כבר מאוגד</string>
<string name="pref_force_enable_heartrate_support">אילוץ תמיכה בדופק</string>
<string name="pref_force_enable_spo2_support_summary">אילוץ תמיכה במדידת חמצן בדם.
\nלשימוש על אחריותך בלבד</string>
<string name="state_scanned">נסרק</string>
<string name="weeksleepchart_sleep_a_week_or_month">שינה בשבוע/חודש</string>
<string name="pref_header_audio">שמע</string>
<string name="weekstepschart_steps_a_week_or_month">צעדים לשבוע/חודש</string>
<string name="busy_task_fetch_sports_details_interrupted">משיכת פרטי הספורט נקטעה</string>
<string name="fw_upgrade_notice_amazfitbip3">פעולה זו תתקין את הקושחה %s על ה־Amazfit Bip 3 שלך.
\n
\nנא לוודא את התקנת קושחת ה־‎.fw בהתחלה, לאחר מכן את קובץ ה־‎.res השעון שלך יופעל מחדש לאחר התקנת קובץ ה־fw.
\n
\nלתשומת לבך: אין צורך בהתקנת קובץ ה־‎.res אם הוא כבר זהה לזה שהתקנת בעבר.
\n
\nהמשך התהליך הוא על אחריותך!</string>
<string name="pref_header_generic">גנרי</string>
<string name="pref_title_notification_wake_on_open">התעוררות ושחרור נעילה אוטומטיים</string>
<string name="pref_summary_notification_wake_on_open">להעיר ולשחרר את הנעילה של מכשיר ה־Android כשההתקן שולח תגובת פתיחה בחזרה. חייב להיות במצב אמין.</string>
<string name="pref_auto_reply_calls_delay_title">השהיית מענה אוטומטי</string>
<string name="pref_auto_reply_calls_delay_summary">מספר השניות שלאחריהן השיחה תתקבל אוטומטית</string>
<string name="pref_auto_reply_calls_title">לענות לשיחות טלפון אוטומטית</string>
<string name="pref_auto_reply_calls_summary">הטלפון יקבל שיחות נכנסות אוטומטית</string>
<string name="pref_dashboard_widget_today_hr_interval_title">משך דופק</string>
<string name="pref_dashboard_select_devices_summary">שילוב פעילות מהתקנים מסוימים לסיכומים של לוח הבקרה</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">כמות הדקות שהתרשים מציג ‚נענד’ אחרי כל מדידת דופק מוצלחת</string>
<string name="devicetype_amazfit_active_edge">Amazfit Active Edge</string>
<string name="devicetype_amazfit_bip3">Amazfit Bip 3</string>
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="sony_protocol_v2">גרסה 2</string>
<string name="sony_protocol_v1">גרסה 1</string>
<string name="companion_pairing_request_title">התקן ליווי</string>
<string name="zepp_os_watchface_the_ultima">האולטימה</string>
<string name="prefs_workmode">מצב עבודה</string>
<string name="devicetype_mijia_mho_c303">Mijia MHO-C303</string>
<string name="devicetype_sony_linkbuds">Sony LinkBuds</string>
<string name="zepp_os_watchface_lightning_flash">הבזק מהבהב</string>
<string name="zepp_os_watchface_free_combination">שילוב חופשי</string>
<string name="zepp_os_watchface_pure_white">לבן טהור</string>
<string name="devicetype_huawei_band8">Huawei Band 8</string>
<string name="zepp_os_watchface_starry_sky">ליל כוכבים</string>
<string name="devicetype_honor_band5">Honor Band 5</string>
<string name="devicetype_honor_band3">Honor Band 3</string>
<string name="devicetype_honor_band4">Honor Band 4</string>
<string name="sony_protocol_v3">גרסה 3</string>
<string name="devicetype_miband8active">Xiaomi Smart Band 8 Active</string>
<string name="devicetype_amazfit_balance">Amazfit Balance</string>
<string name="devicetype_colacao21">ColaCao 2021</string>
<string name="devicetype_colacao23">ColaCao 2023</string>
<string name="devicetype_huawei_band_aw70">Huawei Band (AW70)</string>
<string name="devicetype_huawei_band6">Huawei Band 6</string>
<string name="devicetype_huawei_band7">Huawei Band 7</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="zepp_os_watchface_vast_sky">שמיים פרוסים</string>
<string name="zepp_os_watchface_guider">מנחה</string>
<string name="flatDistance">מרחק במישור</string>
<string name="huawei_trusleep_title">HUAWEI TruSleep ™‎</string>
<string name="widget_layout_top_wide_bot_large">רחב למעלה, גדול למטה</string>
<string name="widget_layout_top_large_bot_wide">גדול למעלה, רחב למטה</string>
<string name="widget_name_colored_tile">%1$s (אריח צבעוני)</string>
<string name="widget_name_untitled">וידג׳ט ללא שם (%1$s)</string>
<string name="pref_force_connection_type_ble">בלוטות׳ LE (אנרגיה נמוכה)</string>
<string name="devicetype_honor_magicwatch2">Honor MagicWatch 2</string>
<string name="devicetype_amazfit_active">Amazfit Active</string>
<string name="devicetype_sony_wi_sp600n">Sony WI-SP600N</string>
<string name="devicetype_honor_band6">Honor Band 6</string>
<string name="devicetype_honor_band7">Honor Band 7</string>
<string name="protocol_version">גרסת פרוטוקול</string>
<string name="stepRateSum">סיכום קצב הצעדים</string>
<string name="stepRateAvg">קצב צעדים ממוצע</string>
<string name="stepLengthAvg">אורך צעד ממוצע</string>
<string name="groundContactTimeAvg">זמן מגע ממוצע עם הקרקע</string>
<string name="impactAvg">הלימה ממוצעת</string>
<string name="impactMax">הלימה מרבית</string>
<string name="swingAngleAvg">זווית הנפה ממוצעת</string>
<string name="unknownDataEncountered">התגלו נתונים לא מוכרים</string>
<string name="milliseconds">מילישניות</string>
<string name="bottom_nav_dashboard">לוח בקרה</string>
<string name="bottom_nav_devices">התקנים</string>
<string name="dashboard_settings">הגדרות לוח בקרה</string>
<string name="pref_dashboard_first_title">להציג את לוח הבקרה תחילה</string>
<string name="pref_dashboard_first_summary">להציג את לוח הבקרה עם הפעלת Gadgetbridge במקום את מסך ההתקנים</string>
<string name="pref_dashboard_widget_today_24h_title">מצב 24 שעות</string>
<string name="pref_dashboard_cards_title">הצגת וידג׳טים על הכרטיסים</string>
<string name="pref_dashboard_widget_today_title">תרשים פעילות</string>
<string name="pref_dashboard_widget_settings">הגדרות וידג׳ט</string>
<string name="pref_dashboard_cards_summary">ציור כרטיסים סביב הווידג׳טים בלוח הבקרה</string>
<string name="pref_dashboard_widget_show_legend_title">הצגת מקרא</string>
<string name="pref_dashboard_widget_double_size_title">גודל כפול</string>
<string name="pref_dashboard_devices_to_include">התקנים שיש לכלול</string>
<string name="pref_dashboard_widget_goals_chart_title">תרשים יעדים</string>
<string name="pref_dashboard_all_devices_summary">שילוב נתוני הפעילות מכל ההתקנים שנוספו לסיכומים שבלוח הבקרה</string>
<string name="pref_dashboard_widget_show_legend_summary">הצגת מקרא מתחת לווידג׳ט שמסביר את הצבעים</string>
<string name="devicesetting_scannable_minimum_unseen">זמן נתק מזערי (שניות)</string>
<string name="pref_dashboard_widget_today_24h_summary">להציג את הפעילות בעיגול אחיד של 24 שעות במקום שני עיגולים של 12 שעות</string>
<string name="activity_type_worn">נענד</string>
<string name="pref_dashboard_select_devices_title">בחירת התקנים…</string>
<string name="pref_dashboard_all_devices_title">כל ההתקנים</string>
<string name="pref_dashboard_widget_double_size_summary">לאפשר לווידג׳ט לתפוס שתי עמודות בלוח הבקרה</string>
<string name="error_showing_changelog">שגיאה בהצגת יומן השינויים</string>
<string name="devicesetting_scannable_rssi_summary">סף הקליטה המזערי לזיהוי</string>
<string name="devicesetting_scannable_rssi">סף קליטה מזערי</string>
<string name="devicesetting_scannable_minimum_unseen_summary">לאחר הסריקה, ההתקן צריך להיות בנתק למשך פרק הזמן שהוגדר לפני שיירשם שוב</string>
<string name="pref_dashboard_widgets_order_summary">נא לבחור אילו וידג׳טים יופעלו ובאיזה סדר יוצגו בלוח הבקרה</string>
<string name="pref_header_calls_and_notifications">שיחות והתראות</string>
<string name="pref_speak_notifications_aloud_title">הקראת התראות בקול רם</string>
<string name="pref_speak_notifications_aloud_summary">התראות תיקראנה בקול רם דרך האוזניות</string>
<string name="armenian">ארמנית</string>
<string name="pref_sleepasandroid_device_title">התקן ספק</string>
<string name="pref_sleepasandroid_features_summary">התמיכה משתנה מהתקן להתקן</string>
<string name="pref_sleepasandroid_feat_spo2">SpO2</string>
<string name="pref_sleepasandroid_feat_heartrate">דופק</string>
<string name="pref_sleepasandroid_feat_movement">מד תאוצה</string>
<string name="pref_sleepasandroid_feat_oximetry">מדידת חמצן</string>
<string name="pref_sleepasandroid_feat_notifications">הודעות</string>
<string name="pref_sleepasandroid_features_title">יכולות</string>
</resources>

File diff suppressed because it is too large Load Diff

View File

@ -1408,7 +1408,7 @@
<string name="sony_equalizer_preset_vocal">Vokal</string>
<string name="sony_anc_optimizer_status_wearing_condition">Mengukur kondisi pemakaian…</string>
<string name="pref_activity_recognize_running">mengenal berlari</string>
<string name="info_no_devices_connected">tidak ada perangkat terhubung</string>
<string name="info_no_devices_connected">Tidak ada perangkat yang terhubung</string>
<string name="info_connected_count">%d perangkat terhubung</string>
<string name="watchface_setting_light_up_on_notification">Nyalakan pada notifikasi baru</string>
<string name="connection_over_ble">Koneksi melalui BLE</string>
@ -2831,4 +2831,119 @@
<string name="busy_task_fetch_sports_details_interrupted">Pengambilan detail olahraga ditunda</string>
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="companion_pairing_request_title">Perangkat pendamping</string>
<string name="companion_pairing_request_description">Sandingkan perangkat ini sebagai pendamping?
\n
\nIni disarankan untuk beberapa fungsi seperti cari perangkat, dan menyediakan koneksi yang lebih baik.</string>
<string name="unbind_before_pair_title">Sudah tersanding</string>
<string name="unbind_before_pair_message">Perangkat ini sudah disandingkan dalam pengaturan Android yang dapat membuat penyandingan gagal untuk beberapa perangkat.
\n
\nJika penambahan perangkat gagal, silakan hapus dari pengaturan Android dan coba lagi.</string>
<string name="devicesetting_scannable_debounce">Waktu habis penghilangan pemindaian (detik)</string>
<string name="devicesetting_scannable_rssi_summary">Ambang RSSI minimum untuk deteksi</string>
<string name="devicetype_scannable">Perangkat dapat dipindai</string>
<string name="state_scanned">Dipindai</string>
<string name="devicesetting_scannable_minimum_unseen">Waktu tidak terlihat minimum (detik)</string>
<string name="devicesetting_scannable_rssi">Ambang RSSI minimal</string>
<string name="devicesetting_scannable_debounce_summary">Setelah dipindai, perangkat akan ditetapkan sebagai dipindai dan diabaikan selama waktu yang sudah ditentukan</string>
<string name="devicesetting_scannable_minimum_unseen_summary">Setelah dipindai, perangkat harus tidak terlihat selama waktu ini sebelum didaftarkan lagi</string>
<string name="swolfAvg">Swolf rata-rata</string>
<string name="swolfMax">Swolf maksimum</string>
<string name="swolfMin">Swolf minimum</string>
<string name="stepRateSum">Jumlah laju langkah</string>
<string name="stepRateAvg">Laju langkah rata-rata</string>
<string name="stepLengthAvg">Panjang Langkah Rata-rata</string>
<string name="groundContactTimeAvg">Waktu kontak tanah rata-rata</string>
<string name="impactAvg">Dampak rata-rata</string>
<string name="impactMax">Dampak maksimum</string>
<string name="swingAngleAvg">Sudut ayunan rata-rata</string>
<string name="backFootLandings">Landasan kaki belakang</string>
<string name="eversionAngleAvg">Sudut eversi rata-rata</string>
<string name="eversionAngleMax">Sudut eversi maksimum</string>
<string name="fmtPaceDistance">Jarak laju %d</string>
<string name="fmtPaceType">Jenis laju %d</string>
<string name="fmtPacePace">Laju dalam laju %d</string>
<string name="fmtPaceCorrection">Koreksi laju %d</string>
<string name="fmtPaceTypeAverage">Rata-rata Jenis Laju %d</string>
<string name="unknownDataEncountered">Mendapatkan data tidak diketahui</string>
<string name="milliseconds">milidetik</string>
<string name="degrees">derajat</string>
<string name="Pace">Laju</string>
<string name="midFootLandings">Landasan kaki tengah</string>
<string name="foreFootLandings">Landasan kaki depan</string>
<string name="RunningForm">Bentuk Lari</string>
<string name="pref_force_enable_heartrate_support">Paksa dukungan detak jantung</string>
<string name="pref_force_enable_heartrate_support_summary">Paksa nengaktifkan dukungan detak jantung.
\n
\nGUNAKAN DENGAN RISIKO ANDA SENDIRI</string>
<string name="pref_force_enable_spo2_support">Paksa dukungan SpO2</string>
<string name="pref_force_enable_spo2_support_summary">Paksa mengaktifkan dukungan SpO2.
\nGUNAKAN DENGAN RISIKO ANDA SENDIRI</string>
<string name="activity_type_worn">Dipakai</string>
<string name="dashboard_settings">Pengaturan dasbor</string>
<string name="bottom_nav_devices">Perangkat</string>
<string name="pref_dashboard_first_title">Tampilkan dasbor terlebih dahulu</string>
<string name="pref_dashboard_first_summary">Tampilkan dasbor ketika Gadgetbridge dibuka, daripada layar perangkat</string>
<string name="pref_dashboard_cards_title">Tampilkan widget pada kartu</string>
<string name="pref_dashboard_widget_today_title">Bagan aktivitas</string>
<string name="pref_dashboard_widget_today_24h_title">Mode 24j</string>
<string name="pref_dashboard_widget_double_size_title">Ukuran ganda</string>
<string name="pref_dashboard_widget_show_legend_title">Tampilkan legenda</string>
<string name="pref_dashboard_widget_goals_chart_title">Bagan capaian</string>
<string name="pref_dashboard_devices_to_include">Perangkat untuk disertakan</string>
<string name="pref_dashboard_widget_today_24h_summary">Tampilkan aktivitas dalam lingkaran 24j daripada lingkaran 12j ganda</string>
<string name="pref_dashboard_widget_double_size_summary">Perbolehkan widget untuk memakai sampai dua kolom di dasbor</string>
<string name="pref_dashboard_widget_show_legend_summary">Tampilkan legenda di bawah widget menjelaskan warnanya</string>
<string name="pref_dashboard_all_devices_summary">Gabungkan data aktivitas dari semua perangkat yang ditambahkan untuk jumlah di dasbor</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Interval detak jantung</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">Jumlah menit bagan menampilkan \'dipakai\' setelah pengukuran detak jantung berhasil</string>
<string name="error_showing_changelog">Terjadi kesalahan menampilkan catatan perubahan</string>
<string name="bottom_nav_dashboard">Dasbor</string>
<string name="pref_dashboard_widget_settings">Pengaturan widget</string>
<string name="pref_dashboard_all_devices_title">Semua perangkat</string>
<string name="pref_dashboard_select_devices_title">Pilih perangkat...</string>
<string name="pref_dashboard_widgets_order_summary">Pilih widget apa saja yang diaktifkan dan dalam urutan yang ditampilkan di dasbor</string>
<string name="pref_dashboard_select_devices_summary">Gabungkan data aktivitas dari perangkat tertentu untuk jumlah di dasbor</string>
<string name="pref_dashboard_cards_summary">Gambar kartu di sekitar widget dalam dasbor</string>
<string name="pref_auto_reply_calls_summary">Ponsel akan mengangkat panggilan masuk secara otomatis</string>
<string name="pref_auto_reply_calls_title">Jawab panggilan telepon secara otomatis</string>
<string name="pref_auto_reply_calls_delay_summary">Detik setelah panggilan diambil secara otomatis</string>
<string name="pref_auto_reply_calls_delay_title">Jeda Penjawaban Otomatis</string>
<string name="pref_header_audio">Audio</string>
<string name="pref_header_generic">Generik</string>
<string name="pref_title_notification_wake_on_open">Bangun dan buka kunci otomatis</string>
<string name="pref_summary_notification_wake_on_open">Bangun dan buka kunci perangkat Android ketika perangkat mengirim respons OPEN kembali. Perlu dalam keadaan terpercaya.</string>
<string name="pref_speak_notifications_aloud_summary">Notifikasi akan dibaca melalui headphone</string>
<string name="pref_speak_notifications_aloud_title">Bacakan Notifikasi</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="widget_layout_top_large_bot_wide">Besar atas, lebar bawah</string>
<string name="widget_layout_top_wide_bot_large">Lebar atas, besar bawah</string>
<string name="widget_name_colored_tile">%1$s (ubin berwarna)</string>
<string name="widget_name_untitled">Widget tidak berjudul (%1$s)</string>
<string name="pref_header_calls_and_notifications">Panggilan dan notifikasi</string>
<string name="armenian">Armenia</string>
<string name="pref_sleepasandroid_feat_spo2">SPO2</string>
<string name="pref_title_huawei_account">Akun Huawei</string>
<string name="pref_summary_huawei_account">Akun Huawei digunakan dalam proses penyandingan. Dapat menyandingkan tanpa pengaturan ulang ke pengaturan pabrik.</string>
<string name="serbian">Serbia</string>
<string name="pref_sleepasandroid_enable_summary">Aktifkan integrasi Sleep As Android</string>
<string name="pref_sleepasandroid_device_title">Perangkat penyedia</string>
<string name="pref_sleepasandroid_features_summary">Dukungan tergantung pada perangkat</string>
<string name="pref_sleepasandroid_slot_title">Slot alarm</string>
<string name="pref_sleepasandroid_slot_summary">Slot alarm mana yang digunakan ketika mengatur alarm</string>
<string name="alarm_slot_reset">Slot alarm telah diatur menjadi bawaan</string>
<string name="pref_sleepasandroid_feat_notifications">Notifikasi</string>
<string name="pref_dashboard_widget_today_upside_down_title">Tengah malam di bawah</string>
<string name="pref_dashboard_widget_today_upside_down_summary">Dalam mode 24 jam, gambar tengah malam di bawah, tengah hari di atas bagan</string>
<string name="sleepasandroid_settings">Sleep As Android</string>
<string name="pref_sleepasandroid_device_summary">Pilih perangkat sebagai penyedia data Sleep As Amdroid</string>
<string name="pref_sleepasandroid_features_title">Fitur</string>
<string name="pref_sleepasandroid_feat_alarms">Alarm</string>
<string name="pref_sleepasandroid_feat_movement">Akselerometer</string>
<string name="pref_sleepasandroid_feat_heartrate">Detak jantung</string>
<string name="pref_sleepasandroid_feat_oximetry">Oksimetri</string>
<string name="pref_title_bottom_navigation_bar">Bilah navigasi bawah</string>
<string name="pref_summary_bottom_navigation_bar_on">Ganti antara layar utama menggunakan bilah navigasi atau pengusapan horizontal</string>
<string name="pref_summary_bottom_navigation_bar_off">Ganti antara layar utama hanya menggunakan pengusapan horizontal</string>
<string name="watchface_resolution_doesnt_match">Resolusi wajah jam tidak cocok dengan layar perangkat. Resolusi wajah jam adalah %1$s dan layar perangkat adalah %2$s</string>
</resources>

View File

@ -52,14 +52,14 @@
<!--Strings related to Settings-->
<string name="title_activity_settings">Impostazioni</string>
<string name="pref_header_general">Impostazioni generali</string>
<string name="pref_title_general_autoconnectonbluetooth">Collegati al dispositivo Gadgetbridge quando il Bluetooth viene acceso</string>
<string name="pref_title_general_autoconnectonbluetooth">Collegati al/ai dispositivo/i Gadgetbridge quando il Bluetooth viene acceso</string>
<string name="pref_title_general_autostartonboot">Avvio automatico</string>
<string name="pref_title_general_autoreconnect">Riconnessione automatica</string>
<string name="pref_title_audio_player">Riproduttore musicale preferito</string>
<string name="pref_default">Predefinito</string>
<string name="pref_header_datetime">Data e ora</string>
<string name="pref_title_datetime_syctimeonconnect">Sincronizza l\'ora</string>
<string name="pref_summary_datetime_syctimeonconnect">Sincronizza l\'orario del dispositivo al collegamento con Gadgetbridge e quando viene cambiata l\'ora o il fuso orario sul dispositivo Android</string>
<string name="pref_summary_datetime_syctimeonconnect">Sincronizza l\'orario del/i dispositivo/i al collegamento con Gadgetbridge e quando viene cambiata l\'ora o il fuso orario sul dispositivo e periodicamente</string>
<string name="pref_title_theme">Tema</string>
<string name="pref_theme_light">Chiaro</string>
<string name="pref_theme_dark">Scuro</string>
@ -1122,7 +1122,7 @@
<string name="prefs_events_forwarding_summary">Utilizza gli eventi del dispositivo per avviare azioni e broadcast di Android</string>
<string name="seconds_m">sec/m</string>
<string name="descentSeconds">Discendente</string>
<string name="swolfIndex">Indice SWOLF</string>
<string name="swolfIndex">SWOLF</string>
<string name="pref_title_lower_button_function_double">Pulsante inferiore, doppio</string>
<string name="pref_title_middle_button_function_double">Pulsante centrale, doppio</string>
<string name="pref_title_upper_button_function_double">Pulsante superiore, doppio</string>
@ -2451,4 +2451,235 @@
<string name="prefs_wena3_notification_settings_title">Impostazioni Notifiche</string>
<string name="devicetype_sony_wf_1000xm5">Sony WF-1000XM5</string>
<string name="devicetype_femometer_vinca2">Femometer Vinca II</string>
<string name="pai_chart_per_week">PAI settimanale</string>
<string name="pai_chart_per_month">PAI mensile</string>
<string name="weekstepschart_steps_a_week_or_month">Passi mensili/settimanali</string>
<string name="weeksleepchart_sleep_a_week_or_month">Sono mensile/settimanale</string>
<string name="dnd_all_day">Tutto il giorno</string>
<string name="busy_task_fetch_sports_details_interrupted">Il recupero dei dettagli sportivi è stato interrotto</string>
<string name="heartrate_bpm_165">165 bpm</string>
<string name="heartrate_bpm_175">175 bpm</string>
<string name="heartrate_bpm_185">185 bpm</string>
<string name="pref_title_casio_alert_email">Avviso per notifiche e-mail</string>
<string name="pref_summary_casio_alert_email">Avviso (vibrazione/bip) per le notifiche via e-mail</string>
<string name="pref_title_casio_alert_sms">Avviso per notifiche SMS</string>
<string name="pref_summary_casio_alert_sms">Avviso (vibrazione/bip) per le notifiche SMS (messaggi di testo)</string>
<string name="pref_title_casio_alert_other">Avviso per altre notifiche</string>
<string name="pref_summary_casio_alert_other">Avviso (vibrazione/bip) per le notifiche con altre categorie</string>
<string name="busy_task_fetch_pai_data">Recupero dati PAI</string>
<string name="manual">Manuale</string>
<string name="updatefirmwareoperation_updateproblem_low_battery">Il dispositivo è troppo scarico</string>
<string name="clap_hands_to_wakeup_device">Batti le mani per attivare lo schermo</string>
<string name="clap_hands_to_wakeup_device_summary">Battere di nuovo le mani spegnerà lo schermo</string>
<string name="pixoo_power_saving_summary">Lo schermo si spegnerà se il microfono rileva silenzio per un certo periodo</string>
<string name="prefs_wearmode">Modalità uso</string>
<string name="wearmode_pebble">Pebble (fibbia per scarpe)</string>
<string name="wearmode_necklace">Collana (laccetto collo)</string>
<string name="danish">Danese</string>
<string name="pref_title_general_reconnectonlytoconnected">Riconnetti solo ai dispositivi collegati</string>
<string name="pref_summary_general_reconnectonlytoconnected">Riconnetti solo ai dispositivi collegati, invece di riconnettersi a tutti i dispositivi</string>
<string name="pref_title_preview_message_in_title">Mostra anteprima del messaggio nel titolo</string>
<string name="pref_summary_preview_message_in_title">Mostra un\'anteprima del messaggio nel titolo di una notifica, come consentito dal dispositivo</string>
<string name="pref_title_casio_alert_call">Avviso per chiamate in arrivo</string>
<string name="heartrate_bpm_195">195 bpm</string>
<string name="wearmode_band">Cinturino (polsino)</string>
<string name="pref_title_send_app_notifications">Invia notifiche</string>
<string name="pref_summary_send_app_notifications">Inviare le notifiche delle app al dispositivo</string>
<string name="alarm_smart_wakeup_interval_default">5 minuti</string>
<string name="heartrate_bpm_155">155 bpm</string>
<string name="heartrate_bpm_205">205 bpm</string>
<string name="prefs_device_name">Nome dispositivo</string>
<string name="pref_title_goal_secondary">Obiettivo secondario</string>
<string name="pref_summary_casio_alert_call">Avviso (vibrazione/bip) per le chiamate in arrivo</string>
<string name="pref_title_casio_alert_calendar">Avviso per notifiche del calendario</string>
<string name="pref_summary_casio_alert_calendar">Avviso (vibrazione/bip) per le notifiche del calendario</string>
<string name="fw_upgrade_notice_amazfitbip3">Stai per installare il firmware %s sul tuo Amazfit Bip 3.
\n
\nAssicurati di installare prima il file .fw e dopo il file .res. L\'orologio si riavvierà al termine del caricamento del file .fw.
\n
\nNota: non è necessario installare il file .res se è uguale a quello installato in precedenza.
\n
\nPROCEDI A TUO RISCHIO E PERICOLO!</string>
<string name="pref_header_generic">Generico</string>
<string name="pref_header_audio">Suono</string>
<string name="activity_type_darts">Freccette</string>
<string name="activity_type_kite_flying">Aquilone</string>
<string name="devicetype_miband7pro">Xiaomi Smart Band 7 Pro</string>
<string name="devicetype_colacao21">ColaCao 2021</string>
<string name="hydration_dnd_summary">Disattivare avvisi di idratazione per un intervallo di tempo</string>
<string name="silent_mode_vibrate_silent">Vibrazione / Silenzioso</string>
<string name="activity_type_mountain_hike">Escursione in montagna</string>
<string name="activity_type_fitness_exercises">Esercizi fitness</string>
<string name="activity_type_cross_country_running">Corsa campestre</string>
<string name="activity_type_karate">Karate</string>
<string name="activity_type_cooldown">Raffreddamento</string>
<string name="activity_type_cross_training">Allenamento incrociato</string>
<string name="activity_type_plank">Plancia</string>
<string name="activity_type_aerobic_exercise">Esercizi aerobici</string>
<string name="activity_type_javelin">Giavellotto</string>
<string name="activity_type_long_jump">Salto in lungo</string>
<string name="activity_type_high_jump">Salto in alto</string>
<string name="activity_type_trampoline">Trampolino</string>
<string name="activity_type_dumbbell">Pesi</string>
<string name="activity_type_tai_chi">Tai chi</string>
<string name="activity_type_hula_hooping">Hula hoop</string>
<string name="activity_type_disc_sports">Lancio del disco</string>
<string name="activity_type_shuttlecock">Volano</string>
<string name="activity_type_archery">Tiro con l\'arco</string>
<string name="activity_type_softball">Softball</string>
<string name="activity_type_sailing">Vela</string>
<string name="activity_type_ice_hockey">Hockey su ghiaccio</string>
<string name="activity_type_dodgeball">Palla prigioniera</string>
<string name="activity_type_skateboarding">Skateboard</string>
<string name="activity_type_rock_climbing">Arrampicata su roccia</string>
<string name="activity_type_hunting">Caccia</string>
<string name="activity_type_trail_run">Corsa su sentiero</string>
<string name="devicetype_huawei_watchfit">Huawei Watch Fit</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="menuitem_zepp_pay">Zepp Pay</string>
<string name="zepp_os_watchface_guider">Guida</string>
<string name="menuitem_zepp_coach">Zepp Coach</string>
<string name="prefs_disconnect_notification_summary">Notifica sul dispositivo quando viene disconnesso dal BT.</string>
<string name="prefs_phone_silent_mode">Telefono in silenzioso</string>
<string name="pref_do_not_disturb_not_wear">Non disturbare quando non indossato</string>
<string name="devicetype_amazfit_bip3">Amazfit Bip 3</string>
<string name="devicetype_huawei_talk_band_b6">Huawei Talk Band B6</string>
<string name="devicetype_huawei_watchgt2e">Huawei Watch GT 2e</string>
<string name="pref_title_notification_wake_on_open">Risveglio e sblocco automatico</string>
<string name="pref_summary_notification_wake_on_open">Risveglia e sblocca il dispositivo Android quando il gadget invia una risposta OPEN. Deve essere segnato come affidabile.</string>
<string name="activity_type_crossfit">Crossfit</string>
<string name="activity_type_functional_training">Allenamento funzionale</string>
<string name="activity_type_physical_training">Allenamento fisico</string>
<string name="activity_type_taekwondo">Taekwondo</string>
<string name="activity_type_fencing">Scherma</string>
<string name="activity_type_kendo">Kendo</string>
<string name="devicetype_mijia_lywsd03">Sensore di temperatura e umidità Mijia 2</string>
<string name="devicetype_mijia_mho_c303">Mijia MHO-C303</string>
<string name="devicetype_sony_linkbuds">Sony LinkBuds</string>
<string name="devicetype_honor_band3">Honor Band 3</string>
<string name="devicetype_honor_band6">Honor Band 6</string>
<string name="devicetype_huawei_band8">Huawei Band 8</string>
<string name="devicetype_huawei_watch_gt">Huawei Watch GT</string>
<string name="devicetype_huawei_band4pro">Huawei Band 4 (Pro)</string>
<string name="devicetype_huawei_watchgt3">Huawei Watch GT 3 (Pro)</string>
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="devicetype_xiaomi_watch_lite">Xiaomi Watch Lite</string>
<string name="devicetype_redmiwatch3active">Redmi Watch 3 Active</string>
<string name="devicetype_redmiwatch3">Redmi Watch 3</string>
<string name="devicetype_redmi_smart_band_2">Redmi Smart Band 2</string>
<string name="prefs_heartrate_alert_active_high_threshold">Soglia di allarme per elevata frequenza cardiaca</string>
<string name="activity_type_flexibility">Flessibilità</string>
<string name="activity_type_track_and_field">Atletica leggera</string>
<string name="activity_type_pull_ups">Trazioni</string>
<string name="activity_type_jazz_dance">Danza jazz</string>
<string name="activity_type_latin_dance">Danza latina</string>
<string name="activity_type_kabaddi">Kabaddi</string>
<string name="activity_type_mind_and_body">Corpo e mente</string>
<string name="activity_type_karting">Go-kart</string>
<string name="activity_type_australian_football">Football australiano</string>
<string name="activity_type_lacross">Lacrosse</string>
<string name="activity_type_shot">Tiro</string>
<string name="activity_type_skating">Pattinaggio</string>
<string name="devicetype_miband8">Xiaomi Smart Band 8</string>
<string name="devicetype_miband8pro">Xiaomi Smart Band 8 Pro</string>
<string name="devicetype_honor_magicwatch2">Honor MagicWatch 2</string>
<string name="devicetype_huawei_band6">Huawei Band 6</string>
<string name="zepp_os_watchface_the_ultima">L\'ultima</string>
<string name="devicetype_honor_band4">Honor Band 4</string>
<string name="devicetype_honor_band5">Honor Band 5</string>
<string name="devicetype_honor_band7">Honor Band 7</string>
<string name="silent_mode_normal_silent">Normale / Silenzioso</string>
<string name="silent_mode_normal_vibrate">Normale / Vibrazione</string>
<string name="activity_type_wrestling">Lotta</string>
<string name="devicetype_colacao23">ColaCao 2023</string>
<string name="devicetype_miband8active">Xiaomi Smart Band 8 Active</string>
<string name="devicetype_huawei_band_aw70">Huawei Band (AW70)</string>
<string name="armenian">Armeno</string>
<string name="activity_type_indoor_running">Corsa al coperto</string>
<string name="activity_type_free_training">Allenamento libero</string>
<string name="activity_type_rower">Vogatore</string>
<string name="activity_type_stair_stepper">Stepper</string>
<string name="activity_type_horizontal_bar">Barre orizzontali</string>
<string name="activity_type_parallel_bar">Barre parallele</string>
<string name="activity_type_sit_ups">Addominali</string>
<string name="activity_type_push_ups">Flessioni</string>
<string name="activity_type_battle_rope">Tiro della fune</string>
<string name="activity_type_belly_dance">Danza del ventre</string>
<string name="activity_type_ballet">Balletto</string>
<string name="activity_type_other_dance">Altre danze</string>
<string name="activity_type_roller_skating">Pattini a rotelle</string>
<string name="activity_type_martial_arts">Arti marziali</string>
<string name="activity_type_horse_riding">Equitazione</string>
<string name="activity_type_swing">Altalena</string>
<string name="activity_type_stairs">Scale</string>
<string name="activity_type_fishing">Pesca</string>
<string name="activity_type_hand_cycling">Ciclismo manuale</string>
<string name="activity_type_billiards">Bigliardo</string>
<string name="activity_type_cross_country_skiing">Sci di fondo</string>
<string name="activity_type_snow_sports">Sport invernali</string>
<string name="activity_type_outdoor_walking">Camminata all\'estero</string>
<string name="devicetype_huawei_band7">Huawei Band 7</string>
<string name="devicetype_huawei_watchgt2">Huawei Watch GT 2 (Pro)</string>
<string name="devicetype_redmi_watch_2">Redmi Watch 2</string>
<string name="devicetype_redmi_smart_band_pro">Redmi Smart Band Pro</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="menuitem_readiness">Preparazione</string>
<string name="menuitem_body_composition">Composizione corporea</string>
<string name="menuitem_buzzer_intensity">Intensità cicalino</string>
<string name="alarm_smart_wakeup_interval">Intervallo di attivazione intelligente:</string>
<string name="standing_time">Tempo di riposo</string>
<string name="devicetype_redmi_watch_2_lite">Redmi Watch 2 Lite</string>
<string name="prefs_password_4_digits_0_to_9_summary">La password deve essere di 4 cifre, utilizzando solo numeri</string>
<string name="active_time">Tempo di attività</string>
<string name="devicetype_sony_wi_sp600n">Sony WI-SP600N</string>
<string name="swolfAvg">Swolf medio</string>
<string name="swolfMax">Swolf massimo</string>
<string name="swolfMin">Swolf minimo</string>
<string name="zepp_os_watchface_lightning_flash">Lampo di luce</string>
<string name="yard">iarda</string>
<string name="stepLengthAvg">Lunghezza media dei passi</string>
<string name="pref_header_sony_sound_control">Controllo sonoro</string>
<string name="pai_total">Totale</string>
<string name="sony_protocol_v3">Versione 3</string>
<string name="protocol_version">Versione protocollo</string>
<string name="maxStrokeRate">Frequenza Massima Corse</string>
<string name="strokes">Corse Totali</string>
<string name="pref_device_action_dnd_off">Non disturbare - Spento</string>
<string name="activity_type_curling">Curling</string>
<string name="devicetype_nothingear2">Nothing Ear (2)</string>
<string name="do_not_disturb_lift_wrist_summary">Solo se l\'attivazione del display al sollevamento è abilitata</string>
<string name="sony_protocol_v2">Versione 2</string>
<string name="activity_type_pickleball">Pickleball</string>
<string name="activity_type_jet_skiing">Moto d\'acqua</string>
<string name="activity_type_trekking">Escursionismo</string>
<string name="fmtPaceTypeAverage">Tipo di ritmo %d medio</string>
<string name="unknownDataEncountered">Dati sconosciuti riscontrati</string>
<string name="strokes_minute">serie/min</string>
<string name="devicetype_nothingearstick">Nothing Ear (Stick)</string>
<string name="devicetype_nothing_cmf_watch_pro">CMF Watch Pro</string>
<string name="pai_day">Aumento giornaliero</string>
<string name="sony_protocol_v1">Versione 1</string>
<string name="activity_type_smith_machine">Macchina Smith</string>
<string name="zepp_os_watchface_free_combination">Combinazione libera</string>
<string name="zepp_os_watchface_city_of_speed">Città di velocità</string>
<string name="avgStrokeRate">Frequenza Media Corse</string>
<string name="stepRateAvg">Velocità media dei passi</string>
<string name="eversionAngleAvg">Angolo medio di estroflessione</string>
<string name="eversionAngleMax">Angolo massimo di estroflessione</string>
<string name="fmtPaceDistance">Ritmo %d distanza</string>
<string name="fmtPaceType">Tipo %d ritmo</string>
<string name="fmtPacePace">Ritmo %d</string>
<string name="fmtPaceCorrection">Correzione ritmo %d</string>
<string name="milliseconds">millisecondi</string>
<string name="degrees">gradi</string>
<string name="pref_device_action_dnd_priority">Non disturbare - Solo priorità</string>
<string name="pref_device_action_dnd_alarms">Non disturbare - Solo sveglie</string>
<string name="pref_device_action_dnd_on">Non disturbare - Acceso</string>
<string name="huawei_trusleep_title">HUAWEI TruSleep ™</string>
<string name="prefs_workmode">Modalità lavoro</string>
<string name="flatDistance">Distanza piana</string>
<string name="prefs_active_noise_cancelling_transparency">Trasparenza</string>
<string name="laneLength">Lunghezza Corsia</string>
<string name="stepRateSum">Velocità totale dei passi</string>
<string name="Pace">Ritmo</string>
</resources>

File diff suppressed because it is too large Load Diff

View File

@ -1728,7 +1728,7 @@
<string name="prefs_password_summary">Vergrendel de band met een wachtwoord wanneer deze van de pols wordt verwijderd</string>
<string name="prefs_password_enabled">Wachtwoord ingeschakeld</string>
<string name="prefs_password_4_digits_1_to_4_summary">Het wachtwoord moet 4 cijfers hebben, met de nummers 1 tot en met 4</string>
<string name="info_no_devices_connected">geen apparaten aangesloten</string>
<string name="info_no_devices_connected">Geen apparaten aangesloten</string>
<string name="pref_blacklist_calendars_summary">Agenda\'s op de zwarte lijst worden niet gesynchroniseerd met het apparaat</string>
<string name="bengali">Bengaals</string>
<string name="czech">Tsjechisch</string>
@ -2832,13 +2832,127 @@
<string name="pref_adaptive_volume_control_summary">Verhoog volume automatisch bij veel omgevingsgeluid</string>
<string name="pref_header_sony_sound_control">Geluidsinstellingen</string>
<string name="error_scan_failed">Scan mislukt: %d</string>
<string name="scan_scanning_all_devices">Scannen voor alle apparaten</string>
<string name="scan_scanning_all_devices">Scannen naar alle apparaten</string>
<string name="scan_not_scanning">Niet aan het scannen</string>
<string name="scan_scanning_single_device">Scannen voor 1 apparaat</string>
<string name="scan_scanning_multiple_devices">Scannen voor %d apparaten</string>
<string name="scan_scanning_single_device">Scannen naar 1 apparaat</string>
<string name="scan_scanning_multiple_devices">Scannen naar %d apparaten</string>
<string name="notification_channel_scan_service_name">Scan-service</string>
<string name="device_state_waiting_scan">Wachten op apparaatscan</string>
<string name="devicetype_miband8active">Xiaomi Smart Band 8 Active</string>
<string name="alarm_smart_wakeup_interval_default">5 minuten</string>
<string name="alarm_smart_wakeup_interval">Interval slim wekken:</string>
<string name="companion_pairing_request_title">Bijbehorend apparaat</string>
<string name="unbind_before_pair_title">Al gekoppeld</string>
<string name="unbind_before_pair_message">Dit apparaat is al gekoppeld aan de Android-instellingen, waardoor het koppelen op sommige apparaten kan mislukken.
\n
\nAls het toevoegen van het apparaat mislukt, verwijder het dan in de Android-instellingen en probeer het opnieuw.</string>
<string name="companion_pairing_request_description">Koppel je dit apparaat als begeleider?
\n
\nDit wordt aanbevolen voor sommige functies zoals zoeken naar apparaten en biedt een betere verbinding.</string>
<string name="devicesetting_scannable_minimum_unseen_summary">Na te zijn gevonden, moet het apparaat deze tijd buiten bereik zijn om opnieuw gevonden te kunnen worden</string>
<string name="devicetype_scannable">Scanbaar apparaat</string>
<string name="state_scanned">Gescand</string>
<string name="devicesetting_scannable_debounce">Seconden zichtbaar na gescand</string>
<string name="devicesetting_scannable_minimum_unseen">Seconden afwezig na niet gescand</string>
<string name="devicesetting_scannable_rssi">Minimaal RSSI-niveau</string>
<string name="devicesetting_scannable_debounce_summary">Na te zijn gevonden, blijft het apparaat deze tijd actief als gescand en wordt verder genegeerd</string>
<string name="devicesetting_scannable_rssi_summary">Het minimale RSSI-niveau om gevonden te kunnen worden</string>
<string name="pref_force_enable_heartrate_support">Forceer hartslagmeting</string>
<string name="pref_force_enable_heartrate_support_summary">Forceer ondersteuning van hartslagmeting
\nGEBRUIK OP EIGEN RISICO</string>
<string name="pref_force_enable_spo2_support">Forceer SpO2-ondersteuning</string>
<string name="pref_force_enable_spo2_support_summary">Forceer ondersteuning van bloedzuurstofmetingen
\nGEBRUIK OP EIGEN RISICO</string>
<string name="error_showing_changelog">Fout bij tonen wijzigingenlijst</string>
<string name="activity_type_worn">Gedragen</string>
<string name="bottom_nav_dashboard">Dashboard</string>
<string name="pref_dashboard_first_title">Toon dashboard eerst</string>
<string name="pref_dashboard_first_summary">Toon het dashboard wanneer Gadgetbridge opstart, in plaats van het apparatenscherm</string>
<string name="pref_dashboard_cards_title">Widgets op kaarten</string>
<string name="pref_dashboard_widget_settings">Widget-instellingen</string>
<string name="pref_dashboard_widget_double_size_title">Dubbele grootte</string>
<string name="pref_dashboard_widget_show_legend_title">Toon legenda</string>
<string name="pref_dashboard_widget_goals_chart_title">Doelen-diagram</string>
<string name="pref_dashboard_devices_to_include">Apparaten</string>
<string name="pref_dashboard_all_devices_title">Alle apparaten</string>
<string name="pref_dashboard_select_devices_title">Selecteer apparaten...</string>
<string name="pref_dashboard_widgets_order_summary">Selecteer welke widgets op het dashboard getoond worden en in welke volgorde</string>
<string name="pref_dashboard_all_devices_summary">Combineer activiteitsgegevens van alle toegevoegde apparaten voor het dashboard</string>
<string name="pref_dashboard_widget_today_24h_summary">Toon de activiteit in een enkele 24-uurscirkel in plaats van een dubbele 12-uurscirkel</string>
<string name="pref_dashboard_widget_show_legend_summary">Toon een legenda onder de widget om de kleuren uit te leggen</string>
<string name="pref_dashboard_select_devices_summary">Combineer activiteitsgegevens van specifieke apparaten voor het dashboard</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Interval hartslagmeting</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">Het aantal minuten dat het diagram \'gedragen\' toont na elke succesvolle hartslagmeting</string>
<string name="pref_auto_reply_calls_summary">De telefoon neemt binnenkomende telefoongesprekken automatisch op</string>
<string name="pref_auto_reply_calls_title">Binnenkomende gesprekken automatisch opnemen</string>
<string name="dashboard_settings">Dashboard-instellingen</string>
<string name="bottom_nav_devices">Apparaten</string>
<string name="pref_dashboard_cards_summary">Toon de widgets op kaarten op het dashboard</string>
<string name="pref_dashboard_widget_today_title">Activiteit-diagram</string>
<string name="pref_dashboard_widget_today_24h_title">24-uursmodus</string>
<string name="pref_dashboard_widget_double_size_summary">Sta de widget toe om twee kolommen van het dashboard te gebruiken</string>
<string name="pref_auto_reply_calls_delay_summary">Aantal seconden waarna een binnenkomend telefoongesprek automatisch opgenomen wordt</string>
<string name="pref_auto_reply_calls_delay_title">Vertraging automatisch opnemen</string>
<string name="swolfAvg">Gemiddelde SWOLF</string>
<string name="swolfMax">Maximale SWOLF</string>
<string name="swolfMin">Minimale SWOLF</string>
<string name="stepRateSum">Opgetelde stapsnelheid</string>
<string name="stepRateAvg">Gemiddelde stapsnelheid</string>
<string name="stepLengthAvg">Gemiddelde staplengte</string>
<string name="groundContactTimeAvg">Gemiddelde contacttijd met grond</string>
<string name="impactAvg">Gemiddelde impact</string>
<string name="impactMax">Maximale impact</string>
<string name="swingAngleAvg">Gemiddelde zwaaihoek</string>
<string name="foreFootLandings">Voorvoetlandingen</string>
<string name="midFootLandings">Midvoetlandingen</string>
<string name="backFootLandings">Hiellandingen</string>
<string name="eversionAngleAvg">Gemiddelde eversiehoek</string>
<string name="eversionAngleMax">Maximale eversiehoek</string>
<string name="fmtPaceDistance">Tempo %d afstand</string>
<string name="fmtPaceType">Tempo %d type</string>
<string name="fmtPacePace">Tempo %d tempo</string>
<string name="fmtPaceCorrection">Tempo %d correctie</string>
<string name="fmtPaceTypeAverage">Tempotype %d gemiddelde</string>
<string name="unknownDataEncountered">Niet-herkende gegevens aangetroffen</string>
<string name="milliseconds">milliseconden</string>
<string name="degrees">graden</string>
<string name="Pace">Tempo</string>
<string name="RunningForm">Hardloopkwaliteit</string>
<string name="pref_header_audio">Audio</string>
<string name="pref_header_generic">Algemeen</string>
<string name="pref_title_notification_wake_on_open">Automatisch ontgrendelen</string>
<string name="pref_summary_notification_wake_on_open">Ontgrendel het scherm van het Android-apparaat wanneer de gadget een OPEN-commando stuurt. Werkt alleen wanneer vertrouwde ontgrendeling actief is.</string>
<string name="pref_speak_notifications_aloud_summary">Meldingen zullen opgelezen worden via de koptelefoon</string>
<string name="pref_speak_notifications_aloud_title">Meldingen oplezen</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="widget_name_untitled">Widget zonder titel (%1$s)</string>
<string name="pref_header_calls_and_notifications">Gesprekken en meldingen</string>
<string name="widget_layout_top_wide_bot_large">Breed boven, groot onder</string>
<string name="widget_layout_top_large_bot_wide">Groot boven, breed onder</string>
<string name="widget_name_colored_tile">%1$s (gekleurde titel)</string>
<string name="pref_dashboard_widget_today_upside_down_summary">Toon in 24-uursmodus middernacht onderaan en 12 uur bovenaan de cirkel</string>
<string name="sleepasandroid_settings">Sleep As Android</string>
<string name="pref_summary_bottom_navigation_bar_off">Wissel tussen de hoofdschermen alleen met horizontaal vegen</string>
<string name="pref_dashboard_widget_today_upside_down_title">Middernacht onderaan</string>
<string name="pref_sleepasandroid_device_title">Gekoppeld apparaat</string>
<string name="pref_sleepasandroid_device_summary">Selecteer apparaat als databron voor Sleep As Android</string>
<string name="pref_sleepasandroid_features_title">Functies</string>
<string name="pref_sleepasandroid_features_summary">Ondersteuning verschilt per apparaat</string>
<string name="pref_sleepasandroid_feat_alarms">Wekkers</string>
<string name="pref_sleepasandroid_slot_summary">Welk wekkerslot wordt gebruikt voor het instellen van wekkers</string>
<string name="pref_sleepasandroid_slot_title">Wekkerslot</string>
<string name="pref_sleepasandroid_feat_movement">Bewegingssensor</string>
<string name="pref_sleepasandroid_feat_heartrate">Hartslag</string>
<string name="pref_sleepasandroid_feat_spo2">SpO2</string>
<string name="pref_sleepasandroid_enable_summary">Integratie met Sleep As Android inschakelen</string>
<string name="alarm_slot_reset">Wekkerslot is teruggezet naar standaard</string>
<string name="pref_sleepasandroid_feat_notifications">Meldingen</string>
<string name="pref_sleepasandroid_feat_oximetry">Bloedzuurstof</string>
<string name="armenian">Armeens</string>
<string name="pref_title_bottom_navigation_bar">Navigatiebalk onderaan</string>
<string name="pref_summary_bottom_navigation_bar_on">Wissel tussen de hoofdschermen met de navigatiebalk of horizontaal vegen</string>
<string name="pref_title_huawei_account">Huawei-account</string>
<string name="serbian">Servisch</string>
<string name="pref_summary_huawei_account">Huawei-account dat gebruikt is tijdens het bindingsproces. Het hier instellen staat toe dat het apparaat gebonden kan worden zonder reset naar fabrieksinstellingen.</string>
<string name="watchface_resolution_doesnt_match">Resolutie van wijzerplaat komt niet overeen met het scherm van het apparaat. Wijzerplaat is %1$s en scherm is %2$s</string>
</resources>

View File

@ -766,7 +766,7 @@
<string name="prefs_find_phone_duration">Duração do toque sonoro em segundos</string>
<string name="maximum_duration">Duração</string>
<string name="discovery_need_to_enter_authkey">Esse dispositivo precisa de sua chave de autenticação secreta, realize pressionamento longo no dispositivo para inseri-lo. Leia o wiki.</string>
<string name="fw_upgrade_notice_amazfitbip_lite">Você está prestes a instalar o firmware %s no seu Amazit Bip Lite.
<string name="fw_upgrade_notice_amazfitbip_lite">Você está prestes a instalar o firmware %s no seu Amazfit Bip Lite.
\n
\nCertifique-se de instalar o arquivo .fw, e depois o arquivo .res. Seu relógio será reiniciado após a instalação do arquivo .fw.
\n
@ -1510,7 +1510,7 @@
<string name="about_description_banglejs_nightly">Aplicativo companheiro Android para Bangle.js construído em cima do projeto Gadgetbridge, com acesso adicional à Internet.
\n
\nDevido às políticas Google Play Store, não somos permitidos ter um link de doação no próprio aplicativo, mas se você gosta deste aplicativo, por favor, considere doar através da página inicial do Gadgetbridge abaixo.</string>
<string name="single_band">Banda única</string>
<string name="single_band">Single Band</string>
<string name="about_activity_title_banglejs_nightly">Sobre o Bangle.js Gadgetbridge (Nightly)</string>
<string name="power_saving">Economia de energia</string>
<string name="gadgetbridge_running_banglejs_nightly">Nightly Bangle.js em execução</string>
@ -1519,4 +1519,92 @@
<string name="action_changelog">Registro de mudanças</string>
<string name="custom">Personalizado</string>
<string name="application_name_banglejs_nightly">Bangle.js Gadgetbridge (Nightly)</string>
<string name="pref_header_health">Saúde</string>
<string name="error_showing_changelog">Erro ao exibir o registro de alterações</string>
<string name="appmanager_watchface_activate">Ativar</string>
<string name="pref_header_audio">Áudio</string>
<string name="pref_header_generic">Genérico</string>
<string name="pref_title_mb_intents">Transmitir diretamente as intenções dos botões de mídia</string>
<string name="pref_summary_mb_intents">Ative se o controle de mídia do dispositivo não estiver funcionando para determinados aplicativos</string>
<string name="pref_theme_dynamic">Cores dinâmicas</string>
<string name="pref_show_changelog_summary">Exibir o registro de alterações desde a última versão após a atualização do Gadgetbridge</string>
<string name="accuracy_first">Precisão primeiro</string>
<string name="speed_first">Velocidade primeiro</string>
<string name="pref_show_changelog">Mostrar registro de alterações na inicialização</string>
<string name="steps_streaks">Sequência de passos</string>
<string name="step_streak_total">Total</string>
<string name="steps_streaks_average_steps">Média de
\npassos</string>
<string name="steps_streaks_achievement_rate">Taxa de
\nconquista</string>
<string name="steps_streaks_total_steps_hint_totals">Número total de passos já registrados</string>
<string name="step_streaks_achievements_sharing_title">Conquistas de passos</string>
<string name="changelog_show_full">Mais…</string>
<string name="uploadwatchfaceoperation_in_progress">Carregando o watchface</string>
<string name="steps_streaks_total_steps_hint">Número total de passos em toda a sequência</string>
<string name="steps_streaks_total_steps_average_hint">Média total de %d passos por dia</string>
<string name="step_streak_days_hint">Número de dias consecutivos em que a meta de passos foi atingida</string>
<string name="steps_streaks_hint">Sequência de dias consecutivos sem interrupção com metas de passos sendo alcançadas</string>
<string name="uploading_watchface">Carregando o watchface…</string>
<string name="step_streak_longest">Mais longo</string>
<string name="appmanager_app_share">Compartilhar</string>
<string name="debugactivity_confirm_remove_device_preferences_title">Remover as preferências do dispositivo?</string>
<string name="debugactivity_confirm_remove_device_preferences">Isso redefinirá as preferências do dispositivo para todos os dispositivos conectados. Tem certeza?</string>
<string name="pref_header_calendar">Calendário</string>
<string name="pref_title_general_reconnectonlytoconnected">Reconectar somente a dispositivos conectados</string>
<string name="pref_summary_general_reconnectonlytoconnected">Reconectar somente a dispositivos conectados, em vez de reconectar a todos os dispositivos</string>
<string name="steps_streaks_total_steps">Passos
\ntotais</string>
<string name="steps_streaks_streak_days">Dias
\nseguidos</string>
<string name="fw_upgrade_notice_amazfitbip3pro">Você está prestes a instalar o firmware %s no seu Amazfit Bip 3 Pro.
\n
\nCertifique-se de instalar o arquivo .fw, e depois o arquivo .res. Seu relógio será reiniciado após a instalação do arquivo .fw.
\n
\nNota: você não precisa instalar .res se esse arquivo for exatamente o mesmo que os instalados anteriormente.
\n
\nPROSSIGA POR SUA CONTA E RISCO!</string>
<string name="open_fw_installer_select_file">Selecione um arquivo que deseja enviar para o dispositivo: %s</string>
<string name="pref_header_display">Exibir</string>
<string name="step_streak_average_steps_hint">Média de passos por dia da sequência</string>
<string name="appmanager_app_start">Iniciar</string>
<string name="appmanager_app_download">Download para o cache</string>
<string name="appmanager_item_outdated">(desatualizado)</string>
<string name="appmanager_download_started">Download do aplicativo iniciado</string>
<string name="pref_header_connection">Conexão</string>
<string name="step_streak_ongoing">Em andamento</string>
<string name="pref_title_navigation_prefs">Preferências de navegação</string>
<string name="pref_sleepasandroid_features_title">Recursos</string>
<string name="pref_sleepasandroid_feat_heartrate">Frequência cardíaca</string>
<string name="pref_summary_huawei_account">Conta da Huawei usada no processo de emparelhamento. Sua configuração permite emparelhar sem redefinição de fábrica.</string>
<string name="pref_header_time">Hora</string>
<string name="steps_streaks_total_days_hint_totals">Porcentagem de dias com meta atingida em relação a todos os dias com passos</string>
<string name="pref_cache_weather">Informações sobre o clima em cache</string>
<string name="pref_cache_weather_summary">As informações do clima serão armazenadas em cache durante as reinicializações do aplicativo.</string>
<string name="dual_band">Dual Band</string>
<string name="steps_streaks_since_date">Desde %s</string>
<string name="step_streaks_achievements_sharing_message">Minhas conquistas diárias de passos!</string>
<string name="watchface_resolution_doesnt_match">A resolução do watchface não corresponde à tela do dispositivo. Watchface é %1$s a tela do dispositivo é %2$s</string>
<string name="pref_title_huawei_account">Conta da Huawei</string>
<string name="appmanager_downloaded_to_cache">Download de %s para o cache</string>
<string name="appmanager_download_app_error">Erro no download do aplicativo</string>
<string name="open_fw_installer_connect_minimum_one_device">Conecte pelo menos um dispositivo para o qual você deseja enviar o arquivo.</string>
<string name="pref_header_sound_vibration">Som e vibração</string>
<string name="open_fw_installer_connect_maximum_one_device">Conecte APENAS UM dispositivo para o qual você deseja enviar o arquivo.</string>
<string name="pref_header_offline_voice">Voz offline</string>
<string name="open_fw_installer_ensure_device_connected">Certifique-se de que o dispositivo %s esteja conectado</string>
<string name="fw_upgrade_notice_amazfitbip3">Você está prestes a instalar o firmware %s no seu Amazfit Bip 3.
\n
\nCertifique-se de instalar o arquivo .fw, e depois o arquivo .res. Seu relógio será reiniciado após a instalação do arquivo .fw.
\n
\nNota: você não precisa instalar .res se esse arquivo for exatamente o mesmo que os instalados anteriormente.
\n
\nPROSSIGA POR SUA CONTA E RISCO!</string>
<string name="fw_upgrade_notice_miband7">Você está prestes a instalar o firmware %s no seu Xiaomi Smart Band 7.
\n
\nCertifique-se de instalar o arquivo .fw, e depois o arquivo .res. Seu relógio será reiniciado após a instalação do arquivo .fw.
\n
\nPROSSIGA POR SUA CONTA E RISCO!</string>
<string name="uploadwatchfaceoperation_complete">Instalação do Watchface concluída</string>
<string name="uploadwatchfaceoperation_failed">Falha na instalação do Watchface</string>
</resources>

View File

@ -1118,7 +1118,7 @@
<string name="movement_intensity">Интенсивность движения</string>
<string name="devicestatus_upload_started">Загрузка началась</string>
<string name="activity_list_summary_activities">Активности</string>
<string name="menuitem_sleep">Шаги</string>
<string name="menuitem_sleep">Сон</string>
<string name="devicetype_amazfit_bipu">Amazfit Bip U</string>
<string name="pref_title_upper_button_function_double">Двойное нажатие на верхнюю кнопку</string>
<string name="pref_title_lower_button_function_double">Двойное нажатие на нижнюю кнопку</string>
@ -1855,7 +1855,7 @@
<string name="error_setting_parent_folder">Ошибка задания родительской папки: %s</string>
<string name="autoconnect_from_device_summary">Подключаться в случае когда соединение инициировано устройством, например, наушниками</string>
<string name="devicetype_sony_wh_1000xm2">Sony WH-1000XM2</string>
<string name="info_no_devices_connected">нет подключенных устройств</string>
<string name="info_no_devices_connected">Нет подключенных устройств</string>
<string name="controlcenter_set_parent_folder">Задать родительскую папку</string>
<string name="controlcenter_set_folder_title">Укажите папку или создайте новую</string>
<string name="autoconnect_from_device_title">Подключаться при подключении с устройства</string>
@ -2665,13 +2665,13 @@
<string name="pref_heartrate_automatic_enable">Автоизмерение сердцебиения</string>
<string name="pref_spo_automatic_enable">Автоизмерение кислорода в крови</string>
<string name="pref_force_options">Форсирование опций</string>
<string name="pref_force_smart_alarm">Форсировать умный будильник</string>
<string name="pref_force_smart_alarm">Поддержка умного будильника</string>
<string name="pref_force_smart_alarm_summary">Форсировать поддержку умных будильников.
\nИСПОЛЬЗУЙТЕ НА СВОЙ РИСК</string>
<string name="pref_force_wear_location">Форсировать место ношения</string>
<string name="pref_force_wear_location">Поддержка места ношения</string>
<string name="pref_force_wear_location_summary">Форсировать поддержку расположения ношения устройства.
\nИСПОЛЬЗУЙТЕ НА СВОЙ РИСК</string>
<string name="pref_force_dnd_support">Форсировать поддержку \"не беспокоить\"</string>
<string name="pref_force_dnd_support">Поддержка \"не беспокоить\"</string>
<string name="huawei_ignore_wakeup_status_start">Игнорировать статус начала вставания</string>
<string name="huawei_ignore_wakeup_status_start_description">Может помочь исправить распознание сна. Сразу видимо в обзоре дневных активностей.</string>
<string name="huawei_ignore_wakeup_status_end">Игнорировать статус окончания вставания</string>
@ -2787,4 +2787,43 @@
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="busy_task_fetch_sports_details_interrupted">Получение подробностей о спорте было прервано</string>
<string name="pref_force_enable_heartrate_support">Поддержка измерения пульса</string>
<string name="pref_force_enable_spo2_support_summary">Форсировать поддержку измерения уровня кислорода в крови.
\nИСПОЛЬЗУЙТЕ НА СВОЙ РИСК</string>
<string name="pref_force_enable_heartrate_support_summary">Форсировать поддержку измерения пульса.
\nИСПОЛЬЗУЙТЕ НА СВОЙ РИСК</string>
<string name="pref_force_enable_spo2_support">Поддержка измерения SpO2</string>
<string name="pref_dashboard_widget_double_size_summary">Позволить виджету занять две колонки на обзорной панели</string>
<string name="pref_dashboard_widget_show_legend_summary">Показывать значения цветов под виджетом</string>
<string name="pref_dashboard_select_devices_title">Выбрать устройства...</string>
<string name="pref_dashboard_widgets_order_summary">Выберите виджеты и порядок их отображения на главном экране</string>
<string name="pref_dashboard_widget_today_24h_summary">Показывать активность в одном 24-часовом кружке вместо двойного 12ч</string>
<string name="pref_auto_reply_calls_title">Принимать звонки автоматически</string>
<string name="pref_auto_reply_calls_delay_title">Задержка перед автоприёмом</string>
<string name="pref_auto_reply_calls_summary">Телефон будет автоматически принимать входящие звонки</string>
<string name="pref_auto_reply_calls_delay_summary">Время в секундах до того, как звонок будет автоматически принят</string>
<string name="pref_header_generic">Общий</string>
<string name="pref_header_audio">Звук</string>
<string name="activity_type_free_training">Свободная тренировка</string>
<string name="activity_type_dynamic_cycle">Динамический цикл</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Интервал измерений пульса</string>
<string name="pref_speak_notifications_aloud_title">Произносить уведомления вслух</string>
<string name="pref_header_calls_and_notifications">Вызовы и уведомления</string>
<string name="pref_dashboard_widget_show_legend_title">Показывать обозначения</string>
<string name="armenian">Армянский</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="pref_title_notification_wake_on_open">Автопробуждение и разблокировка</string>
<string name="pref_summary_notification_wake_on_open">Пробуждать и разблокировать Android-устройство когда носимое устройство отвечает с OPEN. Нужно быть в доверенном состоянии.</string>
<string name="pref_sleepasandroid_features_title">Функции</string>
<string name="pref_sleepasandroid_features_summary">Поддержка варьируется в зависимости от устройства</string>
<string name="pref_sleepasandroid_feat_movement">Акселерометр</string>
<string name="pref_sleepasandroid_feat_heartrate">Пульс</string>
<string name="pref_sleepasandroid_feat_spo2">SpO2</string>
<string name="pref_title_bottom_navigation_bar">Нижняя панель навигации</string>
<string name="pref_summary_bottom_navigation_bar_on">Переключаться между основными экранами через панель навигации или жестами</string>
<string name="pref_sleepasandroid_feat_notifications">Уведомления</string>
<string name="pref_summary_bottom_navigation_bar_off">Переключаться между основными экранами только по жестам</string>
<string name="serbian">Сербский</string>
<string name="pref_title_huawei_account">Учётная запись Huawei</string>
<string name="pref_summary_huawei_account">Используется для сопряжения без сброса устройства.</string>
</resources>

View File

@ -1,21 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="about_activity_title_generic">เกี่ยวกับ Gadgetbridge</string>
<string name="application_name_generic"></string>
<string name="application_name_generic">Gadgetbridge</string>
<string name="gadgetbridge_running_generic">Gadgetbridge กำลังทำงาน</string>
<string name="about_description_generic">แอปเสรีไม่สงวนลิขสิทธิ์ ไม่พึ่งระบบคลาวด์ สำหรับใช้ทดแทนแอปจากผู้ผลิตที่ไม่เปิดเผยโค้ดอิสระ</string>
<string name="title_activity_controlcenter_generic"></string>
<string name="title_activity_controlcenter_generic">Gadgetbridge</string>
<string name="about_activity_title_banglejs_main">เกี่ยวกับ Bangle.js Gadgetbridge</string>
<string name="gadgetbridge_running_banglejs_main">Bangle.js กำลังทำงานอยู่</string>
<string name="application_name_banglejs_nightly"></string>
<string name="title_activity_controlcenter_banglejs_nightly"></string>
<string name="application_name_banglejs_nightly">Bangle.js Gadgetbridge (Nightly)</string>
<string name="title_activity_controlcenter_banglejs_nightly">Bangle.js Gadgetbridge (Nightly)</string>
<string name="gadgetbridge_running_banglejs_nightly">Nightly Bangle.js กำลังทำงานอยู่</string>
<string name="about_activity_title_main_nightly">เกี่ยวกับ Gadgetbridge Nightly</string>
<string name="title_activity_controlcenter_main_nightly"></string>
<string name="about_activity_title_main_nightly">เกี่ยวกับ Gadgetbridge รุ่นทดสอบ</string>
<string name="title_activity_controlcenter_main_nightly">Gadgetbridge Nightly</string>
<string name="gadgetbridge_running_main_nightly">Nightly GB กำลังทำงานอยู่</string>
<string name="application_name_main_nopebble">Gadgetbridge (Nightly โดยไม่มี Pebble provider)</string>
<string name="title_activity_controlcenter_main_nopebble">Gadgetbridge Nightly แบบไม่มี Pebbleล</string>
<string name="about_activity_title_main_nopebble">เกี่ยวกับ Gadgetbridge Nightly แบบไม่มี Pebbleล</string>
<string name="about_activity_title_main_nopebble">About Gadgetbridge Nightly No Pebble</string>
<string name="action_settings">การตั้งค่า</string>
<string name="action_debug">ดีบั้ก</string>
<string name="action_quit">ออก</string>
@ -67,8 +67,8 @@
<string name="title_activity_debug">ดีบั้ก</string>
<string name="debugactivity_really_factoryreset_title">คืนค่าเรื่มต้นจากโรงงาน?</string>
<string name="debugactivity_confirm_remove_device_preferences_title">ลบการตั้งค่าของอุปกรณ์?</string>
<string name="about_activity_title_banglejs_nightly">เกี่ยวกับ Bangle.js Gadgetbridge (Nightly)</string>
<string name="about_description_main_nightly">แอปเสรีไม่สงวนลิขสิทธิ์ ไม่พึ่งระบบคลาวด์ สำหรับใช้ทดแทนแอปแก็ดเจ็ตต่างๆจากผู้ผลิตที่ไม่เปิดเผยโค้ดอิสระ เวอร์ชั่น Nightly ของ Gadgetbridge ไม่สามารถติดตั้งซ้อนได้หากคุณมีแอป Gadgetbridge หรือ Pebble ติดตั้งอยู่แล้ว เนื่องจากการขัดแย้งกันของ Pebble provider</string>
<string name="about_activity_title_banglejs_nightly">เกี่ยวกับ Bangle.js Gadgetbridge (รุ่นทดสอบ)</string>
<string name="about_description_main_nightly">แอปเสรีไม่สงวนลิขสิทธิ์ ไม่พึ่งระบบคลาวด์ สำหรับใช้ทดแทนแอปแก็ดเจ็ตต่างๆจากผู้ผลิตที่ไม่เปิดเผยโค้ดอิสระ เวอร์ชั่นทดสอบของ Gadgetbridge ไม่สามารถติดตั้งคู่กันได้หากคุณมีแอป Gadgetbridge หรือ Pebble ติดตั้งอยู่แล้ว เนื่องจากการขัดแย้งกันของ Pebble provider</string>
<string name="controlcenter_delete_device">ลบอุปกรณ์</string>
<string name="prefs_activity_in_device_card_title">แสดงข้อมูลกิจกรรมบนการ์ดของอุปกรณ์</string>
<string name="prefs_activity_in_device_card_title_summary">แสดงจำนวนก้าวเดินปัจจุบัน ระยะทางหรือการนอนหลับบนการ์ดของอุปกรณ์</string>
@ -81,4 +81,40 @@
\n
\nเนื่องจากนโยบายของ Google Play เราจึงไม่สามารถเพื่มช่องการบริจาคในแอปได้โดยตรง แต่ถ้าคุณชอบแอปนี้โปรดพิจารณาบริจาคผ่านหน้าหลักของ Gadgetbridge ด้านล่างนี้</string>
<string name="debugactivity_really_factoryreset">การคืนค่าโรงงานจะลบข้อมูลทุกอย่างของอุปกรณ์ Xiaomi/Huami (ที่รองรับ) และยังเปลี่ยนที่อยู่ Bluetooth MAC address ฉะนั้น Gadgetbridge จะมองเห็นเป็นอุปกรณ์ใหม่</string>
<string name="application_name_banglejs_main">Bangle.js Gadgetbridge</string>
<string name="title_activity_controlcenter_banglejs_main">Bangle.js Gadgetbridge</string>
<string name="application_name_main_nightly">Gadgetbridge (รุ่นทดสอบ)</string>
<string name="about_links">ลิงก์</string>
<string name="single_band">ช่องความถี่เดี่ยว</string>
<string name="dual_band">ช่องความถี่คู่</string>
<string name="debugactivity_confirm_remove_device_preferences">นี่จะเป็นการรีเซ็ตการตั้งค่าของทุกอุปกรณ์ที่เชื่อมต่ออยู่ แน่ใจหรือ?</string>
<string name="about_description_main_nopebble">แอปเสรีไม่สงวนลิขสิทธิ์ ไม่พึ่งระบบคลาวด์ สำหรับใช้ทดแทนแอปแก็ดเจ็ตต่างๆจากผู้ผลิตที่ไม่เปิดเผยโค้ดอิสระ เวอร์ชั่นทดสอบของ Gadgetbridge มี Pebble provider ที่ถูกเปลี่ยนชื่อเพื่อป้องกันการขัดแย้งกัน ฉะนั้นการทำงานร่วมกับฟีเจอร์บางอย่างของ Pebble อาจใช้ไม่ได้ แต่สามารถติดตั้งแอปนี้คู่กับแอป Gadgetbridge ที่มีอยู่แล้วได้</string>
<string name="appmanager_installed_watchapps">แอปที่ติดตั้งแล้ว</string>
<string name="appmanager_installed_watchfaces">หน้าปัดนาฬิกาที่ติดตั้งแล้ว</string>
<string name="about_core_team_title">ผู้ร่วมพัฒนาหลักๆ(ตั้งแต่เรื่มพัฒนาแรกๆ)</string>
<string name="gadgetbridge_running_main_nopebble">Nightly NoPebble GB กำลังทำงาน</string>
<string name="appmanager_app_share">แชร์</string>
<string name="title_activity_notification_management">การตั้งค่าการแจ้งเตือน</string>
<string name="pref_title_notifications_call">เมื่อมีสายเข้า</string>
<string name="pref_title_notifications_ignore_low_priority">ไม่สนใจการแจ้งเตือนความสำคัญต่ำ</string>
<string name="pref_title_notifications_generic_settings">การตั้งค่าการแจ้งเตือนของ Android</string>
<string name="pref_title_notifications_generic">การรองรับการแจ้งเตือนทั่วไป</string>
<string name="pref_title_whenscreenon">...และเมื่อหน้าจอเปิดอยู่</string>
<string name="pref_summary_notifications_ignore_low_priority">ไม่ต้องส่งการแจ้งเตือนที่มีความสำคัญต่ำต่างๆไปยังอุปกรณ์</string>
<string name="pref_title_support_voip_calls">การโทรจากระบบ VoIP</string>
<string name="pref_summary_notification_prefer_long_text">หากเป็นไปได้ ให้ส่งการแจ้งเตือนที่มีข้อความยาวๆ ไปยังอุปกรณ์</string>
<string name="pref_summary_notifications_ignore_work_profile">ไม่ต้องส่งการแจ้งเตือนจากแอปที่อยู่ในโปรไฟล์งานไปยังอุปกรณ์</string>
<string name="pref_title_notification_cache_while_disconnected">แคชการแจังเตือนไว้</string>
<string name="pref_summary_notification_cache_while_disconnected">ส่งการแจ้งเตือนที่พลาดไป เมื่ออุปกรณ์กลับมาเชื่อมต่ออีกครั้งหลังจากไม่อยู่ในระยะการเชื่อมต่อ</string>
<string name="pref_title_notification_prefer_long_text">ส่งการแจ้งเตือนข้อความยาวๆ</string>
<string name="never">ไม่เลย</string>
<string name="always">ตลอดเวลา</string>
<string name="pref_title_notifications_ignore_work_profile">ไม่สนใจการแจ้งเตือนจากโปรไฟล์งาน</string>
<string name="pref_title_ping_tone">เสียงตอนปิงอุปกรณ์</string>
<string name="pref_title_notification_delay_calls">หน่วงการแจ้งเตือนการโทร</string>
<string name="pref_summary_notification_delay_calls">หน่วงไว้ก่อนจะส่งการไปแจ้งเตือนไปยังอุปกรณ์ หน่วยเป็นวินาที</string>
<string name="about_contributors">ผู้ร่วมพัฒนา</string>
<string name="about_additional_device_support">ผู้สนับสนุนการรองรับอุปกรณ์เพื่มเติม</string>
<string name="about_additional_contributions">ขอขอบคุณผู่ร่วมพัฒนาทุกท่านที่ช่วยกันแก้ไขโค้ด, แปลภาษา, ช่วยเหลือ, ออกไอเดีย, ให้กำลังใจ, แจ้งบั้ก, และบริจาคเงิน... ✊</string>
<string name="action_discover">เชื่อมต่ออุปกรณ์ใหม่</string>
</resources>

View File

@ -1734,7 +1734,7 @@
<string name="permission_location">%1$s ekranınız kapalıyken bile saatinize bağlı kalmasını sağlamak için arka planda konumunuza erişmeye ihtiyaç duyuyor.
\n
\nKabul etmek için lütfen \'%2$s\' düğmesine dokunun.</string>
<string name="info_no_devices_connected">bağlı aygıt yok</string>
<string name="info_no_devices_connected">Bağlı aygıt yok</string>
<string name="info_connected_count">%d aygıt bağlı</string>
<string name="estonian">Estonca</string>
<string name="lithuanian">Litvanyaca</string>
@ -2854,4 +2854,122 @@
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="busy_task_fetch_sports_details_interrupted">Spor bilgilerinin getirilmesi yarıda kesildi</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="companion_pairing_request_title">Yardımcı aygıt</string>
<string name="companion_pairing_request_description">Bu aygıt yardımcı olarak eşleştirilsin mi?
\n
\nBu, aygıt bulma gibi bazı işlevler için tavsiye edilir ve daha iyi bir bağlantı sağlar.</string>
<string name="unbind_before_pair_title">Zaten bağlı</string>
<string name="unbind_before_pair_message">Bu aygıt Android ayarlarında zaten bağlı, bu da bazı aygıtlar için eşleştirmenin başarısız olmasına neden olabilir.
\n
\nAygıtı eklemek başarısız olursa, lütfen Android ayarlarından kaldırın ve tekrar deneyin.</string>
<string name="devicesetting_scannable_debounce">Taranabilir hata giderme zaman aşımı (saniye)</string>
<string name="devicesetting_scannable_rssi">En düşük RSSI eşiği</string>
<string name="devicesetting_scannable_debounce_summary">Tarandıktan sonra aygıt tarandı olarak kalır ve belirtilen süre boyunca yok sayılır</string>
<string name="devicetype_scannable">Taranabilir aygıt</string>
<string name="state_scanned">Tarandı</string>
<string name="devicesetting_scannable_minimum_unseen">En kısa görülmeme süresi (saniye)</string>
<string name="devicesetting_scannable_minimum_unseen_summary">Tarandıktan sonra, aygıtın tekrar kaydedilmeden önce bu süre boyunca görülmemesi gerekir</string>
<string name="devicesetting_scannable_rssi_summary">Algılama için en düşük RSSI eşiği</string>
<string name="swolfAvg">Ortalama swolf</string>
<string name="swolfMax">En yüksek swolf</string>
<string name="swolfMin">En düşük swolf</string>
<string name="stepRateSum">Adım hızı toplamı</string>
<string name="stepRateAvg">Ortalama adım hızı</string>
<string name="stepLengthAvg">Ortalama Adım Uzunluğu</string>
<string name="groundContactTimeAvg">Ortalama yerle temas süresi</string>
<string name="impactAvg">Ortalama etki</string>
<string name="impactMax">En yüksek etki</string>
<string name="swingAngleAvg">Ortalama salınım açısı</string>
<string name="foreFootLandings">Ön ayak inişi</string>
<string name="midFootLandings">Orta ayak inişi</string>
<string name="backFootLandings">Arka ayak inişi</string>
<string name="eversionAngleAvg">Ortalama ters dönme açısı</string>
<string name="eversionAngleMax">En yüksek ters dönme açısı</string>
<string name="fmtPaceDistance">Hız %d mesafe</string>
<string name="fmtPaceType">Hız %d tür</string>
<string name="fmtPacePace">Hız %d hız</string>
<string name="fmtPaceCorrection">Hız %d düzeltme</string>
<string name="fmtPaceTypeAverage">Hız Türü %d ortalama</string>
<string name="unknownDataEncountered">Bilinmeyen veriyle karşılaşıldı</string>
<string name="milliseconds">milisaniye</string>
<string name="degrees">derece</string>
<string name="Pace">Hız</string>
<string name="RunningForm">Koşu Biçimi</string>
<string name="pref_force_enable_heartrate_support">Kalp ritmi desteğini zorla</string>
<string name="pref_force_enable_heartrate_support_summary">Kalp ritmi desteğini etkinleştirmeye zorla.
\nKULLANMANIZ DURUMUNDA RİSK SİZE AİTTİR</string>
<string name="pref_force_enable_spo2_support">SpO2 desteğini zorla</string>
<string name="pref_force_enable_spo2_support_summary">SpO2 desteğini etkinleştirmeye zorla.
\nKULLANMANIZ DURUMUNDA RİSK SİZE AİTTİR</string>
<string name="activity_type_worn">Yorgun</string>
<string name="pref_dashboard_cards_title">Kartlarda widget\'ları göster</string>
<string name="error_showing_changelog">Değişiklik günlüğü gösterilirken hata oluştu</string>
<string name="dashboard_settings">Gösterge tablosu ayarları</string>
<string name="pref_dashboard_cards_summary">Gösterge tablosunda widget\'ların etrafına kartlar çiz</string>
<string name="pref_dashboard_first_title">Önce gösterge tablosunu göster</string>
<string name="pref_dashboard_first_summary">Gadgetbridge başladığında aygıtlar ekranı yerine gösterge tablosunu göster</string>
<string name="pref_dashboard_widget_settings">Widget ayarları</string>
<string name="pref_dashboard_widget_today_title">Etkinlik çizelgesi</string>
<string name="pref_dashboard_all_devices_title">Tüm aygıtlar</string>
<string name="pref_dashboard_widget_today_hr_interval_title">Kalp ritmi aralığı</string>
<string name="pref_dashboard_widget_double_size_summary">Widget\'ın gösterge tablosunda iki sütun kaplamasına izin ver</string>
<string name="pref_dashboard_widget_show_legend_summary">Widget\'ın altında renkleri açıklayan bir açıklama göster</string>
<string name="pref_dashboard_all_devices_summary">Gösterge tablosundaki toplamlar için eklenen tüm aygıtlardan gelen etkinlik verilerini birleştir</string>
<string name="bottom_nav_dashboard">Gösterge tablosu</string>
<string name="bottom_nav_devices">Aygıtlar</string>
<string name="pref_dashboard_widget_today_24h_title">24 saat modu</string>
<string name="pref_dashboard_widget_double_size_title">İki katı boyut</string>
<string name="pref_dashboard_widget_goals_chart_title">Hedefler çizelgesi</string>
<string name="pref_dashboard_devices_to_include">Dahil edilecek aygıtlar</string>
<string name="pref_dashboard_select_devices_title">Aygıtları seç...</string>
<string name="pref_dashboard_widgets_order_summary">Hangi widget\'ların etkinleştirileceğini ve gösterge tablosunda hangi sırada görüntüleneceğini seçin</string>
<string name="pref_dashboard_widget_today_24h_summary">Etkinliği iki tane 12 saatlik daire yerine bir tane 24 saatlik daire içinde göster</string>
<string name="pref_dashboard_select_devices_summary">Gösterge tablosundaki toplamlar için belirli aygıtlardan gelen etkinlik verilerini birleştir</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">Her başarılı kalp ritmi ölçümünden sonra grafiğin \'yorgun\' olarak gösterdiği dakika miktarı</string>
<string name="pref_dashboard_widget_show_legend_title">ıklamaları göster</string>
<string name="pref_auto_reply_calls_summary">Telefon gelen aramaları otomatik olarak yanıtlayacaktır</string>
<string name="pref_auto_reply_calls_delay_summary">Aramanın otomatik olarak yanıtlanacağı saniye sayısı</string>
<string name="pref_auto_reply_calls_title">Telefon aramalarını otomatik yanıtla</string>
<string name="pref_auto_reply_calls_delay_title">Otomatik Yanıt Gecikmesi</string>
<string name="pref_header_audio">Ses</string>
<string name="pref_header_generic">Genel</string>
<string name="pref_title_notification_wake_on_open">Otomatik uyandır ve kilidi aç</string>
<string name="pref_summary_notification_wake_on_open">Aygıt bir OPEN (AÇ) yanıtı gönderdiğinde Android aygıtını uyandırın ve kilidini açın. Güvenilir bir durumda olması gerekir.</string>
<string name="pref_speak_notifications_aloud_summary">Bildirimler kulaklıklardan yüksek sesle okunacaktır</string>
<string name="pref_speak_notifications_aloud_title">Bildirimleri Sesli Oku</string>
<string name="devicetype_redmi_watch_4">Redmi Watch 4</string>
<string name="widget_layout_top_wide_bot_large">Yukarıda geniş, aşağıda büyük</string>
<string name="widget_layout_top_large_bot_wide">Yukarıda büyük, aşağıda geniş</string>
<string name="widget_name_colored_tile">%1$s (renkli döşeme)</string>
<string name="widget_name_untitled">Başlıksız widget (%1$s)</string>
<string name="pref_header_calls_and_notifications">Çağrılar ve bildirimler</string>
<string name="armenian">Ermenice</string>
<string name="pref_summary_bottom_navigation_bar_off">Yalnızca yatay kaydırma kullanarak ana ekranlar arasında geçiş yapın</string>
<string name="pref_summary_bottom_navigation_bar_on">Gezinme çubuğunu veya yatay kaydırmayı kullanarak ana ekranlar arasında geçiş yapın</string>
<string name="pref_title_bottom_navigation_bar">Alt gezinme çubuğu</string>
<string name="pref_dashboard_widget_today_upside_down_title">Gece yarısı altta</string>
<string name="pref_dashboard_widget_today_upside_down_summary">24 saat modunda, gece yarısını grafiğin alt kısmına, gün ortasını ise grafiğin üst kısmına çiz</string>
<string name="pref_sleepasandroid_features_summary">Destek aygıttan aygıta farklılık gösterir</string>
<string name="pref_sleepasandroid_feat_alarms">Alarmlar</string>
<string name="pref_sleepasandroid_slot_title">Alarm yuvası</string>
<string name="alarm_slot_reset">Alarm yuvası öntanımlı olarak ayarlandı</string>
<string name="pref_sleepasandroid_feat_heartrate">Kalp ritmi</string>
<string name="pref_sleepasandroid_feat_oximetry">Oksimetri</string>
<string name="pref_sleepasandroid_feat_spo2">SPO2</string>
<string name="sleepasandroid_settings">Sleep As Android</string>
<string name="pref_sleepasandroid_slot_summary">Alarmları ayarlarken hangi alarm yuvasının kullanılacağı</string>
<string name="pref_sleepasandroid_feat_notifications">Bildirimler</string>
<string name="pref_sleepasandroid_feat_movement">İvmeölçer</string>
<string name="pref_sleepasandroid_enable_summary">Sleep As Android bütünleşmesini etkinleştir</string>
<string name="pref_sleepasandroid_device_title">Sağlayıcı aygıt</string>
<string name="pref_sleepasandroid_device_summary">Sleep As Android veri sağlayıcısı olarak aygıtı seçin</string>
<string name="pref_sleepasandroid_features_title">Özellikler</string>
<string name="pref_summary_huawei_account">Eşleştirme işleminde kullanılan Huawei hesabı. Ayarlanması, fabrika ayarlarına sıfırlamadan eşleştirmeyi sağlar.</string>
<string name="pref_title_huawei_account">Huawei Hesabı</string>
<string name="serbian">Sırpça</string>
<string name="watchface_resolution_doesnt_match">Saat arayüzü çözünürlüğü aygıt ekranıyla eşleşmiyor. Saat arayüzü %1$s, aygıt ekranı %2$s</string>
<string name="cyclingPowerMin">En düşük bisiklet gücü</string>
<string name="cyclingPowerAverage">Ortalama bisiklet gücü</string>
<string name="cyclingPowerMax">En yüksek bisiklet gücü</string>
<string name="devicetype_huawei_watchfit2">Huawei Watch Fit 2</string>
</resources>

View File

@ -553,7 +553,7 @@
<string name="activity_type_activity">活动</string>
<string name="activity_type_light_sleep">浅睡眠</string>
<string name="activity_type_deep_sleep">深睡眠</string>
<string name="activity_type_not_worn">设备没有磨损</string>
<string name="activity_type_not_worn">设备没有佩戴</string>
<string name="activity_type_running">跑步</string>
<string name="activity_type_walking">走路</string>
<string name="activity_type_swimming">游泳</string>
@ -2842,4 +2842,122 @@
<string name="devicetype_huawei_watchgt4">华为手表 GT 4</string>
<string name="busy_task_fetch_sports_details_interrupted">获取运动详情时被中断</string>
<string name="devicetype_huawei_watchultimate">华为手表 Ultimate</string>
<string name="unbind_before_pair_title">已绑定</string>
<string name="companion_pairing_request_title">陪伴设备</string>
<string name="companion_pairing_request_description">将此设备配对为陪伴设备?
\n
\n建议将此功能用于某些功能例如查找设备并提供更好的连接。</string>
<string name="unbind_before_pair_message">该设备已在 Android 设置中绑定,这可能会导致某些设备配对失败。
\n
\n如果添加设备失败请在 Android 设置中将其删除,然后重试。</string>
<string name="devicetype_scannable">可扫描的设备</string>
<string name="state_scanned">已扫描</string>
<string name="devicesetting_scannable_rssi">最小 RSSI 阈值</string>
<string name="devicesetting_scannable_rssi_summary">检测的最小 RSSI 阈值</string>
<string name="devicesetting_scannable_debounce">可扫描的去抖动超时(秒)</string>
<string name="devicesetting_scannable_minimum_unseen">最短未发现时间(秒)</string>
<string name="devicesetting_scannable_debounce_summary">扫描后,设备将保持扫描状态并在指定时间内被忽略</string>
<string name="devicesetting_scannable_minimum_unseen_summary">扫描后,设备必须在这段时间内不可见,然后才能再次注册</string>
<string name="swolfAvg">平均 Swolf</string>
<string name="swolfMax">最大 Swolf</string>
<string name="swolfMin">最小 Swolf</string>
<string name="stepRateSum">步速总和</string>
<string name="stepRateAvg">平均步速</string>
<string name="stepLengthAvg">平均步长</string>
<string name="groundContactTimeAvg">平均触地时间</string>
<string name="impactAvg">平均影响</string>
<string name="impactMax">最大影响</string>
<string name="swingAngleAvg">平均摆角</string>
<string name="foreFootLandings">前脚落地</string>
<string name="midFootLandings">中足落地</string>
<string name="backFootLandings">后脚落地</string>
<string name="eversionAngleAvg">平均外翻角度</string>
<string name="eversionAngleMax">最大外翻角度</string>
<string name="fmtPaceDistance">步速 %d 距离</string>
<string name="fmtPaceType">步速 %d 类型</string>
<string name="fmtPacePace">步速 %d 步速</string>
<string name="degrees"></string>
<string name="fmtPaceCorrection">步速 %d 修正</string>
<string name="fmtPaceTypeAverage">配速类型 %d 平均值</string>
<string name="unknownDataEncountered">遇到未知数据</string>
<string name="milliseconds">毫秒</string>
<string name="Pace">步伐</string>
<string name="RunningForm">跑步形式</string>
<string name="pref_force_enable_heartrate_support">强制支持心率</string>
<string name="pref_force_enable_spo2_support">强制支持血氧</string>
<string name="pref_force_enable_heartrate_support_summary">强制启用心率支持。
\n风险自担</string>
<string name="pref_force_enable_spo2_support_summary">强制启用血氧支持。
\n风险自担</string>
<string name="pref_dashboard_devices_to_include">要包括的设备</string>
<string name="pref_dashboard_all_devices_title">所有设备</string>
<string name="pref_dashboard_select_devices_title">选择设备...</string>
<string name="pref_dashboard_widgets_order_summary">选择启用哪些小部件以及它们在仪表板上的显示顺序</string>
<string name="pref_dashboard_widget_today_24h_summary">以单个 24 小时圆圈而不是双 12 小时圆圈显示活动</string>
<string name="pref_dashboard_widget_show_legend_summary">在小部件下方显示说明颜色的图例</string>
<string name="pref_dashboard_select_devices_summary">将来自特定设备的活动数据合并到仪表板上的总计中</string>
<string name="activity_type_worn">佩戴</string>
<string name="bottom_nav_dashboard">仪表板</string>
<string name="error_showing_changelog">显示变更日志时出错</string>
<string name="dashboard_settings">仪表板设置</string>
<string name="bottom_nav_devices">设备</string>
<string name="pref_dashboard_first_title">首先显示仪表板</string>
<string name="pref_dashboard_first_summary">Gadgetbridge 启动时显示仪表板,而不是设备屏幕</string>
<string name="pref_dashboard_cards_title">在卡片上显示小部件</string>
<string name="pref_dashboard_cards_summary">在仪表板上的小部件周围绘制卡片</string>
<string name="pref_dashboard_widget_settings">小部件设置</string>
<string name="pref_dashboard_widget_today_title">活动图表</string>
<string name="pref_dashboard_widget_today_24h_title">24小时模式</string>
<string name="pref_dashboard_widget_double_size_title">双倍尺寸</string>
<string name="pref_dashboard_widget_goals_chart_title">目标图表</string>
<string name="pref_dashboard_widget_show_legend_title">显示图例</string>
<string name="pref_dashboard_widget_double_size_summary">允许小部件占据仪表板上的两列</string>
<string name="pref_dashboard_all_devices_summary">将所有添加设备的活动数据合并到仪表板上的总计中</string>
<string name="pref_dashboard_widget_today_hr_interval_title">心率区间</string>
<string name="pref_dashboard_widget_today_hr_interval_summary">每次成功测量心率后图表显示“佩戴”的分钟数</string>
<string name="pref_auto_reply_calls_summary">手机将自动接听来电</string>
<string name="pref_auto_reply_calls_title">自动接听电话</string>
<string name="pref_auto_reply_calls_delay_summary">自动接听电话之前的秒数</string>
<string name="pref_auto_reply_calls_delay_title">自动应答延迟</string>
<string name="pref_header_audio">音频</string>
<string name="pref_header_generic">普通</string>
<string name="pref_title_notification_wake_on_open">自动唤醒并解锁</string>
<string name="pref_summary_notification_wake_on_open">当小工具发回 OPEN 响应时,唤醒并解锁 Android 设备。需要处于可信状态。</string>
<string name="widget_layout_top_wide_bot_large">上面宽,下面大</string>
<string name="widget_layout_top_large_bot_wide">上面大,下面宽</string>
<string name="widget_name_colored_tile">%1$s (彩色磁贴)</string>
<string name="devicetype_redmi_watch_4">红米手表 4</string>
<string name="pref_speak_notifications_aloud_summary">通知将通过耳机大声朗读</string>
<string name="pref_speak_notifications_aloud_title">大声说出通知</string>
<string name="widget_name_untitled">无标题小部件(%1$s</string>
<string name="pref_header_calls_and_notifications">来电和通知</string>
<string name="armenian">亚美尼亚语</string>
<string name="pref_title_bottom_navigation_bar">底部导航栏</string>
<string name="pref_summary_bottom_navigation_bar_off">仅使用水平滑动在主屏幕之间切换</string>
<string name="pref_summary_bottom_navigation_bar_on">使用导航栏或横向滑动在主屏幕之间切换</string>
<string name="pref_dashboard_widget_today_upside_down_summary">在 24 小时模式下,在图表底部绘制午夜,在图表顶部绘制中午</string>
<string name="pref_dashboard_widget_today_upside_down_title">午夜在底部</string>
<string name="pref_sleepasandroid_device_summary">选择 Sleep As Android 作为设备数据提供者</string>
<string name="pref_sleepasandroid_device_title">设备提供者</string>
<string name="pref_sleepasandroid_features_title">特点</string>
<string name="pref_sleepasandroid_features_summary">支持因设备而异</string>
<string name="pref_sleepasandroid_feat_movement">加速计</string>
<string name="pref_sleepasandroid_feat_heartrate">心率</string>
<string name="pref_sleepasandroid_feat_oximetry">血氧饱和度</string>
<string name="pref_sleepasandroid_feat_spo2">SPO2</string>
<string name="pref_sleepasandroid_feat_alarms">闹钟</string>
<string name="pref_sleepasandroid_slot_summary">设置闹钟时使用哪个闹钟槽</string>
<string name="pref_sleepasandroid_slot_title">闹钟槽</string>
<string name="alarm_slot_reset">闹钟槽已设置为默认值</string>
<string name="pref_sleepasandroid_feat_notifications">通知</string>
<string name="sleepasandroid_settings">Sleep As Android</string>
<string name="pref_summary_huawei_account">配对过程中使用的华为帐号。 设置它以允许在不恢复出厂设置的情况下进行配对。</string>
<string name="pref_title_huawei_account">华为账号</string>
<string name="serbian">塞尔维亚语</string>
<string name="pref_sleepasandroid_enable_summary">启用 Sleep As Android 集成</string>
<string name="watchface_resolution_doesnt_match">表盘分辨率与设备屏幕不匹配。表盘为 %1$s 设备屏幕为 %2$s</string>
<string name="cyclingPowerMin">最小骑行功率</string>
<string name="cyclingPowerAverage">平均骑行功率</string>
<string name="cyclingPowerMax">最大骑行功率</string>
<string name="devicetype_huawei_watchfit2">华为 Watch Fit 2</string>
</resources>

View File

@ -531,6 +531,11 @@
<string name="pref_agps_expiry_reminder_time">AGPS Expiry Reminder Time</string>
<string name="pref_agps_update_time">AGPS Update Time</string>
<string name="pref_agps_expire_time">AGPS Expire Time</string>
<string name="pref_agps_status">AGPS Status</string>
<string name="agps_status_missing">Missing</string>
<string name="agps_status_pending">Pending</string>
<string name="agps_status_current">Current</string>
<string name="agps_status_error">Error</string>
<string name="pref_camera_remote_title">Camera Remote</string>
<string name="pref_camera_remote_summary">Allows the watch to trigger the phone\'s camera</string>
<string name="pref_morning_updates_title">Morning Updates</string>
@ -1561,6 +1566,7 @@
<string name="devicetype_huawei_watchgt3">Huawei Watch GT 3 (Pro)</string>
<string name="devicetype_huawei_watchgt4">Huawei Watch GT 4</string>
<string name="devicetype_huawei_watchfit">Huawei Watch Fit</string>
<string name="devicetype_huawei_watchfit2">Huawei Watch Fit 2</string>
<string name="devicetype_huawei_watchultimate">Huawei Watch Ultimate</string>
<string name="devicetype_femometer_vinca2">Femometer Vinca II</string>
<string name="devicetype_xiaomi_watch_lite">Xiaomi Watch Lite</string>
@ -1916,6 +1922,9 @@
<string name="fmtPaceCorrection">Pace %d correction</string>
<string name="fmtPaceTypeAverage">Pace Type %d average</string>
<string name="unknownDataEncountered">Unknown data encountered</string>
<string name="cyclingPowerAverage">Average cycling power</string>
<string name="cyclingPowerMin">Min cycling power</string>
<string name="cyclingPowerMax">Max cycling power</string>
<!-- activity summary units-->
<string name="meters">m</string>
<string name="cm">cm</string>
@ -2386,6 +2395,7 @@
<string name="huawei_trusleep_title">HUAWEI TruSleep &#8482;</string>
<string name="huawei_trusleep_summary">Monitor your sleep quality and breathing pattern in real time.\nAnalyze your sleep patterns and accurately diagnose 6 types of sleeping problems.</string>
<string name="huawei_trusleep_summary_light">Improved sleep monitoring</string>
<string name="huawei_trusleep_warning">Warning: enabling this will stop sleep from showing up in Gadgetbridge! Click here if you accept this.</string>
<string name="prefs_activity_recognition">Activity recognition settings</string>
<string name="pref_activity_recognize_running">recognize running</string>
<string name="pref_activity_recognize_biking">recognize biking</string>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceCategory
android:icon="@drawable/ic_gps_edit"
android:key="pref_header_agps"
android:title="@string/pref_agps_header">
<Preference
android:key="pref_agps_status"
android:title="@string/pref_agps_status" />
<Preference
android:key="pref_agps_update_time"
android:title="@string/pref_agps_update_time" />
<!-- <Preference-->
<!-- android:key="pref_agps_expire_time"-->
<!-- android:title="@string/pref_agps_expire_time" />-->
</PreferenceCategory>
</androidx.preference.PreferenceScreen>

View File

@ -1,19 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.preference.PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
<PreferenceScreen
android:icon="@drawable/ic_access_time"
android:icon="@drawable/ic_activity_sleep"
android:key="screen_trusleep"
android:persistent="false"
android:title="@string/huawei_trusleep_title"
android:summary="@string/huawei_trusleep_summary_light">
<SwitchPreferenceCompat
android:icon="@drawable/ic_access_time"
android:defaultValue="false"
android:key="trusleep"
android:layout="@layout/preference_checkbox"
<PreferenceScreen
android:icon="@drawable/ic_activity_sleep"
android:key="screen_trusleep_warning"
android:title="@string/huawei_trusleep_title"
android:summary="@string/huawei_trusleep_summary"/>
android:summary="@string/huawei_trusleep_warning">
<SwitchPreferenceCompat
android:icon="@drawable/ic_activity_sleep"
android:defaultValue="false"
android:key="trusleep"
android:layout="@layout/preference_checkbox"
android:title="@string/huawei_trusleep_title"
android:summary="@string/huawei_trusleep_summary"/>
</PreferenceScreen>
</PreferenceScreen>
</androidx.preference.PreferenceScreen>

View File

@ -259,6 +259,14 @@ public class TestWorkout {
byte backFootLanding2 = 0x26;
byte eversionAngle2 = 0x27;
// TODO: Add:
// - swolf
// - stoke rate
// - calories
// - cycling power
// - frequency
// - altitude
ByteBuffer headerBuf = ByteBuffer.allocate(14);
headerBuf.putShort(workoutNumber);
headerBuf.putShort(dataNumber);

View File

@ -53,7 +53,7 @@ public class LanguageUtilsTest extends TestBase {
final Map<String, String> tests = new LinkedHashMap<String, String>() {{
put("Тхе qицк брон фоx јумпед овер тхе лаз* дог", "The qick bron fox jumped over the laz* dog");
put("Српска ћирилица", "Srpska cirilica");
put("Novak Đoković", "Novak Dokovic");
put("Novak Đoković", "Novak Djokovic");
put("Џ, Њ and Љ", "Dz, Nj and Lj");
put("Љуљачка", "Ljuljacka");
put("Наковањ", "Nakovanj");
@ -63,7 +63,7 @@ public class LanguageUtilsTest extends TestBase {
put("Ћ, ћ", "C, c");
put("Ж, ж", "Z, z");
put("Ш, ш", "S, s");
put("Ђ, ђ", "D, d");
put("Ђ, ђ", "Dj, dj");
put("Џ, џ", "Dz, dz");
put("Њ, њ", "Nj, nj");
put("Љ, љ", "Lj, lj");