Merge remote-tracking branch 'Nightscout/dev' into wear/new_custom_watchface

# Conflicts:
#	wear/src/main/kotlin/app/aaps/wear/watchfaces/CustomWatchface.kt
This commit is contained in:
Philoul 2023-10-16 10:19:15 +02:00
commit a7649fd4a8
179 changed files with 8004 additions and 2178 deletions

View file

@ -117,6 +117,7 @@ android {
flavorDimensions = ["standard"] flavorDimensions = ["standard"]
productFlavors { productFlavors {
full { full {
getIsDefault().set(true)
applicationId "info.nightscout.androidaps" applicationId "info.nightscout.androidaps"
dimension "standard" dimension "standard"
resValue "string", "app_name", "AAPS" resValue "string", "app_name", "AAPS"

View file

@ -43,7 +43,8 @@ import app.aaps.plugins.configuration.maintenance.MaintenancePlugin
import app.aaps.plugins.constraints.safety.SafetyPlugin import app.aaps.plugins.constraints.safety.SafetyPlugin
import app.aaps.plugins.insulin.InsulinOrefFreePeakPlugin import app.aaps.plugins.insulin.InsulinOrefFreePeakPlugin
import app.aaps.plugins.main.general.smsCommunicator.SmsCommunicatorPlugin import app.aaps.plugins.main.general.smsCommunicator.SmsCommunicatorPlugin
import app.aaps.plugins.main.general.wear.WearPlugin import app.aaps.plugins.sync.garmin.GarminPlugin
import app.aaps.plugins.sync.wear.WearPlugin
import app.aaps.plugins.sensitivity.SensitivityAAPSPlugin import app.aaps.plugins.sensitivity.SensitivityAAPSPlugin
import app.aaps.plugins.sensitivity.SensitivityOref1Plugin import app.aaps.plugins.sensitivity.SensitivityOref1Plugin
import app.aaps.plugins.sensitivity.SensitivityWeightedAveragePlugin import app.aaps.plugins.sensitivity.SensitivityWeightedAveragePlugin
@ -128,6 +129,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
@Inject lateinit var nsSettingStatus: NSSettingsStatus @Inject lateinit var nsSettingStatus: NSSettingsStatus
@Inject lateinit var openHumansUploaderPlugin: OpenHumansUploaderPlugin @Inject lateinit var openHumansUploaderPlugin: OpenHumansUploaderPlugin
@Inject lateinit var diaconnG8Plugin: DiaconnG8Plugin @Inject lateinit var diaconnG8Plugin: DiaconnG8Plugin
@Inject lateinit var garminPlugin: GarminPlugin
override fun onAttach(context: Context) { override fun onAttach(context: Context) {
AndroidSupportInjection.inject(this) AndroidSupportInjection.inject(this)
@ -229,6 +231,7 @@ class MyPreferenceFragment : PreferenceFragmentCompat(), OnSharedPreferenceChang
addPreferencesFromResource(app.aaps.plugins.configuration.R.xml.pref_datachoices, rootKey) addPreferencesFromResource(app.aaps.plugins.configuration.R.xml.pref_datachoices, rootKey)
addPreferencesFromResourceIfEnabled(maintenancePlugin, rootKey) addPreferencesFromResourceIfEnabled(maintenancePlugin, rootKey)
addPreferencesFromResourceIfEnabled(openHumansUploaderPlugin, rootKey) addPreferencesFromResourceIfEnabled(openHumansUploaderPlugin, rootKey)
addPreferencesFromResourceIfEnabled(garminPlugin, rootKey)
} }
initSummary(preferenceScreen, pluginId != -1) initSummary(preferenceScreen, pluginId != -1)
preprocessPreferences() preprocessPreferences()

View file

@ -22,11 +22,12 @@ import app.aaps.plugins.insulin.InsulinOrefRapidActingPlugin
import app.aaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin import app.aaps.plugins.insulin.InsulinOrefUltraRapidActingPlugin
import app.aaps.plugins.main.general.actions.ActionsPlugin import app.aaps.plugins.main.general.actions.ActionsPlugin
import app.aaps.plugins.main.general.food.FoodPlugin import app.aaps.plugins.main.general.food.FoodPlugin
import app.aaps.plugins.sync.garmin.GarminPlugin
import app.aaps.plugins.main.general.overview.OverviewPlugin import app.aaps.plugins.main.general.overview.OverviewPlugin
import app.aaps.plugins.main.general.persistentNotification.PersistentNotificationPlugin import app.aaps.plugins.main.general.persistentNotification.PersistentNotificationPlugin
import app.aaps.plugins.main.general.smsCommunicator.SmsCommunicatorPlugin import app.aaps.plugins.main.general.smsCommunicator.SmsCommunicatorPlugin
import app.aaps.plugins.main.general.themes.ThemeSwitcherPlugin import app.aaps.plugins.main.general.themes.ThemeSwitcherPlugin
import app.aaps.plugins.main.general.wear.WearPlugin import app.aaps.plugins.sync.wear.WearPlugin
import app.aaps.plugins.main.iob.iobCobCalculator.IobCobCalculatorPlugin import app.aaps.plugins.main.iob.iobCobCalculator.IobCobCalculatorPlugin
import app.aaps.plugins.main.profile.ProfilePlugin import app.aaps.plugins.main.profile.ProfilePlugin
import app.aaps.plugins.sensitivity.SensitivityAAPSPlugin import app.aaps.plugins.sensitivity.SensitivityAAPSPlugin
@ -309,12 +310,6 @@ abstract class PluginsListModule {
@IntKey(320) @IntKey(320)
abstract fun bindFoodPlugin(plugin: FoodPlugin): PluginBase abstract fun bindFoodPlugin(plugin: FoodPlugin): PluginBase
@Binds
@AllConfigs
@IntoMap
@IntKey(330)
abstract fun bindWearPlugin(plugin: WearPlugin): PluginBase
@Binds @Binds
@AllConfigs @AllConfigs
@IntoMap @IntoMap
@ -340,16 +335,28 @@ abstract class PluginsListModule {
abstract fun bindXdripPlugin(plugin: XdripPlugin): PluginBase abstract fun bindXdripPlugin(plugin: XdripPlugin): PluginBase
@Binds @Binds
@AllConfigs @NotNSClient
@IntoMap @IntoMap
@IntKey(366) @IntKey(366)
abstract fun bindsOpenHumansPlugin(plugin: OpenHumansUploaderPlugin): PluginBase
@Binds
@AllConfigs
@IntoMap
@IntKey(367)
abstract fun bindWearPlugin(plugin: WearPlugin): PluginBase
@Binds
@AllConfigs
@IntoMap
@IntKey(368)
abstract fun bindDataBroadcastPlugin(plugin: DataBroadcastPlugin): PluginBase abstract fun bindDataBroadcastPlugin(plugin: DataBroadcastPlugin): PluginBase
@Binds @Binds
@NotNSClient @AllConfigs
@IntoMap @IntoMap
@IntKey(368) @IntKey(369)
abstract fun bindsOpenHumansPlugin(plugin: OpenHumansUploaderPlugin): PluginBase abstract fun bindGarminPlugin(plugin: GarminPlugin): PluginBase
@Binds @Binds
@AllConfigs @AllConfigs

View file

@ -14,6 +14,7 @@ import app.aaps.activities.PreferencesActivity
import app.aaps.core.interfaces.notifications.Notification import app.aaps.core.interfaces.notifications.Notification
import app.aaps.core.interfaces.nsclient.NSAlarm import app.aaps.core.interfaces.nsclient.NSAlarm
import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventDismissNotification
import app.aaps.core.interfaces.ui.UiInteraction import app.aaps.core.interfaces.ui.UiInteraction
import app.aaps.core.main.events.EventNewNotification import app.aaps.core.main.events.EventNewNotification
import app.aaps.core.ui.toast.ToastUtils import app.aaps.core.ui.toast.ToastUtils
@ -169,6 +170,10 @@ class UiInteractionImpl @Inject constructor(
} }
} }
override fun dismissNotification(id: Int) {
rxBus.send(EventDismissNotification(id))
}
override fun addNotification(id: Int, text: String, level: Int) { override fun addNotification(id: Int, text: String, level: Int) {
rxBus.send(EventNewNotification(Notification(id, text, level))) rxBus.send(EventNewNotification(Notification(id, text, level)))
} }

View file

@ -25,7 +25,7 @@ buildscript {
preferencektx_version = '1.2.1' preferencektx_version = '1.2.1'
commonslang3_version = '3.13.0' commonslang3_version = '3.13.0'
commonscodec_version = '1.16.0' commonscodec_version = '1.16.0'
guava_version = '32.1.2-jre' guava_version = '32.1.3-jre'
jodatime_version = '2.12.5' jodatime_version = '2.12.5'
work_version = '2.8.1' work_version = '2.8.1'
tink_version = '1.10.0' tink_version = '1.10.0'
@ -80,7 +80,7 @@ buildscript {
plugins { plugins {
// Test Gradle build, keep disabled under normal circumstances // Test Gradle build, keep disabled under normal circumstances
// id "com.osacky.doctor" version "0.8.1" // id "com.osacky.doctor" version "0.8.1"
id "org.jlleitschuh.gradle.ktlint" version "11.6.0" id "org.jlleitschuh.gradle.ktlint" version "11.6.1"
// Aggregates and/or logs Jacoco test coverage to the Gradle build log // Aggregates and/or logs Jacoco test coverage to the Gradle build log
//id 'org.barfuin.gradle.jacocolog' version '3.1.0' //id 'org.barfuin.gradle.jacocolog' version '3.1.0'
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
@ -97,6 +97,7 @@ allprojects {
kotlinOptions { kotlinOptions {
freeCompilerArgs = [ freeCompilerArgs = [
'-opt-in=kotlin.RequiresOptIn', '-opt-in=kotlin.RequiresOptIn',
'-opt-in=kotlin.ExperimentalUnsignedTypes',
'-Xjvm-default=all' //Support @JvmDefault '-Xjvm-default=all' //Support @JvmDefault
] ]
jvmTarget = "11" jvmTarget = "11"

View file

@ -140,7 +140,7 @@ public abstract class BaseSeries<E extends DataPointInterface> implements Series
* @return the highest y value, or 0 if there is no data * @return the highest y value, or 0 if there is no data
*/ */
public double getHighestValueY() { public double getHighestValueY() {
if (mData.isEmpty()) return 0d; if (mData.isEmpty()) return 100d;
double h = mData.get(0).getY(); double h = mData.get(0).getY();
for (int i = 1; i < mData.size(); i++) { for (int i = 1; i < mData.size(); i++) {
double c = mData.get(i).getY(); double c = mData.get(i).getY();

View file

@ -12,6 +12,7 @@ enum class LTag(val tag: String, val defaultValue: Boolean = true, val requiresR
DATABASE("DATABASE"), DATABASE("DATABASE"),
DATATREATMENTS("DATATREATMENTS"), DATATREATMENTS("DATATREATMENTS"),
EVENTS("EVENTS", defaultValue = false, requiresRestart = true), EVENTS("EVENTS", defaultValue = false, requiresRestart = true),
GARMIN("GARMIN"),
GLUCOSE("GLUCOSE", defaultValue = false), GLUCOSE("GLUCOSE", defaultValue = false),
HTTP("HTTP"), HTTP("HTTP"),
LOCATION("LOCATION"), LOCATION("LOCATION"),

View file

@ -1,6 +1,7 @@
package app.aaps.core.interfaces.maintenance package app.aaps.core.interfaces.maintenance
import app.aaps.core.interfaces.rx.weardata.CwfData import app.aaps.core.interfaces.rx.weardata.CwfData
import app.aaps.core.interfaces.rx.weardata.CwfFile
import java.io.File import java.io.File
interface PrefFileListProvider { interface PrefFileListProvider {
@ -13,7 +14,7 @@ interface PrefFileListProvider {
fun newExportCsvFile(): File fun newExportCsvFile(): File
fun newCwfFile(filename: String, withDate: Boolean = true): File fun newCwfFile(filename: String, withDate: Boolean = true): File
fun listPreferenceFiles(loadMetadata: Boolean = false): MutableList<PrefsFile> fun listPreferenceFiles(loadMetadata: Boolean = false): MutableList<PrefsFile>
fun listCustomWatchfaceFiles(): MutableList<CwfData> fun listCustomWatchfaceFiles(): MutableList<CwfFile>
fun checkMetadata(metadata: Map<PrefsMetadataKey, PrefMetadata>): Map<PrefsMetadataKey, PrefMetadata> fun checkMetadata(metadata: Map<PrefsMetadataKey, PrefMetadata>): Map<PrefsMetadataKey, PrefMetadata>
fun formatExportedAgo(utcTime: String): String fun formatExportedAgo(utcTime: String): String
} }

View file

@ -2,4 +2,4 @@ package app.aaps.core.interfaces.rx.events
import app.aaps.core.interfaces.rx.weardata.EventData import app.aaps.core.interfaces.rx.weardata.EventData
class EventMobileDataToWear(val payload: EventData.ActionSetCustomWatchface) : Event() class EventMobileDataToWear(val payload: ByteArray) : Event()

View file

@ -12,6 +12,7 @@ import com.caverock.androidsvg.SVG
import kotlinx.serialization.Serializable import kotlinx.serialization.Serializable
import org.json.JSONObject import org.json.JSONObject
import java.io.BufferedOutputStream import java.io.BufferedOutputStream
import java.io.ByteArrayInputStream
import java.io.ByteArrayOutputStream import java.io.ByteArrayOutputStream
import java.io.File import java.io.File
import java.io.FileOutputStream import java.io.FileOutputStream
@ -135,9 +136,15 @@ data class ResData(val value: ByteArray, val format: ResFormat) {
typealias CwfResDataMap = MutableMap<String, ResData> typealias CwfResDataMap = MutableMap<String, ResData>
typealias CwfMetadataMap = MutableMap<CwfMetadataKey, String> typealias CwfMetadataMap = MutableMap<CwfMetadataKey, String>
fun CwfResDataMap.isEquals(dataMap: CwfResDataMap) = (this.size == dataMap.size) && this.all { (key, resData) -> dataMap[key]?.value.contentEquals(resData.value) == true } fun CwfResDataMap.isEquals(dataMap: CwfResDataMap) = (this.size == dataMap.size) && this.all { (key, resData) -> dataMap[key]?.value.contentEquals(resData.value) == true }
@Serializable @Serializable
data class CwfData(val json: String, var metadata: CwfMetadataMap, val resDatas: CwfResDataMap) data class CwfData(val json: String, var metadata: CwfMetadataMap, val resDatas: CwfResDataMap) {
fun simplify(): CwfData? = resDatas[ResFileMap.CUSTOM_WATCHFACE.fileName]?.let {
val simplifiedDatas: CwfResDataMap = mutableMapOf()
simplifiedDatas[ResFileMap.CUSTOM_WATCHFACE.fileName] = it
CwfData(json, metadata, simplifiedDatas)
}
}
data class CwfFile(val cwfData: CwfData, val zipByteArray: ByteArray)
enum class CwfMetadataKey(val key: String, @StringRes val label: Int, val isPref: Boolean) { enum class CwfMetadataKey(val key: String, @StringRes val label: Int, val isPref: Boolean) {
@ -287,11 +294,11 @@ class ZipWatchfaceFormat {
const val CWF_EXTENTION = ".zip" const val CWF_EXTENTION = ".zip"
const val CWF_JSON_FILE = "CustomWatchface.json" const val CWF_JSON_FILE = "CustomWatchface.json"
fun loadCustomWatchface(zipInputStream: ZipInputStream, zipName: String, authorization: Boolean): CwfData? { fun loadCustomWatchface(byteArray: ByteArray, zipName: String, authorization: Boolean): CwfFile? {
var json = JSONObject() var json = JSONObject()
var metadata: CwfMetadataMap = mutableMapOf() var metadata: CwfMetadataMap = mutableMapOf()
val resDatas: CwfResDataMap = mutableMapOf() val resDatas: CwfResDataMap = mutableMapOf()
val zipInputStream = byteArrayToZipInputStream(byteArray)
try { try {
var zipEntry: ZipEntry? = zipInputStream.nextEntry var zipEntry: ZipEntry? = zipInputStream.nextEntry
while (zipEntry != null) { while (zipEntry != null) {
@ -325,7 +332,7 @@ class ZipWatchfaceFormat {
// Valid CWF file must contains a valid json file with a name within metadata and a custom watchface image // Valid CWF file must contains a valid json file with a name within metadata and a custom watchface image
return if (metadata.containsKey(CwfMetadataKey.CWF_NAME) && resDatas.containsKey(ResFileMap.CUSTOM_WATCHFACE.fileName)) return if (metadata.containsKey(CwfMetadataKey.CWF_NAME) && resDatas.containsKey(ResFileMap.CUSTOM_WATCHFACE.fileName))
CwfData(json.toString(4), metadata, resDatas) CwfFile(CwfData(json.toString(4), metadata, resDatas), byteArray)
else else
null null
@ -369,5 +376,10 @@ class ZipWatchfaceFormat {
} }
return metadata return metadata
} }
fun byteArrayToZipInputStream(byteArray: ByteArray): ZipInputStream {
val byteArrayInputStream = ByteArrayInputStream(byteArray)
return ZipInputStream(byteArrayInputStream)
}
} }
} }

View file

@ -292,10 +292,9 @@ sealed class EventData : Event() {
} }
@Serializable @Serializable
data class ActionSetCustomWatchface( data class ActionSetCustomWatchface(val customWatchfaceData: CwfData) : EventData()
val customWatchfaceData: CwfData @Serializable
) : EventData() data class ActionUpdateCustomWatchface(val customWatchfaceData: CwfData) : EventData()
@Serializable @Serializable
data class ActionrequestCustomWatchface(val exportFile: Boolean) : EventData() data class ActionrequestCustomWatchface(val exportFile: Boolean) : EventData()

View file

@ -68,6 +68,7 @@ interface UiInteraction {
fun runCareDialog(fragmentManager: FragmentManager, options: EventType, @StringRes event: Int) fun runCareDialog(fragmentManager: FragmentManager, options: EventType, @StringRes event: Int)
fun dismissNotification(id: Int)
fun addNotification(id: Int, text: String, level: Int) fun addNotification(id: Int, text: String, level: Int)
fun addNotificationValidFor(id: Int, text: String, level: Int, validMinutes: Int) fun addNotificationValidFor(id: Int, text: String, level: Int, validMinutes: Int)
fun addNotificationWithSound(id: Int, text: String, level: Int, @RawRes soundId: Int?) fun addNotificationWithSound(id: Int, text: String, level: Int, @RawRes soundId: Int?)

View file

@ -51,7 +51,7 @@
<string name="pref_show_avgdelta">Vis Gj. snitt Delta</string> <string name="pref_show_avgdelta">Vis Gj. snitt Delta</string>
<string name="pref_show_phone_battery">Vis telefonbatteri</string> <string name="pref_show_phone_battery">Vis telefonbatteri</string>
<string name="pref_show_rig_battery">Vis riggens batteri</string> <string name="pref_show_rig_battery">Vis riggens batteri</string>
<string name="pref_show_basal_rate">Vis basalrate</string> <string name="pref_show_basal_rate">Vis basaldose</string>
<string name="pref_show_loop_status">Vis loop status</string> <string name="pref_show_loop_status">Vis loop status</string>
<string name="pref_show_bg">Vis BS</string> <string name="pref_show_bg">Vis BS</string>
<string name="pref_show_bgi">Vis BGI</string> <string name="pref_show_bgi">Vis BGI</string>
@ -75,7 +75,7 @@
<string name="cwf_comment_avg_delta">Gj.snitt BS-endring (15min)</string> <string name="cwf_comment_avg_delta">Gj.snitt BS-endring (15min)</string>
<string name="cwf_comment_uploader_battery">Telefonbatteri (%)</string> <string name="cwf_comment_uploader_battery">Telefonbatteri (%)</string>
<string name="cwf_comment_rig_battery">Rig-batteri (%)</string> <string name="cwf_comment_rig_battery">Rig-batteri (%)</string>
<string name="cwf_comment_basalRate">Basalrate</string> <string name="cwf_comment_basalRate">Basaldose</string>
<string name="cwf_comment_bgi">BGI verdi</string> <string name="cwf_comment_bgi">BGI verdi</string>
<string name="cwf_comment_time">Tid (TT:MM eller TT:MM:SS)</string> <string name="cwf_comment_time">Tid (TT:MM eller TT:MM:SS)</string>
<string name="cwf_comment_hour">Time (TT)</string> <string name="cwf_comment_hour">Time (TT)</string>

View file

@ -3,6 +3,7 @@ android {
flavorDimensions = ["standard"] flavorDimensions = ["standard"]
productFlavors { productFlavors {
full { full {
getIsDefault().set(true)
dimension "standard" dimension "standard"
} }
pumpcontrol { pumpcontrol {

View file

@ -13,7 +13,6 @@ dependencies {
androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1' androidTestImplementation 'androidx.test.espresso:espresso-core:3.5.1'
androidTestImplementation "androidx.test.ext:junit-ktx:$androidx_junit_version" androidTestImplementation "androidx.test.ext:junit-ktx:$androidx_junit_version"
androidTestImplementation "androidx.test:rules:$androidx_rules_version" androidTestImplementation "androidx.test:rules:$androidx_rules_version"
androidTestImplementation "org.junit.jupiter:junit-jupiter-api:$junit_jupiter_version"
androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0' androidTestImplementation 'androidx.test.uiautomator:uiautomator:2.2.0'
} }

View file

@ -74,8 +74,8 @@
<string name="target_label">Målverdi</string> <string name="target_label">Målverdi</string>
<string name="dia_long_label">Insulinets virkningstid (DIA)</string> <string name="dia_long_label">Insulinets virkningstid (DIA)</string>
<string name="ic_long_label">Insulin-karbohydratfaktor (IK)</string> <string name="ic_long_label">Insulin-karbohydratfaktor (IK)</string>
<string name="isf_long_label">Insulin sensitivitetsfaktor (ISF)</string> <string name="isf_long_label">Insulinsensitivitetsfaktor (ISF)</string>
<string name="basal_long_label">Basalrate</string> <string name="basal_long_label">Basaldose</string>
<string name="target_long_label">Blodsukkermål</string> <string name="target_long_label">Blodsukkermål</string>
<string name="shortgram">g</string> <string name="shortgram">g</string>
<string name="shortpercent">%</string> <string name="shortpercent">%</string>
@ -155,7 +155,7 @@
<string name="login">Login</string> <string name="login">Login</string>
<string name="prime_fill">Prime/fylling</string> <string name="prime_fill">Prime/fylling</string>
<string name="overview_insulin_label">Insulin</string> <string name="overview_insulin_label">Insulin</string>
<string name="stoptemptarget">Avbryt midlertidig målverdi</string> <string name="stoptemptarget">Avbryt midlertidig mål</string>
<string name="closedloop">Lukket Loop</string> <string name="closedloop">Lukket Loop</string>
<string name="openloop">Åpen Loop</string> <string name="openloop">Åpen Loop</string>
<string name="lowglucosesuspend">Stopp ved lavt BS</string> <string name="lowglucosesuspend">Stopp ved lavt BS</string>
@ -193,7 +193,7 @@
<!-- Temptarget--> <!-- Temptarget-->
<string name="mins">%1$d min</string> <string name="mins">%1$d min</string>
<!-- Translator--> <!-- Translator-->
<string name="careportal">Careportal</string> <string name="careportal">Helseportal</string>
<string name="careportal_bgcheck">BS-kontroll</string> <string name="careportal_bgcheck">BS-kontroll</string>
<string name="careportal_mbg">Manuelt BS eller kalibrering</string> <string name="careportal_mbg">Manuelt BS eller kalibrering</string>
<string name="careportal_announcement">Melding</string> <string name="careportal_announcement">Melding</string>
@ -294,19 +294,19 @@
<string name="uel_cancel_bolus">AVBRYT BOLUS</string> <string name="uel_cancel_bolus">AVBRYT BOLUS</string>
<string name="uel_cancel_extended_bolus">AVBRYT FORLENGET BOLUS</string> <string name="uel_cancel_extended_bolus">AVBRYT FORLENGET BOLUS</string>
<string name="uel_cancel_tt">AVBRYT MIDL. MÅL</string> <string name="uel_cancel_tt">AVBRYT MIDL. MÅL</string>
<string name="uel_careportal">CAREPORTAL</string> <string name="uel_careportal">HELSEPORTAL</string>
<string name="uel_site_change">BYTTE SLANGESETT</string> <string name="uel_site_change">BYTTE SLANGESETT</string>
<string name="uel_reservoir_change">BYTTE RESERVOAR</string> <string name="uel_reservoir_change">BYTTE RESERVOAR</string>
<string name="uel_calibration">KALIBRERING</string> <string name="uel_calibration">KALIBRERING</string>
<string name="uel_prime_bolus">PRIME BOLUS</string> <string name="uel_prime_bolus">PRIME BOLUS</string>
<string name="uel_treatment">BEHANDLING</string> <string name="uel_treatment">BEHANDLING</string>
<string name="uel_careportal_ns_refresh">CAREPORTAL NS OPPDATERING</string> <string name="uel_careportal_ns_refresh">HELSEPORTAL NS-OPPDATERING</string>
<string name="uel_profile_switch_ns_refresh">PROFILBYTTE NS OPPDATERING</string> <string name="uel_profile_switch_ns_refresh">PROFILBYTTE NS OPPDATERING</string>
<string name="uel_treatments_ns_refresh">BEHANDLINGER NS OPPDATERING</string> <string name="uel_treatments_ns_refresh">BEHANDLINGER NS OPPDATERING</string>
<string name="uel_tt_ns_refresh">OPPDATER MIDL. MÅL NS</string> <string name="uel_tt_ns_refresh">OPPDATER MIDL. MÅL NS</string>
<string name="uel_automation_removed">AUTOMASJON FJERNET</string> <string name="uel_automation_removed">AUTOMASJON FJERNET</string>
<string name="uel_bg_removed">BS FJERNET</string> <string name="uel_bg_removed">BS FJERNET</string>
<string name="uel_careportal_removed">CAREPORTAL FJERNET</string> <string name="uel_careportal_removed">HELSEPORTAL FJERNET</string>
<string name="uel_bolus_removed">BOLUS FJERNET</string> <string name="uel_bolus_removed">BOLUS FJERNET</string>
<string name="uel_carbs_removed">KARBO FJERNET</string> <string name="uel_carbs_removed">KARBO FJERNET</string>
<string name="uel_temp_basal_removed">MIDL. MÅL FJERNET</string> <string name="uel_temp_basal_removed">MIDL. MÅL FJERNET</string>
@ -363,7 +363,7 @@
<string name="temp_target_high_target">Øvre grense for midl. mål</string> <string name="temp_target_high_target">Øvre grense for midl. mål</string>
<string name="temp_target_value">Midl. målverdi</string> <string name="temp_target_value">Midl. målverdi</string>
<string name="profile_dia">Profil DIA verdi</string> <string name="profile_dia">Profil DIA verdi</string>
<string name="profile_sensitivity_value">Profil insulinfølsomhet</string> <string name="profile_sensitivity_value">Profilens insulinfølsomhet</string>
<string name="profile_max_daily_basal_value">Maksimal profil basalverdi</string> <string name="profile_max_daily_basal_value">Maksimal profil basalverdi</string>
<string name="current_basal_value">Nåværende basalverdi</string> <string name="current_basal_value">Nåværende basalverdi</string>
<string name="profile_carbs_ratio_value">Profil karbohydratfaktor (IK)</string> <string name="profile_carbs_ratio_value">Profil karbohydratfaktor (IK)</string>
@ -389,7 +389,7 @@
<string name="temp_basal_absolute">MIDL. BASAL %1$.2f E/t %2$d min</string> <string name="temp_basal_absolute">MIDL. BASAL %1$.2f E/t %2$d min</string>
<string name="temp_basal_percent">MIDL. BASAL %1$d E/t %2$d min</string> <string name="temp_basal_percent">MIDL. BASAL %1$d E/t %2$d min</string>
<string name="insight_set_tbr_over_notification">INSIGHT SET TBR OVER NOTIFIKASJON</string> <string name="insight_set_tbr_over_notification">INSIGHT SET TBR OVER NOTIFIKASJON</string>
<string name="read_status" comment="10 characters max for READSTATUS translation">READSTATUS %1$s</string> <string name="read_status" comment="10 characters max for READSTATUS translation">LESESTATUS %1$s</string>
<string name="keepalive_status_outdated" comment="26 characters max for translation">Oppretthold tilkobling. Status er ikke oppdatert.</string> <string name="keepalive_status_outdated" comment="26 characters max for translation">Oppretthold tilkobling. Status er ikke oppdatert.</string>
<string name="keepalive_basal_outdated" comment="26 characters max for translation">Oppretthold tilkobling. Basal er ikke oppdatert.</string> <string name="keepalive_basal_outdated" comment="26 characters max for translation">Oppretthold tilkobling. Basal er ikke oppdatert.</string>
<string name="sms" comment="26 characters max for translation">SMS</string> <string name="sms" comment="26 characters max for translation">SMS</string>
@ -486,7 +486,7 @@
<string name="resistant_adult">Insulinresistent voksen</string> <string name="resistant_adult">Insulinresistent voksen</string>
<string name="pregnant">Graviditet</string> <string name="pregnant">Graviditet</string>
<string name="patient_age_summary">Velg pasienttype for oppsett av sikkerhetsgrenser</string> <string name="patient_age_summary">Velg pasienttype for oppsett av sikkerhetsgrenser</string>
<string name="max_bolus_title">Maks tillatt bolus [U]</string> <string name="max_bolus_title">Maks tillatt bolus [E]</string>
<string name="max_carbs_title">Maks tillatt karbohydrater [g]</string> <string name="max_carbs_title">Maks tillatt karbohydrater [g]</string>
<string name="patient_type">Pasienttype</string> <string name="patient_type">Pasienttype</string>
<!-- Protection--> <!-- Protection-->
@ -561,9 +561,9 @@
<!-- SmsCommunicator --> <!-- SmsCommunicator -->
<string name="smscommunicator_missingsmspermission">Mangler SMS-tillatelse</string> <string name="smscommunicator_missingsmspermission">Mangler SMS-tillatelse</string>
<!-- About --> <!-- About -->
<string name="cta_dont_kill_my_app_info">Hvordan hindre at appen stenges?</string> <string name="cta_dont_kill_my_app_info">Ikke steng appen min?</string>
<string name="fabric_upload_disabled">Opplast av krasjlogger er deaktivert!</string> <string name="fabric_upload_disabled">Opplast av krasjlogger er deaktivert!</string>
<string name="about_link_urls">\n\nDokumentasjon:\nhttps://androidaps.readthedocs.io\n\nfacebook:\nhttps://www.facebook.com/groups/AndroidAPSUsers</string> <string name="about_link_urls">\n\nDokumentasjon:\nhttps://androidaps.readthedocs.io\n\nFacebook:\nhttps://www.facebook.com/groups/AndroidAPSUsers</string>
<plurals name="days"> <plurals name="days">
<item quantity="one">%1$d dag</item> <item quantity="one">%1$d dag</item>
<item quantity="other">%1$d dager</item> <item quantity="other">%1$d dager</item>

View file

@ -116,6 +116,9 @@
<string name="key_wearwizard_cob" translatable="false">wearwizard_cob</string> <string name="key_wearwizard_cob" translatable="false">wearwizard_cob</string>
<string name="key_wearwizard_iob" translatable="false">wearwizard_iob</string> <string name="key_wearwizard_iob" translatable="false">wearwizard_iob</string>
<string name="key_wear_custom_watchface_autorization" translatable="false">wear_custom_watchface_autorization</string> <string name="key_wear_custom_watchface_autorization" translatable="false">wear_custom_watchface_autorization</string>
<string name="key_wear_cwf_watchface_name" translatable="false">wear_cwf_watchface_name</string>
<string name="key_wear_cwf_author_version" translatable="false">wear_cwf_author_version</string>
<string name="key_wear_cwf_filename" translatable="false">wear_cwf_filename</string>
<string name="key_objectives_bg_is_available_in_ns" translatable="false">ObjectivesbgIsAvailableInNS</string> <string name="key_objectives_bg_is_available_in_ns" translatable="false">ObjectivesbgIsAvailableInNS</string>
<string name="key_objectives_pump_status_is_available_in_ns" translatable="false">ObjectivespumpStatusIsAvailableInNS</string> <string name="key_objectives_pump_status_is_available_in_ns" translatable="false">ObjectivespumpStatusIsAvailableInNS</string>
<string name="key_statuslights_cage_warning" translatable="false">statuslights_cage_warning</string> <string name="key_statuslights_cage_warning" translatable="false">statuslights_cage_warning</string>

View file

@ -187,7 +187,9 @@ data class UserEntry(
Overview, //From OverViewPlugin Overview, //From OverViewPlugin
Stats, //From Stat Activity Stats, //From Stat Activity
Aaps, // MainApp Aaps, // MainApp
GarminDevice,
Unknown //if necessary Unknown //if necessary
,
; ;
companion object { companion object {

File diff suppressed because it is too large Load diff

View file

@ -16,7 +16,7 @@ import org.junit.Test
import org.junit.runner.RunWith import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class) @RunWith(AndroidJUnit4::class)
internal class HeartRateDaoTest { class HeartRateDaoTest {
private val context = ApplicationProvider.getApplicationContext<Context>() private val context = ApplicationProvider.getApplicationContext<Context>()
private fun createDatabase() = private fun createDatabase() =
@ -86,9 +86,9 @@ internal class HeartRateDaoTest {
dao.insertNewEntry(hr1) dao.insertNewEntry(hr1)
dao.insertNewEntry(hr2) dao.insertNewEntry(hr2)
assertEquals(listOf(hr1, hr2), dao.getFromTime(timestamp)) assertEquals(listOf(hr1, hr2), dao.getFromTime(timestamp).blockingGet())
assertEquals(listOf(hr2), dao.getFromTime(timestamp + 1)) assertEquals(listOf(hr2), dao.getFromTime(timestamp + 1).blockingGet())
assertTrue(dao.getFromTime(timestamp + 2).isEmpty()) assertTrue(dao.getFromTime(timestamp + 2).blockingGet().isEmpty())
} }
} }

View file

@ -86,7 +86,7 @@ import kotlin.math.roundToInt
removed.add(Pair("ExtendedBolus", database.extendedBolusDao.deleteOlderThan(than))) removed.add(Pair("ExtendedBolus", database.extendedBolusDao.deleteOlderThan(than)))
removed.add(Pair("Bolus", database.bolusDao.deleteOlderThan(than))) removed.add(Pair("Bolus", database.bolusDao.deleteOlderThan(than)))
removed.add(Pair("MultiWaveBolus", database.multiwaveBolusLinkDao.deleteOlderThan(than))) removed.add(Pair("MultiWaveBolus", database.multiwaveBolusLinkDao.deleteOlderThan(than)))
// keep TDD removed.add(Pair("TotalDailyDose", database.totalDailyDoseDao.deleteOlderThan(than))) removed.add(Pair("TotalDailyDose", database.totalDailyDoseDao.deleteOlderThan(than)))
removed.add(Pair("Carbs", database.carbsDao.deleteOlderThan(than))) removed.add(Pair("Carbs", database.carbsDao.deleteOlderThan(than)))
removed.add(Pair("TemporaryTarget", database.temporaryTargetDao.deleteOlderThan(than))) removed.add(Pair("TemporaryTarget", database.temporaryTargetDao.deleteOlderThan(than)))
removed.add(Pair("ApsResultLink", database.apsResultLinkDao.deleteOlderThan(than))) removed.add(Pair("ApsResultLink", database.apsResultLinkDao.deleteOlderThan(than)))
@ -111,7 +111,7 @@ import kotlin.math.roundToInt
removed.add(Pair("CHANGES Bolus", database.bolusDao.deleteTrackedChanges())) removed.add(Pair("CHANGES Bolus", database.bolusDao.deleteTrackedChanges()))
removed.add(Pair("CHANGES ExtendedBolus", database.extendedBolusDao.deleteTrackedChanges())) removed.add(Pair("CHANGES ExtendedBolus", database.extendedBolusDao.deleteTrackedChanges()))
removed.add(Pair("CHANGES MultiWaveBolus", database.multiwaveBolusLinkDao.deleteTrackedChanges())) removed.add(Pair("CHANGES MultiWaveBolus", database.multiwaveBolusLinkDao.deleteTrackedChanges()))
// keep TDD removed.add(Pair("CHANGES TotalDailyDose", database.totalDailyDoseDao.deleteTrackedChanges())) removed.add(Pair("CHANGES TotalDailyDose", database.totalDailyDoseDao.deleteTrackedChanges()))
removed.add(Pair("CHANGES Carbs", database.carbsDao.deleteTrackedChanges())) removed.add(Pair("CHANGES Carbs", database.carbsDao.deleteTrackedChanges()))
removed.add(Pair("CHANGES TemporaryTarget", database.temporaryTargetDao.deleteTrackedChanges())) removed.add(Pair("CHANGES TemporaryTarget", database.temporaryTargetDao.deleteTrackedChanges()))
removed.add(Pair("CHANGES ApsResultLink", database.apsResultLinkDao.deleteTrackedChanges())) removed.add(Pair("CHANGES ApsResultLink", database.apsResultLinkDao.deleteTrackedChanges()))

View file

@ -17,5 +17,16 @@ class InsertOrUpdateHeartRateTransaction(private val heartRate: HeartRate) :
} }
} }
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false
other as InsertOrUpdateHeartRateTransaction
return heartRate == other.heartRate
}
override fun hashCode(): Int {
return heartRate.hashCode()
}
data class TransactionResult(val inserted: List<HeartRate>, val updated: List<HeartRate>) data class TransactionResult(val inserted: List<HeartRate>, val updated: List<HeartRate>)
} }

View file

@ -108,6 +108,7 @@ class UserEntryPresentationHelperImpl @Inject constructor(
Sources.ConfigBuilder -> app.aaps.core.ui.R.drawable.ic_cogs Sources.ConfigBuilder -> app.aaps.core.ui.R.drawable.ic_cogs
Sources.Overview -> app.aaps.core.ui.R.drawable.ic_home Sources.Overview -> app.aaps.core.ui.R.drawable.ic_home
Sources.Aaps -> R.drawable.ic_aaps Sources.Aaps -> R.drawable.ic_aaps
Sources.GarminDevice -> app.aaps.core.ui.R.drawable.ic_generic_icon
Sources.Unknown -> app.aaps.core.ui.R.drawable.ic_generic_icon Sources.Unknown -> app.aaps.core.ui.R.drawable.ic_generic_icon
} }

View file

@ -41,8 +41,8 @@
<string name="openapsama_use_autosens">Bruk Autosens-funksjon</string> <string name="openapsama_use_autosens">Bruk Autosens-funksjon</string>
<string name="openapsma_max_basal_title">Max E/t en midl. basal kan settes til</string> <string name="openapsma_max_basal_title">Max E/t en midl. basal kan settes til</string>
<string name="openapsma_max_basal_summary">Denne verdien kalles max basal i OpenAPS</string> <string name="openapsma_max_basal_summary">Denne verdien kalles max basal i OpenAPS</string>
<string name="openapsma_max_iob_title">Maksimum basal IOB som OpenAPS kan levere [U]</string> <string name="openapsma_max_iob_title">Maksimum basal IOB som OpenAPS kan levere [E]</string>
<string name="openapsma_max_iob_summary">Denne verdien kalles Max IOB i OpenAPS.\nDet er maks insulinmengde i [U] som APS kan levere i en dose.</string> <string name="openapsma_max_iob_summary">Denne verdien kalles Max IOB i OpenAPS.\nDet er maks insulinmengde i [E] som APS kan levere i en dose.</string>
<string name="openapsama_autosens_adjust_targets_summary">Standard verdi: sann\nGir autosens tillatelse til å justere BS-mål, i tillegg til ISF og basaler.</string> <string name="openapsama_autosens_adjust_targets_summary">Standard verdi: sann\nGir autosens tillatelse til å justere BS-mål, i tillegg til ISF og basaler.</string>
<string name="openapsama_autosens_adjust_targets">Autosens justerer også BS målverdier</string> <string name="openapsama_autosens_adjust_targets">Autosens justerer også BS målverdier</string>
<string name="openapsama_min_5m_carb_impact_summary">Standardverdi er: 3.0 (AMA) eller 8.0 (SMB). Dette er grunninnstillingen for KH-opptak per 5 minutt. Den påvirker hvor raskt COB skal reduseres, og benyttes i beregning av fremtidig BS-kurve når BS enten synker eller øker mer enn forventet. Standardverdi er 3mg/dl/5 min.</string> <string name="openapsama_min_5m_carb_impact_summary">Standardverdi er: 3.0 (AMA) eller 8.0 (SMB). Dette er grunninnstillingen for KH-opptak per 5 minutt. Den påvirker hvor raskt COB skal reduseres, og benyttes i beregning av fremtidig BS-kurve når BS enten synker eller øker mer enn forventet. Standardverdi er 3mg/dl/5 min.</string>
@ -54,8 +54,8 @@
<string name="always_use_short_avg_summary">Nyttig når data fra ufiltrerte kilder som xDrip+ registrerer mye støy.</string> <string name="always_use_short_avg_summary">Nyttig når data fra ufiltrerte kilder som xDrip+ registrerer mye støy.</string>
<string name="openapsama_max_daily_safety_multiplier">Multiplikator for maks daglig basal</string> <string name="openapsama_max_daily_safety_multiplier">Multiplikator for maks daglig basal</string>
<string name="openapsama_current_basal_safety_multiplier">Multiplikator for gjeldende basal</string> <string name="openapsama_current_basal_safety_multiplier">Multiplikator for gjeldende basal</string>
<string name="openapssmb_max_iob_title">Maks total IOB OpenAPS ikke kan overstige [U]</string> <string name="openapssmb_max_iob_title">Maks total IOB OpenAPS ikke kan overstige [E]</string>
<string name="openapssmb_max_iob_summary">Denne verdien kalles Maks IOB av OpenAPS\nOpenAPS vil ikke gi mere insulin hvis mengden insulin ombord (IOB) overstiger denne verdien</string> <string name="openapssmb_max_iob_summary">Denne verdien kalles Maks IOB av OpenAPS\nAAPS vil ikke gi mere insulin hvis mengden insulin ombord (IOB) overstiger denne verdien</string>
<string name="enable_uam">Aktiver UAM</string> <string name="enable_uam">Aktiver UAM</string>
<string name="enable_smb">Aktiver SMB</string> <string name="enable_smb">Aktiver SMB</string>
<string name="enable_smb_summary">Bruk Supermikrobolus i stedet for midl. basal for raskere resultat</string> <string name="enable_smb_summary">Bruk Supermikrobolus i stedet for midl. basal for raskere resultat</string>
@ -65,7 +65,7 @@
<string name="enable_smb_after_carbs">Aktiver SMB etter karbohydrater</string> <string name="enable_smb_after_carbs">Aktiver SMB etter karbohydrater</string>
<string name="enable_smb_after_carbs_summary">Aktiver SMB i 6t etter karbohydratinntak, selv med 0 COB. Bare mulig med en bra filtrert BS kilde som f. eks. Dexcom G5/G6</string> <string name="enable_smb_after_carbs_summary">Aktiver SMB i 6t etter karbohydratinntak, selv med 0 COB. Bare mulig med en bra filtrert BS kilde som f. eks. Dexcom G5/G6</string>
<string name="enable_smb_with_cob">Aktiver SMB med COB</string> <string name="enable_smb_with_cob">Aktiver SMB med COB</string>
<string name="enable_smb_with_cob_summary">Aktiver SMB når COB er aktiv.</string> <string name="enable_smb_with_cob_summary">Aktiver SMB når COB (karbohydrater ombord) er aktiv.</string>
<string name="enable_smb_with_temp_target">Aktiver SMB med midl. målverdi</string> <string name="enable_smb_with_temp_target">Aktiver SMB med midl. målverdi</string>
<string name="enable_smb_with_temp_target_summary">Aktiver SMB når midl. målverdi er aktivert (spise snart, trening)</string> <string name="enable_smb_with_temp_target_summary">Aktiver SMB når midl. målverdi er aktivert (spise snart, trening)</string>
<string name="enable_smb_with_high_temp_target">Aktiver SMB ved høy midl. målverdi</string> <string name="enable_smb_with_high_temp_target">Aktiver SMB ved høy midl. målverdi</string>

View file

@ -129,7 +129,7 @@ class AutomationPlugin @Inject constructor(
init { init {
refreshLoop = Runnable { refreshLoop = Runnable {
processActions() processActions()
handler.postDelayed(refreshLoop, T.mins(1).msecs()) handler.postDelayed(refreshLoop, T.secs(150).msecs())
} }
} }

View file

@ -87,7 +87,7 @@
<string name="cobcompared">COB %1$s %2$.0f</string> <string name="cobcompared">COB %1$s %2$.0f</string>
<string name="triggerHeartRate">Puls</string> <string name="triggerHeartRate">Puls</string>
<string name="triggerHeartRateDesc">HR %1$s %2$.0f</string> <string name="triggerHeartRateDesc">HR %1$s %2$.0f</string>
<string name="iob_u">IOB [U]:</string> <string name="iob_u">IOB [E]:</string>
<string name="distance_short">Dist [m]:</string> <string name="distance_short">Dist [m]:</string>
<string name="recurringTime">Gjentakende tidspunkt</string> <string name="recurringTime">Gjentakende tidspunkt</string>
<string name="every">Hver</string> <string name="every">Hver</string>

View file

@ -12,6 +12,7 @@ import app.aaps.core.interfaces.maintenance.PrefsMetadataKey
import app.aaps.core.interfaces.resources.ResourceHelper import app.aaps.core.interfaces.resources.ResourceHelper
import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.weardata.CwfData import app.aaps.core.interfaces.rx.weardata.CwfData
import app.aaps.core.interfaces.rx.weardata.CwfFile
import app.aaps.core.interfaces.rx.weardata.EventData import app.aaps.core.interfaces.rx.weardata.EventData
import app.aaps.core.interfaces.rx.weardata.ZipWatchfaceFormat import app.aaps.core.interfaces.rx.weardata.ZipWatchfaceFormat
import app.aaps.core.interfaces.sharedPreferences.SP import app.aaps.core.interfaces.sharedPreferences.SP
@ -97,11 +98,11 @@ class PrefFileListProviderImpl @Inject constructor(
return prefFiles return prefFiles
} }
override fun listCustomWatchfaceFiles(): MutableList<CwfData> { override fun listCustomWatchfaceFiles(): MutableList<CwfFile> {
val customWatchfaceFiles = mutableListOf<CwfData>() val customWatchfaceFiles = mutableListOf<CwfFile>()
val customAwtchfaceAuthorization = sp.getBoolean(app.aaps.core.utils.R.string.key_wear_custom_watchface_autorization, false) val customWatchfaceAuthorization = sp.getBoolean(app.aaps.core.utils.R.string.key_wear_custom_watchface_autorization, false)
exportsPath.walk().filter { it.isFile && it.name.endsWith(ZipWatchfaceFormat.CWF_EXTENTION) }.forEach { file -> exportsPath.walk().filter { it.isFile && it.name.endsWith(ZipWatchfaceFormat.CWF_EXTENTION) }.forEach { file ->
ZipWatchfaceFormat.loadCustomWatchface(ZipInputStream(file.inputStream()), file.name, customAwtchfaceAuthorization)?.also { customWatchface -> ZipWatchfaceFormat.loadCustomWatchface(file.readBytes(), file.name, customWatchfaceAuthorization)?.also { customWatchface ->
customWatchfaceFiles.add(customWatchface) customWatchfaceFiles.add(customWatchface)
} }
} }
@ -110,12 +111,11 @@ class PrefFileListProviderImpl @Inject constructor(
val assetFiles = context.assets.list("") ?: arrayOf() val assetFiles = context.assets.list("") ?: arrayOf()
for (assetFileName in assetFiles) { for (assetFileName in assetFiles) {
if (assetFileName.endsWith(ZipWatchfaceFormat.CWF_EXTENTION)) { if (assetFileName.endsWith(ZipWatchfaceFormat.CWF_EXTENTION)) {
val assetInputStream = context.assets.open(assetFileName) val assetByteArray = context.assets.open(assetFileName).readBytes()
ZipWatchfaceFormat.loadCustomWatchface(ZipInputStream(assetInputStream), assetFileName, customAwtchfaceAuthorization)?.also { customWatchface -> ZipWatchfaceFormat.loadCustomWatchface(assetByteArray, assetFileName, customWatchfaceAuthorization)?.also { customWatchface ->
customWatchfaceFiles.add(customWatchface) customWatchfaceFiles.add(customWatchface)
rxBus.send(EventData.ActionGetCustomWatchface(EventData.ActionSetCustomWatchface(customWatchface), exportFile = true, withDate = false)) rxBus.send(EventData.ActionGetCustomWatchface(EventData.ActionSetCustomWatchface(customWatchface.cwfData), exportFile = true, withDate = false))
} }
assetInputStream.close()
} }
} }
} catch (e: Exception) { } catch (e: Exception) {

View file

@ -15,6 +15,7 @@ import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventMobileDataToWear import app.aaps.core.interfaces.rx.events.EventMobileDataToWear
import app.aaps.core.interfaces.rx.weardata.CUSTOM_VERSION import app.aaps.core.interfaces.rx.weardata.CUSTOM_VERSION
import app.aaps.core.interfaces.rx.weardata.CwfData import app.aaps.core.interfaces.rx.weardata.CwfData
import app.aaps.core.interfaces.rx.weardata.CwfFile
import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_AUTHOR import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_AUTHOR
import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_AUTHOR_VERSION import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_AUTHOR_VERSION
import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_CREATED_AT import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_CREATED_AT
@ -22,6 +23,7 @@ import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_FILENAME
import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_NAME import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_NAME
import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_VERSION import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey.CWF_VERSION
import app.aaps.core.interfaces.rx.weardata.CwfMetadataMap import app.aaps.core.interfaces.rx.weardata.CwfMetadataMap
import app.aaps.core.interfaces.rx.weardata.CwfResDataMap
import app.aaps.core.interfaces.rx.weardata.EventData import app.aaps.core.interfaces.rx.weardata.EventData
import app.aaps.core.interfaces.rx.weardata.ResFileMap import app.aaps.core.interfaces.rx.weardata.ResFileMap
import app.aaps.core.interfaces.rx.weardata.ZipWatchfaceFormat import app.aaps.core.interfaces.rx.weardata.ZipWatchfaceFormat
@ -56,10 +58,10 @@ class CustomWatchfaceImportListActivity : TranslatedDaggerAppCompatActivity() {
supportActionBar?.setDisplayShowTitleEnabled(true) supportActionBar?.setDisplayShowTitleEnabled(true)
binding.recyclerview.layoutManager = LinearLayoutManager(this) binding.recyclerview.layoutManager = LinearLayoutManager(this)
binding.recyclerview.adapter = RecyclerViewAdapter(prefFileListProvider.listCustomWatchfaceFiles().sortedBy { it.metadata[CWF_NAME] }) binding.recyclerview.adapter = RecyclerViewAdapter(prefFileListProvider.listCustomWatchfaceFiles().sortedBy { it.cwfData.metadata[CWF_NAME] })
} }
inner class RecyclerViewAdapter internal constructor(private var customWatchfaceFileList: List<CwfData>) : RecyclerView.Adapter<RecyclerViewAdapter.CwfFileViewHolder>() { inner class RecyclerViewAdapter internal constructor(private var customWatchfaceFileList: List<CwfFile>) : RecyclerView.Adapter<RecyclerViewAdapter.CwfFileViewHolder>() {
inner class CwfFileViewHolder(val customWatchfaceImportListItemBinding: CustomWatchfaceImportListItemBinding) : RecyclerView.ViewHolder(customWatchfaceImportListItemBinding.root) { inner class CwfFileViewHolder(val customWatchfaceImportListItemBinding: CustomWatchfaceImportListItemBinding) : RecyclerView.ViewHolder(customWatchfaceImportListItemBinding.root) {
@ -67,11 +69,14 @@ class CustomWatchfaceImportListActivity : TranslatedDaggerAppCompatActivity() {
with(customWatchfaceImportListItemBinding) { with(customWatchfaceImportListItemBinding) {
root.isClickable = true root.isClickable = true
customWatchfaceImportListItemBinding.root.setOnClickListener { customWatchfaceImportListItemBinding.root.setOnClickListener {
val customWatchfaceFile = filelistName.tag as CwfData val customWatchfaceFile = filelistName.tag as CwfFile
val customWF = EventData.ActionSetCustomWatchface(customWatchfaceFile) sp.putString(app.aaps.core.utils.R.string.key_wear_cwf_watchface_name, customWatchfaceFile.cwfData.metadata[CWF_NAME] ?:"")
sp.putString(app.aaps.core.utils.R.string.key_wear_cwf_author_version, customWatchfaceFile.cwfData.metadata[CWF_AUTHOR_VERSION] ?:"")
sp.putString(app.aaps.core.utils.R.string.key_wear_cwf_filename, customWatchfaceFile.cwfData.metadata[CWF_FILENAME] ?:"")
val i = Intent() val i = Intent()
setResult(FragmentActivity.RESULT_OK, i) setResult(FragmentActivity.RESULT_OK, i)
rxBus.send(EventMobileDataToWear(customWF)) rxBus.send(EventMobileDataToWear(customWatchfaceFile.zipByteArray))
finish() finish()
} }
} }
@ -89,8 +94,8 @@ class CustomWatchfaceImportListActivity : TranslatedDaggerAppCompatActivity() {
override fun onBindViewHolder(holder: CwfFileViewHolder, position: Int) { override fun onBindViewHolder(holder: CwfFileViewHolder, position: Int) {
val customWatchfaceFile = customWatchfaceFileList[position] val customWatchfaceFile = customWatchfaceFileList[position]
val metadata = customWatchfaceFile.metadata val metadata = customWatchfaceFile.cwfData.metadata
val drawable = customWatchfaceFile.resDatas[ResFileMap.CUSTOM_WATCHFACE.fileName]?.toDrawable(resources) val drawable = customWatchfaceFile.cwfData.resDatas[ResFileMap.CUSTOM_WATCHFACE.fileName]?.toDrawable(resources)
with(holder.customWatchfaceImportListItemBinding) { with(holder.customWatchfaceImportListItemBinding) {
val fileName = metadata[CWF_FILENAME]?.let { "$it${ZipWatchfaceFormat.CWF_EXTENTION}" } ?: "" val fileName = metadata[CWF_FILENAME]?.let { "$it${ZipWatchfaceFormat.CWF_EXTENTION}" } ?: ""
filelistName.text = rh.gs(app.aaps.core.interfaces.R.string.metadata_wear_import_filename, fileName) filelistName.text = rh.gs(app.aaps.core.interfaces.R.string.metadata_wear_import_filename, fileName)

View file

@ -44,12 +44,12 @@
<string name="setupwizard_pump_pump_not_initialized"><b>Merk:</b> Du kan fortsette oppsettet når pumpen er satt opp.\n</string> <string name="setupwizard_pump_pump_not_initialized"><b>Merk:</b> Du kan fortsette oppsettet når pumpen er satt opp.\n</string>
<string name="startobjective">Start første læringsmål</string> <string name="startobjective">Start første læringsmål</string>
<string name="setupwizard_pump_riley_link_status">RileyLink status:</string> <string name="setupwizard_pump_riley_link_status">RileyLink status:</string>
<string name="readstatus">Les status</string> <string name="readstatus">Lesestatus</string>
<string name="data_choices">Datavalg</string> <string name="data_choices">Datavalg</string>
<string name="fabric_upload">Innlesing av fabrikkinnstillinger</string> <string name="fabric_upload">Innlesing av fabrikkinnstillinger</string>
<string name="allow_automated_crash_reporting">Tillat automatisk rapportering av appkrasj og bruksdata til utviklerne via fabrioc.io-tjenesten.</string> <string name="allow_automated_crash_reporting">Tillat automatisk rapportering av appkrasj og bruksdata til utviklerne via fabrioc.io-tjenesten.</string>
<string name="summary_email_for_crash_report">Denne e-postadressen vedlegges krasjrapporter slik at vi kan kontakte deg i akutte tilfeller. Det er valgfritt.</string> <string name="summary_email_for_crash_report">Denne e-postadressen vedlegges krasjrapporter slik at vi kan kontakte deg i akutte tilfeller. Det er valgfritt.</string>
<string name="identification">Identifikasjon (e-post, Facebook eller Discord nick osv.)</string> <string name="identification">Identifikasjon (e-post, Facebook eller Discord-nick osv.)</string>
<string name="request">Forespørsel</string> <string name="request">Forespørsel</string>
<string name="apsmode_title">APS modus</string> <string name="apsmode_title">APS modus</string>
<string name="setupwizard_preferred_aps_mode">Foretrukket APS modus</string> <string name="setupwizard_preferred_aps_mode">Foretrukket APS modus</string>
@ -117,12 +117,12 @@
<string name="database_cleanup">Databaseopprydding</string> <string name="database_cleanup">Databaseopprydding</string>
<string name="reset_db_confirm">Vil du virkelig nullstille databasene?</string> <string name="reset_db_confirm">Vil du virkelig nullstille databasene?</string>
<string name="maintenance_settings">Vedlikeholdsinnstillinger</string> <string name="maintenance_settings">Vedlikeholdsinnstillinger</string>
<string name="maintenance_email">E-post mottaker</string> <string name="maintenance_email">Mottaker av e-post</string>
<string name="maintenance_amount">Antall logger du vil sende</string> <string name="maintenance_amount">Antall logger du vil sende</string>
<string name="send_all_logs">Send logger via e-post</string> <string name="send_all_logs">Send logger via e-post</string>
<string name="delete_logs">Slett logger</string> <string name="delete_logs">Slett logger</string>
<string name="configbuilder_nightscoutversion_label">Nightscout versjon:</string> <string name="configbuilder_nightscoutversion_label">Nightscout-versjon:</string>
<string name="engineering_mode_enabled">Engineering Mode aktivert</string> <string name="engineering_mode_enabled">Engineering mode aktivert</string>
<string name="log_files">Loggfiler</string> <string name="log_files">Loggfiler</string>
<string name="nav_logsettings">Logginnstillinger</string> <string name="nav_logsettings">Logginnstillinger</string>
<string name="miscellaneous">Annet</string> <string name="miscellaneous">Annet</string>

View file

@ -167,13 +167,13 @@
<string name="extendedcarbs_rescue">For å registrere karbohydrater som brukes til å korrigere lavt blodsukker.</string> <string name="extendedcarbs_rescue">For å registrere karbohydrater som brukes til å korrigere lavt blodsukker.</string>
<string name="extendedcarbs_hint1">https://wiki.aaps.app/en/latest/Usage/Extended-Carbs.html</string> <string name="extendedcarbs_hint1">https://wiki.aaps.app/en/latest/Usage/Extended-Carbs.html</string>
<string name="nsclient_label">Fjernovervåking</string> <string name="nsclient_label">Fjernovervåking</string>
<string name="nsclient_howcanyou">Hvordan kan du overvåke AndroidAPS (for eksempel for ditt barn) på eksternt?</string> <string name="nsclient_howcanyou">Hvordan kan du eksternt overvåke AndroidAPS (for eksempel for ditt barn)?</string>
<string name="nsclient_nightscout">AAPSClient app, Nightscout app og Nightscout websiden gjør det mulig for deg å følge AAPS eksternt.</string> <string name="nsclient_nightscout">Appene AAPSClient og xDrip+ samt Nightscout-websiden gjør det mulig for deg å følge AAPS eksternt.</string>
<string name="nsclient_dexcomfollow">Andre apper (f.eks. Dexcom follow, xDrip som kjører i følger modus) lar deg følge noen parametere (f.eks. blodsukker/sensor verdier) på avstand, men bruker forskjellige beregningsmetoder og kan derfor vise andre IOB eller COB verdier.</string> <string name="nsclient_dexcomfollow">Andre apper (f.eks. Dexcom follow, xDrip som kjører i følger modus) lar deg følge noen parametere (f.eks. blodsukker/sensor verdier) på avstand, men bruker forskjellige beregningsmetoder og kan derfor vise andre IOB eller COB verdier.</string>
<string name="nsclient_data">For å følge AAPS eksternt må begge enhetene ha Internett-tilgang (f.eks. via Wi-Fi eller mobildata).</string> <string name="nsclient_data">For å følge AAPS eksternt må begge enhetene ha Internett-tilgang (f.eks. via Wi-Fi eller mobildata).</string>
<string name="nsclient_fullcontrol">AAPSClient som brukes som ekstern følger app vil både overvåke og gi full kontroll over AAPS.</string> <string name="nsclient_fullcontrol">AAPSClient som brukes som ekstern følger app vil både overvåke og gi full kontroll over AAPS.</string>
<string name="nsclient_hint1">https://wiki.aaps.app/en/latest/Children/Children.html</string> <string name="nsclient_hint1">https://wiki.aaps.app/en/latest/Children/Children.html</string>
<string name="isf_label_exam">Insulin Sensitivitetsfaktor (ISF)</string> <string name="isf_label_exam">Insulinsensitivitetsfaktor (ISF)</string>
<string name="isf_increasingvalue">Økte ISF-verdiene vil føre til levering av mer insulin for å dekke opp en viss mengde karbohydrater.</string> <string name="isf_increasingvalue">Økte ISF-verdiene vil føre til levering av mer insulin for å dekke opp en viss mengde karbohydrater.</string>
<string name="isf_decreasingvalue">Redusering av ISF verdien vil føre til mer insulintilførsel for å korrigere et blodsukker som ligger over målverdien.</string> <string name="isf_decreasingvalue">Redusering av ISF verdien vil føre til mer insulintilførsel for å korrigere et blodsukker som ligger over målverdien.</string>
<string name="isf_noeffect">Å øke eller senke ISF verdien har ingen effekt på insulintilførselen når blodsukkeret er lavere enn målverdien.</string> <string name="isf_noeffect">Å øke eller senke ISF verdien har ingen effekt på insulintilførselen når blodsukkeret er lavere enn målverdien.</string>
@ -211,7 +211,7 @@
<string name="profileswitchtime_100">Gjør et profilbytte til mer enn 100%.</string> <string name="profileswitchtime_100">Gjør et profilbytte til mer enn 100%.</string>
<string name="profileswitchtime_hint1">https://wiki.aaps.app/en/latest/Usage/Profiles.html#timeshift</string> <string name="profileswitchtime_hint1">https://wiki.aaps.app/en/latest/Usage/Profiles.html#timeshift</string>
<string name="profileswitch4_label">Endring av profil</string> <string name="profileswitch4_label">Endring av profil</string>
<string name="profileswitch4_rates">Basalrater, ISF, KH ratio, etc., bør defineres i profiler.</string> <string name="profileswitch4_rates">Basaldoser, ISF, IK-faktor osv. bør defineres i profiler.</string>
<string name="profileswitch4_internet">Aktivering av endringer i Nightscout profilen din krever at din AndroidAPS telefon er koblet til Internett.</string> <string name="profileswitch4_internet">Aktivering av endringer i Nightscout profilen din krever at din AndroidAPS telefon er koblet til Internett.</string>
<string name="profileswitch4_sufficient">Å redigere verdier i profilen din er tilstrekkelig for å aktivere profilendringen.</string> <string name="profileswitch4_sufficient">Å redigere verdier i profilen din er tilstrekkelig for å aktivere profilendringen.</string>
<string name="profileswitch4_multi">Flere profiler kan defineres og velges for å håndtere endringer i omstendigheter (f.eks. hormonelle endringer, skift arbeid, hverdager/helgedager).</string> <string name="profileswitch4_multi">Flere profiler kan defineres og velges for å håndtere endringer i omstendigheter (f.eks. hormonelle endringer, skift arbeid, hverdager/helgedager).</string>

View file

@ -24,7 +24,7 @@
<string name="objectives_autosens_gate">1 uke vellykket looping på dagtid hvor alle måltider (KH) angis</string> <string name="objectives_autosens_gate">1 uke vellykket looping på dagtid hvor alle måltider (KH) angis</string>
<string name="objectives_autosens_learned">Hvis dine autosens resultater ikke ligger rundt 100% kan det tyde på at profilen din er feil.</string> <string name="objectives_autosens_learned">Hvis dine autosens resultater ikke ligger rundt 100% kan det tyde på at profilen din er feil.</string>
<string name="objectives_smb_objective">Aktiver ekstra funksjoner for bruk på dagtid, slik som SMB (Super Micro Bolus)</string> <string name="objectives_smb_objective">Aktiver ekstra funksjoner for bruk på dagtid, slik som SMB (Super Micro Bolus)</string>
<string name="objectives_smb_gate">Du må lese wiki og øke din maxIOB for å få SMB til å fungere. Et godt utgangspunkt er maxIOB = gjennomsnittlig måltidsbolus + 3*max daglig basal</string> <string name="objectives_smb_gate">Du må lese wiki og øke din maxIOB for å få SMB til å fungere. Et godt utgangspunkt er å sette maxIOB til gjennomsnittlig måltidsbolus + 3x max daglig basaldose</string>
<string name="objectives_smb_learned">Bruk av SMB er en målsetting. Oref1 algoritmen ble designet for å hjelpe deg med dine bolusdoseringer. Det anbefales å ikke gi full bolusdose for måltider, men bare en del av den, og la AAPS styre resten om nødvendig. På denne måten får du større fleksibilitet med hensyn på feilberegnede KH. Visste du at du kan angi en prosentandel for boluskalkulatoren som resulterer i redusert bolusstørrelse?</string> <string name="objectives_smb_learned">Bruk av SMB er en målsetting. Oref1 algoritmen ble designet for å hjelpe deg med dine bolusdoseringer. Det anbefales å ikke gi full bolusdose for måltider, men bare en del av den, og la AAPS styre resten om nødvendig. På denne måten får du større fleksibilitet med hensyn på feilberegnede KH. Visste du at du kan angi en prosentandel for boluskalkulatoren som resulterer i redusert bolusstørrelse?</string>
<string name="objectives_dyn_isf_objective">Aktivere ekstra funksjoner for bruk på dagtid, slik som Dynamisk Sensitivitet</string> <string name="objectives_dyn_isf_objective">Aktivere ekstra funksjoner for bruk på dagtid, slik som Dynamisk Sensitivitet</string>
<string name="objectives_dyn_isf_gate">Sørg for at SMB fungerer som den skal. Aktiver DynamicISF-tillegget og finn riktig kalibrering for dine behov. Det anbefales å starte med en verdi lavere enn 100% for sikkerhets skyld.</string> <string name="objectives_dyn_isf_gate">Sørg for at SMB fungerer som den skal. Aktiver DynamicISF-tillegget og finn riktig kalibrering for dine behov. Det anbefales å starte med en verdi lavere enn 100% for sikkerhets skyld.</string>

View file

@ -45,7 +45,4 @@ dependencies {
// Food // Food
api "androidx.work:work-runtime-ktx:$work_version" api "androidx.work:work-runtime-ktx:$work_version"
// DataLayerListenerService
api "com.google.android.gms:play-services-wearable:$play_services_wearable_version"
} }

View file

@ -24,7 +24,7 @@
</activity> </activity>
<activity <activity
android:name=".general.wear.activities.CwfInfosActivity" android:name="app.aaps.plugins.sync.wear.activities.CwfInfosActivity"
android:exported="false" android:exported="false"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
@ -35,7 +35,7 @@
android:exported="false" /> android:exported="false" />
<service <service
android:name=".general.wear.wearintegration.DataLayerListenerServiceMobile" android:name="app.aaps.plugins.sync.wear.wearintegration.DataLayerListenerServiceMobile"
android:exported="true"> android:exported="true">
<intent-filter> <intent-filter>
<action android:name="com.google.android.gms.wearable.CHANNEL_EVENT" /> <action android:name="com.google.android.gms.wearable.CHANNEL_EVENT" />

View file

@ -4,7 +4,6 @@ import app.aaps.core.interfaces.iob.IobCobCalculator
import app.aaps.core.interfaces.smsCommunicator.SmsCommunicator import app.aaps.core.interfaces.smsCommunicator.SmsCommunicator
import app.aaps.plugins.main.general.persistentNotification.DummyService import app.aaps.plugins.main.general.persistentNotification.DummyService
import app.aaps.plugins.main.general.smsCommunicator.SmsCommunicatorPlugin import app.aaps.plugins.main.general.smsCommunicator.SmsCommunicatorPlugin
import app.aaps.plugins.main.general.wear.WearFragment
import app.aaps.plugins.main.iob.iobCobCalculator.IobCobCalculatorPlugin import app.aaps.plugins.main.iob.iobCobCalculator.IobCobCalculatorPlugin
import app.aaps.plugins.main.iob.iobCobCalculator.data.AutosensDataObject import app.aaps.plugins.main.iob.iobCobCalculator.data.AutosensDataObject
import dagger.Binds import dagger.Binds
@ -21,15 +20,13 @@ import dagger.android.ContributesAndroidInjector
SkinsModule::class, SkinsModule::class,
SkinsUiModule::class, SkinsUiModule::class,
ActionsModule::class, ActionsModule::class,
WearModule::class, OverviewModule::class,
OverviewModule::class
] ]
) )
@Suppress("unused") @Suppress("unused")
abstract class PluginsModule { abstract class PluginsModule {
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
@ContributesAndroidInjector abstract fun contributesDummyService(): DummyService @ContributesAndroidInjector abstract fun contributesDummyService(): DummyService
@ContributesAndroidInjector abstract fun autosensDataObjectInjector(): AutosensDataObject @ContributesAndroidInjector abstract fun autosensDataObjectInjector(): AutosensDataObject

View file

@ -1,14 +0,0 @@
package app.aaps.plugins.main.di
import app.aaps.plugins.main.general.wear.activities.CwfInfosActivity
import app.aaps.plugins.main.general.wear.wearintegration.DataLayerListenerServiceMobile
import dagger.Module
import dagger.android.ContributesAndroidInjector
@Module
@Suppress("unused")
abstract class WearModule {
@ContributesAndroidInjector abstract fun contributesWatchUpdaterService(): DataLayerListenerServiceMobile
@ContributesAndroidInjector abstract fun contributesCustomWatchfaceInfosActivity(): CwfInfosActivity
}

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">употреба:</string> <string name="cannula_usage">употреба:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Изпрати последните лог файлове на разработчиците. Непредвидена ситуация.</string> <string name="send_logfiles">Изпрати последните лог файлове на разработчиците. Непредвидена ситуация.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Наблюдавайте и контролирайте AndroidAPS, от вашия WearOS часовник.</string>
<string name="no_watch_connected">(Няма активна връзка)</string>
<string name="pump_status">Статус на помпата</string>
<string name="loop_status">Статус на цикъл</string>
<string name="wizard_result">Съветник:\nИнсулин: %1$.2fЕ\nВъгл: %2$dгр</string>
<string name="quick_wizard_not_available">Избраният съветник вече не е наличен, моля, опреснете</string>
<string name="quick_wizard_message">Съветник:%1$s\nИнсулин: %2$.2fЕ\nВъгл:%3$dгр</string>
<string name="wear_action_tempt_preset_error">Временна цел непознат шаблон %1$s</string>
<string name="wear_action_tempt_cancel_message">Изключи текуща Временна цел?</string>
<string name="wear_action_tempt_unit_error">Различни мерни единици се ползват на телефона и часовника!</string>
<string name="wear_action_tempt_zero_message">Нулева цел - изключвам временна цел?</string>
<string name="wear_action_tempt_min_bg_error">Мин КЗ е извън обхват!</string>
<string name="wear_action_tempt_max_bg_error">Макс КЗ е извън обхват!</string>
<string name="wear_action_tempt_manual_range_message">Временна цел \nМин: %1$s\nМакс: %2$s\nПрод: %3$s</string>
<string name="wear_action_tempt_manual_message">Временна цел \nцел: %1$s\nПрод: %2$s</string>
<string name="wear_action_tempt_preset_message">Временна цел \nЦел: %1$s\nЦел: %2$s\nПрод: %3$s</string>
<string name="no_success">неуспешно - моля проверете телефона</string>
<string name="wear_settings">Настройки на часовник</string>
<string name="wearcontrol_title">Контролиране от часовник</string>
<string name="wearcontrol_summary">Задаване временни цели и въвеждане Лечения от часовник Android wear</string>
<string name="wear_wizard_settings_summary">Изчисления, включени в резултата на съветника:</string>
<string name="wear_general_settings">Основни настройки</string>
<string name="wear_notifysmb_title">Уведомяване при SMB</string>
<string name="wear_notifysmb_summary">Покажи SMB на часовника като стандартен болус.</string>
<string name="wear_custom_watchface_settings">Настройки на Watchface</string>
<string name="wear_custom_watchface_authorization_title">Разрешаване на персонализиран Watchface</string>
<string name="wear_custom_watchface_authorization_summary">Разрешете заредения Watchface да променя и заключва определени настройки за екрана на часовника, за да съответстват на дизайна</string>
<string name="wear_custom_watchface">Персонализиран Watchface: %1$s</string>
<string name="wear_load_watchface">Зареди Watchface</string>
<string name="wear_infos_watchface">Информация за Watchface</string>
<string name="wear_export_watchface">Експорт на шаблона</string>
<string name="wear_new_custom_watchface_exported">Шаблон за watchface експортиран</string>
<string name="resend_all_data">Изпрати отново всички дани</string>
<string name="open_settings_on_wear">Отвори настройките на часовника</string>
<string name="cwf_infos_pref_locked">Списък с опции заключен от Watchface</string>
<string name="cwf_infos_pref_required">Списък с необходими настройки за Watchface</string>
<string name="cwf_infos_view_title">Списък с полета включени в Watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Показва известие с резюме на това, което прави вашия APS</string> <string name="description_persistent_notification">Показва известие с резюме на това, което прави вашия APS</string>
<string name="old_data">СТАРИ ДАННИ</string> <string name="old_data">СТАРИ ДАННИ</string>
<string name="pump_fetching_data">опитвам се да изтегля данни от помпата.</string>
<string name="pump_old_data">ОДД: Все още стари данни! Не може да се заредят от помпата.</string>
<string name="grams_short">гр.</string>
<string name="hour_short">ч</string>
<string name="no_active_profile">Не е настроен активен профил!</string>
<string name="profile_message">Профил:\n\nОтместване във времето: %1$d\nПроцент: %2$d%%\"</string>
<string name="tdd_line">%1$.2fЕ %1$.0f%%</string>
<string name="no_profile">Не е зареден профил</string>
<string name="aps_only">Прилагане само в режим АПС!</string>
<string name="last_aps_result_na">Последният резултат не е наличен!</string>
<string name="loop_status_closed">ЗАТВОРЕН ЦИКЪЛ</string>
<string name="loop_status_open">ОТВОРЕН ЦИКЪЛ</string>
<string name="loop_status_disabled">ЦИКЪЛ ИЗКЛЮЧЕН</string>
<string name="aps">АПС</string>
<string name="last_run">Последно изпълнение</string>
<string name="last_enact">Последно зададено</string>
<string name="today">Днес</string>
<string name="weighted">тегло</string>
<string name="target_only_aps_mode">Целите се прилагат само в режим АПС!</string>
<string name="no_history">Няма хронология!</string>
<string name="units_short">Е</string>
<string name="temp_target">Временна цел</string>
<string name="until">до</string>
<string name="default_range">НАЧАЛНИ СТОЙНОСТИ</string>
<string name="target">цел</string>
<string name="rate_duration">Скорост: %1$.2fЕ/ч (%2$.2f%%) \nПродължителност %3$d мин</string>
</resources> </resources>

View file

@ -250,18 +250,6 @@
<string name="skin">Tema</string> <string name="skin">Tema</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Enviar logs del dia als desenvolupadors. Situació inesperada.</string> <string name="send_logfiles">Enviar logs del dia als desenvolupadors. Situació inesperada.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="no_success">no funciona - si us plau comproveu al mòbil</string>
<string name="wear_settings">Configuració de Wear</string>
<string name="wearcontrol_title">Control des de rellotge</string>
<string name="wearcontrol_summary">Marcar objectius temporals i introduir tractaments des del rellotge.</string>
<string name="wear_wizard_settings_summary">Càlculs inclosos al resultat de l\'assistent:</string>
<string name="wear_general_settings">Configuració general</string>
<string name="wear_notifysmb_title">Avís d\'SMB</string>
<string name="wear_notifysmb_summary">Mostrar SMB al rellotge com un bolus estàndard.</string>
<string name="resend_all_data">Reenviar totes les dades</string>
<string name="open_settings_on_wear">Obrir Configuració a Wear</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Va mostrant avisos amb un petit resum del que el llaç està fent</string> <string name="description_persistent_notification">Va mostrant avisos amb un petit resum del que el llaç està fent</string>
<string name="old_data">DADES ANTIGUES</string> <string name="old_data">DADES ANTIGUES</string>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">použití:</string> <string name="cannula_usage">použití:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Odešlete dnešní soubory protokolů vývojářům spolu s tímto časem. Neočekávaná situace.</string> <string name="send_logfiles">Odešlete dnešní soubory protokolů vývojářům spolu s tímto časem. Neočekávaná situace.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Zobrazování stavu a řízení AAPS z hodinek s WearOS.</string>
<string name="no_watch_connected">(Žádné hodinky nejsou připojeny)</string>
<string name="pump_status">Stav pumpy</string>
<string name="loop_status">Stav smyčky</string>
<string name="wizard_result">Kalkulátor: \nInzulín: %1$.2fU\nSacharidy: %2$dg</string>
<string name="quick_wizard_not_available">Vybraný rychlý bolus již není k dispozici, obnovte prosím dlaždici</string>
<string name="quick_wizard_message">Rychlý bolus: %1$s\nInzulín: %2$.2fU\nSacharidy: %3$dg</string>
<string name="wear_action_tempt_preset_error">Dočasný cíl neznámá předvolba: %1$s</string>
<string name="wear_action_tempt_cancel_message">Zrušení běžícího dočasného cíle?</string>
<string name="wear_action_tempt_unit_error">Různé jednotky používané na hodinkách a telefonu!</string>
<string name="wear_action_tempt_zero_message">Nulový dočasný cíl - zrušení běžícího dočasného cíle?</string>
<string name="wear_action_tempt_min_bg_error">Minimální glykémie mimo rozsah!</string>
<string name="wear_action_tempt_max_bg_error">Maximální glykémie mimo rozsah!</string>
<string name="wear_action_tempt_manual_range_message">Doč. cíl:\nMin: %1$s\nMax: %2$s\nTrvání: %3$s</string>
<string name="wear_action_tempt_manual_message">Doč. cíl:\nCíl: %1$s\nTrvání: %2$s</string>
<string name="wear_action_tempt_preset_message">Doč. cíl:\nDůvod: %1$s\nCíl: %2$s\nTrvání: %3$s</string>
<string name="no_success">neúspěšně - zkontrolujte mobil</string>
<string name="wear_settings">Nastavení hodinek</string>
<string name="wearcontrol_title">Řízení z hodinek Wear</string>
<string name="wearcontrol_summary">Nastavování dočasných cílů a vkládání ošetření na hodinkách Wear.</string>
<string name="wear_wizard_settings_summary">Kalkulace použité ve výsledku wizardu:</string>
<string name="wear_general_settings">Základní nastavení</string>
<string name="wear_notifysmb_title">Oznámení při SMB</string>
<string name="wear_notifysmb_summary">Ukazovat SMB na hodinkách jako normální bolus.</string>
<string name="wear_custom_watchface_settings">Nastavení vlastního ciferníku</string>
<string name="wear_custom_watchface_authorization_title">Autorizace vlastního ciferníku</string>
<string name="wear_custom_watchface_authorization_summary">Autorizujte načtený vlastní ciferník, aby se změnila a uzamkla některá nastavení hodinek tak, aby vyhovovala designu ciferníku</string>
<string name="wear_custom_watchface">Vlastní ciferník: %1$s</string>
<string name="wear_load_watchface">Nahrát ciferník</string>
<string name="wear_infos_watchface">Informace o ciferníku</string>
<string name="wear_export_watchface">Exportovat šablonu</string>
<string name="wear_new_custom_watchface_exported">Vlastní šablona ciferníku exportována</string>
<string name="resend_all_data">Znovu poslat všechna data</string>
<string name="open_settings_on_wear">Otevřít nastavení na hodinkách Wear</string>
<string name="cwf_infos_pref_locked">Seznam preferencí uzamčený hodinkami</string>
<string name="cwf_infos_pref_required">Seznam preferencí požadovaných ciferníkem</string>
<string name="cwf_infos_view_title">Seznam polí zahrnutých do ciferníku</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Zobrazení průběžného oznámení v Androidu s krátkým přehledem, co smyčka právě dělá</string> <string name="description_persistent_notification">Zobrazení průběžného oznámení v Androidu s krátkým přehledem, co smyčka právě dělá</string>
<string name="old_data">ZASTARALÉ</string> <string name="old_data">ZASTARALÉ</string>
<string name="pump_fetching_data">pokus o načtení dat z pumpy.</string>
<string name="pump_old_data">CDD: Stále stará data! Nelze načíst z pumpy.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Není nastaven žádný aktivní profil!</string>
<string name="profile_message">Profil:\n\nPosunutí: %1$d\nProcento: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Není vybrán žádný profil</string>
<string name="aps_only">Použít pouze v APS módu!</string>
<string name="last_aps_result_na">Poslední výsledek není k dispozici!</string>
<string name="loop_status_closed">UZAVŘENÁ SMYČKA</string>
<string name="loop_status_open">OTEVŘENÁ SMYČKA</string>
<string name="loop_status_disabled">SMYČKA ZAKÁZÁNA</string>
<string name="aps">APS</string>
<string name="last_run">Poslední spuštění</string>
<string name="last_enact">Poslední provedení</string>
<string name="today">Dnes</string>
<string name="weighted">vážený</string>
<string name="target_only_aps_mode">Cíle se použijí pouze v režimu APS!</string>
<string name="no_history">Žádné údaje o historii!</string>
<string name="units_short">U</string>
<string name="temp_target">Dočasný cíl</string>
<string name="until">až do</string>
<string name="default_range">VÝCHOZÍ ROZSAH</string>
<string name="target">cíl</string>
<string name="rate_duration">Rychlost: %1$.2fU/h (%2$.2f%%) \nTrvání %3$d min</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">brug:</string> <string name="cannula_usage">brug:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Send dagens logfiler til udviklere sammen med denne tid. Uventet situation.</string> <string name="send_logfiles">Send dagens logfiler til udviklere sammen med denne tid. Uventet situation.</string>
<!-- Wear-->
<string name="wear_shortname">UR</string>
<string name="description_wear">Overvåg og kontrollér AndroidAPS ved hjælp af dit WearOS-ur.</string>
<string name="no_watch_connected">(Intet ur forbundet)</string>
<string name="pump_status">Pumpestatus</string>
<string name="loop_status">Loop status</string>
<string name="wizard_result">Guide:\nInsulin: %1$.2fE\nKH: %2$dg</string>
<string name="quick_wizard_not_available">Valgt guide er ikke længere tilgængeligt. Opdater venligst din widget</string>
<string name="quick_wizard_message">Hurtigguide: %1$s\nInsulin: %2$.2fE\nKH: %3$dg</string>
<string name="wear_action_tempt_preset_error">Midlertidigmål ukendt forudindstilling: %1$s</string>
<string name="wear_action_tempt_cancel_message">Annullér aktuelt midlertidig mål?</string>
<string name="wear_action_tempt_unit_error">Forskellige enheder brugt på ur og telefon!</string>
<string name="wear_action_tempt_zero_message">0-mål - annuller midlertidigt mål?</string>
<string name="wear_action_tempt_min_bg_error">Min-BS udenfor området!</string>
<string name="wear_action_tempt_max_bg_error">Max-BS udenfor området!</string>
<string name="wear_action_tempt_manual_range_message">Midlertidigt mål:\nMin: %1$s\nMax: %2$s\nVarighed: %3$s</string>
<string name="wear_action_tempt_manual_message">Midlertigt mål:\nMål: %1$s\nVarighed: %2$s</string>
<string name="wear_action_tempt_preset_message">Midlertigt mål:\nGrund: %1$s\nMål: %2$s\nVarighed: %3$s</string>
<string name="no_success">mislykkedes - tjek venligst telefonen</string>
<string name="wear_settings">Indstillinger for Wear</string>
<string name="wearcontrol_title">Kontrolleringer fra Ur</string>
<string name="wearcontrol_summary">Sæt midlertidige mål og indtast behandlinger fra uret.</string>
<string name="wear_wizard_settings_summary">Beregninger inkluderet i guide resultatet:</string>
<string name="wear_general_settings">Generelle indstillinger</string>
<string name="wear_notifysmb_title">Giv besked ved SMB</string>
<string name="wear_notifysmb_summary">Vis SMB på uret som en standard bolus.</string>
<string name="wear_custom_watchface_settings">Brugerdefinerede Urskiveindstillinger</string>
<string name="wear_custom_watchface_authorization_title">Brugerdefineret Urskivegodkendelse</string>
<string name="wear_custom_watchface_authorization_summary">Godkend indlæste brugerdefinerede urskive til at ændre og låse nogle overvågningsindstillinger der passer til urskivens design</string>
<string name="wear_custom_watchface">Brugerdefineret Urskive: %1$s</string>
<string name="wear_load_watchface">Indlæs Urskive</string>
<string name="wear_infos_watchface">Infos Urskiver</string>
<string name="wear_export_watchface">Eksporter skabelon</string>
<string name="wear_new_custom_watchface_exported">Brugerdefineret urskiveskabelon eksporteret</string>
<string name="resend_all_data">Send alle data igen</string>
<string name="open_settings_on_wear">Åbn indstillinger på ur</string>
<string name="cwf_infos_pref_locked">Liste over præferencer låst af urskiven</string>
<string name="cwf_infos_pref_required">Liste over præferencer påkrævet af urskiven</string>
<string name="cwf_infos_view_title">Liste over felter inkluderet i Urskiven</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Viser en løbende notifikation med en kort oversigt over, hvad dit loop gør</string> <string name="description_persistent_notification">Viser en løbende notifikation med en kort oversigt over, hvad dit loop gør</string>
<string name="old_data">GAMLE DATA</string> <string name="old_data">GAMLE DATA</string>
<string name="pump_fetching_data">forsøger at hente data fra pumpen.</string>
<string name="pump_old_data">TDD: Stadig gammel data! Kan ikke indlæse fra pumpen.</string>
<string name="grams_short">g</string>
<string name="hour_short">t</string>
<string name="no_active_profile">Ingen aktiv profilskift!</string>
<string name="profile_message">Profil:\n\nTidsskift: %1$d\nProcent: %2$d%%\"</string>
<string name="tdd_line">%1$.2fIE %1$.0f%%</string>
<string name="no_profile">Ingen profil indlæst</string>
<string name="aps_only">Gælder kun i APS-tilstand!</string>
<string name="last_aps_result_na">Sidste resultat ikke tilgængeligt!</string>
<string name="loop_status_closed">LUKKET LOOP</string>
<string name="loop_status_open">ÅBEN LOOP</string>
<string name="loop_status_disabled">LOOP DEAKTIVERET</string>
<string name="aps">APS</string>
<string name="last_run">Sidste brug</string>
<string name="last_enact">Sidste Aktivering</string>
<string name="today">I dag</string>
<string name="weighted">vægtet</string>
<string name="target_only_aps_mode">Mål gælder kun i APS-tilstand!</string>
<string name="no_history">Ingen historisk data!</string>
<string name="units_short">IE</string>
<string name="temp_target">Midlertidigt mål</string>
<string name="until">indtil</string>
<string name="default_range">Standardmål</string>
<string name="target">mål</string>
<string name="rate_duration">Rate: %1$.2fIE/t (%2$.2f%%) \nVarighed %3$d min</string>
</resources> </resources>

View file

@ -287,72 +287,7 @@
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Sende die heutigen Logdateien unter Angabe dieser Uhrzeit an die Entwickler. <string name="send_logfiles">Sende die heutigen Logdateien unter Angabe dieser Uhrzeit an die Entwickler.
Unerwartetes Verhalten.</string> Unerwartetes Verhalten.</string>
<!-- Wear-->
<string name="wear_shortname">UHR</string>
<string name="description_wear">Überwache und steuere AndroidAPS mit Deiner WearOS-Smartwatch.</string>
<string name="no_watch_connected">(keine Uhr verbunden)</string>
<string name="pump_status">Status der Pumpe</string>
<string name="loop_status">Loop Status</string>
<string name="wizard_result">Calc. Wizard:\nInsulin: %1$.2fU\nCarbs: %2$dg</string>
<string name="quick_wizard_not_available">Ausgewählter Quickwizard nicht mehr verfügbar, bitte aktualisiere die Kachel</string>
<string name="quick_wizard_message">QuickWizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
<string name="wear_action_tempt_preset_error">Temp-Target unbekannte Voreinstellung: %1$s</string>
<string name="wear_action_tempt_cancel_message">Ausführung des Temp-Targets abbrechen?</string>
<string name="wear_action_tempt_unit_error">Verschiedene Einheiten werden auf Uhr und Telefon verwendet!</string>
<string name="wear_action_tempt_zero_message">Zero-Temp-Target - abbrechen des laufenden Temp-Targets?</string>
<string name="wear_action_tempt_min_bg_error">Min-BG ist außerhalb des Bereichs!</string>
<string name="wear_action_tempt_max_bg_error">Max-BG ist außerhalb des Bereichs!</string>
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDauer: %3$s</string>
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDauer: %2$s</string>
<string name="wear_action_tempt_preset_message">Temp-Target:\nGrund: %1$s\nTarget: %2$s\nDauer: %3$s</string>
<string name="no_success">Nicht erfolgreich - bitte Telefon prüfen</string>
<string name="wear_settings">Wear-Einstellungen</string>
<string name="wearcontrol_title">Steuerung durch die Uhr</string>
<string name="wearcontrol_summary">Setze temporäre Ziele und Behandlungen mit der Uhr</string>
<string name="wear_wizard_settings_summary">Berechnungen, die im Assistenten berücksichtigt werden:</string>
<string name="wear_general_settings">Allgemeine Einstellungen</string>
<string name="wear_notifysmb_title">Bei SMB benachrichtigen</string>
<string name="wear_notifysmb_summary">Zeige SMB auf der Uhr wie einen normalen Bolus an.</string>
<string name="wear_custom_watchface_settings">Benutzerdefinierte Watchface Einstellungen</string>
<string name="wear_custom_watchface_authorization_title">Benutzerdefinierte Watchface Autorisierung</string>
<string name="wear_custom_watchface_authorization_summary">Autorisiere geladene benutzerdefinierte Watchface zum Ändern und Sperren einiger Watchscreen-Einstellungen für das Design der Uhr</string>
<string name="wear_custom_watchface">Benutzerdefiniertes Watchface: %1$s</string>
<string name="wear_load_watchface">Watchface laden</string>
<string name="wear_infos_watchface">Infos Watchface</string>
<string name="wear_export_watchface">Vorlage exportieren</string>
<string name="wear_new_custom_watchface_exported">Benutzerdefinierte Watchface Vorlage exportiert</string>
<string name="resend_all_data">Alle Daten erneut senden</string>
<string name="open_settings_on_wear">Öffne Einstellungen auf der Uhr</string>
<string name="cwf_infos_pref_locked">Liste der von der Watchface gesperrten Prefs</string>
<string name="cwf_infos_pref_required">Liste der von der Watchface angeforderten Voreinstellungen</string>
<string name="cwf_infos_view_title">Liste der Felder, die in der Watchface enthalten sind</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Zeigt eine fortlaufende Benachrichtigung mit einer kurzen Übersicht darüber, was dein Loop derzeit tut</string> <string name="description_persistent_notification">Zeigt eine fortlaufende Benachrichtigung mit einer kurzen Übersicht darüber, was dein Loop derzeit tut</string>
<string name="old_data">VERALTETE DATEN</string> <string name="old_data">VERALTETE DATEN</string>
<string name="pump_fetching_data">versuche Daten von der Pumpe abzurufen.</string>
<string name="pump_old_data">TDD: verwendet alte Daten! Auslesen der Pumpe nicht möglich.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Kein aktiver Profilwechsel!</string>
<string name="profile_message">Profil:\n\nZeitverschiebung: %1$\nProzent: %2$d%%\"</string>
<string name="tdd_line">%1$.2fE %1$.0f%%</string>
<string name="no_profile">Kein Profil geladen</string>
<string name="aps_only">Nur im APS-Modus anwendbar!</string>
<string name="last_aps_result_na">Letztes Ergebnis ist nicht verfügbar!</string>
<string name="loop_status_closed">CLOSED LOOP</string>
<string name="loop_status_open">OPEN LOOP</string>
<string name="loop_status_disabled">LOOP DEAKTIVIERT</string>
<string name="aps">APS</string>
<string name="last_run">Letzte Ausführung</string>
<string name="last_enact">Letzte Abgabe</string>
<string name="today">Heute</string>
<string name="weighted">gewichtet</string>
<string name="target_only_aps_mode">Ziele gelten nur im APS-Modus!</string>
<string name="no_history">Keine Verlaufsdaten!</string>
<string name="units_short">E</string>
<string name="temp_target">Temporäres Ziel</string>
<string name="until">bis</string>
<string name="default_range">STANDARD-BEREICH</string>
<string name="target">Ziel</string>
<string name="rate_duration">Rate: %1$.2fIE/h (%2$.2f%%) \nDauer %3$d min</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">χρήσιμες συμβουλές:</string> <string name="cannula_usage">χρήσιμες συμβουλές:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Στείλτε τα αρχεία καταγραφής της ημέρας στους προγραμματιστές μαζί με αυτή τη φορά. Απροσδόκητη κατάσταση.</string> <string name="send_logfiles">Στείλτε τα αρχεία καταγραφής της ημέρας στους προγραμματιστές μαζί με αυτή τη φορά. Απροσδόκητη κατάσταση.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Παρακολούθηση και χειρισμός του AAPS χρησιμοποιώντας το ρολόι WearOS.</string>
<string name="no_watch_connected">(Χωρίς Σύνδεση Ρολογιού)</string>
<string name="pump_status">Κατάσταση Αντλίας</string>
<string name="loop_status">Κατάσταση κυκλώματος</string>
<string name="wizard_result">Υπολογισμός. Οδηγός:\nΙνσουλίνη: %1$.2fU\nΥδατάνθρακες: %2$dg</string>
<string name="quick_wizard_not_available">Ο επιλεγμένος οδηγός δεν είναι πλέον διαθέσιμος, παρακαλώ ανανεώστε το πλακίδιο σας</string>
<string name="quick_wizard_message">Γρήγορος οδηγός: %1$s\nΙνσουλίνη: %2$.2fU\nΥδατάνθρακες: %3$dg</string>
<string name="wear_action_tempt_preset_error">Άγνωστη προεπιλογή προσωρινού στόχου: %1$s</string>
<string name="wear_action_tempt_cancel_message">Ακύρωση εκτέλεσης προσωρινών στόχων;</string>
<string name="wear_action_tempt_unit_error">Χρησιμοποιούνται διαφορετικές μονάδες στο ρολόι και το τηλέφωνο!</string>
<string name="wear_action_tempt_zero_message">Μηδενικός-Προσωρινός-Στόχος - ακύρωση εκτέλεσης Πρισωρινών-Στόχων;</string>
<string name="wear_action_tempt_min_bg_error">Ελάσιχτο-BG εκτός εύρους!</string>
<string name="wear_action_tempt_max_bg_error">Μέγιστο-BG εκτός εύρους!</string>
<string name="wear_action_tempt_manual_range_message">Προσωρινός στόχος:\nΕλάχιστο: %1$s\nΜέγιστο: %2$s\nΔιάρκεια: %3$s</string>
<string name="wear_action_tempt_manual_message">Προσωρινός στόχος:\nΣτόχος: %1$s\nΔιάρκεια: %2$s</string>
<string name="wear_action_tempt_preset_message">Προσωρινός στόχος:\nΑιτία: %1$s\nΣτόχος: %2$s\nΔιάρκεια: %3$s</string>
<string name="no_success">αποτυχία - ελέγξτε τηλέφωνο</string>
<string name="wear_settings">Ρυθμίσεις Wear</string>
<string name="wearcontrol_title">Έλεγχος από ρολόι</string>
<string name="wearcontrol_summary">Ρυθμίστε Στόχους-Προσ Ρυθμού και βάλτε Θεραπείες από το ρολόι.</string>
<string name="wear_wizard_settings_summary">Υπολογισμοί που περιλαμβάνονται στο αποτέλεσμα του γρήγορου οδηγού:</string>
<string name="wear_general_settings">Γενικές Ρυθμίσεις</string>
<string name="wear_notifysmb_title">Ειδοποίηση στο SMB</string>
<string name="wear_notifysmb_summary">Εμφάνιση SMB στο ρολόι όπως ένα τυπικό bolus.</string>
<string name="wear_custom_watchface_settings">Προσαρμοσμένες Ρυθμίσεις Watchface</string>
<string name="wear_custom_watchface_authorization_title">Προσαρμοσμένη Εξουσιοδότηση Watchface</string>
<string name="wear_custom_watchface_authorization_summary">Εξουσιοδοτήστε το φορτωμένο προσαρμοσμένο ρολόι για να αλλάξετε και να κλειδώσετε ορισμένες ρυθμίσεις οθόνης ρολογιού για να ταιριάζει στο σχεδιασμό watchface</string>
<string name="wear_custom_watchface">Προσαρμοσμένο Watchface: %1$s</string>
<string name="wear_load_watchface">Φόρτωση Watchface</string>
<string name="wear_infos_watchface">Πληροφορίες Watchface</string>
<string name="wear_export_watchface">Εξαγωγή Προτύπου</string>
<string name="wear_new_custom_watchface_exported">Εξήχθη προσαρμοσμένο πρότυπο watchface</string>
<string name="resend_all_data">Ξαναστείλτε όλα τα Δεδομένα</string>
<string name="open_settings_on_wear">Ρυθμίσεις στο Wear</string>
<string name="cwf_infos_pref_locked">Λίστα προτιμήσεων που κλειδώθηκαν από το Watchface</string>
<string name="cwf_infos_pref_required">Λίστα προτιμήσεων που απαιτούνται για το Watchface</string>
<string name="cwf_infos_view_title">Λίστα πεδίων που περιλαμβάνονται στο Watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Εμφανίζει μία τρέχουσα ειδοποίηση με σύντομη επισκόπηση του τι κάνει το κύκλωμα τώρα</string> <string name="description_persistent_notification">Εμφανίζει μία τρέχουσα ειδοποίηση με σύντομη επισκόπηση του τι κάνει το κύκλωμα τώρα</string>
<string name="old_data">Παλιά Δεδομένα</string> <string name="old_data">Παλιά Δεδομένα</string>
<string name="pump_fetching_data">προσπάθεια λήψης δεδομένων από την αντλία.</string>
<string name="pump_old_data">TDD: Ακόμα είναι παλιά τα δεδομένα! Δεν μπορεί να φορτωθεί από την αντλία.</string>
<string name="grams_short">g</string>
<string name="hour_short">ω</string>
<string name="no_active_profile">Μη ενεργή αλλαγή προφίλ!</string>
<string name="profile_message">Προφίλ:\n\nΧρονική μετατόπιση: %1$d\nΠοσοστό: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Δεν φορτώθηκε προφίλ</string>
<string name="aps_only">Ισχύει μόνο σε λειτουργία APS!</string>
<string name="last_aps_result_na">Τελευταίο αποτέλεσμα μη διαθέσιμο!</string>
<string name="loop_status_closed">ΚΛΕΙΣΤΟ ΚΥΚΛΩΜΑ</string>
<string name="loop_status_open">ΑΝΟΙΚΤΟ ΚΥΚΛΩΜΑ</string>
<string name="loop_status_disabled">ΚΥΚΛΩΜΑ ΑΠΕΝΕΡΓΟΠΟΙΗΜΕΝΟ</string>
<string name="aps">APS</string>
<string name="last_run">Τελευταία εκτέλεση</string>
<string name="last_enact">Τελευταία Ενέργεια</string>
<string name="today">Σήμερα</string>
<string name="weighted">σταθμισμένο</string>
<string name="target_only_aps_mode">Οι στόχοι ισχύουν μόνο στη λειτουργία APS!</string>
<string name="no_history">Δεν υπάρχουν ιστορικά δεδομένα!</string>
<string name="units_short">U</string>
<string name="temp_target">Προσωρινός Στόχος</string>
<string name="until">μέχρι</string>
<string name="default_range">ΠΡΟΕΠΙΛΕΓΜΕΝΟ ΕΥΡΟΣ</string>
<string name="target">στόχος</string>
<string name="rate_duration">Τιμή: %1$.2fU/h (%2$.2f%%) \nΔιάρκεια %3$d λεπτά</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">Uso:</string> <string name="cannula_usage">Uso:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Enviar los archivos de registro de hoy a los desarrolladores. Situación inesperada.</string> <string name="send_logfiles">Enviar los archivos de registro de hoy a los desarrolladores. Situación inesperada.</string>
<!-- Wear-->
<string name="wear_shortname">RELOJ</string>
<string name="description_wear">Supervisar y controlar AAPS usando un reloj WearOS</string>
<string name="no_watch_connected">(Ningún reloj conectado)</string>
<string name="pump_status">Estado de la bomba de insulina</string>
<string name="loop_status">Estado del bucle</string>
<string name="wizard_result">Calc. Asistente:\nInsulina: %1$.2fU\nCarbohidratos: %2$dg</string>
<string name="quick_wizard_not_available">El asistente rápido seleccionado ya no está disponible, por favor actualice su tarjeta</string>
<string name="quick_wizard_message">Asistente Rápido: %1$s\nInsulina: %2$.2fU\nCarbohidratos: %3$dg</string>
<string name="wear_action_tempt_preset_error">Objetivo Temporal preestablecido desconocido: %1$s</string>
<string name="wear_action_tempt_cancel_message">¿Cancelar la ejecución del objetivo temporal?</string>
<string name="wear_action_tempt_unit_error">¡Diferentes unidades usadas en el reloj y en el teléfono!</string>
<string name="wear_action_tempt_zero_message">Objetivo Temporal Zero - ¿Cancelar el Objetivo Temporal en ejecución?</string>
<string name="wear_action_tempt_min_bg_error">¡Glucosa mínima fuera de rango!</string>
<string name="wear_action_tempt_max_bg_error">¡Glucosa máxima fuera de rango!</string>
<string name="wear_action_tempt_manual_range_message">Objetivo temporal:\nMin: %1$s\nMax: %2$s\nDuración: %3$s</string>
<string name="wear_action_tempt_manual_message">Objetivo temporal:\nObjetivo: %1$s\nDuración: %2$s</string>
<string name="wear_action_tempt_preset_message">ObjetivoTemporal:\nRazón: %1$s\nObjetivo: %2$s\nDuración: %3$s</string>
<string name="no_success">sin efecto - por favor verificar en teléfono</string>
<string name="wear_settings">Ajustes del reloj</string>
<string name="wearcontrol_title">Control desde el reloj</string>
<string name="wearcontrol_summary">Establece objetivos temporales (OT) y añade tratamientos desde el reloj</string>
<string name="wear_wizard_settings_summary">Cálculos incluidos en el resultado del asistente:</string>
<string name="wear_general_settings">Configuración general</string>
<string name="wear_notifysmb_title">Notificar los SMB</string>
<string name="wear_notifysmb_summary">Mostrar los SMB en el reloj como un bolo estándar</string>
<string name="wear_custom_watchface_settings">Configuración personalizada de esferas</string>
<string name="wear_custom_watchface_authorization_title">Autorización de esferas personalizadas</string>
<string name="wear_custom_watchface_authorization_summary">Autorizar a la esfera personalizada a cambiar y bloquear algunos ajustes de la pantalla del reloj, para que se adapten al diseño de la esfera</string>
<string name="wear_custom_watchface">Esfera personalizada: %1$s</string>
<string name="wear_load_watchface">Cargar esfera</string>
<string name="wear_infos_watchface">Información de esferas</string>
<string name="wear_export_watchface">Exportar plantilla</string>
<string name="wear_new_custom_watchface_exported">Plantilla de esfera personalizada exportada</string>
<string name="resend_all_data">Reenviar todos los datos</string>
<string name="open_settings_on_wear">Abrir ajustes en el reloj</string>
<string name="cwf_infos_pref_locked">Lista de preferencias bloqueadas por la esfera</string>
<string name="cwf_infos_pref_required">Lista de preferencias necesarias para la esfera</string>
<string name="cwf_infos_view_title">Lista de campos incluidos en la esfera</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Muestra una notificación en curso con un breve resumen de lo que está haciendo tu bucle</string> <string name="description_persistent_notification">Muestra una notificación en curso con un breve resumen de lo que está haciendo tu bucle</string>
<string name="old_data">DATOS CADUCADOS</string> <string name="old_data">DATOS CADUCADOS</string>
<string name="pump_fetching_data">tratando de obtener datos de la bomba.</string>
<string name="pump_old_data">TDD: ¡Siguen siendo datos antiguos! No se puede cargar desde la bomba</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Sin cambio de perfil activo</string>
<string name="profile_message">Perfil:\n\nAjuste de tiempo: %1$d\nPorcentaje: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Ningún perfil cargado</string>
<string name="aps_only">Sólo se aplica en modo APS</string>
<string name="last_aps_result_na">¡Último resultado no disponible!</string>
<string name="loop_status_closed">BUCLE CERRADO</string>
<string name="loop_status_open">BUCLE ABIERTO</string>
<string name="loop_status_disabled">BUCLE DESACTIVADO</string>
<string name="aps">APS</string>
<string name="last_run">Última ejecución</string>
<string name="last_enact">Último acto</string>
<string name="today">Hoy</string>
<string name="weighted">ponderado</string>
<string name="target_only_aps_mode">¡Los objetivos sólo se aplican en modo APS!</string>
<string name="no_history">No hay datos históricos</string>
<string name="units_short">U</string>
<string name="temp_target">Objetivo temporal</string>
<string name="until">hasta</string>
<string name="default_range">RANGO POR DEFECTO</string>
<string name="target">objetivo</string>
<string name="rate_duration">Tasa: %1$.2fU/h (%2$.2f%%) \nDuración %3$d min</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">utilisation:</string> <string name="cannula_usage">utilisation:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Envoyer les fichiers journaux d\'aujourd\'hui aux développeurs avec l\'heure actuel. Situation inattendue.</string> <string name="send_logfiles">Envoyer les fichiers journaux d\'aujourd\'hui aux développeurs avec l\'heure actuel. Situation inattendue.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Surveillez et contrôlez AAPS en utilisant votre montre WearOS.</string>
<string name="no_watch_connected">(Pas de montre connectée)</string>
<string name="pump_status">État de la pompe</string>
<string name="loop_status">État de la boucle</string>
<string name="wizard_result">Calc. Assistant :\nInsuline : %1$.2fU\nGlucides : %2$dg</string>
<string name="quick_wizard_not_available">L\'assistant rapide sélectionné n\'est plus disponible, veuillez actualiser l\'écran</string>
<string name="quick_wizard_message">Assistant : %1$s\nInsuline : %2$.2fU\nGlucides : %3$dg</string>
<string name="wear_action_tempt_preset_error">Préréglage inconnu de la cible temp. : %1$s</string>
<string name="wear_action_tempt_cancel_message">Annuler l\'exécution des cibles Temp?</string>
<string name="wear_action_tempt_unit_error">Différentes unités utilisées sur la montre et le téléphone!</string>
<string name="wear_action_tempt_zero_message">Pas de Cible Temp - annuler la cible temporaire en cours?</string>
<string name="wear_action_tempt_min_bg_error">Gly mini hors limite!</string>
<string name="wear_action_tempt_max_bg_error">Gly maxi hors limite!</string>
<string name="wear_action_tempt_manual_range_message">Cible temp.:\nMin: %1$s\nMax : %2$s\nDurée : %3$s</string>
<string name="wear_action_tempt_manual_message">Cible temp.:\nCible: %1$s\nDurée: %2$s</string>
<string name="wear_action_tempt_preset_message">Cible temp.:\nRaison: %1$s\nCible : %2$s\nDurée : %3$s</string>
<string name="no_success">échec - veuillez vérifier le téléphone</string>
<string name="wear_settings">Paramètres Wear</string>
<string name="wearcontrol_title">Commandes depuis la montre</string>
<string name="wearcontrol_summary">Définir les Cibles Temp et entrer les Traitements depuis la montre.</string>
<string name="wear_wizard_settings_summary">Calculs inclus dans le résultat de lAssistant :</string>
<string name="wear_general_settings">Paramètres généraux</string>
<string name="wear_notifysmb_title">Notifier en cas de SMB</string>
<string name="wear_notifysmb_summary">Afficher SMB sur la montre comme un bolus standard.</string>
<string name="wear_custom_watchface_settings">Paramètres du Cadran Personnalisé</string>
<string name="wear_custom_watchface_authorization_title">Autorisation du Cadran Personnalisé</string>
<string name="wear_custom_watchface_authorization_summary">Autoriser le cadran perso chargé à modifier et bloquer certains paramètres d\'affichage de la montre pour un affichage correct du cadran</string>
<string name="wear_custom_watchface">Cadran personnalisé : %1$s</string>
<string name="wear_load_watchface">Charger le cadran</string>
<string name="wear_infos_watchface">Infos Cadran</string>
<string name="wear_export_watchface">Exporter le modèle</string>
<string name="wear_new_custom_watchface_exported">Modèle du cadran personnalisé exporté</string>
<string name="resend_all_data">Renvoyer toutes les données</string>
<string name="open_settings_on_wear">Afficher les Paramètres sur la Montre</string>
<string name="cwf_infos_pref_locked">Liste des préférences verrouillées par le cadran</string>
<string name="cwf_infos_pref_required">Liste des préférences requises pour le cadran</string>
<string name="cwf_infos_view_title">Liste des champs inclus dans le cadran</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Affiche une notification en cours avec un bref aperçu de ce que fait votre Boucle</string> <string name="description_persistent_notification">Affiche une notification en cours avec un bref aperçu de ce que fait votre Boucle</string>
<string name="old_data">DONNÉES ANCIENNES</string> <string name="old_data">DONNÉES ANCIENNES</string>
<string name="pump_fetching_data">tentative de récupération des données de la pompe.</string>
<string name="pump_old_data">DTQ: Données encore anciennes ! Impossible de charger depuis la pompe.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Aucun profil actif!</string>
<string name="profile_message">Profil :\n\nDécalage: %1$d\nPourcentage: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Aucun profil séléctionné</string>
<string name="aps_only">S\'applique uniquement en mode APS!</string>
<string name="last_aps_result_na">Dernier résultat non disponible!</string>
<string name="loop_status_closed">BOUCLE FERMÉE</string>
<string name="loop_status_open">BOUCLE OUVERTE</string>
<string name="loop_status_disabled">BOUCLE DÉSACTIVÉE</string>
<string name="aps">APS</string>
<string name="last_run">Dernière exécution</string>
<string name="last_enact">Dernière injection</string>
<string name="today">Aujourdhui</string>
<string name="weighted">pondération</string>
<string name="target_only_aps_mode">Les cibles ne s\'appliquent qu\'en mode APS!</string>
<string name="no_history">Aucune donnée d\'historique!</string>
<string name="units_short">U</string>
<string name="temp_target">Cibles Temp</string>
<string name="until">jusqu\'à</string>
<string name="default_range">PLAGE PAR DEFAUT</string>
<string name="target">cible</string>
<string name="rate_duration">Taux: %1$.2fU/h (%2$.2f%%) \nDurée: %3$d min</string>
</resources> </resources>

View file

@ -120,11 +120,6 @@
<string name="graph_scale">Skala grafikona</string> <string name="graph_scale">Skala grafikona</string>
<!-- Skins --> <!-- Skins -->
<!-- Iob--> <!-- Iob-->
<!-- Wear-->
<string name="description_wear">Pratite i kontrolirajte AAPS koristeći svoj WearOS sat.</string>
<string name="no_watch_connected">(Sat nije povezan)</string>
<string name="loop_status">Loop status</string>
<string name="wear_action_tempt_preset_message">Trenutni cilj:\nRazlog: %1$s\nCilj: %2$s\nTrajanje: %3$s</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Prikazuje tekuće obavijesti sa kratkim pregledom što loop radi</string> <string name="description_persistent_notification">Prikazuje tekuće obavijesti sa kratkim pregledom što loop radi</string>
</resources> </resources>

View file

@ -53,9 +53,6 @@
<string name="lowres_description">Alacsony felbontás</string> <string name="lowres_description">Alacsony felbontás</string>
<string name="skin">Megjelenés</string> <string name="skin">Megjelenés</string>
<!-- Iob--> <!-- Iob-->
<!-- Wear-->
<string name="wear_settings">Wear beállítások</string>
<string name="wear_general_settings">Általános beállítások</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="old_data">RÉGI ADAT</string> <string name="old_data">RÉGI ADAT</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">uso:</string> <string name="cannula_usage">uso:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Invia agli sviluppatori i file log di oggi e di questo momento. Situazione inaspettata.</string> <string name="send_logfiles">Invia agli sviluppatori i file log di oggi e di questo momento. Situazione inaspettata.</string>
<!-- Wear-->
<string name="wear_shortname">SMWA</string>
<string name="description_wear">Monitora e controlla AAPS usando il tuo smartwatch WearOS.</string>
<string name="no_watch_connected">(Nessuno smartwatch connesso)</string>
<string name="pump_status">Stato micro</string>
<string name="loop_status">Stato loop</string>
<string name="wizard_result">Calc. Wizard:\nInsulina: %1$.2fU\nCHO: %2$dg</string>
<string name="quick_wizard_not_available">Il calcolo rapido selezionato non è più disponibile, aggiorna il riquadro</string>
<string name="quick_wizard_message">QuickWizard: %1$s\nInsulina: %2$.2fU\nCHO: %3$dg</string>
<string name="wear_action_tempt_preset_error">Preset sconosciuto target temporaneo: %1$s</string>
<string name="wear_action_tempt_cancel_message">Cancellare i target temporanei in esecuzione?</string>
<string name="wear_action_tempt_unit_error">Differenti unità usate su smartwatch e telefono!</string>
<string name="wear_action_tempt_zero_message">Nessuno target temporaneo - cancellare i target temporanei in esecuzione?</string>
<string name="wear_action_tempt_min_bg_error">Min-BG fuori range!</string>
<string name="wear_action_tempt_max_bg_error">Max-BG fuori range!</string>
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDurata: %3$s</string>
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDurata: %2$s</string>
<string name="wear_action_tempt_preset_message">Temptarget:\nMotivo: %1$s\nTarget: %2$s\nDurata: %3$s</string>
<string name="no_success">non riuscito - controlla il telefono</string>
<string name="wear_settings">Impostazioni smartwatch</string>
<string name="wearcontrol_title">Controlli da smartwatch</string>
<string name="wearcontrol_summary">Imposta Temp-Target e inserisci trattamenti dallo smartwatch.</string>
<string name="wear_wizard_settings_summary">Calcoli inclusi nel risultato del Calcolatore:</string>
<string name="wear_general_settings">Impostazioni generali</string>
<string name="wear_notifysmb_title">Notifica SMB</string>
<string name="wear_notifysmb_summary">Mostra SMB sullo smartwatch come un bolo standard.</string>
<string name="wear_custom_watchface_settings">Impostazioni watchface personalizzata</string>
<string name="wear_custom_watchface_authorization_title">Autorizzazione watchface personalizzata</string>
<string name="wear_custom_watchface_authorization_summary">Autorizza la watchface personalizzata caricata a cambiare e bloccare alcune delle impostazioni di visualizzazione dell\'orologio per adattarsi al design della watchface</string>
<string name="wear_custom_watchface">Watchface personalizzata: %1$s</string>
<string name="wear_load_watchface">Carica watchface</string>
<string name="wear_infos_watchface">Informazioni watchface</string>
<string name="wear_export_watchface">Esporta template</string>
<string name="wear_new_custom_watchface_exported">Esportato template personalizzato di Watchface</string>
<string name="resend_all_data">Invia di nuovo tutti i dati</string>
<string name="open_settings_on_wear">Apri impostazioni sullo smartwatch</string>
<string name="cwf_infos_pref_locked">Elenco impostazioni bloccate dalla watchface</string>
<string name="cwf_infos_pref_required">Elenco impostazioni richieste per la watchface</string>
<string name="cwf_infos_view_title">Elenco dei campi inclusi nella watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Mostra una notifica persistente con una breve panoramica di ciò che sta facendo il tuo loop</string> <string name="description_persistent_notification">Mostra una notifica persistente con una breve panoramica di ciò che sta facendo il tuo loop</string>
<string name="old_data">DATI VECCHI</string> <string name="old_data">DATI VECCHI</string>
<string name="pump_fetching_data">tentativo di recupero dati dal micro.</string>
<string name="pump_old_data">TDD: Dati ancora vecchi! Non è possibile caricare dal micro.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Nessun cambio profilo attivo!</string>
<string name="profile_message">Profilo:\n\nTimeshift: %1$d\nPercentuale: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Nessun profilo caricato</string>
<string name="aps_only">Si applica solo in modalità APS!</string>
<string name="last_aps_result_na">Ultimo risultato non disponibile!</string>
<string name="loop_status_closed">LOOP CHIUSO</string>
<string name="loop_status_open">LOOP APERTO</string>
<string name="loop_status_disabled">LOOP DISABILITATO</string>
<string name="aps">APS</string>
<string name="last_run">Ultima esecuzione</string>
<string name="last_enact">Ultima attivazione</string>
<string name="today">Oggi</string>
<string name="weighted">ponderato</string>
<string name="target_only_aps_mode">I target si applicano solo in modalità APS!</string>
<string name="no_history">Nessun dato storico!</string>
<string name="units_short">U</string>
<string name="temp_target">Target Temporaneo</string>
<string name="until">fino a</string>
<string name="default_range">RANGE PREDEFINITO</string>
<string name="target">target</string>
<string name="rate_duration">Velocità: %1$.2fU/h (%2$.2f%%) \nDurata %3$d min</string>
</resources> </resources>

View file

@ -286,70 +286,7 @@
<string name="cannula_usage">שימוש:</string> <string name="cannula_usage">שימוש:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">שלח קובצי יומן של היום למפתחים יחד עם זמן זה. מצב לא צפוי.</string> <string name="send_logfiles">שלח קובצי יומן של היום למפתחים יחד עם זמן זה. מצב לא צפוי.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">ניטור ושליטה ב-AndroidAPS באמצעות שעון WearOS.</string>
<string name="no_watch_connected">(השעון לא מחובר)</string>
<string name="pump_status">סטטוס המשאבה</string>
<string name="loop_status">סטטוס הלולאה</string>
<string name="wizard_result">מחשבון: %1$s\n אינס\': %2$.2f יח\'\nפחמ\': %3$d גר\'</string>
<string name="quick_wizard_not_available">האשף המהיר שנבחר אינו זמין, נא לרענן את האריח</string>
<string name="quick_wizard_message">אשף מהיר: %1$s\n אינס\': %2$.2f יח\'\nפחמ\': %3$d גר\'</string>
<string name="wear_action_tempt_preset_error">תצורה לא ידועה של מטרה זמנית: %1$s</string>
<string name="wear_action_tempt_cancel_message">מבטל ערך מטרה זמני נוכחי</string>
<string name="wear_action_tempt_unit_error">יחידות המידה שונות בין הטלפון והשעון!</string>
<string name="wear_action_tempt_zero_message">Zero-Temp-Target - בוטל, הפעלת ערכי מטרה זמניים?</string>
<string name="wear_action_tempt_min_bg_error">ערך הסוכר המינימלי מחוץ לטווח!</string>
<string name="wear_action_tempt_max_bg_error">ערך הסוכר המקסימלי מחוץ לטווח!</string>
<string name="wear_action_tempt_manual_range_message">ע\' מטרה זמני:\nמינ\': %1$s\nמקס\': %2$s\nמשך: %3$s</string>
<string name="wear_action_tempt_manual_message">ע\' מטרה זמני:\nמטרה: %1$s\n משך: %2$s</string>
<string name="wear_action_tempt_preset_message">ע\' מטרה זמני:\nסיבה: %1$s\nמטרה: %2$s\nמשך: %3$s</string>
<string name="no_success">נכשל - נא לבדוק את הטלפון</string>
<string name="wear_settings">הגדרות Wear</string>
<string name="wearcontrol_title">שליטה מהשעון</string>
<string name="wearcontrol_summary">הגדירו ערכי מטרה זמניים וציינו טיפולים מהשעון.</string>
<string name="wear_wizard_settings_summary">חישובים הכלולים בתוצאת האשף:</string>
<string name="wear_general_settings">הגדרות כלליות</string>
<string name="wear_notifysmb_title">דיווח על SMB</string>
<string name="wear_notifysmb_summary">הצג SMB על השעון כמו בולוס סטנדרטי.</string>
<string name="wear_custom_watchface_settings">הגדרות פני שעון מותאמים אישית</string>
<string name="wear_custom_watchface_authorization_title">אישור פני שעון מותאמים אישית</string>
<string name="wear_custom_watchface">פני שעון מותאמים אישית: %1$s</string>
<string name="wear_load_watchface">טעינת פני שעון</string>
<string name="wear_infos_watchface">פני שעון מידע</string>
<string name="wear_export_watchface">ייצוא תבנית</string>
<string name="wear_new_custom_watchface_exported">תבנית פני השעון יוצאה</string>
<string name="resend_all_data">שלח מחדש את כל הנתונים</string>
<string name="open_settings_on_wear">פתיחת הגדרות Wear</string>
<string name="cwf_infos_pref_locked">רשימת העדפות ננעלה ע\"י פני השעון</string>
<string name="cwf_infos_pref_required">רשימת ההעדפות הנדרשת ע\"י פני השעון</string>
<string name="cwf_infos_view_title">רשימת שדות הכלולים בפני השעון</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">מציג הודעה קבועה עם סקירה קצרה של מה שהלולאה שלכם עושה</string> <string name="description_persistent_notification">מציג הודעה קבועה עם סקירה קצרה של מה שהלולאה שלכם עושה</string>
<string name="old_data">נתונים ישנים</string> <string name="old_data">נתונים ישנים</string>
<string name="pump_fetching_data">מנסה לטעון נתונים מהמשאבה.</string>
<string name="pump_old_data">סטטיסטיקות (TDD): נתונים ישנים! לא ניתן לטעון מהמשאבה.</string>
<string name="grams_short">גר\'</string>
<string name="hour_short">ש\'</string>
<string name="no_active_profile">לא הופעלה החלפת פרופיל!</string>
<string name="tdd_line">%1$.2fיח\' %1$.0f%</string>
<string name="no_profile">לא נטען פרופיל</string>
<string name="aps_only">חל רק במצב APS!</string>
<string name="last_aps_result_na">התוצאה האחרונה לא זמינה!</string>
<string name="loop_status_closed">לולאה סגורה</string>
<string name="loop_status_open">לולאה פתוחה</string>
<string name="loop_status_disabled">לולאה מושבתת</string>
<string name="aps">APS</string>
<string name="last_run">ההפעלה האחרונה</string>
<string name="last_enact">נקבעו לאחרונה</string>
<string name="today">היום</string>
<string name="weighted">משוקלל</string>
<string name="target_only_aps_mode">ערכי מטרה חלים רק במצב APS!</string>
<string name="no_history">אין נתוני עבר!</string>
<string name="units_short">יח\'</string>
<string name="temp_target">ערכי מטרה זמניים</string>
<string name="until">עד</string>
<string name="default_range">טווח ברירת מחדל</string>
<string name="target">מטרה</string>
<string name="rate_duration">מינון: %1$.2f יח\'\\שעה (%2$.2f%%) \nמשך: %3$d דק\'</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">사용:</string> <string name="cannula_usage">사용:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">예상치 못한 상황 보고를 위해 오늘의 로그 파일을 개발자에게 전송합니다.</string> <string name="send_logfiles">예상치 못한 상황 보고를 위해 오늘의 로그 파일을 개발자에게 전송합니다.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">WearOS 시계를 사용하여 AAPS를 모니터링하고 제어합니다.</string>
<string name="no_watch_connected">(열결된 워치가 없습니다)</string>
<string name="pump_status">펌프 상태</string>
<string name="loop_status">Loop 상태</string>
<string name="wizard_result">계산. 마법사:\n인슐린:%1$.2fU\n탄수화물: %2$dg</string>
<string name="quick_wizard_not_available">선택한 빠른 마법사를 더 이상 사용할 수 없습니다, 타일을 새로고침 하십시오</string>
<string name="quick_wizard_message">빠른 마법사: %1$s\n인슐린: %2$.2fU\n탄수화물: %3$dg</string>
<string name="wear_action_tempt_preset_error">임시 목표 알 수 없는 사전 설정: %1$s</string>
<string name="wear_action_tempt_cancel_message">임시-목표 실행을 취소하시겠습니까?</string>
<string name="wear_action_tempt_unit_error">워치와 폰과 다른 단위입니다!</string>
<string name="wear_action_tempt_zero_message">제로-임시-목표- 임시-목표 실행을 취소하시겠습니까?</string>
<string name="wear_action_tempt_min_bg_error">최소-BG 범위가 넘었습니다!</string>
<string name="wear_action_tempt_max_bg_error">최대-BG 범위가 넘었습니다!</string>
<string name="wear_action_tempt_manual_range_message">임시 목표:\n최소: %1$s\n최대: %2$s\n기간: %3$s</string>
<string name="wear_action_tempt_manual_message">임시 목표:\n목표: %1$s\n기간: %2$s</string>
<string name="wear_action_tempt_preset_message">임시 목표:\n이유: %1$s\n목표: %2$s\n기간: %3$s</string>
<string name="no_success">성공하지 못했습니다. 폰을 확인하세요</string>
<string name="wear_settings">워치 설정</string>
<string name="wearcontrol_title">워치로 제어하기</string>
<string name="wearcontrol_summary">임시목표와 관리입력을 워치로 설정합니다.</string>
<string name="wear_wizard_settings_summary">마법사 결과에 사용 된 계산:</string>
<string name="wear_general_settings">일반 설정</string>
<string name="wear_notifysmb_title">SMB 알림</string>
<string name="wear_notifysmb_summary">일반 Bolus처럼 워치에 SMB 표시</string>
<string name="wear_custom_watchface_settings">사용자 지정- 워치 페이스 설정</string>
<string name="wear_custom_watchface_authorization_title">사용자 지정 워치 페이스 승인</string>
<string name="wear_custom_watchface_authorization_summary">로드된 사용자 지정 워치 페이스를 승인하여 워치 페이스 디자인에 맞게 일부 시계 화면의 설정을 변경하고 잠급니다</string>
<string name="wear_custom_watchface">사용자 지정 워치 페이스: %1$s</string>
<string name="wear_load_watchface">워치 페이스 로딩하기</string>
<string name="wear_infos_watchface">워치 페이스 정보</string>
<string name="wear_export_watchface">템플릿 내보내기</string>
<string name="wear_new_custom_watchface_exported">사용자 지정 워치 페이스 템플릿 내보내기</string>
<string name="resend_all_data">모든 데이터 다시 보내기</string>
<string name="open_settings_on_wear">워치에서 설정 열기</string>
<string name="cwf_infos_pref_locked">워치 페이스에 의해 잠긴 선호 목록</string>
<string name="cwf_infos_pref_required">워치 페이스에 필요한 선호 목록</string>
<string name="cwf_infos_view_title">워치 페이스에 포함된 필드 목록</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Loop가 어떤 작동하는지에 대한 간략한 개요를 연속 알림으로 보여줍니다.</string> <string name="description_persistent_notification">Loop가 어떤 작동하는지에 대한 간략한 개요를 연속 알림으로 보여줍니다.</string>
<string name="old_data">오래된 데이터</string> <string name="old_data">오래된 데이터</string>
<string name="pump_fetching_data">펌프에서 데이터를 가져오려고 합니다.</string>
<string name="pump_old_data">TDD: 여전히 오래된 데이터입니다! 펌프에서 로드할 수 없습니다.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">활성화된 프로파일 스위치가 없습니다!</string>
<string name="profile_message">프로파일:\n\n시간 변화: %1$d\n백분율: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">프로파일이 로딩되지 않았습니다</string>
<string name="aps_only">APS 모드에서만 이용 가능합니다!</string>
<string name="last_aps_result_na">지난 결과를 이용할 수 없습니다!</string>
<string name="loop_status_closed">CLOSED LOOP</string>
<string name="loop_status_open">OPEN LOOP</string>
<string name="loop_status_disabled">LOOP 비활성화</string>
<string name="aps">APS</string>
<string name="last_run">마지막 실행</string>
<string name="last_enact">마지막 실행</string>
<string name="today">오늘</string>
<string name="weighted">몸무게</string>
<string name="target_only_aps_mode">목표는 APS 모드에서만 적용 가능합니다!</string>
<string name="no_history">기록이 없습니다!</string>
<string name="units_short">U</string>
<string name="temp_target">임시 목표</string>
<string name="until">까지</string>
<string name="default_range">기본 범위</string>
<string name="target">목표</string>
<string name="rate_duration">비율: %1$.2fU/h (%2$.2f%%) \n기간%3$d 분</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">naudojimas:</string> <string name="cannula_usage">naudojimas:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Siųsti šios dienos žurnalo įrašus kūrėjams dabar. Netikėta situacija.</string> <string name="send_logfiles">Siųsti šios dienos žurnalo įrašus kūrėjams dabar. Netikėta situacija.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Stebėti ir kontroliuoti AndroidAPS naudojant WearOS laikrodį.</string>
<string name="no_watch_connected">(nėra prijungto laikrodžio)</string>
<string name="pump_status">Pompos statusas</string>
<string name="loop_status">Ciklo statusas</string>
<string name="wizard_result">Wizard asistento skaičiuotuvas:\nInsulinas: %1$.2fU\nAngliavandeniai: %2$dg</string>
<string name="quick_wizard_not_available">Pasirinktas greitasis patarėjas nebepasiekiamas, atnaujinkite valdiklį</string>
<string name="quick_wizard_message">QuickWizard asistentas: %1$s\nInsulinas: %2$.2fU\nAngliavandeniai: %3$dg</string>
<string name="wear_action_tempt_preset_error">Nežinomas laikino tikslo ruošinys: %1$s</string>
<string name="wear_action_tempt_cancel_message">Atšaukti laikinus tikslus?</string>
<string name="wear_action_tempt_unit_error">Laikrodyje ir telefone naudojami skirtingi vienetai!</string>
<string name="wear_action_tempt_zero_message">Zero-Temp-Target - atšaukti laikinus tikslus?</string>
<string name="wear_action_tempt_min_bg_error">Min. cukraus kiekis nepatenka į diapozoną!</string>
<string name="wear_action_tempt_max_bg_error">Max. cukraus kiekis nepatenka į diapozoną!</string>
<string name="wear_action_tempt_manual_range_message">Laikinas tikslas:\nMin: %1$s\nMax: %2$s\nLaikotarpis: %3$s</string>
<string name="wear_action_tempt_manual_message">Laikinas tikslas:\nTikslas: %1$s\nLaikotarpis: %2$s</string>
<string name="wear_action_tempt_preset_message">LT:\npriežastis: %1$s\ntikslas: %2$s\ntrukmė: %3$s</string>
<string name="no_success">Bandymas nesėkmingas - pasitikrinkite telefoną</string>
<string name="wear_settings">Išmaniojo laikrodžio nustatymai</string>
<string name="wearcontrol_title">Laikrodžio valdikliai</string>
<string name="wearcontrol_summary">Nustatyti Laikinus Tikslus ir įvesti terapinius įrašus iš laikrodžio.</string>
<string name="wear_wizard_settings_summary">Skaičiavimai, įtraukti į Patarėjo rezultatą:</string>
<string name="wear_general_settings">Bendrieji nustatymai</string>
<string name="wear_notifysmb_title">Pranešti apie SMB</string>
<string name="wear_notifysmb_summary">Rodyti SMB laikrodyje kaip standartinį bolusą.</string>
<string name="wear_custom_watchface_settings">Pasirinktiniai laikrodžio ekrano nustatymai</string>
<string name="wear_custom_watchface_authorization_title">Pasirinktinė laikrodžio ekrano autorizacija</string>
<string name="wear_custom_watchface_authorization_summary">Leisti įkeltam pasirinktiniam ekranui keisti ir užrakinti kai kuriuos laikrodžio nustatymus, kad jie atitiktų ekrano dizainą</string>
<string name="wear_custom_watchface">Pasirinktinis ekranas: %1$s</string>
<string name="wear_load_watchface">Įkelti laikrodžio ekraną</string>
<string name="wear_infos_watchface">Ekrano info</string>
<string name="wear_export_watchface">Eksportuoti šabloną</string>
<string name="wear_new_custom_watchface_exported">Pasirinktinio ekrano šablonas eksportuotas</string>
<string name="resend_all_data">Pakartotinai siųsti visus duomenis</string>
<string name="open_settings_on_wear">Atidaryti išmaniojo laikrodžio nustatymus</string>
<string name="cwf_infos_pref_locked">Užrakintų nustatymų sąrašas</string>
<string name="cwf_infos_pref_required">Ekranui reikalingų nustatymų sąrašas</string>
<string name="cwf_infos_view_title">Į ekraną įtrauktų laukų sąrašas</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Rodo atsinaujinančius pranešimus su trumpa Ciklo veiklos apžvalga</string> <string name="description_persistent_notification">Rodo atsinaujinančius pranešimus su trumpa Ciklo veiklos apžvalga</string>
<string name="old_data">SENI DUOMENYS</string> <string name="old_data">SENI DUOMENYS</string>
<string name="pump_fetching_data">Bandoma įkelti pompos duomenis</string>
<string name="pump_old_data">BPD: seni duomenys! Nepavyksta nuskaityti pompos.</string>
<string name="grams_short">g</string>
<string name="hour_short">val</string>
<string name="no_active_profile">Neparinktas aktyvus profilis!</string>
<string name="profile_message">Profilis:\n\nLaiko perstūmimas: %1$\nProcentai: %2$d%%\"</string>
<string name="tdd_line">%1$.2fv %1$.0f%%</string>
<string name="no_profile">Profilis neįkeltas</string>
<string name="aps_only">Tik APS režime!</string>
<string name="last_aps_result_na">Paskutinis rezultatas nežinomas!</string>
<string name="loop_status_closed">UŽDARAS CIKLAS</string>
<string name="loop_status_open">ATVIRAS CIKLAS</string>
<string name="loop_status_disabled">CIKLAS IŠJUNGTAS</string>
<string name="aps">APS</string>
<string name="last_run">Paskutinis veiksmas</string>
<string name="last_enact">Paskutinis veiksmas</string>
<string name="today">Šiandien</string>
<string name="weighted">svertinis</string>
<string name="target_only_aps_mode">Tikslai galioja tik APS režime!</string>
<string name="no_history">Nėra istorijos!</string>
<string name="units_short">v</string>
<string name="temp_target">Laikinas tikslas</string>
<string name="until">iki</string>
<string name="default_range">NUMATYTASIS DIAPAZONAS</string>
<string name="target">tikslas</string>
<string name="rate_duration">Dydis: %1$.2fv/val (%2$.2f%%) \nTrukmė %3$d min</string>
</resources> </resources>

View file

@ -156,7 +156,7 @@
<!-- Actions --> <!-- Actions -->
<string name="actions">Handlinger</string> <string name="actions">Handlinger</string>
<string name="description_actions">Hurtigknapper for rask tilgang til ofte brukte funksjoner</string> <string name="description_actions">Hurtigknapper for rask tilgang til ofte brukte funksjoner</string>
<string name="actions_shortname">ACT</string> <string name="actions_shortname">HNDL</string>
<string name="tempbasal_button">Midlertidig basal</string> <string name="tempbasal_button">Midlertidig basal</string>
<string name="extended_bolus_button">Forlenget bolus</string> <string name="extended_bolus_button">Forlenget bolus</string>
<string name="extended_bolus_cancel_button">Avbryt forlenget bolus</string> <string name="extended_bolus_cancel_button">Avbryt forlenget bolus</string>
@ -174,18 +174,18 @@
<string name="patch_pump">Pumpe</string> <string name="patch_pump">Pumpe</string>
<!-- Overview --> <!-- Overview -->
<string name="show_statuslights">Vis statusindikatorer på hjem-skjermen</string> <string name="show_statuslights">Vis statusindikatorer på hjem-skjermen</string>
<string name="statuslights_cage_warning">Terskel for advarsel om alder på slangesett [h]</string> <string name="statuslights_cage_warning">Terskel for advarsel om alder på slangesett [t]</string>
<string name="statuslights_cage_critical">Terskel for kritisk alder på slangesett [h]</string> <string name="statuslights_cage_critical">Terskel for kritisk alder på slangesett [t]</string>
<string name="statuslights_iage_warning">Terskel for advarsel, alder på insulin [h]</string> <string name="statuslights_iage_warning">Terskel for advarsel, alder på insulin [t]</string>
<string name="statuslights_iage_critical">Terskel for kritisk alder på insulin [h]</string> <string name="statuslights_iage_critical">Terskel for kritisk alder på insulin [t]</string>
<string name="statuslights_sage_warning">Terskel for advarsel, alder på CGM [h]</string> <string name="statuslights_sage_warning">Terskel for advarsel, alder på sensor [t]</string>
<string name="statuslights_sage_critical">Terskel for kritisk alder på CGM [h]</string> <string name="statuslights_sage_critical">Terskel for kritisk alder på sensor [t]</string>
<string name="statuslights_sbat_warning">Terskel for advarsel, batterinivå for sensor [%]</string> <string name="statuslights_sbat_warning">Terskel for advarsel, batterinivå for sensor [%]</string>
<string name="statuslights_sbat_critical">Terskel for kritisk batterinivå for sensor [%]</string> <string name="statuslights_sbat_critical">Terskel for kritisk batterinivå for sensor [%]</string>
<string name="statuslights_bage_warning">Terskel for advarsel, batterialder for pumpe [h]</string> <string name="statuslights_bage_warning">Terskel for advarsel, batterialder for pumpe [t]</string>
<string name="statuslights_bage_critical">Terskel for kritisk batterialder for pumpe [h]</string> <string name="statuslights_bage_critical">Terskel for kritisk batterialder for pumpe [t]</string>
<string name="statuslights_res_warning">Terskel for advarsel, insulinreservoar [U]</string> <string name="statuslights_res_warning">Terskel for advarsel, insulinreservoar [E]</string>
<string name="statuslights_res_critical">Terskel for kritisk insulinreservoar [U]</string> <string name="statuslights_res_critical">Terskel for kritisk insulinreservoar [E]</string>
<string name="statuslights_bat_warning">Terskel for advarsel, batterinivå for pumpe [%]</string> <string name="statuslights_bat_warning">Terskel for advarsel, batterinivå for pumpe [%]</string>
<string name="statuslights_bat_critical">Terskel for kritisk batterinivå for pumpe [%]</string> <string name="statuslights_bat_critical">Terskel for kritisk batterinivå for pumpe [%]</string>
<string name="statuslights_copy_ns">Kopier innstillingene fra NS</string> <string name="statuslights_copy_ns">Kopier innstillingene fra NS</string>
@ -242,11 +242,11 @@
<string name="high_mark">Høy verdi</string> <string name="high_mark">Høy verdi</string>
<string name="short_tabtitles">Korte navn i menyfaner</string> <string name="short_tabtitles">Korte navn i menyfaner</string>
<string name="overview_show_notes_field_in_dialogs_title">Vis merknadsfelt i dialogvindu for boluskalkulator</string> <string name="overview_show_notes_field_in_dialogs_title">Vis merknadsfelt i dialogvindu for boluskalkulator</string>
<string name="deliverpartofboluswizard">Bolusveiviser utfører beregninger, men bare denne del av beregnet insulin leveres. Nyttig ved bruk av SMB-algoritmen.</string> <string name="deliverpartofboluswizard">Boluskalkulator utfører beregninger, men bare denne del av beregnet insulin leveres. Nyttig ved bruk av SMB-algoritmen.</string>
<string name="deliver_part_of_boluswizard_reset_time">Gi full bolus (100 %) dersom blodsukker er eldre enn</string> <string name="deliver_part_of_boluswizard_reset_time">Gi full bolus (100 %) dersom blodsukker er eldre enn</string>
<string name="enable_bolus_advisor">Aktiver bolusveileder</string> <string name="enable_bolus_advisor">Aktiver bolusveileder</string>
<string name="enable_bolus_advisor_summary">Bruk en påminnelse om å spise senere istedet for boluskalkulatorens resultat når blodsukker er høyt (\"pre-bolus\")</string> <string name="enable_bolus_advisor_summary">Bruk en påminnelse om å spise senere istedet for boluskalkulatorens resultat når blodsukker er høyt (\"pre-bolus\")</string>
<string name="enablesuperbolus">Aktiver superbolus i veiviser</string> <string name="enablesuperbolus">Aktiver superbolus i boluskalkulator</string>
<string name="enablesuperbolus_summary">Aktiver superbolus-funksjonen i boluskalkulatoren. Ikke aktiver denne før du vet hvordan den fungerer. DEN KAN LEDE TIL EN OVERDOSERING AV INSULIN HVIS DEN BRUKES UKRITISK!</string> <string name="enablesuperbolus_summary">Aktiver superbolus-funksjonen i boluskalkulatoren. Ikke aktiver denne før du vet hvordan den fungerer. DEN KAN LEDE TIL EN OVERDOSERING AV INSULIN HVIS DEN BRUKES UKRITISK!</string>
<string name="enablebolusreminder">Aktiver boluspåminnelse</string> <string name="enablebolusreminder">Aktiver boluspåminnelse</string>
<string name="enablebolusreminder_summary">Bruk en påminnelse for å sette bolusdosen senere med boluskalkulatoren («post bolus»)</string> <string name="enablebolusreminder_summary">Bruk en påminnelse for å sette bolusdosen senere med boluskalkulatoren («post bolus»)</string>
@ -285,72 +285,7 @@
<string name="cannula_usage">bruk:</string> <string name="cannula_usage">bruk:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Send dagens loggfiler og tidspunkt til utviklere. Uventet situasjon oppstod.</string> <string name="send_logfiles">Send dagens loggfiler og tidspunkt til utviklere. Uventet situasjon oppstod.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Overvåke og kontrollere AAPS ved hjelp av WearOS-klokken.</string>
<string name="no_watch_connected">(Ingen klokke tilkoblet)</string>
<string name="pump_status">Pumpestatus</string>
<string name="loop_status">Loopstatus</string>
<string name="wizard_result">Boluskalkulator:\nInsulin: %1$.2fE\nKarbo: %2$dg</string>
<string name="quick_wizard_not_available">Den valgte hurtigknappen er ikke lenger tilgjengelig, oppdater klokkeflis</string>
<string name="quick_wizard_message">Hurtigknapp: %1$s\ninsulin: %2$.2fE\nKarbo: %3$dg</string>
<string name="wear_action_tempt_preset_error">Ukjent forhåndsinnstilling midl. mål: %1$s</string>
<string name="wear_action_tempt_cancel_message">Avbryt gjeldende midl. mål?</string>
<string name="wear_action_tempt_unit_error">Forskjellige enheter brukt på klokke og telefon!</string>
<string name="wear_action_tempt_zero_message">Null-midl.mål - skal gjeldende midl. mål avbrytes?</string>
<string name="wear_action_tempt_min_bg_error">Min-BS utenfor område!</string>
<string name="wear_action_tempt_max_bg_error">Maks-BS utenfor område!</string>
<string name="wear_action_tempt_manual_range_message">Midl. mål:\nMin: %1$s\nMaks: %2$s\nVarighet: %3$s</string>
<string name="wear_action_tempt_manual_message">Midl. mål:\nMål: %1$s\nVarighet: %2$s</string>
<string name="wear_action_tempt_preset_message">Midl. mål:\nÅrsak: %1$s\nMål: %2$s\nVarighet: %3$s</string>
<string name="no_success">feilet - sjekk telefonen</string>
<string name="wear_settings">Klokkeinnstillinger</string>
<string name="wearcontrol_title">Kontroller fra klokke</string>
<string name="wearcontrol_summary">Sett midl. mål og angi behandlinger fra klokken.</string>
<string name="wear_wizard_settings_summary">Beregninger inkludert i resultatet fra kalkulator:</string>
<string name="wear_general_settings">Generelle innstillinger</string>
<string name="wear_notifysmb_title">Varsle ved SMB</string>
<string name="wear_notifysmb_summary">Vis SMB på klokken som en standard bolus.</string>
<string name="wear_custom_watchface_settings">Innstillinger for tilpasset klokkebakgrunn</string>
<string name="wear_custom_watchface_authorization_title">Godkjenning for tilpasset klokkebakgrunn</string>
<string name="wear_custom_watchface_authorization_summary">Godkjenne at tilpasset klokkebakgrunn endrer AAPS- og klokkeinnstillinger i henhold til klokkebakgrunnens design</string>
<string name="wear_custom_watchface">Tilpasset klokkebakgrunn: %1$s</string>
<string name="wear_load_watchface">Last inn klokkebakgrunn</string>
<string name="wear_infos_watchface">Info urskive</string>
<string name="wear_export_watchface">Eksporter mal</string>
<string name="wear_new_custom_watchface_exported">Tilpasset klokkebakgrunn eksportert</string>
<string name="resend_all_data">Send alle data på nytt</string>
<string name="open_settings_on_wear">Åpne Innstillinger på klokken</string>
<string name="cwf_infos_pref_locked">Liste over forhåndsvalg låst av urskive</string>
<string name="cwf_infos_pref_required">Liste over innstillinger som kreves av klokkebakgrunnen</string>
<string name="cwf_infos_view_title">Liste over felt som er inkludert i urskive</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Viser en konstant melding med en kort oppsummering av hva loop gjør</string> <string name="description_persistent_notification">Viser en konstant melding med en kort oppsummering av hva loop gjør</string>
<string name="old_data">GAMLE DATA</string> <string name="old_data">GAMLE DATA</string>
<string name="pump_fetching_data">prøver å lese data fra pumpen.</string>
<string name="pump_old_data">TDD: Fortsatt gamle data! Kan ikke lese fra pumpe.</string>
<string name="grams_short">g</string>
<string name="hour_short">t</string>
<string name="no_active_profile">Det er ikke angitt noen aktiv profil!</string>
<string name="profile_message">Profil:\n\nTidsforskyving: %1$d\nProsent: %2$d%%</string>
<string name="tdd_line">%1$.2fE %1$.0f%%</string>
<string name="no_profile">Ingen profil valgt</string>
<string name="aps_only">Bare bruk i APS-modus!</string>
<string name="last_aps_result_na">Siste resultat ikke tilgjengelig!</string>
<string name="loop_status_closed">LUKKET LOOP</string>
<string name="loop_status_open">ÅPEN LOOP</string>
<string name="loop_status_disabled">LOOP DEAKTIVERT</string>
<string name="aps">APS</string>
<string name="last_run">Siste beregning</string>
<string name="last_enact">Siste utført</string>
<string name="today">Idag</string>
<string name="weighted">vektlagt</string>
<string name="target_only_aps_mode">Mål gjelder bare i APS-modus!</string>
<string name="no_history">Ingen historikkdata!</string>
<string name="units_short">E</string>
<string name="temp_target">Midl. mål</string>
<string name="until">inntil</string>
<string name="default_range">STANDARD OMRÅDE</string>
<string name="target">målverdi</string>
<string name="rate_duration">Tilførsel: %1$.2fE/t (%2$.2f%%) \nVarighet %3$d min</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">gebruik:</string> <string name="cannula_usage">gebruik:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Logboekbestanden van vandaag verzenden aan ontwikkelaars samen met de onverwachte situatie.</string> <string name="send_logfiles">Logboekbestanden van vandaag verzenden aan ontwikkelaars samen met de onverwachte situatie.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Monitor en bedien AAPS met uw WearOS horloge.</string>
<string name="no_watch_connected">(Geen horloge verbonden)</string>
<string name="pump_status">Pomp status</string>
<string name="loop_status">Loop status</string>
<string name="wizard_result">Reken. Wizard:\nInsuline: %1$.2fE\nKoolhy.: %2$dg</string>
<string name="quick_wizard_not_available">Geselecteerde QuickWizard is niet meer beschikbaar, vernieuw uw tegel</string>
<string name="quick_wizard_message">QuickWizard: %1$s\nInsuline: %2$.2fE\nKoolhy.: %3$dg</string>
<string name="wear_action_tempt_preset_error">Tijdelijke doel onbekende preset: %1$s</string>
<string name="wear_action_tempt_cancel_message">Huidige tijdelijk streefdoel annuleren?</string>
<string name="wear_action_tempt_unit_error">Verschillende eenheden gebruikt op horloge en telefoon!</string>
<string name="wear_action_tempt_zero_message">Tijdelijk streefdoel 0 minuten, huidige tijdelijk streefdoel annuleren?</string>
<string name="wear_action_tempt_min_bg_error">Min BG buiten bereik!</string>
<string name="wear_action_tempt_max_bg_error">Max BG buiten bereik!</string>
<string name="wear_action_tempt_manual_range_message">Tijdelijk streefdoel:\nMin: %1$s\nMax: %2$s\nDuur: %3$s</string>
<string name="wear_action_tempt_manual_message">Tijdelijk streefdoel:\nDoel: %1$s\nDuur: %2$s</string>
<string name="wear_action_tempt_preset_message">Tijdelijk streefdoel:\nReden: %1$s\nDoel: %2$s\nDuur: %3$s</string>
<string name="no_success">Niet geslaagd - controleer de telefoon</string>
<string name="wear_settings">Wear instellingen</string>
<string name="wearcontrol_title">Bedieningen via horloge</string>
<string name="wearcontrol_summary">Stel tijdelijke doelen en bolussen in vanop je horloge.</string>
<string name="wear_wizard_settings_summary">Berekeningen inclusief in het resultaat van de wizard</string>
<string name="wear_general_settings">Algemene instellingen</string>
<string name="wear_notifysmb_title">Waarschuw bij SMB</string>
<string name="wear_notifysmb_summary">Toon SMB op horloge zoals gewone bolussen.</string>
<string name="wear_custom_watchface_settings">Aanpasbare Wijzerplaat Instellingen</string>
<string name="wear_custom_watchface_authorization_title">Aanpasbare Wijzerplaat Autorisatie</string>
<string name="wear_custom_watchface_authorization_summary">Sta geladen aanpasbare wijzerplaat toe om sommige weergave-instellingen van horloge te wijzigen en te vergrendelen voor het ontwerp van de wijzerplaat</string>
<string name="wear_custom_watchface">Aanpasbare Watchface: %1$s</string>
<string name="wear_load_watchface">Laad Watchface</string>
<string name="wear_infos_watchface">Watchface informatie</string>
<string name="wear_export_watchface">Exporteer template</string>
<string name="wear_new_custom_watchface_exported">Aanpasbare watchface template geëxporteerd</string>
<string name="resend_all_data">Update Wear gegevens</string>
<string name="open_settings_on_wear">Open instellingen op Wear</string>
<string name="cwf_infos_pref_locked">Lijst met instellingen die zijn vergrendeld door watchface</string>
<string name="cwf_infos_pref_required">Lijst met instellingen vereist voor watchface</string>
<string name="cwf_infos_view_title">Lijst van velden opgenomen in de watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Toont een permanente melding met een beknopt overzicht van hetgeen de Loop momenteel doet</string> <string name="description_persistent_notification">Toont een permanente melding met een beknopt overzicht van hetgeen de Loop momenteel doet</string>
<string name="old_data">Oude gegevens</string> <string name="old_data">Oude gegevens</string>
<string name="pump_fetching_data">proberen gegevens van de pomp op te halen.</string>
<string name="pump_old_data">TDD: Nog steeds oude gegevens! Kan niet laden van de pomp.</string>
<string name="grams_short">g</string>
<string name="hour_short">u</string>
<string name="no_active_profile">Geen actieve profielwissel!</string>
<string name="profile_message">Profiel:\n\nTijdverschuiving: %1$d\nPercentage: %2$d%%\"</string>
<string name="tdd_line">%1$.2fE %1$.0f%%</string>
<string name="no_profile">Geen profiel geladen</string>
<string name="aps_only">Alleen gebruiken in de APS modus!</string>
<string name="last_aps_result_na">Laatste resultaat niet beschikbaar!</string>
<string name="loop_status_closed">GESLOTEN LOOP</string>
<string name="loop_status_open">OPEN LOOP</string>
<string name="loop_status_disabled">LOOP UITGESCHAKELD</string>
<string name="aps">APS</string>
<string name="last_run">Laatst uitgevoerd</string>
<string name="last_enact">Laatste uitvoering</string>
<string name="today">Vandaag</string>
<string name="weighted">gewogen</string>
<string name="target_only_aps_mode">Streefdoelen zijn alleen van toepassing in de APS modus!</string>
<string name="no_history">Geen geschiedenisgegevens!</string>
<string name="units_short">E</string>
<string name="temp_target">Tijdelijk streefdoel</string>
<string name="until">tot</string>
<string name="default_range">Standaard streefbereik</string>
<string name="target">streefwaarde</string>
<string name="rate_duration">Basaal: %1$.2fE/uur (%2$.2f%%) \nDuur %3$d min</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">użytkowanie:</string> <string name="cannula_usage">użytkowanie:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Wyślij dzisiejsze pliki logów razem z datą i czasem do programistów. Nieoczekiwana sytuacja.</string> <string name="send_logfiles">Wyślij dzisiejsze pliki logów razem z datą i czasem do programistów. Nieoczekiwana sytuacja.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Monitoruj i steruj AAPS używając zegarka z WearOS.</string>
<string name="no_watch_connected">(Brak połączonego zegarka)</string>
<string name="pump_status">Status pompy</string>
<string name="loop_status">Status pętli</string>
<string name="wizard_result">Kalkulator:\nInsulina: %1$.2fU\nWęgle: %2$dg</string>
<string name="quick_wizard_not_available">Wybrany szybki bolus nie jest już dostępny, odśwież swój kafelek</string>
<string name="quick_wizard_message">Szybki bolus: %1$s\nInsulina: %2$.2fU\nWęgle: %3$dg</string>
<string name="wear_action_tempt_preset_error">Nieznane ustawienie celu tymczasowego: %1$s</string>
<string name="wear_action_tempt_cancel_message">Anulować bieżący cel tymczasowy?</string>
<string name="wear_action_tempt_unit_error">Różne jednostki używane na zegarku i telefonie!</string>
<string name="wear_action_tempt_zero_message">Zerowy cel tymczasowy - anulować bieżący cel tymczasowy?</string>
<string name="wear_action_tempt_min_bg_error">Min-BG poza zakresem!</string>
<string name="wear_action_tempt_max_bg_error">Max-BG poza zakresem!</string>
<string name="wear_action_tempt_manual_range_message">Cel tymczasowy:\nMin: %1$s\nMax: %2$s\nCzas trwania: %3$s</string>
<string name="wear_action_tempt_manual_message">Cel tymczasowy:\nCel: %1$s\nCzas trwania: %2$s</string>
<string name="wear_action_tempt_preset_message">Cel tymczasowy:\nPowód: %1$s\nCel: %2$s\nCzas trwania: %3$s</string>
<string name="no_success">nie udało się - proszę sprawdzić telefon</string>
<string name="wear_settings">Ustawienia Wear</string>
<string name="wearcontrol_title">Sterowanie z zegarka</string>
<string name="wearcontrol_summary">Ustawiaj wartości docelowe i wprowadzaj leczenie z zegarka.</string>
<string name="wear_wizard_settings_summary">Obliczenia uwzględnione w wynikach kreatora:</string>
<string name="wear_general_settings">Ustawienia ogólne</string>
<string name="wear_notifysmb_title">Powiadom na SMB</string>
<string name="wear_notifysmb_summary">Pokaż SMB na zegarku jak bolus standardowy.</string>
<string name="wear_custom_watchface_settings">Ustawienia niestandardowej tarczy</string>
<string name="wear_custom_watchface_authorization_title">Uprawnienia niestandardowej tarczy</string>
<string name="wear_custom_watchface_authorization_summary">Upoważnij załadowaną niestandardową tarczę zegarka, aby mogła zmieniać i zablokować niektóre ustawienia wyświetlacza zegarka w celu dopasowania ich do tarczy</string>
<string name="wear_custom_watchface">Niestandardowa tarcza: %1$s</string>
<string name="wear_load_watchface">Załaduj Tarczę</string>
<string name="wear_infos_watchface">O tarczy</string>
<string name="wear_export_watchface">Eksportuj szablon</string>
<string name="wear_new_custom_watchface_exported">Szablon tarczy niestandardowej wyeksportowany</string>
<string name="resend_all_data">Prześlij ponownie wszystkie dane</string>
<string name="open_settings_on_wear">Otwórz ustawienia dla Wear</string>
<string name="cwf_infos_pref_locked">Lista opcji zablokowanych przez tarczę</string>
<string name="cwf_infos_pref_required">Lista opcji wymaganych przez tarczę</string>
<string name="cwf_infos_view_title">Lista pól dołączonych do tarczy</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Wyświetla bieżące powiadomienia z krótkim omówieniem działania pętli</string> <string name="description_persistent_notification">Wyświetla bieżące powiadomienia z krótkim omówieniem działania pętli</string>
<string name="old_data">NIEAKTUALNE DANE</string> <string name="old_data">NIEAKTUALNE DANE</string>
<string name="pump_fetching_data">próbuję pobrać dane z pompy.</string>
<string name="pump_old_data">TDD: Nadal stare dane! Nie można załadować z pompy.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Nie ustawiono aktywnego profilu!</string>
<string name="profile_message">Profil:\n\nZmiana czasu: %1$d\nProcent: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Nie załadowano profilu</string>
<string name="aps_only">Stosuje się tylko w trybie APS!</string>
<string name="last_aps_result_na">Ostatni wynik niedostępny!</string>
<string name="loop_status_closed">ZAMKNIĘTA PĘTLA</string>
<string name="loop_status_open">OTWARTA PĘTLA</string>
<string name="loop_status_disabled">PĘTLA WYŁĄCZONA</string>
<string name="aps">APS</string>
<string name="last_run">Ostatnie uruchomienie</string>
<string name="last_enact">Ostatnie działanie</string>
<string name="today">Dziś</string>
<string name="weighted">ważone</string>
<string name="target_only_aps_mode">Cele mają zastosowanie tylko w trybie APS!</string>
<string name="no_history">Brak danych historycznych!</string>
<string name="units_short">U</string>
<string name="temp_target">Cel tymczasowy</string>
<string name="until">do</string>
<string name="default_range">ZAKRES DOMYŚLNY</string>
<string name="target">cel</string>
<string name="rate_duration">Dawka: %1$.2fU/h (%2$.2f%%) \nCzas trwania %3$d min</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">Uso:</string> <string name="cannula_usage">Uso:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Enviar os ficheiros de registo do dia de hoje para os programadores. Situação inesperada.</string> <string name="send_logfiles">Enviar os ficheiros de registo do dia de hoje para os programadores. Situação inesperada.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Monitore e controle AndroidAPS usando seu relógio WearOS.</string>
<string name="no_watch_connected">(Nenhum relógio conectado)</string>
<string name="pump_status">Estado da Bomba</string>
<string name="loop_status">Status do loop</string>
<string name="wizard_result">Calculadora:\nInsulin: %1$.2fU\nCarbs: %2$dg</string>
<string name="quick_wizard_not_available">O assistente rápido selecionado não está mais disponível, atualize seu atalho</string>
<string name="quick_wizard_message">Assistente rápido: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
<string name="wear_action_tempt_preset_error">Alvo temporário pré-definido desconhecido: %1$s</string>
<string name="wear_action_tempt_cancel_message">Cancelando Alvos temporários em execução?</string>
<string name="wear_action_tempt_unit_error">Unidades diferentes usadas no relógio e telefone!</string>
<string name="wear_action_tempt_zero_message">Desligar alvo temporário - cancelando Alvos temporários atuais?</string>
<string name="wear_action_tempt_min_bg_error">Glicemia mínima fora do alvo!</string>
<string name="wear_action_tempt_max_bg_error">Glicemia maxima fora da meta!</string>
<string name="wear_action_tempt_manual_range_message">Alvo temporário:\nMin: %1$s\nMax: %2$s\nDuração: %3$s</string>
<string name="wear_action_tempt_manual_message">Alvo temporário:\nTarget: %1$s\nDuration: %2$s</string>
<string name="wear_action_tempt_preset_message">Tempo no alvo:\nMotivo: %1$s\nAlvo: %2$s\nDuração: %3$s</string>
<string name="no_success">não foi bem sucedido - por favor, verifique o telefone</string>
<string name="wear_settings">Definições Wear</string>
<string name="wearcontrol_title">Controles do Relógio</string>
<string name="wearcontrol_summary">Definir Alvo-Temp and inserir Tratamentos do relógio.</string>
<string name="wear_wizard_settings_summary">Resultado cálculos incluídos no Assistente:</string>
<string name="wear_general_settings">Configurações gerais</string>
<string name="wear_notifysmb_title">Notificar no SMB</string>
<string name="wear_notifysmb_summary">Mostrar SMB no relogio como bolus normal.</string>
<string name="wear_custom_watchface_settings">Configurações personalizadas de Watchface</string>
<string name="wear_custom_watchface_authorization_title">Autorização de Watchface Personalizada</string>
<string name="wear_custom_watchface_authorization_summary">Autorizar watchface carregado e carregado para alterar e bloquear algumas configurações de relógio para o design do watchface</string>
<string name="wear_custom_watchface">Watchface Personalizado: %1$s</string>
<string name="wear_load_watchface">Carregar Watchface</string>
<string name="wear_infos_watchface">Infos Watchface</string>
<string name="wear_export_watchface">Exportar modelo</string>
<string name="wear_new_custom_watchface_exported">Modelo de watchface personalizado exportado</string>
<string name="resend_all_data">Reenviar Todos os Dados</string>
<string name="open_settings_on_wear">Abrir Definições em Wear</string>
<string name="cwf_infos_pref_locked">Lista de preferências bloqueadas pela Watchface</string>
<string name="cwf_infos_pref_required">Lista de preferências solicitadas pela Watchface</string>
<string name="cwf_infos_view_title">Lista de campos incluídos na Watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Mostra uma notificação em curso com um breve resumo do que o seu loop está a fazer</string> <string name="description_persistent_notification">Mostra uma notificação em curso com um breve resumo do que o seu loop está a fazer</string>
<string name="old_data">DADOS ANTIGOS</string> <string name="old_data">DADOS ANTIGOS</string>
<string name="pump_fetching_data">tentando buscar dados da Bomba.</string>
<string name="pump_old_data">TDD: Dados ainda antigos! Não é possível carregar da bomba.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Nenhum perfil ativo definido!</string>
<string name="profile_message">Perfil:\n\nFuso: %1$d\nPorcentagem: %2$d%%\"</string>
<string name="tdd_line">%1$.2f / %1$.0f U%%</string>
<string name="no_profile">Nenhum perfil selecionado</string>
<string name="aps_only">Aplique somente no modo APS!</string>
<string name="last_aps_result_na">Último resultado indisponível!</string>
<string name="loop_status_closed">LOOP FECHADO</string>
<string name="loop_status_open">LOOP ABERTO</string>
<string name="loop_status_disabled">LOOP DESATIVADO</string>
<string name="aps">APS</string>
<string name="last_run">Última execução</string>
<string name="last_enact">Ultima execução</string>
<string name="today">Hoje</string>
<string name="weighted">ponderado</string>
<string name="target_only_aps_mode">Alvos só se aplicam no modo APS!</string>
<string name="no_history">Nenhum dado no histórico!</string>
<string name="units_short">U</string>
<string name="temp_target">Alvos Temporários</string>
<string name="until">até</string>
<string name="default_range">DEFAULT RANGE</string>
<string name="target">alvo</string>
<string name="rate_duration">Taxa: %1$.2fU/h (%2$.2f%%) \nDuração %3$d min</string>
</resources> </resources>

View file

@ -285,48 +285,7 @@
<string name="cannula_usage">utilização:</string> <string name="cannula_usage">utilização:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Enviar os ficheiros de registo do dia de hoje para os programadores. Situação inesperada.</string> <string name="send_logfiles">Enviar os ficheiros de registo do dia de hoje para os programadores. Situação inesperada.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Monitorizar e controlar a AndroidAPS utilizando o seu relógio WearOS.</string>
<string name="no_watch_connected">(Nenhum relógio Conectado)</string>
<string name="pump_status">Estado da Bomba</string>
<string name="loop_status">Estado do loop</string>
<string name="wizard_result">Calc. Assistente:\nInsulina: %1$.2fU\nHidratos: %2$dg</string>
<string name="quick_wizard_not_available">O assistente rápido selecionado não está mais disponível, atualize o ecrã</string>
<string name="quick_wizard_message">Assistente rápido: %1$s\nInsulina: %2$.2fU\nHidratos: %3$dg</string>
<string name="wear_action_tempt_preset_error">Predefinição de alvo temporário desconhecido: %1$s</string>
<string name="wear_action_tempt_cancel_message">Cancelando Alvos Temporários em execução?</string>
<string name="wear_action_tempt_unit_error">Diferentes unidades usadas no relógio e telefone!</string>
<string name="wear_action_tempt_zero_message">Alvo-temporário-Zero - cancelar Alvos -Temporários em progresso?</string>
<string name="wear_action_tempt_min_bg_error">Min-GLIC fora do alvo!</string>
<string name="wear_action_tempt_max_bg_error">Máx-GLIC fora do alvo!</string>
<string name="wear_action_tempt_manual_range_message">AlvoTemporário:\nMin: %1$s\nMax: %2$s\nDuração: %3$s</string>
<string name="wear_action_tempt_manual_message">AlvoTemporário:\nAlvo: %1$s\nDuração: %2$s</string>
<string name="wear_action_tempt_preset_message">AlvoTemporário:\nMotivo %1$s\nAlvo: %2$s\nDuração: %3$s</string>
<string name="no_success">sem efeito - por favor verifique no telemóvel</string>
<string name="wear_settings">Definições do Relógio</string>
<string name="wearcontrol_title">Controles do Relógio</string>
<string name="wearcontrol_summary">Definir Alvo-Temp and inserir Tratamentos do relógio.</string>
<string name="wear_wizard_settings_summary">Resultado cálculos incluídos no Assistente:</string>
<string name="wear_general_settings">Definições Gerais</string>
<string name="wear_notifysmb_title">Notificar no SMB</string>
<string name="wear_notifysmb_summary">Mostrar SMB no relogio como bolus normal.</string>
<string name="wear_custom_watchface_settings">Definições da watchface predefinida</string>
<string name="wear_custom_watchface_authorization_title">Autorização da watchface predefinida</string>
<string name="wear_custom_watchface_authorization_summary">Autorizar watchface por definição para alterar e bloquear algumas configurações de exibição do relógio para se adequarem ao design do watchface</string>
<string name="wear_custom_watchface">Watchface Predefinida: %1$s</string>
<string name="wear_load_watchface">Carregar Watchface</string>
<string name="wear_infos_watchface">Infos Watchface</string>
<string name="wear_export_watchface">Exportar modelo</string>
<string name="wear_new_custom_watchface_exported">Modelo de Watchface Predefinida exportado</string>
<string name="resend_all_data">Reenviar Todos os Dados</string>
<string name="open_settings_on_wear">Abrir Definições no Relógio</string>
<string name="cwf_infos_pref_locked">Lista de preferências bloqueadas pela Watchface</string>
<string name="cwf_infos_pref_required">Lista de preferências necessárias para a Watchface</string>
<string name="cwf_infos_view_title">Lista de campos incluídos na Watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Mostra uma notificação em curso com um breve resumo do que o seu loop está a fazer</string> <string name="description_persistent_notification">Mostra uma notificação em curso com um breve resumo do que o seu loop está a fazer</string>
<string name="old_data">DADOS ANTIGOS</string> <string name="old_data">DADOS ANTIGOS</string>
<string name="pump_old_data">TID: Ainda dados antigos! Não é possível carregar a partir da bomba.</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">folosire:</string> <string name="cannula_usage">folosire:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Trimite înregistrările zilei de astăzi către dezvoltatori, împreună cu timpul curent. Situație neașteptată.</string> <string name="send_logfiles">Trimite înregistrările zilei de astăzi către dezvoltatori, împreună cu timpul curent. Situație neașteptată.</string>
<!-- Wear-->
<string name="wear_shortname">CEAS</string>
<string name="description_wear">Monitorizează și controlează AAPS folosind ceasul WearOS.</string>
<string name="no_watch_connected">(Niciun ceas conectat)</string>
<string name="pump_status">Stare pompă</string>
<string name="loop_status">Stare buclă</string>
<string name="wizard_result">Calc. Asistent:\nInsulină: %1$.2fU\nCarburi: %2$dg</string>
<string name="quick_wizard_not_available">Asistentul rapid selectat nu mai este disponibil, vă rugăm să reîncărcați iconița</string>
<string name="quick_wizard_message">Asistent calcul: %1$s\nInsulină: %2$.2fU\nCarbohidrați: %3$dg</string>
<string name="wear_action_tempt_preset_error">Presetare ȚintăTemporară necunoscută: %1$s</string>
<string name="wear_action_tempt_cancel_message">Se anulează rularea țintelor temporare?</string>
<string name="wear_action_tempt_unit_error">Unități diferite folosite pe ceas și telefon!</string>
<string name="wear_action_tempt_zero_message">Zero-Temp-Target - anulați ȚinteleTemporare actuale?</string>
<string name="wear_action_tempt_min_bg_error">Min-BG în afara intervalului!</string>
<string name="wear_action_tempt_max_bg_error">Max-BG în afara intervalului!</string>
<string name="wear_action_tempt_manual_range_message">ȚintăTemporară:\nMin: %1$s\nMax: %2$s\nDurată: %3$s</string>
<string name="wear_action_tempt_manual_message">ȚintăTemporară:\nȚintă: %1$s\nDurată: %2$s</string>
<string name="wear_action_tempt_preset_message">ȚintăTemporarăt:\nMotiv: %1$s\nȚintă: %2$s\nDurată: %3$s</string>
<string name="no_success">fără succes - verificați telefonul</string>
<string name="wear_settings">Setări Wear</string>
<string name="wearcontrol_title">Controlare din ceas</string>
<string name="wearcontrol_summary">Setare Ținte-Temporare și se introduc Tratamente din ceas.</string>
<string name="wear_wizard_settings_summary">Calcule incluse în rezultatul asistentului:</string>
<string name="wear_general_settings">Setări generale</string>
<string name="wear_notifysmb_title">Notifică despre SMB</string>
<string name="wear_notifysmb_summary">Arată SMB pe ceas ca și un bolus standard.</string>
<string name="wear_custom_watchface_settings">Cadran ceas - Setări personalizate </string>
<string name="wear_custom_watchface_authorization_title">Autorizare cadran personalizat</string>
<string name="wear_custom_watchface_authorization_summary">Autorizează cadranul personalizat să modifice și să blocheze unele setări de afișare ale ceasului pentru a se potrivi designului cadranului</string>
<string name="wear_custom_watchface">Cadran personalizat: %1$s</string>
<string name="wear_load_watchface">Încărcaţi cadranul</string>
<string name="wear_infos_watchface">Info cadran</string>
<string name="wear_export_watchface">Exportă șablon</string>
<string name="wear_new_custom_watchface_exported">Șablon ceas personalizat exportat</string>
<string name="resend_all_data">Retrimite toate datele</string>
<string name="open_settings_on_wear">Deschide setările pe Wear</string>
<string name="cwf_infos_pref_locked">Lista de preferințe blocate de cadranul ceasului</string>
<string name="cwf_infos_pref_required">Lista de preferințe solicitate de cadranul ceasului</string>
<string name="cwf_infos_view_title">Lista câmpurilor incluse în fața ceasului</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Afişează o notificare activă cu o scurtă descriere referitoare la starea buclei</string> <string name="description_persistent_notification">Afişează o notificare activă cu o scurtă descriere referitoare la starea buclei</string>
<string name="old_data">DATE VECHI</string> <string name="old_data">DATE VECHI</string>
<string name="pump_fetching_data">se încearcă preluarea datelor din pompă.</string>
<string name="pump_old_data">TDD: Date încă vechi! Nu se poate încărca din pompă.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Nicio schimbare de profil activă!</string>
<string name="profile_message">Profil:\n\nDecalare: %1$d\nProcent: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Niciun profil încărcat</string>
<string name="aps_only">Aplicați doar în modul APS!</string>
<string name="last_aps_result_na">Ultimul rezultat nu este disponibil!</string>
<string name="loop_status_closed">BUCLĂ ÎNCHISĂ</string>
<string name="loop_status_open">BUCLĂ DESCHISĂ</string>
<string name="loop_status_disabled">BUCLĂ INACTIVĂ</string>
<string name="aps">APS</string>
<string name="last_run">Ultima rulare</string>
<string name="last_enact">Ultima implementare</string>
<string name="today">Astăzi</string>
<string name="weighted">ponderat</string>
<string name="target_only_aps_mode">Țintele se aplică numai în modul APS!</string>
<string name="no_history">Nu există date istorice!</string>
<string name="units_short">U</string>
<string name="temp_target">Țintă temporară</string>
<string name="until">până la</string>
<string name="default_range">INTERVAL IMPLICIT</string>
<string name="target">țintă</string>
<string name="rate_duration">Rată: %1$.2fU/h (%2$.2f%%) \nDurată %3$d min</string>
</resources> </resources>

View file

@ -285,72 +285,7 @@
<string name="cannula_usage">применение:</string> <string name="cannula_usage">применение:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Отправьте файлы сегодняшнего лога разработчикам наряду с этим. Непредвиденная ситуация.</string> <string name="send_logfiles">Отправьте файлы сегодняшнего лога разработчикам наряду с этим. Непредвиденная ситуация.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Мониторить и контролировать AAPS при помощи часов WearOS.</string>
<string name="no_watch_connected">(Часы не подключены)</string>
<string name="pump_status">Статус помпы</string>
<string name="loop_status">Статус цикла</string>
<string name="wizard_result">Мастер:\nИнсулин: %1$.2fед\nУгл: %2$dг</string>
<string name="quick_wizard_not_available">Выбранный мастер быстрого доступа больше недоступен, обновите плитку</string>
<string name="quick_wizard_message">Мастер: %1$s\nИнсулин: %2$.2fЕд\nУгл: %3$dg</string>
<string name="wear_action_tempt_preset_error">Неизвестная конфигурация врем цели: %1$s</string>
<string name="wear_action_tempt_cancel_message">Отменить врем цели?</string>
<string name="wear_action_tempt_unit_error">На часах и телефоне различные единицы измерения!</string>
<string name="wear_action_tempt_zero_message">Нулевая врем цель - отмена?</string>
<string name="wear_action_tempt_min_bg_error">Мин ГК вне диапазона!</string>
<string name="wear_action_tempt_max_bg_error">Макс ГК вне диапазона!</string>
<string name="wear_action_tempt_manual_range_message">ВремЦель:\nМин: %1$s\nМакс.: %2$s\nДлительность: %3$s</string>
<string name="wear_action_tempt_manual_message">ВремЦель:\nЦель: %1$s\nДлительность: %2$s</string>
<string name="wear_action_tempt_preset_message">ВремЦель:\nПричина: %1$s\nЦель.: %2$s\nДлительность: %3$s</string>
<string name="no_success">неуспешно - проверьте телефон</string>
<string name="wear_settings">настройки смарт-часов Wear</string>
<string name="wearcontrol_title">Контроль с часов</string>
<string name="wearcontrol_summary">Ставить временные цели и вводить терапию с часов.</string>
<string name="wear_wizard_settings_summary">Расчеты включены в результат калькулятора: </string>
<string name="wear_general_settings">Общие настройки</string>
<string name="wear_notifysmb_title">Сообщить о супер микро болюсе SMB</string>
<string name="wear_notifysmb_summary">Показывать супер микро болюс SMB на часах как стандартный болюс.</string>
<string name="wear_custom_watchface_settings">Настройка циферблатов</string>
<string name="wear_custom_watchface_authorization_title">Авторизация пользовательских циферблатов</string>
<string name="wear_custom_watchface_authorization_summary">Авторизовать загруженные пользовательские циферблаты для изменения и блокировки некоторых параметров отображения часов в соответствии с дизайном часов</string>
<string name="wear_custom_watchface">Пользовательский циферблат %1$s</string>
<string name="wear_load_watchface">Загрузить циферблат</string>
<string name="wear_infos_watchface">Циферблат Infos</string>
<string name="wear_export_watchface">Экспортировать шаблон</string>
<string name="wear_new_custom_watchface_exported">Пользовательский шаблон циферблата экспортирован</string>
<string name="resend_all_data">повторить отправку всех данных</string>
<string name="open_settings_on_wear">Открыть настройки на Wear</string>
<string name="cwf_infos_pref_locked">Список настроек, блокируемых циферблатом</string>
<string name="cwf_infos_pref_required">Список настроек, требующихся для циферблата</string>
<string name="cwf_infos_view_title">Список полей, входящих в циферблат</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Показывает текущие уведомления и краткий обзор событий цикла</string> <string name="description_persistent_notification">Показывает текущие уведомления и краткий обзор событий цикла</string>
<string name="old_data">старые данные</string> <string name="old_data">старые данные</string>
<string name="pump_fetching_data">пытаюсь получить данные с помпы.</string>
<string name="pump_old_data">TDD: До сих пор старые данные! Невозможно загрузить с помпы.</string>
<string name="grams_short">г</string>
<string name="hour_short">ч</string>
<string name="no_active_profile">Активный профиль не установлен!</string>
<string name="profile_message">Профиль:\n\nСдвиг по времени: %1$d$\nПроцент: %2$d%%\"</string>
<string name="tdd_line">%1$.2fед%1$.0f%%</string>
<string name="no_profile">Профиль не загружен</string>
<string name="aps_only">Применять только в режиме APS!</string>
<string name="last_aps_result_na">Последний результат недоступен!</string>
<string name="loop_status_closed">ЗАМКНУТЫЙ ЦИКЛ</string>
<string name="loop_status_open">ОТКРЫТЫЙ ЦИКЛ</string>
<string name="loop_status_disabled">ЦИКЛ ВЫКЛЮЧЕН</string>
<string name="aps">APS</string>
<string name="last_run">Предыдущее выполнение</string>
<string name="last_enact">Предыдущая активация</string>
<string name="today">Сегодня</string>
<string name="weighted">взвешенный</string>
<string name="target_only_aps_mode">Цели применяются только в режиме APS!</string>
<string name="no_history">Нет данных истории!</string>
<string name="units_short">Ед</string>
<string name="temp_target">Врем. цель</string>
<string name="until">до</string>
<string name="default_range">ДИАПАЗОН ПО УМОЛЧАНИЮ</string>
<string name="target">целевое значение ГК:</string>
<string name="rate_duration">Скорость: %1$.2fед/ч (%2$.2f%%) \nПродолжительность %3$d мин</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">používanie:</string> <string name="cannula_usage">používanie:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Odošlite dnešné súbory protokolov vývojárom spolu s týmto časom. Neočakávaná situácia.</string> <string name="send_logfiles">Odošlite dnešné súbory protokolov vývojárom spolu s týmto časom. Neočakávaná situácia.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Zobrazovanie stavu a riadenie AndroidAPS z hodiniek s WearOS.</string>
<string name="no_watch_connected">(Žiadne hodinky nie sú pripojené)</string>
<string name="pump_status">Stav pumpy</string>
<string name="loop_status">Stav uzavretého okruhu</string>
<string name="wizard_result">Kalkulačka: \nInzulín: %1$.2fJI\nSacharidy: %2$dg</string>
<string name="quick_wizard_not_available">Vybraný rýchly bolus už nie je k dispozícii, obnovte prosím dlaždicu</string>
<string name="quick_wizard_message">Rýchly bolus: %1$s\nInzulín: %2$.2fJI\nSacharidy: %3$dg</string>
<string name="wear_action_tempt_preset_error">Dočasný cieľ neznáma predvoľba: %1$s</string>
<string name="wear_action_tempt_cancel_message">Zrušenie bežiaceho dočasného cieľa?</string>
<string name="wear_action_tempt_unit_error">Použité rozdielne jednotky v hodinkách a v telefóne!</string>
<string name="wear_action_tempt_zero_message">Nulový dočasný cieľ - zrušenie bežiaceho dočasného cieľa?</string>
<string name="wear_action_tempt_min_bg_error">Minimálna glykémia mimo rozsah!</string>
<string name="wear_action_tempt_max_bg_error">Maximálna glykémia mimo rozsah!</string>
<string name="wear_action_tempt_manual_range_message">Doč. cieľ:\nMin: %1$s\nMax: %2$s\nTrvanie: %3$s</string>
<string name="wear_action_tempt_manual_message">Doč. cieľ:\nCieľ: %1$s\nTrvanie: %2$s</string>
<string name="wear_action_tempt_preset_message">Doč. cieľ:\nDôvod: %1$s\nCieľ: %2$s\nTrvanie: %3$s</string>
<string name="no_success">Neúspešné - skontrolujte telefón</string>
<string name="wear_settings">Nastavenie hodiniek</string>
<string name="wearcontrol_title">Ovládanie z hodiniek</string>
<string name="wearcontrol_summary">Nastavovanie dočasných cieľov a vkladanie ošetrení hodinkami.</string>
<string name="wear_wizard_settings_summary">Kalkulácia použitá vo výsledku wizardu:</string>
<string name="wear_general_settings">Všeobecné nastavenia</string>
<string name="wear_notifysmb_title">Oznámenie pri SMB</string>
<string name="wear_notifysmb_summary">Ukazovať SMB na hodinkách ako normálny bolus.</string>
<string name="wear_custom_watchface_settings">Nastavenie vlastného ciferníka</string>
<string name="wear_custom_watchface_authorization_title">Autorizácia vlastného ciferníka</string>
<string name="wear_custom_watchface_authorization_summary">Autorizujte načítaný vlastný ciferník, aby se zmenili a uzamkli niektoré nastavenia hodiniek tak, aby vyhovovali designu ciferníka</string>
<string name="wear_custom_watchface">Vlastný ciferník: %1$s</string>
<string name="wear_load_watchface">Nahrať ciferník</string>
<string name="wear_infos_watchface">Informácie o ciferníku</string>
<string name="wear_export_watchface">Exportovať šablónu</string>
<string name="wear_new_custom_watchface_exported">Vlastná šablóna ciferníka exportovaná</string>
<string name="resend_all_data">Všetky dáta poslať znova</string>
<string name="open_settings_on_wear">Otvoriť nastavenia na hodinkách</string>
<string name="cwf_infos_pref_locked">Zoznam preferencií uzamknutý hodinkami</string>
<string name="cwf_infos_pref_required">Zoznam preferencií potrebných pre ciferník</string>
<string name="cwf_infos_view_title">Zoznam polí zahrnutých do ciferníka</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Zobrazuje priebežné oznámenia v Androide s krátkym prehľadom, čo práve uzavretý okruh robí</string> <string name="description_persistent_notification">Zobrazuje priebežné oznámenia v Androide s krátkym prehľadom, čo práve uzavretý okruh robí</string>
<string name="old_data">ZASTARALÉ DÁTA</string> <string name="old_data">ZASTARALÉ DÁTA</string>
<string name="pump_fetching_data">pokus o načítanie dát z pumpy.</string>
<string name="pump_old_data">CDD: Stále staré dáta! Nie je možné načítať z pumpy.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Nie je nastavený žiadny aktívny profil!</string>
<string name="profile_message">Profil:\n\nPosunutie: %1$d\nPercento: %2$d%%\"</string>
<string name="tdd_line">%1$.2fJI %1$.0f%%</string>
<string name="no_profile">Nie je vybraný žiadny profil</string>
<string name="aps_only">Použiť iba v APS móde!</string>
<string name="last_aps_result_na">Posledný výsledok nie je k dispozícii!</string>
<string name="loop_status_closed">UZAVRETÝ OKRUH</string>
<string name="loop_status_open">OTVORENÝ OKRUH</string>
<string name="loop_status_disabled">UZAVRETÝ OKRUH DEAKTIVOVANÝ</string>
<string name="aps">APS</string>
<string name="last_run">Posledné spustenie</string>
<string name="last_enact">Naposledy vykonané</string>
<string name="today">Dnes</string>
<string name="weighted">vážený</string>
<string name="target_only_aps_mode">Ciele sa použijú iba v režime APS!</string>
<string name="no_history">Žiadne údaje o histórii!</string>
<string name="units_short">J</string>
<string name="temp_target">Dočasný cieľ</string>
<string name="until">až do</string>
<string name="default_range">ŠTANDARDNÝ ROZSAH</string>
<string name="target">cieľ</string>
<string name="rate_duration">Rýchlosť: %1$.2fJI/h (%2$.2f%%) \nTrvanie %3$d min</string>
</resources> </resources>

View file

@ -73,8 +73,6 @@
<string name="overview_show_treatments">Tretmani</string> <string name="overview_show_treatments">Tretmani</string>
<!-- Skins --> <!-- Skins -->
<!-- Iob--> <!-- Iob-->
<!-- Wear-->
<string name="description_wear">Pratite i kontrolirajte AAPS koristeći svoj WearOS sat.</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Prikazuje tekuće obaveštenje sa kratkim pregledom onoga što vaša petlja radi</string> <string name="description_persistent_notification">Prikazuje tekuće obaveštenje sa kratkim pregledom onoga što vaša petlja radi</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">användning:</string> <string name="cannula_usage">användning:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Skicka dagens loggfiler till utvecklarna tillsammans med denna datumstämpel. Oväntad situation.</string> <string name="send_logfiles">Skicka dagens loggfiler till utvecklarna tillsammans med denna datumstämpel. Oväntad situation.</string>
<!-- Wear-->
<string name="wear_shortname">Wear</string>
<string name="description_wear">Följ och kontrollera AAPS med din Wear OS-klocka.</string>
<string name="no_watch_connected">(Ingen klocka ansluten)</string>
<string name="pump_status">Pumpstatus</string>
<string name="loop_status">Loop-status</string>
<string name="wizard_result">Kalkylator:\nInsulin: %1$.2fU\nKolhydrater: %2$dg</string>
<string name="quick_wizard_not_available">Vald snabbknapp inte längre tillgänglig. Vänligen uppdatera vyn</string>
<string name="quick_wizard_message">Snabbsteg: %1$s\nInsulin: %2$.2fU\nKolhydrater: %3$dg</string>
<string name="wear_action_tempt_preset_error">Tempmål okänd förinställning: %1$s</string>
<string name="wear_action_tempt_cancel_message">Avbryt temp-mål?</string>
<string name="wear_action_tempt_unit_error">Olika enheter på klocka och telefon!</string>
<string name="wear_action_tempt_zero_message">Noll-temp - avbyta nuvarande temp-mål?</string>
<string name="wear_action_tempt_min_bg_error">Ogiltigt minimum BG!</string>
<string name="wear_action_tempt_max_bg_error">Ogiltigt maximum BG!</string>
<string name="wear_action_tempt_manual_range_message">Temp-mål:\nMin: %1$s\nMax: %2$s\nVaraktighet: %3$s</string>
<string name="wear_action_tempt_manual_message">Temp-mål:\nMål: %1$s\nDuration: %2$s</string>
<string name="wear_action_tempt_preset_message">Tillfälligt mål:\nOrsak: %1$s\nMål: %2$s\nVaraktighet: %3$s</string>
<string name="no_success">misslyckat - kontrollera telefonen</string>
<string name="wear_settings">Inställningar för klocka (Wear)</string>
<string name="wearcontrol_title">Kontrollera från klockan</string>
<string name="wearcontrol_summary">Sätt temp målvärde och ange behandlingar från klockan.</string>
<string name="wear_wizard_settings_summary">Kalkyler inkluderade i resultatet</string>
<string name="wear_general_settings">Generella inställningar</string>
<string name="wear_notifysmb_title">Skicka notis vid SMB</string>
<string name="wear_notifysmb_summary">Visa SMB på klockan som en standardbolus.</string>
<string name="wear_custom_watchface_settings">Anpassade inställningar för urtavla</string>
<string name="wear_custom_watchface_authorization_title">Anpassad auktorisering för urtavla</string>
<string name="wear_custom_watchface_authorization_summary">Auktorisera inlästa anpassade urtavlor för att ändra och låsa vissa visningsinställningar för att passa design av urtavlan</string>
<string name="wear_custom_watchface">Anpassad urtavla: %1$s</string>
<string name="wear_load_watchface">Ladda urtavla</string>
<string name="wear_infos_watchface">Info urtavla</string>
<string name="wear_export_watchface">Exportera mall</string>
<string name="wear_new_custom_watchface_exported">Anpassad mall exporterad</string>
<string name="resend_all_data">Uppdatera klockans data</string>
<string name="open_settings_on_wear">Öppna inställningar på klockan</string>
<string name="cwf_infos_pref_locked">Inställningar som är låsta av urtavlan</string>
<string name="cwf_infos_pref_required">Inställningar som krävs av urtavlan</string>
<string name="cwf_infos_view_title">Fält som ingår i urtavlan</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Visar en konstant avisering med en kort sammanfattning av vad din loop gör</string> <string name="description_persistent_notification">Visar en konstant avisering med en kort sammanfattning av vad din loop gör</string>
<string name="old_data">Aktuellt BG saknas!</string> <string name="old_data">Aktuellt BG saknas!</string>
<string name="pump_fetching_data">försöker hämta data från pump.</string>
<string name="pump_old_data">TDD: Fortfarande gamla data! Kan inte hämta från pump.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">Ingen aktiv profil!</string>
<string name="profile_message">Profil:\n\nTidsförskjutning: %1$d\nProcent: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">Ingen profil inläst</string>
<string name="aps_only">Använd endast i APS-läge!</string>
<string name="last_aps_result_na">Senaste resultat ej tillgängligt!</string>
<string name="loop_status_closed">CLOSED LOOP</string>
<string name="loop_status_open">OPEN LOOP</string>
<string name="loop_status_disabled">LOOP INAKTIVERAD</string>
<string name="aps">APS</string>
<string name="last_run">Kördes senast</string>
<string name="last_enact">Senaste handling</string>
<string name="today">Idag</string>
<string name="weighted">viktad</string>
<string name="target_only_aps_mode">Målen gäller endast i APS-läge!</string>
<string name="no_history">Inget historiskt data!</string>
<string name="units_short">U</string>
<string name="temp_target">Tillfälligt målvärde</string>
<string name="until">tills</string>
<string name="default_range">STANDARDINTERVALL</string>
<string name="target">målvärde</string>
<string name="rate_duration">Dos: %1$.2fU/h (%2$.2f%%) \nVaraktighet %3$d min</string>
</resources> </resources>

View file

@ -286,72 +286,7 @@
<string name="cannula_usage">kullanım:</string> <string name="cannula_usage">kullanım:</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">Bu günün kayıt dosyalarını geliştiricilere gönderin. Beklenmedik bir durum.</string> <string name="send_logfiles">Bu günün kayıt dosyalarını geliştiricilere gönderin. Beklenmedik bir durum.</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">WearOS saatinizi kullanarak AAPS\'yi izleyin ve kontrol edin.</string>
<string name="no_watch_connected">(Saat Bağlı Değil)</string>
<string name="pump_status">Pompa durumu</string>
<string name="loop_status">Döngü durumu</string>
<string name="wizard_result">Hesap Mak.:\nİnsulin: %1$.2fÜ\nKarb: %2$dg</string>
<string name="quick_wizard_not_available">Seçili hızlı asistan artık mevcut değil, lütfen kutucuğu yenileyin</string>
<string name="quick_wizard_message">Hızlı Asistan: %1$s\nİnsülin: %2$.2fU\nKarb: %3$dg</string>
<string name="wear_action_tempt_preset_error">Geiçici hedef bilinmeyen ön ayarı: %1$s</string>
<string name="wear_action_tempt_cancel_message">Çalışan Geçici-Hedefler iptal edilsin mi?</string>
<string name="wear_action_tempt_unit_error">Saatte ve telefonda farklı birimler kullanılıyor!</string>
<string name="wear_action_tempt_zero_message">Sıfır-Geçici-Hedef - Çalışan Geçici-Hedefler iptal edilsin mi?</string>
<string name="wear_action_tempt_min_bg_error">Min-KŞ aralık dışında!</string>
<string name="wear_action_tempt_max_bg_error">Maks-KŞ aralık dışında!</string>
<string name="wear_action_tempt_manual_range_message">Geçici Hedef:\nMin: %1$s\nMaks: %2$s\nSüre: %3$s</string>
<string name="wear_action_tempt_manual_message">Geçici Hedef:\nHedef: %1$s\nSüre: %2$s</string>
<string name="wear_action_tempt_preset_message">Geçici Hedef:\nNeden: %1$s\nHedef: %2$s\nSüre: %3$s</string>
<string name="no_success">başarısız - lütfen telefonu kontrol edin</string>
<string name="wear_settings">Wear ayarları</string>
<string name="wearcontrol_title">Saat tarafından kontrol</string>
<string name="wearcontrol_summary">Tedavileri ve Geçici hedefleri saat tarafından girin.</string>
<string name="wear_wizard_settings_summary">Sihirbaz sonucuna dahil edilen hesaplamalar:</string>
<string name="wear_general_settings">Genel Ayarlar</string>
<string name="wear_notifysmb_title">SMB\'yi bildir</string>
<string name="wear_notifysmb_summary">Saatte SMB\'yi standart bir bolus gibi göster.</string>
<string name="wear_custom_watchface_settings">Özel Saat arayüzü Ayarları</string>
<string name="wear_custom_watchface_authorization_title">Özel Saat arayüzü Yetkilendirmesi</string>
<string name="wear_custom_watchface_authorization_summary">Bazı saat ekranı ayarlarını saatarayüzü tasarımına uyacak şekilde değiştirmek ve kilitlemek için, yüklenen özel saat arayüzüne yetki verin</string>
<string name="wear_custom_watchface">Özel Saat arayüzü: %1$s</string>
<string name="wear_load_watchface">Saat arayüzü yükle</string>
<string name="wear_infos_watchface">Saat arayüzü bilgisi</string>
<string name="wear_export_watchface">Şablonu Dışarı Aktar</string>
<string name="wear_new_custom_watchface_exported">Saat arayüzü şablonu dışa aktarıldı</string>
<string name="resend_all_data">Tüm verileri yeniden gönderin</string>
<string name="open_settings_on_wear">Wear\'de ayarları</string>
<string name="cwf_infos_pref_locked">Saat arayüzü tarafından kilitlenen tercihlerin listesi</string>
<string name="cwf_infos_pref_required">Saat arayüzü için gerekli tercihlerin listesi</string>
<string name="cwf_infos_view_title">Saat arayüzüne dahil edilen alanların listesi</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">Döngü\'ün ne yaptığını kısa bir genel bakışla devam eden bir bildirimi gösterir</string> <string name="description_persistent_notification">Döngü\'ün ne yaptığını kısa bir genel bakışla devam eden bir bildirimi gösterir</string>
<string name="old_data">ESKİ VERİ</string> <string name="old_data">ESKİ VERİ</string>
<string name="pump_fetching_data">pompadan veri almaya çalışıyor.</string>
<string name="pump_old_data">TGD: Hala eski veriler! Pompadan yüklenemiyor.</string>
<string name="grams_short">gr</string>
<string name="hour_short">sa</string>
<string name="no_active_profile">Etkin profil ayarlanmadı!</string>
<string name="profile_message">Profil:\n\nZaman Kayması: %1$d\nYüzde: %2$d%%\"</string>
<string name="tdd_line">%1$.2fÜ %1$.0f%%</string>
<string name="no_profile">Profil yüklenmedi</string>
<string name="aps_only">Sadece APS modunda uygulayın!</string>
<string name="last_aps_result_na">Son sonuç mevcut değil!</string>
<string name="loop_status_closed">KAPALI DÖNGÜ</string>
<string name="loop_status_open">AÇIK DÖNGÜ</string>
<string name="loop_status_disabled">DÖNGÜ DEVRE DIŞI</string>
<string name="aps">APS (YPS)</string>
<string name="last_run">Son Çalıştırma</string>
<string name="last_enact">Son sahne</string>
<string name="today">Bugün</string>
<string name="weighted">ırlıklı</string>
<string name="target_only_aps_mode">Hedefler yalnızca APS modunda uygulanır!</string>
<string name="no_history">Geçmiş verisi yok!</string>
<string name="units_short">Ü</string>
<string name="temp_target">Geçici Hedef</string>
<string name="until">kadar</string>
<string name="default_range">VARSAYILAN ARALIK</string>
<string name="target">hedef</string>
<string name="rate_duration">Oran: %1$.2fÜ/sa (%2$.2f%%) \nSüre %3$d dk</string>
</resources> </resources>

View file

@ -9,6 +9,5 @@
<!-- OverviewMenu--> <!-- OverviewMenu-->
<!-- Skins --> <!-- Skins -->
<!-- Iob--> <!-- Iob-->
<!-- Wear-->
<!-- PersistentNotification--> <!-- PersistentNotification-->
</resources> </resources>

View file

@ -269,31 +269,6 @@
<string name="skin">皮肤</string> <string name="skin">皮肤</string>
<!-- Iob--> <!-- Iob-->
<string name="send_logfiles">发送包括当前时间的今日的日志文件给开发者。描述一下意外情况</string> <string name="send_logfiles">发送包括当前时间的今日的日志文件给开发者。描述一下意外情况</string>
<!-- Wear-->
<string name="wear_shortname">手表</string>
<string name="loop_status">闭环状态</string>
<string name="wizard_result">计算. 向导:\n胰岛素: %1$.2fU\n碳水: %2$d克</string>
<string name="quick_wizard_not_available">选定的快速向导不再可用,请刷新</string>
<string name="quick_wizard_message">快速向导: %1$s\n胰岛素: %2$.2fU\n碳水: %3$d克</string>
<string name="wear_action_tempt_preset_error">未预设的临时目标: %1$s</string>
<string name="wear_action_tempt_cancel_message">取消正在运行的临时目标?</string>
<string name="wear_action_tempt_unit_error">手表和手机上使用了不同的单位!</string>
<string name="wear_action_tempt_zero_message">无临时目标-取消正在运行的临时目标?</string>
<string name="wear_action_tempt_min_bg_error">目标血糖最小值超出范围!</string>
<string name="wear_action_tempt_max_bg_error">目标血糖最大值超出范围!</string>
<string name="wear_action_tempt_manual_range_message">临时目标:\n最小: %1$s\n最大: %2$s\n持续时间: %3$s</string>
<string name="wear_action_tempt_manual_message">临时目标:\n目标: %1$s\n持续时间: %2$s</string>
<string name="wear_action_tempt_preset_message">临时目标:\n原因 %1$s\n目标 %2$s\n持续时间 %3$s</string>
<string name="no_success">未成功-请检查手机</string>
<string name="wear_settings">手表设置</string>
<string name="wearcontrol_title">从手表上控制</string>
<string name="wearcontrol_summary">设置临时目标并从手表中进行治疗操作。</string>
<string name="wear_wizard_settings_summary">包含在向导中的计算结果:</string>
<string name="wear_general_settings">常规设置</string>
<string name="wear_notifysmb_title">在 SMB 上通知</string>
<string name="wear_notifysmb_summary">在手表上像显示常规大剂量一样显示SMB微型大剂量</string>
<string name="resend_all_data">重新发送所有数据</string>
<string name="open_settings_on_wear">在手表上打开设置</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="description_persistent_notification">显示持续的通知, 其中简要概述了您的闭环正在做什么</string> <string name="description_persistent_notification">显示持续的通知, 其中简要概述了您的闭环正在做什么</string>
<string name="old_data">旧数据</string> <string name="old_data">旧数据</string>

View file

@ -330,76 +330,9 @@
<string name="send_logfiles">Send today\'s log files to developers along with this time. Unexpected situation.</string> <string name="send_logfiles">Send today\'s log files to developers along with this time. Unexpected situation.</string>
<string name="iob_cob_calculator" translatable="false">IobCobCalculator</string> <string name="iob_cob_calculator" translatable="false">IobCobCalculator</string>
<!-- Wear-->
<string name="wear_shortname">WEAR</string>
<string name="description_wear">Monitor and control AAPS using your WearOS watch.</string>
<string name="no_watch_connected">(No Watch Connected)</string>
<string name="pump_status">Pump status</string>
<string name="loop_status">Loop status</string>
<string name="wizard_result">Calc. Wizard:\nInsulin: %1$.2fU\nCarbs: %2$dg</string>
<string name="quick_wizard_not_available">Selected quickwizard no longer available, please refresh your tile</string>
<string name="quick_wizard_message">QuickWizard: %1$s\nInsulin: %2$.2fU\nCarbs: %3$dg</string>
<string name="wear_action_tempt_preset_error">Temptarget unknown preset: %1$s</string>
<string name="wear_action_tempt_cancel_message">Cancelling running Temp-Targets?</string>
<string name="wear_action_tempt_unit_error">Different units used on watch and phone!</string>
<string name="wear_action_tempt_zero_message">Zero-Temp-Target - cancelling running Temp-Targets?</string>
<string name="wear_action_tempt_min_bg_error">Min-BG out of range!</string>
<string name="wear_action_tempt_max_bg_error">Max-BG out of range!</string>
<string name="wear_action_tempt_manual_range_message">Temptarget:\nMin: %1$s\nMax: %2$s\nDuration: %3$s</string>
<string name="wear_action_tempt_manual_message">Temptarget:\nTarget: %1$s\nDuration: %2$s</string>
<string name="wear_action_tempt_preset_message">Temptarget:\nReason: %1$s\nTarget: %2$s\nDuration: %3$s</string>
<string name="no_success">not successful - please check phone</string>
<string name="wear_settings">Wear settings</string>
<string name="wearcontrol_title">Controls from Watch</string>
<string name="wearcontrol_summary">Set Temp-Targets and enter Treatments from the watch.</string>
<string name="wear_wizard_settings_summary">Calculations included in the Wizard result:</string>
<string name="wear_general_settings">General Settings</string>
<string name="wear_notifysmb_title">Notify on SMB</string>
<string name="wear_notifysmb_summary">Show SMB on the watch like a standard bolus.</string>
<string name="wear_custom_watchface_settings">Custom Watchface Settings</string>
<string name="wear_custom_watchface_authorization_title">Custom Watchface Authorization</string>
<string name="wear_custom_watchface_authorization_summary">Authorize loaded custom watchface to change and lock some watch display settings to suit watchface design</string>
<string name="wear_custom_watchface">Custom Watchface: %1$s</string>
<string name="wear_load_watchface">Load Watchface</string>
<string name="wear_infos_watchface">Infos Watchface</string>
<string name="wear_export_watchface">Export template</string>
<string name="wear_new_custom_watchface_exported">Custom watchface template exported</string>
<string name="resend_all_data">Resend All Data</string>
<string name="open_settings_on_wear">Open Settings on Wear</string>
<string name="cwf_infos_pref_locked">List of prefs locked by the Watchface</string>
<string name="cwf_infos_pref_required">List of prefs required for the Watchface</string>
<string name="cwf_infos_view_title">List of fields included into the Watchface</string>
<!-- PersistentNotification--> <!-- PersistentNotification-->
<string name="ongoingnotificaction" translatable="false">Ongoing Notification</string> <string name="ongoingnotificaction" translatable="false">Ongoing Notification</string>
<string name="description_persistent_notification">Shows an ongoing notification with a short overview of what your loop is doing</string> <string name="description_persistent_notification">Shows an ongoing notification with a short overview of what your loop is doing</string>
<string name="old_data">OLD DATA</string> <string name="old_data">OLD DATA</string>
<string name="pump_fetching_data">trying to fetch data from pump.</string>
<string name="pump_old_data">TDD: Still old data! Cannot load from pump.</string>
<string name="grams_short">g</string>
<string name="hour_short">h</string>
<string name="no_active_profile">No active profile switch!</string>
<string name="profile_message">Profile:\n\nTimeshift: %1$d\nPercentage: %2$d%%\"</string>
<string name="tdd_line">%1$.2fU %1$.0f%%</string>
<string name="no_profile">No profile loaded</string>
<string name="aps_only">Only apply in APS mode!</string>
<string name="last_aps_result_na">Last result not available!</string>
<string name="loop_status_closed">CLOSED LOOP</string>
<string name="loop_status_open">OPEN LOOP</string>
<string name="loop_status_disabled">LOOP DISABLED</string>
<string name="aps">APS</string>
<string name="last_run">Last run</string>
<string name="last_enact">Last Enact</string>
<string name="today">Today</string>
<string name="weighted">weighted</string>
<string name="target_only_aps_mode">Targets only apply in APS mode!</string>
<string name="no_history">No history data!</string>
<string name="units_short">U</string>
<string name="temp_target">Temp Target</string>
<string name="until">until</string>
<string name="default_range">DEFAULT RANGE</string>
<string name="target">target</string>
<string name="rate_duration">Rate: %1$.2fU/h (%2$.2f%%) \nDuration %3$d min</string>
</resources> </resources>

View file

@ -9,15 +9,15 @@
<string name="description_sensitivity_weighted_average">Sensitivitet beregnes som en vektet gjennomsnittsverdi av avvikene. Ferske avvik har høyere vekting. Minimum opptak av karbohydrater beregnes ut fra maks opptakstid for karbohydrater angitt i dine innstillinger. Denne algoritmen er den raskeste for å justere endringer i sensitivitet.</string> <string name="description_sensitivity_weighted_average">Sensitivitet beregnes som en vektet gjennomsnittsverdi av avvikene. Ferske avvik har høyere vekting. Minimum opptak av karbohydrater beregnes ut fra maks opptakstid for karbohydrater angitt i dine innstillinger. Denne algoritmen er den raskeste for å justere endringer i sensitivitet.</string>
<string name="uam_disabled_oref1_not_selected">UAM deaktivert fordi den trenger Oref1 sensitivitetsplugin</string> <string name="uam_disabled_oref1_not_selected">UAM deaktivert fordi den trenger Oref1 sensitivitetsplugin</string>
<string name="absorption_settings_title">Absorberingsinnstillinger</string> <string name="absorption_settings_title">Absorberingsinnstillinger</string>
<string name="absorption_max_time_title">Maks absorberingstid for måltid [h]</string> <string name="absorption_max_time_title">Maks absorberingstid for måltid [t]</string>
<string name="absorption_max_time_summary">Tid i timer hvor det forventes at alle karbohydrater fra måltid vil være absorbert</string> <string name="absorption_max_time_summary">Tid i timer hvor det forventes at alle karbohydrater fra måltid vil være absorbert</string>
<string name="openapsama_autosens_period">Intervall for autosens [h]</string> <string name="openapsama_autosens_period">Intervall for autosens [t]</string>
<string name="openapsama_autosens_period_summary">Antall timer med historiske data for beregning av sensitivitet (absorpsjonstid for KH er ekskludert)</string> <string name="openapsama_autosens_period_summary">Antall timer med historiske data for beregning av sensitivitet (absorpsjonstid for KH er ekskludert)</string>
<string name="openapsama_autosens_max_summary">Standardverdi: 1.2\nDette er en multiplikatorbegrensning for autosens (og snart autotune) som begrenser at autosens ikke kan øke med mer enn 20%%, som dermed begrenser hvor mye autosens kan justere opp dine basaler, hvor mye ISF kan reduseres og hvor lavt BS målverdi kan settes.</string> <string name="openapsama_autosens_max_summary">Standardverdi: 1.2\nDette er en multiplikatorbegrensning for autosens (og snart autotune) som begrenser at autosens ikke kan øke med mer enn 20%%, som dermed begrenser hvor mye autosens kan justere opp dine basaler, hvor mye ISF kan reduseres og hvor lavt BS målverdi kan settes.</string>
<string name="openapsama_autosens_min_summary">Standardverdi: 0.7\nDette er en multiplikatorbegrensning for autosens-sikkerhet. Den begrenser autosens til å redusere basalverdier, og øke isulinssensitivitet (ISF) og BS mål med ikke mer enn enn 30%.</string> <string name="openapsama_autosens_min_summary">Standardverdi: 0.7\nDette er en multiplikatorbegrensning for autosens-sikkerhet. Den begrenser autosens til å redusere basalverdier, og øke isulinssensitivitet (ISF) og BS mål med ikke mer enn enn 30%.</string>
<string name="openapsama_autosens_max">Maks autosens ratio</string> <string name="openapsama_autosens_max">Maks autosens ratio</string>
<string name="openapsama_autosens_min">Minimum autosens ratio</string> <string name="openapsama_autosens_min">Minimum autosens ratio</string>
<string name="openapsama_min_5m_carb_impact_summary">Standardverdi er: 3.0 (AMA) eller 8.0 (SMB). Dette er grunninnstillingen for KH-opptak per 5 minutt. Den påvirker hvor raskt COB skal reduseres, og benyttes i beregning av fremtidig BS-kurve når BS enten synker eller øker mer enn forventet. Standardverdi er 3mg/dl/5 min.</string> <string name="openapsama_min_5m_carb_impact_summary">Standardverdi er: 3.0 (AMA) eller 8.0 (SMB). Dette er grunninnstillingen for KH-opptak per 5 minutt. Den påvirker hvor raskt COB skal reduseres, og benyttes i beregning av fremtidig BS-kurve når BS enten synker eller øker mer enn forventet. Standardverdi er 3mg/dl/5 min.</string>
<string name="absorption_cutoff_title">Maks absorpsjonstid for måltid [h]</string> <string name="absorption_cutoff_title">Maks absorpsjonstid for måltid [t]</string>
<string name="absorption_cutoff_summary">Etter denne tiden forventes det at måltidet er absorbert. Eventuelle gjenværende karbo vil tas ut av beregninger.</string> <string name="absorption_cutoff_summary">Etter denne tiden forventes det at måltidet er absorbert. Eventuelle gjenværende karbo vil tas ut av beregninger.</string>
</resources> </resources>

View file

@ -34,6 +34,6 @@
<string name="do_xdrip_upload_summary">I xDrip+, velg 640G/Eversens som datakilde</string> <string name="do_xdrip_upload_summary">I xDrip+, velg 640G/Eversens som datakilde</string>
<string name="bgsource_upload">Innstillinger for opplasting av BS</string> <string name="bgsource_upload">Innstillinger for opplasting av BS</string>
<string name="dexcom_log_ns_sensor_change_title">Logg sensorbytte til NS</string> <string name="dexcom_log_ns_sensor_change_title">Logg sensorbytte til NS</string>
<string name="dexcom_log_ns_sensor_change_summary">Opprett hendelse \"Sensor bytte\" automatisk i NS ved start av sensoren</string> <string name="dexcom_log_ns_sensor_change_summary">Opprett hendelse \"Sensorbytte\" automatisk i NS ved start av sensoren</string>
<string name="direction">retning</string> <string name="direction">retning</string>
</resources> </resources>

View file

@ -19,8 +19,9 @@ dependencies {
implementation project(':shared:impl') implementation project(':shared:impl')
implementation project(':database:entities') implementation project(':database:entities')
implementation project(':database:impl') implementation project(':database:impl')
implementation project(':core:main') implementation project(':core:graphview')
implementation project(':core:interfaces') implementation project(':core:interfaces')
implementation project(':core:main')
implementation project(':core:nssdk') implementation project(':core:nssdk')
implementation project(':core:ui') implementation project(':core:ui')
implementation project(':core:utils') implementation project(':core:utils')
@ -44,9 +45,11 @@ dependencies {
api("io.socket:socket.io-client:2.1.0") api("io.socket:socket.io-client:2.1.0")
api "com.squareup.okhttp3:okhttp:$okhttp3_version" api "com.squareup.okhttp3:okhttp:$okhttp3_version"
api "com.squareup.okhttp3:logging-interceptor:$okhttp3_version" api "com.squareup.okhttp3:logging-interceptor:$okhttp3_version"
//api "com.squareup.retrofit2:retrofit:$retrofit2_version"
api "com.squareup.retrofit2:adapter-rxjava3:$retrofit2_version" api "com.squareup.retrofit2:adapter-rxjava3:$retrofit2_version"
api "com.squareup.retrofit2:converter-gson:$retrofit2_version" api "com.squareup.retrofit2:converter-gson:$retrofit2_version"
api "com.google.code.gson:gson:$gson_version" api "com.google.code.gson:gson:$gson_version"
// DataLayerListenerService
api "com.google.android.gms:play-services-wearable:$play_services_wearable_version"
} }

View file

@ -8,6 +8,10 @@
android:name=".nsclient.services.NSClientService" android:name=".nsclient.services.NSClientService"
android:enabled="true" android:enabled="true"
android:exported="false" /> android:exported="false" />
<service
android:name=".nsclientV3.services.NSClientV3Service"
android:enabled="true"
android:exported="false" />
<activity <activity
android:name=".openhumans.ui.OHLoginActivity" android:name=".openhumans.ui.OHLoginActivity"
android:launchMode="singleTop" android:launchMode="singleTop"

View file

@ -63,7 +63,9 @@ class DataBroadcastPlugin @Inject constructor(
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.SYNC) .mainType(PluginType.SYNC)
.pluginIcon(app.aaps.core.main.R.drawable.ic_watch)
.pluginName(R.string.data_broadcaster) .pluginName(R.string.data_broadcaster)
.shortName(R.string.data_broadcaster_short)
.description(R.string.data_broadcaster_description), .description(R.string.data_broadcaster_description),
aapsLogger, rh, injector aapsLogger, rh, injector
) { ) {

View file

@ -7,6 +7,8 @@ import app.aaps.core.interfaces.nsclient.ProcessedDeviceStatusData
import app.aaps.core.interfaces.nsclient.StoreDataForDb import app.aaps.core.interfaces.nsclient.StoreDataForDb
import app.aaps.core.interfaces.sync.DataSyncSelectorXdrip import app.aaps.core.interfaces.sync.DataSyncSelectorXdrip
import app.aaps.core.interfaces.sync.XDripBroadcast import app.aaps.core.interfaces.sync.XDripBroadcast
import app.aaps.plugins.sync.garmin.LoopHub
import app.aaps.plugins.sync.garmin.LoopHubImpl
import app.aaps.plugins.sync.nsShared.NSClientFragment import app.aaps.plugins.sync.nsShared.NSClientFragment
import app.aaps.plugins.sync.nsShared.StoreDataForDbImpl import app.aaps.plugins.sync.nsShared.StoreDataForDbImpl
import app.aaps.plugins.sync.nsclient.data.NSSettingsStatusImpl import app.aaps.plugins.sync.nsclient.data.NSSettingsStatusImpl
@ -16,6 +18,7 @@ import app.aaps.plugins.sync.nsclient.workers.NSClientAddAckWorker
import app.aaps.plugins.sync.nsclient.workers.NSClientAddUpdateWorker import app.aaps.plugins.sync.nsclient.workers.NSClientAddUpdateWorker
import app.aaps.plugins.sync.nsclient.workers.NSClientMbgWorker import app.aaps.plugins.sync.nsclient.workers.NSClientMbgWorker
import app.aaps.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker import app.aaps.plugins.sync.nsclient.workers.NSClientUpdateRemoveAckWorker
import app.aaps.plugins.sync.nsclientV3.services.NSClientV3Service
import app.aaps.plugins.sync.nsclientV3.workers.DataSyncWorker import app.aaps.plugins.sync.nsclientV3.workers.DataSyncWorker
import app.aaps.plugins.sync.nsclientV3.workers.LoadBgWorker import app.aaps.plugins.sync.nsclientV3.workers.LoadBgWorker
import app.aaps.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker import app.aaps.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
@ -25,6 +28,9 @@ import app.aaps.plugins.sync.nsclientV3.workers.LoadProfileStoreWorker
import app.aaps.plugins.sync.nsclientV3.workers.LoadStatusWorker import app.aaps.plugins.sync.nsclientV3.workers.LoadStatusWorker
import app.aaps.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker import app.aaps.plugins.sync.nsclientV3.workers.LoadTreatmentsWorker
import app.aaps.plugins.sync.tidepool.TidepoolFragment import app.aaps.plugins.sync.tidepool.TidepoolFragment
import app.aaps.plugins.sync.wear.WearFragment
import app.aaps.plugins.sync.wear.activities.CwfInfosActivity
import app.aaps.plugins.sync.wear.wearintegration.DataLayerListenerServiceMobile
import app.aaps.plugins.sync.xdrip.DataSyncSelectorXdripImpl import app.aaps.plugins.sync.xdrip.DataSyncSelectorXdripImpl
import app.aaps.plugins.sync.xdrip.XdripFragment import app.aaps.plugins.sync.xdrip.XdripFragment
import app.aaps.plugins.sync.xdrip.XdripPlugin import app.aaps.plugins.sync.xdrip.XdripPlugin
@ -48,6 +54,7 @@ abstract class SyncModule {
@ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment @ContributesAndroidInjector abstract fun contributesNSClientFragment(): NSClientFragment
@ContributesAndroidInjector abstract fun contributesNSClientService(): NSClientService @ContributesAndroidInjector abstract fun contributesNSClientService(): NSClientService
@ContributesAndroidInjector abstract fun contributesNSClientV3Service(): NSClientV3Service
@ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker @ContributesAndroidInjector abstract fun contributesNSClientWorker(): NSClientAddUpdateWorker
@ContributesAndroidInjector abstract fun contributesNSClientAddAckWorker(): NSClientAddAckWorker @ContributesAndroidInjector abstract fun contributesNSClientAddAckWorker(): NSClientAddAckWorker
@ContributesAndroidInjector abstract fun contributesNSClientUpdateRemoveAckWorker(): NSClientUpdateRemoveAckWorker @ContributesAndroidInjector abstract fun contributesNSClientUpdateRemoveAckWorker(): NSClientUpdateRemoveAckWorker
@ -65,6 +72,9 @@ abstract class SyncModule {
@ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment @ContributesAndroidInjector abstract fun contributesTidepoolFragment(): TidepoolFragment
@ContributesAndroidInjector abstract fun contributesXdripFragment(): XdripFragment @ContributesAndroidInjector abstract fun contributesXdripFragment(): XdripFragment
@ContributesAndroidInjector abstract fun contributesXdripDataSyncWorker(): XdripDataSyncWorker @ContributesAndroidInjector abstract fun contributesXdripDataSyncWorker(): XdripDataSyncWorker
@ContributesAndroidInjector abstract fun contributesWearFragment(): WearFragment
@ContributesAndroidInjector abstract fun contributesWatchUpdaterService(): DataLayerListenerServiceMobile
@ContributesAndroidInjector abstract fun contributesCustomWatchfaceInfosActivity(): CwfInfosActivity
@Module @Module
open class Provide { open class Provide {
@ -82,6 +92,7 @@ abstract class SyncModule {
@Binds fun bindDataSyncSelectorXdripInterface(dataSyncSelectorXdripImpl: DataSyncSelectorXdripImpl): DataSyncSelectorXdrip @Binds fun bindDataSyncSelectorXdripInterface(dataSyncSelectorXdripImpl: DataSyncSelectorXdripImpl): DataSyncSelectorXdrip
@Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb @Binds fun bindStoreDataForDb(storeDataForDbImpl: StoreDataForDbImpl): StoreDataForDb
@Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast @Binds fun bindXDripBroadcastInterface(xDripBroadcastImpl: XdripPlugin): XDripBroadcast
@Binds fun bindLoopHub(loopHub: LoopHubImpl): LoopHub
} }
} }

View file

@ -0,0 +1,187 @@
package app.aaps.plugins.sync.garmin
import java.nio.ByteBuffer
import java.nio.ByteOrder
import java.nio.IntBuffer
import java.nio.LongBuffer
import java.util.Base64
/** Efficient encoding for glucose/timestamp pairs.
*
* Garmin devices don't have much memory when deserializing received JSON messages.
* In particular older devices my kill our app when we send 2h of glucose values. Therefore, we
* encode the values efficiently.
* We use [var encoding](https://en.wikipedia.org/wiki/Variable-width_encoding). In order to
* keep timestamps small, we encode the difference to the previous pair and to encode negative values
* efficiently, we use [zig-zag encoding](https://en.wikipedia.org/wiki/Variable-length_quantity).
*/
class DeltaVarEncodedList {
private var lastValues: IntArray
private var data: ByteArray
private val start: Int = 0
private var end: Int = 0
val byteSize: Int get() = end - start
var size: Int = 0
private set
/** Creates a new list of given size.
*
* @param byteSize How large the internal buffer should be. The buffer doesn't grow
* automatically, so you need to set it large enough.
* @param entrySize Size of each entry (e.g. 2 for glucose+timestamp). Delta is computed on each
* entrySize value.
*/
constructor(byteSize: Int, entrySize: Int) {
data = ByteArray(toLongBoundary(byteSize))
lastValues = IntArray(entrySize)
}
/** Creates a list from encoded values.
*
* @param lastValues the last values of the list. Needs to be entrySize long.
* @param byteBuffer the encoded data
*/
constructor(lastValues: IntArray, byteBuffer: ByteBuffer) {
this.lastValues = lastValues
data = ByteArray(byteBuffer.limit())
byteBuffer.position(0)
byteBuffer.get(data)
end = data.size
val it = DeltaIterator()
while (it.next()) {
size++
}
}
/** Gets the encoded data. */
fun encodedData(): List<Long> {
val byteBuffer: ByteBuffer = ByteBuffer.wrap(data)
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
byteBuffer.limit(toLongBoundary(end))
val buffer: LongBuffer = byteBuffer.asLongBuffer()
val encodedData: MutableList<Long> = ArrayList(buffer.limit())
while (buffer.position() < buffer.limit()) {
encodedData.add(buffer.get())
}
return encodedData
}
fun encodedBase64(): String {
val byteBuffer: ByteBuffer = ByteBuffer.wrap(data, start, end)
byteBuffer.order(ByteOrder.LITTLE_ENDIAN)
return String(Base64.getEncoder().encode(byteBuffer).array())
}
private fun addVarEncoded(value: Int) {
var remaining: Int = value
do {
// Grow data if needed (double size).
if (end == data.size) {
val newData = ByteArray(2 * end)
System.arraycopy(data, 0, newData, 0, end)
data = newData
}
if ((remaining and 0x7f.inv()) != 0) {
data[end++] = ((remaining and 0x7f) or 0x80).toByte()
} else {
data[end++] = remaining.toByte()
}
remaining = remaining ushr 7
} while (remaining != 0)
}
private fun addI(value: Int, idx: Int) {
val delta: Int = value - lastValues[idx]
addVarEncoded(zigzagEncode(delta))
lastValues[idx] = value
}
/** Adds an entry to the buffer.
*
* [values] length must be the same as entrySize provided in the constructor. */
fun add(vararg values: Int) {
if (values.size != lastValues.size) {
throw IllegalArgumentException()
}
for (idx in values.indices) {
addI(values[idx], idx)
}
size++
}
fun toArray(): IntArray {
val values: IntBuffer = IntBuffer.allocate(lastValues.size * size)
val it = DeltaIterator()
while (it.next()) {
values.put(it.current())
}
val next: IntArray = lastValues.copyOf(lastValues.size)
var nextIdx: Int = next.size - 1
for (valueIdx in values.position() - 1 downTo 0) {
val value: Int = values.get(valueIdx)
values.put(valueIdx, next[nextIdx])
next[nextIdx] -= value
nextIdx = (nextIdx + 1) % next.size
}
return values.array()
}
private inner class DeltaIterator {
private val buffer: ByteBuffer = ByteBuffer.wrap(data)
private val currentValues: IntArray = IntArray(lastValues.size)
private var more: Boolean = false
fun current(): IntArray {
return currentValues
}
private fun readNext(): Int {
var v = 0
var offset = 0
var b: Int
do {
if (!buffer.hasRemaining()) {
more = false
return 0
}
b = buffer.get().toInt()
v = v or ((b and 0x7f) shl offset)
offset += 7
} while ((b and 0x80) != 0)
return zigzagDecode(v)
}
operator fun next(): Boolean {
if (!buffer.hasRemaining()) return false
more = true
var i = 0
while (i < currentValues.size && more) {
currentValues[i] = readNext()
i++
}
return more
}
init {
buffer.position(start)
buffer.limit(end)
buffer.order(ByteOrder.LITTLE_ENDIAN)
}
}
companion object {
private fun toLongBoundary(i: Int): Int {
return 8 * ((i + 7) / 8)
}
private fun zigzagEncode(i: Int): Int {
return (i shr 31) xor (i shl 1)
}
private fun zigzagDecode(i: Int): Int {
return (i ushr 1) xor -(i and 1)
}
}
}

View file

@ -0,0 +1,246 @@
package app.aaps.plugins.sync.garmin
import androidx.annotation.VisibleForTesting
import app.aaps.core.interfaces.db.GlucoseUnit
import app.aaps.core.interfaces.logging.AAPSLogger
import app.aaps.core.interfaces.logging.LTag
import app.aaps.core.interfaces.plugin.PluginBase
import app.aaps.core.interfaces.plugin.PluginDescription
import app.aaps.core.interfaces.plugin.PluginType
import app.aaps.core.interfaces.resources.ResourceHelper
import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventNewBG
import app.aaps.core.interfaces.rx.events.EventPreferenceChange
import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.database.entities.GlucoseValue
import app.aaps.plugins.sync.R
import com.google.gson.JsonObject
import dagger.android.HasAndroidInjector
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.schedulers.Schedulers
import java.net.SocketAddress
import java.net.URI
import java.time.Clock
import java.time.Duration
import java.time.Instant
import java.util.*
import java.util.concurrent.locks.Condition
import java.util.concurrent.locks.ReentrantLock
import javax.inject.Inject
import javax.inject.Singleton
import kotlin.concurrent.withLock
import kotlin.math.roundToInt
/** Support communication with Garmin devices.
*
* This plugin supports sending glucose values to Garmin devices and receiving
* carbs, heart rate and pump disconnect events from the device. It communicates
* via HTTP on localhost or Garmin's native CIQ library.
*/
@Singleton
class GarminPlugin @Inject constructor(
injector: HasAndroidInjector,
aapsLogger: AAPSLogger,
resourceHelper: ResourceHelper,
private val loopHub: LoopHub,
private val rxBus: RxBus,
private val sp: SP,
) : PluginBase(
PluginDescription()
.mainType(PluginType.SYNC)
.pluginIcon(app.aaps.core.main.R.drawable.ic_watch)
.pluginName(R.string.garmin)
.shortName(R.string.garmin)
.description(R.string.garmin_description)
.preferencesId(R.xml.pref_garmin),
aapsLogger, resourceHelper, injector
) {
/** HTTP Server for local HTTP server communication (device app requests values) .*/
private var server: HttpServer? = null
private val disposable = CompositeDisposable()
@VisibleForTesting
var clock: Clock = Clock.systemUTC()
private val valueLock = ReentrantLock()
@VisibleForTesting
var newValue: Condition = valueLock.newCondition()
private var lastGlucoseValueTimestamp: Long? = null
private val glucoseUnitStr get() = if (loopHub.glucoseUnit == GlucoseUnit.MGDL) "mgdl" else "mmoll"
private fun onPreferenceChange(event: EventPreferenceChange) {
aapsLogger.info(LTag.GARMIN, "preferences change ${event.changedKey}")
setupHttpServer()
}
override fun onStart() {
super.onStart()
aapsLogger.info(LTag.GARMIN, "start")
disposable.add(
rxBus
.toObservable(EventPreferenceChange::class.java)
.observeOn(Schedulers.io())
.subscribe(::onPreferenceChange)
)
setupHttpServer()
}
private fun setupHttpServer() {
if (sp.getBoolean("communication_http", false)) {
val port = sp.getInt("communication_http_port", 28891)
if (server != null && server?.port == port) return
aapsLogger.info(LTag.GARMIN, "starting HTTP server on $port")
server?.close()
server = HttpServer(aapsLogger, port).apply {
registerEndpoint("/get", ::onGetBloodGlucose)
}
} else if (server != null) {
aapsLogger.info(LTag.GARMIN, "stopping HTTP server")
server?.close()
server = null
}
}
override fun onStop() {
disposable.clear()
aapsLogger.info(LTag.GARMIN, "Stop")
server?.close()
server = null
super.onStop()
}
/** Receive new blood glucose events.
*
* Stores new blood glucose values in lastGlucoseValue to make sure we return
* these values immediately when values are requested by Garmin device.
* Sends a message to the Garmin devices via the ciqMessenger. */
@VisibleForTesting
fun onNewBloodGlucose(event: EventNewBG) {
val timestamp = event.glucoseValueTimestamp ?: return
aapsLogger.info(LTag.GARMIN, "onNewBloodGlucose ${Date(timestamp)}")
valueLock.withLock {
if ((lastGlucoseValueTimestamp?: 0) >= timestamp) return
lastGlucoseValueTimestamp = timestamp
newValue.signalAll()
}
}
/** Gets the last 2+ hours of glucose values. */
@VisibleForTesting
fun getGlucoseValues(): List<GlucoseValue> {
val from = clock.instant().minus(Duration.ofHours(2).plusMinutes(9))
return loopHub.getGlucoseValues(from, true)
}
/** Get the last 2+ hours of glucose values and waits in case a new value should arrive soon. */
private fun getGlucoseValues(maxWait: Duration): List<GlucoseValue> {
val glucoseFrequency = Duration.ofMinutes(5)
val glucoseValues = getGlucoseValues()
val last = glucoseValues.lastOrNull() ?: return emptyList()
val delay = Duration.ofMillis(clock.millis() - last.timestamp)
return if (!maxWait.isZero
&& delay > glucoseFrequency
&& delay < glucoseFrequency.plusMinutes(1)) {
valueLock.withLock {
aapsLogger.debug(LTag.GARMIN, "waiting for new glucose (delay=$delay)")
newValue.awaitNanos(maxWait.toNanos())
}
getGlucoseValues()
} else {
glucoseValues
}
}
private fun encodedGlucose(glucoseValues: List<GlucoseValue>): String {
val encodedGlucose = DeltaVarEncodedList(glucoseValues.size * 16, 2)
for (glucose: GlucoseValue in glucoseValues) {
val timeSec: Int = (glucose.timestamp / 1000).toInt()
val glucoseMgDl: Int = glucose.value.roundToInt()
encodedGlucose.add(timeSec, glucoseMgDl)
}
aapsLogger.info(
LTag.GARMIN,
"retrieved ${glucoseValues.size} last ${Date(glucoseValues.lastOrNull()?.timestamp ?: 0L)} ${encodedGlucose.size}"
)
return encodedGlucose.encodedBase64()
}
/** Responses to get glucose value request by the device.
*
* Also, gets the heart rate readings from the device.
*/
@VisibleForTesting
@Suppress("UNUSED_PARAMETER")
fun onGetBloodGlucose(caller: SocketAddress, uri: URI, requestBody: String?): CharSequence {
aapsLogger.info(LTag.GARMIN, "get from $caller resp , req: $uri")
receiveHeartRate(uri)
val profileName = loopHub.currentProfileName
val waitSec = getQueryParameter(uri, "wait", 0L)
val glucoseValues = getGlucoseValues(Duration.ofSeconds(waitSec))
val jo = JsonObject()
jo.addProperty("encodedGlucose", encodedGlucose(glucoseValues))
jo.addProperty("remainingInsulin", loopHub.insulinOnboard)
jo.addProperty("glucoseUnit", glucoseUnitStr)
loopHub.temporaryBasal.also {
if (!it.isNaN()) jo.addProperty("temporaryBasalRate", it)
}
jo.addProperty("profile", profileName.first().toString())
jo.addProperty("connected", loopHub.isConnected)
return jo.toString().also {
aapsLogger.info(LTag.GARMIN, "get from $caller resp , req: $uri, result: $it")
}
}
private fun getQueryParameter(uri: URI, name: String) = (uri.query ?: "")
.split("&")
.map { kv -> kv.split("=") }
.firstOrNull { kv -> kv.size == 2 && kv[0] == name }?.get(1)
private fun getQueryParameter(
uri: URI,
@Suppress("SameParameterValue") name: String,
@Suppress("SameParameterValue") defaultValue: Boolean): Boolean {
return when (getQueryParameter(uri, name)?.lowercase()) {
"true" -> true
"false" -> false
else -> defaultValue
}
}
private fun getQueryParameter(
uri: URI, name: String,
@Suppress("SameParameterValue") defaultValue: Long
): Long {
val value = getQueryParameter(uri, name)
return try {
if (value.isNullOrEmpty()) defaultValue else value.toLong()
} catch (e: NumberFormatException) {
aapsLogger.error(LTag.GARMIN, "invalid $name value '$value'")
defaultValue
}
}
@VisibleForTesting
fun receiveHeartRate(uri: URI) {
val avg: Int = getQueryParameter(uri, "hr", 0L).toInt()
val samplingStartSec: Long = getQueryParameter(uri, "hrStart", 0L)
val samplingEndSec: Long = getQueryParameter(uri, "hrEnd", 0L)
val device: String? = getQueryParameter(uri, "device")
receiveHeartRate(
Instant.ofEpochSecond(samplingStartSec), Instant.ofEpochSecond(samplingEndSec),
avg, device, getQueryParameter(uri, "test", false))
}
private fun receiveHeartRate(
samplingStart: Instant, samplingEnd: Instant,
avg: Int, device: String?, test: Boolean) {
aapsLogger.info(LTag.GARMIN, "average heart rate $avg BPM test=$test")
if (test) return
if (avg > 10 && samplingStart > Instant.ofEpochMilli(0L) && samplingEnd > samplingStart) {
loopHub.storeHeartRate(samplingStart, samplingEnd, avg, device)
} else {
aapsLogger.warn(LTag.GARMIN, "Skip saving invalid HR $avg $samplingStart..$samplingEnd")
}
}
}

View file

@ -0,0 +1,271 @@
package app.aaps.plugins.sync.garmin
import android.os.StrictMode
import androidx.annotation.VisibleForTesting
import app.aaps.core.interfaces.logging.AAPSLogger
import app.aaps.core.interfaces.logging.LTag
import java.io.BufferedOutputStream
import java.io.ByteArrayOutputStream
import java.io.Closeable
import java.io.IOException
import java.io.InputStream
import java.io.OutputStream
import java.lang.Thread.UncaughtExceptionHandler
import java.net.HttpURLConnection
import java.net.Inet4Address
import java.net.InetSocketAddress
import java.net.ServerSocket
import java.net.Socket
import java.net.SocketAddress
import java.net.SocketTimeoutException
import java.net.URI
import java.nio.charset.Charset
import java.nio.charset.StandardCharsets
import java.time.Duration
import java.util.concurrent.ConcurrentHashMap
import java.util.concurrent.Executor
import java.util.concurrent.Executors
import java.util.concurrent.locks.ReentrantLock
import java.util.regex.Pattern
import kotlin.concurrent.withLock
/** Basic HTTP server to communicate with Garmin device via localhost. */
class HttpServer internal constructor(private var aapsLogger: AAPSLogger, val port: Int) : Closeable {
private val serverThread: Thread
private val workerExecutor: Executor = Executors.newCachedThreadPool()
private val endpoints: MutableMap<String, (SocketAddress, URI, String?) -> CharSequence> =
ConcurrentHashMap()
private var serverSocket: ServerSocket? = null
private val readyLock = ReentrantLock()
private val readyCond = readyLock.newCondition()
init {
serverThread = Thread { runServer() }
serverThread.name = "GarminHttpServer"
serverThread.isDaemon = true
serverThread.uncaughtExceptionHandler = UncaughtExceptionHandler { _, e ->
e.printStackTrace()
aapsLogger.error(LTag.GARMIN, "uncaught in HTTP server", e)
serverSocket?.use {}
}
serverThread.start()
}
override fun close() {
try {
serverSocket?.close()
serverSocket = null
} catch (_: IOException) {
}
try {
serverThread.join(10_000L)
} catch (_: InterruptedException) {
}
}
/** Wait for the server to start listing to requests. */
fun awaitReady(wait: Duration): Boolean {
var waitNanos = wait.toNanos()
readyLock.withLock {
while (serverSocket?.isBound != true && waitNanos > 0L) {
waitNanos = readyCond.awaitNanos(waitNanos)
}
}
return serverSocket?.isBound ?: false
}
/** Register an endpoint (path) to handle requests. */
fun registerEndpoint(path: String, endpoint: (SocketAddress, URI, String?) -> CharSequence) {
aapsLogger.info(LTag.GARMIN, "Register: '$path'")
endpoints[path] = endpoint
}
// @Suppress("all")
private fun respond(
@Suppress("SameParameterValue") code: Int,
body: CharSequence,
@Suppress("SameParameterValue") contentType: String,
out: OutputStream
) {
respond(code, body.toString().toByteArray(Charset.forName("UTF8")), contentType, out)
}
private fun respond(code: Int, out: OutputStream) {
respond(code, null as ByteArray?, null, out)
}
private fun respond(code: Int, body: ByteArray?, contentType: String?, out: OutputStream) {
val header = StringBuilder()
header.append("HTTP/1.1 ").append(code).append(" OK\r\n")
if (body != null) {
appendHeader("Content-Length", "" + body.size, header)
}
if (contentType != null) {
appendHeader("Content-Type", contentType, header)
}
header.append("\r\n")
val bout = BufferedOutputStream(out)
bout.write(header.toString().toByteArray(StandardCharsets.US_ASCII))
if (body != null) {
bout.write(body)
}
bout.flush()
}
private fun handleRequest(s: Socket) {
val out = s.getOutputStream()
try {
val (uri, reqBody) = parseRequest(s.getInputStream())
if ("favicon.ico" == uri.path) {
respond(HttpURLConnection.HTTP_NOT_FOUND, out)
return
}
val endpoint = endpoints[uri.path ?: ""]
if (endpoint == null) {
aapsLogger.error(LTag.GARMIN, "request path not found '" + uri.path + "'")
respond(HttpURLConnection.HTTP_NOT_FOUND, out)
} else {
try {
val body = endpoint(s.remoteSocketAddress, uri, reqBody)
respond(HttpURLConnection.HTTP_OK, body, "application/json", out)
} catch (e: Exception) {
aapsLogger.error(LTag.GARMIN, "endpoint " + uri.path + " failed", e)
respond(HttpURLConnection.HTTP_INTERNAL_ERROR, out)
}
}
} catch (e: SocketTimeoutException) {
// Client may just connect without sending anything.
aapsLogger.debug(LTag.GARMIN, "socket timeout: " + e.message)
return
} catch (e: IOException) {
aapsLogger.error(LTag.GARMIN, "Invalid request", e)
respond(HttpURLConnection.HTTP_BAD_REQUEST, out)
return
}
}
private fun runServer() = try {
// Policy won't work in unit tests, so ignore NULL builder.
@Suppress("UNNECESSARY_SAFE_CALL")
val policy = StrictMode.ThreadPolicy.Builder()?.permitAll()?.build()
if (policy != null) StrictMode.setThreadPolicy(policy)
readyLock.withLock {
serverSocket = ServerSocket()
serverSocket!!.bind(
// Garmin will only connect to IP4 localhost. Therefore, we need to explicitly listen
// on that loopback interface and cannot use InetAddress.getLoopbackAddress(). That
// gives ::1 (IP6 localhost).
InetSocketAddress(Inet4Address.getByAddress(byteArrayOf(127, 0, 0, 1)), port)
)
readyCond.signalAll()
}
aapsLogger.info(LTag.GARMIN, "accept connections on " + serverSocket!!.localSocketAddress)
while (true) {
val socket = serverSocket!!.accept()
aapsLogger.info(LTag.GARMIN, "accept " + socket.remoteSocketAddress)
workerExecutor.execute {
Thread.currentThread().name = "worker" + Thread.currentThread().id
try {
socket.use { s ->
s.soTimeout = 10_000
handleRequest(s)
}
} catch (e: Exception) {
aapsLogger.error(LTag.GARMIN, "response failed", e)
}
}
}
} catch (e: IOException) {
aapsLogger.error("Server crashed", e)
} finally {
try {
serverSocket?.close()
serverSocket = null
} catch (e: IOException) {
aapsLogger.error(LTag.GARMIN, "Socked close failed", e)
}
}
companion object {
private val REQUEST_HEADER = Pattern.compile("(GET|POST) (\\S*) HTTP/1.1")
private val HEADER_LINE = Pattern.compile("([A-Za-z-]+)\\s*:\\s*(.*)")
private fun readLine(input: InputStream, charset: Charset): String {
val buffer = ByteArrayOutputStream(input.available())
loop@ while (true) {
when (val c = input.read()) {
'\r'.code -> {}
-1 -> break@loop
'\n'.code -> break@loop
else -> buffer.write(c)
}
}
return String(buffer.toByteArray(), charset)
}
@VisibleForTesting
internal fun readBody(input: InputStream, length: Int): String {
var remaining = length
val buffer = ByteArrayOutputStream(input.available())
var c: Int = -1
while (remaining-- > 0 && (input.read().also { c = it }) != -1) {
buffer.write(c)
}
return buffer.toString("UTF8")
}
/** Parses a requests and returns the URI and the request body. */
@VisibleForTesting
internal fun parseRequest(input: InputStream): Pair<URI, String?> {
val headerLine = readLine(input, Charset.forName("ASCII"))
val p = REQUEST_HEADER.matcher(headerLine)
if (!p.matches()) {
throw IOException("invalid HTTP header '$headerLine'")
}
val post = ("POST" == p.group(1))
var uri = URI(p.group(2))
val headers: MutableMap<String, String?> = HashMap()
while (true) {
val line = readLine(input, Charset.forName("ASCII"))
if (line.isEmpty()) {
break
}
val m = HEADER_LINE.matcher(line)
if (!m.matches()) {
throw IOException("invalid header line '$line'")
}
headers[m.group(1)!!] = m.group(2)
}
var body: String?
if (post) {
val contentLength = headers["Content-Length"]?.toInt() ?: Int.MAX_VALUE
val keepAlive = ("Keep-Alive" == headers["Connection"])
val contentType = headers["Content-Type"]
if (keepAlive && contentLength == Int.MAX_VALUE) {
throw IOException("keep-alive without content-length for $uri")
}
body = readBody(input, contentLength)
if (("application/x-www-form-urlencoded" == contentType)) {
uri = URI(uri.scheme, uri.userInfo, uri.host, uri.port, uri.path, body, null)
// uri.encodedQuery(body)
body = null
} else if ("application/json" != contentType && body.isNotBlank()) {
body = null
}
} else {
body = null
}
return Pair(uri, body?.takeUnless(String::isBlank))
}
private fun appendHeader(name: String, value: String, header: StringBuilder) {
header.append(name)
header.append(": ")
header.append(value)
header.append("\r\n")
}
}
}

View file

@ -0,0 +1,41 @@
package app.aaps.plugins.sync.garmin
import app.aaps.core.interfaces.db.GlucoseUnit
import app.aaps.core.interfaces.profile.Profile
import app.aaps.database.entities.GlucoseValue
import java.time.Instant
/** Abstraction from all the functionality we need from the AAPS app. */
interface LoopHub {
/** Returns the active insulin profile. */
val currentProfile: Profile?
/** Returns the name of the active insulin profile. */
val currentProfileName: String
/** Returns the glucose unit (mg/dl or mmol/l) as selected by the user. */
val glucoseUnit: GlucoseUnit
/** Returns the remaining bolus insulin on board. */
val insulinOnboard: Double
/** Returns true if the pump is connected. */
val isConnected: Boolean
/** Returns true if the current profile is set of a limited amount of time. */
val isTemporaryProfile: Boolean
/** Returns the factor by which the basal rate is currently raised (> 1) or lowered (< 1). */
val temporaryBasal: Double
/** Retrieves the glucose values starting at from. */
fun getGlucoseValues(from: Instant, ascending: Boolean): List<GlucoseValue>
/** Stores hear rate readings that a taken and averaged of the given interval. */
fun storeHeartRate(
samplingStart: Instant, samplingEnd: Instant,
avgHeartRate: Int,
device: String?
)
}

View file

@ -0,0 +1,88 @@
package app.aaps.plugins.sync.garmin
import androidx.annotation.VisibleForTesting
import app.aaps.core.interfaces.aps.Loop
import app.aaps.core.interfaces.db.GlucoseUnit
import app.aaps.core.interfaces.iob.IobCobCalculator
import app.aaps.core.interfaces.profile.Profile
import app.aaps.core.interfaces.profile.ProfileFunction
import app.aaps.database.ValueWrapper
import app.aaps.database.entities.EffectiveProfileSwitch
import app.aaps.database.entities.GlucoseValue
import app.aaps.database.entities.HeartRate
import app.aaps.database.impl.AppRepository
import app.aaps.database.impl.transactions.InsertOrUpdateHeartRateTransaction
import java.time.Clock
import java.time.Instant
import javax.inject.Inject
import javax.inject.Singleton
@Singleton
/**
* Interface to the functionality of the looping algorithm and storage systems.
*/
class LoopHubImpl @Inject constructor(
private val iobCobCalculator: IobCobCalculator,
private val loop: Loop,
private val profileFunction: ProfileFunction,
private val repo: AppRepository,
) : LoopHub {
@VisibleForTesting
var clock: Clock = Clock.systemUTC()
/** Returns the active insulin profile. */
override val currentProfile: Profile? get() = profileFunction.getProfile()
/** Returns the name of the active insulin profile. */
override val currentProfileName: String
get() = profileFunction.getProfileName()
/** Returns the glucose unit (mg/dl or mmol/l) as selected by the user. */
override val glucoseUnit: GlucoseUnit
get() = profileFunction.getProfile()?.units ?: GlucoseUnit.MGDL
/** Returns the remaining bolus insulin on board. */
override val insulinOnboard: Double
get() = iobCobCalculator.calculateIobFromBolus().iob
/** Returns true if the pump is connected. */
override val isConnected: Boolean get() = !loop.isDisconnected
/** Returns true if the current profile is set of a limited amount of time. */
override val isTemporaryProfile: Boolean
get() {
val resp = repo.getEffectiveProfileSwitchActiveAt(clock.millis())
val ps: EffectiveProfileSwitch? =
(resp.blockingGet() as? ValueWrapper.Existing<EffectiveProfileSwitch>)?.value
return ps != null && ps.originalDuration > 0
}
/** Returns the factor by which the basal rate is currently raised (> 1) or lowered (< 1). */
override val temporaryBasal: Double
get() {
val apsResult = loop.lastRun?.constraintsProcessed
return if (apsResult == null) Double.NaN else apsResult.percent / 100.0
}
/** Retrieves the glucose values starting at from. */
override fun getGlucoseValues(from: Instant, ascending: Boolean): List<GlucoseValue> {
return repo.compatGetBgReadingsDataFromTime(from.toEpochMilli(), ascending)
.blockingGet()
}
/** Stores hear rate readings that a taken and averaged of the given interval. */
override fun storeHeartRate(
samplingStart: Instant, samplingEnd: Instant,
avgHeartRate: Int,
device: String?) {
val hr = HeartRate(
timestamp = samplingStart.toEpochMilli(),
duration = samplingEnd.toEpochMilli() - samplingStart.toEpochMilli(),
dateCreated = clock.millis(),
beatsPerMinute = avgHeartRate.toDouble(),
device = device ?: "Garmin",
)
repo.runTransaction(InsertOrUpdateHeartRateTransaction(hr)).blockingAwait()
}
}

View file

@ -122,6 +122,8 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
ID_MENU_CLEAR_LOG -> { ID_MENU_CLEAR_LOG -> {
nsClientPlugin?.listLog?.let { nsClientPlugin?.listLog?.let {
synchronized(it) { synchronized(it) {
val size = it.size
binding.recyclerview.adapter?.notifyItemRangeRemoved(0, size)
it.clear() it.clear()
updateLog() updateLog()
} }
@ -135,7 +137,7 @@ class NSClientFragment : DaggerFragment(), MenuProvider, PluginFragment {
} }
ID_MENU_SEND_NOW -> { ID_MENU_SEND_NOW -> {
nsClientPlugin?.resend("GUI") handler.post { nsClientPlugin?.resend("GUI") }
true true
} }

View file

@ -2,4 +2,4 @@ package app.aaps.plugins.sync.nsShared.events
import app.aaps.core.interfaces.rx.events.Event import app.aaps.core.interfaces.rx.events.Event
class EventConnectivityOptionChanged(val blockingReason: String) : Event() class EventConnectivityOptionChanged(val blockingReason: String, val connected: Boolean) : Event()

View file

@ -114,7 +114,7 @@ class NSClientPlugin @Inject constructor(
} }
override fun onStop() { override fun onStop() {
context.applicationContext.unbindService(mConnection) if (nsClientService != null) context.unbindService(mConnection)
disposable.clear() disposable.clear()
super.onStop() super.onStop()
} }
@ -233,7 +233,7 @@ class NSClientPlugin @Inject constructor(
is DataSyncSelector.PairProfileSwitch -> dataPair.value.interfaceIDs.nightscoutId is DataSyncSelector.PairProfileSwitch -> dataPair.value.interfaceIDs.nightscoutId
is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.interfaceIDs.nightscoutId is DataSyncSelector.PairEffectiveProfileSwitch -> dataPair.value.interfaceIDs.nightscoutId
is DataSyncSelector.PairOfflineEvent -> dataPair.value.interfaceIDs.nightscoutId is DataSyncSelector.PairOfflineEvent -> dataPair.value.interfaceIDs.nightscoutId
else -> throw IllegalStateException() else -> error("Unsupported type")
} }
when (dataPair) { when (dataPair) {
is DataSyncSelector.PairBolus -> dataPair.value.toJson(false, dateUtil) is DataSyncSelector.PairBolus -> dataPair.value.toJson(false, dateUtil)

View file

@ -94,7 +94,7 @@ class ReceiverDelegate @Inject constructor(
if (newAllowedState != allowed) { if (newAllowedState != allowed) {
allowed = newAllowedState allowed = newAllowedState
if (allowed) blockingReason = "" if (allowed) blockingReason = ""
rxBus.send(EventConnectivityOptionChanged(blockingReason)) rxBus.send(EventConnectivityOptionChanged(blockingReason, receiverStatusStore.isConnected))
} }
} }

View file

@ -2,13 +2,18 @@ package app.aaps.plugins.sync.nsclient.data
import app.aaps.annotations.OpenForTesting import app.aaps.annotations.OpenForTesting
import app.aaps.core.interfaces.configuration.Config import app.aaps.core.interfaces.configuration.Config
import app.aaps.core.interfaces.notifications.Notification
import app.aaps.core.interfaces.nsclient.ProcessedDeviceStatusData import app.aaps.core.interfaces.nsclient.ProcessedDeviceStatusData
import app.aaps.core.interfaces.resources.ResourceHelper
import app.aaps.core.interfaces.sharedPreferences.SP import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.ui.UiInteraction
import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.DateUtil
import app.aaps.core.interfaces.utils.T
import app.aaps.core.nssdk.interfaces.RunningConfiguration import app.aaps.core.nssdk.interfaces.RunningConfiguration
import app.aaps.core.nssdk.localmodel.devicestatus.NSDeviceStatus import app.aaps.core.nssdk.localmodel.devicestatus.NSDeviceStatus
import app.aaps.core.utils.HtmlHelper import app.aaps.core.utils.HtmlHelper
import app.aaps.core.utils.JsonHelper import app.aaps.core.utils.JsonHelper
import app.aaps.plugins.sync.R
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -72,24 +77,31 @@ class NSDeviceStatusHandler @Inject constructor(
private val config: Config, private val config: Config,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val runningConfiguration: RunningConfiguration, private val runningConfiguration: RunningConfiguration,
private val processedDeviceStatusData: ProcessedDeviceStatusData private val processedDeviceStatusData: ProcessedDeviceStatusData,
private val uiInteraction: UiInteraction,
private val rh: ResourceHelper
) { ) {
fun handleNewData(deviceStatuses: Array<NSDeviceStatus>) { fun handleNewData(deviceStatuses: Array<NSDeviceStatus>) {
var configurationDetected = false var configurationDetected = false
for (i in deviceStatuses.size - 1 downTo 0) { for (i in deviceStatuses.size - 1 downTo 0) {
val nsDeviceStatus = deviceStatuses[i] val nsDeviceStatus = deviceStatuses[i]
updatePumpData(nsDeviceStatus) if (config.NSCLIENT) {
updateDeviceData(nsDeviceStatus) updatePumpData(nsDeviceStatus)
updateOpenApsData(nsDeviceStatus) updateDeviceData(nsDeviceStatus)
updateUploaderData(nsDeviceStatus) updateOpenApsData(nsDeviceStatus)
nsDeviceStatus.pump?.let { sp.putBoolean(app.aaps.core.utils.R.string.key_objectives_pump_status_is_available_in_ns, true) } // Objective 0 updateUploaderData(nsDeviceStatus)
}
if (config.NSCLIENT && !configurationDetected) if (config.NSCLIENT && !configurationDetected)
nsDeviceStatus.configuration?.let { nsDeviceStatus.configuration?.let {
// copy configuration of Insulin and Sensitivity from main AAPS // copy configuration of Insulin and Sensitivity from main AAPS
runningConfiguration.apply(it) runningConfiguration.apply(it)
configurationDetected = true // pick only newest configurationDetected = true // pick only newest
} }
if (config.APS) {
nsDeviceStatus.pump?.let { sp.putBoolean(app.aaps.core.utils.R.string.key_objectives_pump_status_is_available_in_ns, true) } // Objective 0
}
} }
} }

View file

@ -68,7 +68,8 @@ import java.net.URISyntaxException
import java.util.* import java.util.*
import javax.inject.Inject import javax.inject.Inject
@Suppress("SpellCheckingInspection") class NSClientService : DaggerService() { @Suppress("SpellCheckingInspection")
class NSClientService : DaggerService() {
@Inject lateinit var injector: HasAndroidInjector @Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger @Inject lateinit var aapsLogger: AAPSLogger

View file

@ -1,8 +1,12 @@
package app.aaps.plugins.sync.nsclientV3 package app.aaps.plugins.sync.nsclientV3
import android.content.ComponentName
import android.content.Context import android.content.Context
import android.content.Intent
import android.content.ServiceConnection
import android.os.Handler import android.os.Handler
import android.os.HandlerThread import android.os.HandlerThread
import android.os.IBinder
import android.os.SystemClock import android.os.SystemClock
import androidx.preference.PreferenceFragmentCompat import androidx.preference.PreferenceFragmentCompat
import androidx.preference.PreferenceScreen import androidx.preference.PreferenceScreen
@ -17,7 +21,6 @@ import app.aaps.core.interfaces.configuration.Constants
import app.aaps.core.interfaces.db.PersistenceLayer import app.aaps.core.interfaces.db.PersistenceLayer
import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.AAPSLogger
import app.aaps.core.interfaces.logging.LTag import app.aaps.core.interfaces.logging.LTag
import app.aaps.core.interfaces.notifications.Notification
import app.aaps.core.interfaces.nsclient.NSAlarm import app.aaps.core.interfaces.nsclient.NSAlarm
import app.aaps.core.interfaces.nsclient.StoreDataForDb import app.aaps.core.interfaces.nsclient.StoreDataForDb
import app.aaps.core.interfaces.plugin.PluginBase import app.aaps.core.interfaces.plugin.PluginBase
@ -29,7 +32,6 @@ import app.aaps.core.interfaces.rx.AapsSchedulers
import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventAppExit import app.aaps.core.interfaces.rx.events.EventAppExit
import app.aaps.core.interfaces.rx.events.EventDeviceStatusChange import app.aaps.core.interfaces.rx.events.EventDeviceStatusChange
import app.aaps.core.interfaces.rx.events.EventDismissNotification
import app.aaps.core.interfaces.rx.events.EventNSClientNewLog import app.aaps.core.interfaces.rx.events.EventNSClientNewLog
import app.aaps.core.interfaces.rx.events.EventNewHistoryData import app.aaps.core.interfaces.rx.events.EventNewHistoryData
import app.aaps.core.interfaces.rx.events.EventOfflineChange import app.aaps.core.interfaces.rx.events.EventOfflineChange
@ -44,29 +46,21 @@ import app.aaps.core.interfaces.source.NSClientSource
import app.aaps.core.interfaces.sync.DataSyncSelector import app.aaps.core.interfaces.sync.DataSyncSelector
import app.aaps.core.interfaces.sync.NsClient import app.aaps.core.interfaces.sync.NsClient
import app.aaps.core.interfaces.sync.Sync import app.aaps.core.interfaces.sync.Sync
import app.aaps.core.interfaces.ui.UiInteraction
import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.DateUtil
import app.aaps.core.interfaces.utils.DecimalFormatter import app.aaps.core.interfaces.utils.DecimalFormatter
import app.aaps.core.interfaces.utils.T import app.aaps.core.interfaces.utils.T
import app.aaps.core.interfaces.utils.fabric.FabricPrivacy import app.aaps.core.interfaces.utils.fabric.FabricPrivacy
import app.aaps.core.nssdk.NSAndroidClientImpl import app.aaps.core.nssdk.NSAndroidClientImpl
import app.aaps.core.nssdk.interfaces.NSAndroidClient import app.aaps.core.nssdk.interfaces.NSAndroidClient
import app.aaps.core.nssdk.mapper.toNSDeviceStatus
import app.aaps.core.nssdk.mapper.toNSFood
import app.aaps.core.nssdk.mapper.toNSSgvV3
import app.aaps.core.nssdk.mapper.toNSTreatment
import app.aaps.core.nssdk.remotemodel.LastModified import app.aaps.core.nssdk.remotemodel.LastModified
import app.aaps.database.ValueWrapper import app.aaps.database.ValueWrapper
import app.aaps.database.entities.interfaces.TraceableDBEntry import app.aaps.database.entities.interfaces.TraceableDBEntry
import app.aaps.plugins.sync.R import app.aaps.plugins.sync.R
import app.aaps.plugins.sync.nsShared.NSAlarmObject
import app.aaps.plugins.sync.nsShared.NSClientFragment import app.aaps.plugins.sync.nsShared.NSClientFragment
import app.aaps.plugins.sync.nsShared.NsIncomingDataProcessor
import app.aaps.plugins.sync.nsShared.events.EventConnectivityOptionChanged import app.aaps.plugins.sync.nsShared.events.EventConnectivityOptionChanged
import app.aaps.plugins.sync.nsShared.events.EventNSClientUpdateGuiData import app.aaps.plugins.sync.nsShared.events.EventNSClientUpdateGuiData
import app.aaps.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus import app.aaps.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import app.aaps.plugins.sync.nsclient.ReceiverDelegate import app.aaps.plugins.sync.nsclient.ReceiverDelegate
import app.aaps.plugins.sync.nsclient.data.NSDeviceStatusHandler
import app.aaps.plugins.sync.nsclientV3.extensions.toNSBolus import app.aaps.plugins.sync.nsclientV3.extensions.toNSBolus
import app.aaps.plugins.sync.nsclientV3.extensions.toNSBolusWizard import app.aaps.plugins.sync.nsclientV3.extensions.toNSBolusWizard
import app.aaps.plugins.sync.nsclientV3.extensions.toNSCarbs import app.aaps.plugins.sync.nsclientV3.extensions.toNSCarbs
@ -80,6 +74,7 @@ import app.aaps.plugins.sync.nsclientV3.extensions.toNSSvgV3
import app.aaps.plugins.sync.nsclientV3.extensions.toNSTemporaryBasal import app.aaps.plugins.sync.nsclientV3.extensions.toNSTemporaryBasal
import app.aaps.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget import app.aaps.plugins.sync.nsclientV3.extensions.toNSTemporaryTarget
import app.aaps.plugins.sync.nsclientV3.extensions.toNSTherapyEvent import app.aaps.plugins.sync.nsclientV3.extensions.toNSTherapyEvent
import app.aaps.plugins.sync.nsclientV3.services.NSClientV3Service
import app.aaps.plugins.sync.nsclientV3.workers.DataSyncWorker import app.aaps.plugins.sync.nsclientV3.workers.DataSyncWorker
import app.aaps.plugins.sync.nsclientV3.workers.LoadBgWorker import app.aaps.plugins.sync.nsclientV3.workers.LoadBgWorker
import app.aaps.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker import app.aaps.plugins.sync.nsclientV3.workers.LoadDeviceStatusWorker
@ -93,19 +88,11 @@ import com.google.gson.GsonBuilder
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import io.socket.client.Ack
import io.socket.client.IO
import io.socket.client.Socket
import io.socket.emitter.Emitter
import kotlinx.serialization.json.Json import kotlinx.serialization.json.Json
import org.json.JSONArray
import org.json.JSONObject
import java.net.URISyntaxException
import java.security.InvalidParameterException import java.security.InvalidParameterException
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Suppress("SpellCheckingInspection")
@OpenForTesting @OpenForTesting
@Singleton @Singleton
class NSClientV3Plugin @Inject constructor( class NSClientV3Plugin @Inject constructor(
@ -120,12 +107,9 @@ class NSClientV3Plugin @Inject constructor(
private val receiverDelegate: ReceiverDelegate, private val receiverDelegate: ReceiverDelegate,
private val config: Config, private val config: Config,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val uiInteraction: UiInteraction,
private val dataSyncSelectorV3: DataSyncSelectorV3, private val dataSyncSelectorV3: DataSyncSelectorV3,
private val persistenceLayer: PersistenceLayer, private val persistenceLayer: PersistenceLayer,
private val nsDeviceStatusHandler: NSDeviceStatusHandler,
private val nsClientSource: NSClientSource, private val nsClientSource: NSClientSource,
private val nsIncomingDataProcessor: NsIncomingDataProcessor,
private val storeDataForDb: StoreDataForDb, private val storeDataForDb: StoreDataForDb,
private val decimalFormatter: DecimalFormatter private val decimalFormatter: DecimalFormatter
) : NsClient, Sync, PluginBase( ) : NsClient, Sync, PluginBase(
@ -156,28 +140,43 @@ class NSClientV3Plugin @Inject constructor(
override val status override val status
get() = get() =
when { when {
sp.getBoolean(R.string.key_ns_paused, false) -> rh.gs(app.aaps.core.ui.R.string.paused) sp.getBoolean(R.string.key_ns_paused, false) -> rh.gs(app.aaps.core.ui.R.string.paused)
isAllowed.not() -> blockingReason isAllowed.not() -> blockingReason
sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true) && wsConnected -> "WS: " + rh.gs(app.aaps.core.interfaces.R.string.connected) sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true) && nsClientV3Service?.wsConnected == true -> "WS: " + rh.gs(app.aaps.core.interfaces.R.string.connected)
sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true) && !wsConnected -> "WS: " + rh.gs(R.string.not_connected) sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true) && nsClientV3Service?.wsConnected == false -> "WS: " + rh.gs(R.string.not_connected)
lastOperationError != null -> rh.gs(app.aaps.core.ui.R.string.error) lastOperationError != null -> rh.gs(app.aaps.core.ui.R.string.error)
nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected) nsAndroidClient?.lastStatus == null -> rh.gs(R.string.not_connected)
workIsRunning() -> rh.gs(R.string.working) workIsRunning() -> rh.gs(R.string.working)
nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(app.aaps.core.interfaces.R.string.connected) nsAndroidClient?.lastStatus?.apiPermissions?.isFull() == true -> rh.gs(app.aaps.core.interfaces.R.string.connected)
nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only) nsAndroidClient?.lastStatus?.apiPermissions?.isRead() == true -> rh.gs(R.string.read_only)
else -> rh.gs(app.aaps.core.ui.R.string.unknown) else -> rh.gs(app.aaps.core.ui.R.string.unknown)
} }
var lastOperationError: String? = null var lastOperationError: String? = null
internal var nsAndroidClient: NSAndroidClient? = null internal var nsAndroidClient: NSAndroidClient? = null
internal var nsClientV3Service: NSClientV3Service? = null
private val isAllowed get() = receiverDelegate.allowed internal val isAllowed get() = receiverDelegate.allowed
private val blockingReason get() = receiverDelegate.blockingReason internal val blockingReason get() = receiverDelegate.blockingReason
val maxAge = T.days(100).msecs() val maxAge = T.days(100).msecs()
internal var newestDataOnServer: LastModified? = null // timestamp of last modification for every collection provided by server internal var newestDataOnServer: LastModified? = null // timestamp of last modification for every collection provided by server
internal var lastLoadedSrvModified = LastModified(LastModified.Collections()) // max srvLastModified timestamp of last fetched data for every collection internal var lastLoadedSrvModified = LastModified(LastModified.Collections()) // max srvLastModified timestamp of last fetched data for every collection
internal var firstLoadContinueTimestamp = LastModified(LastModified.Collections()) // timestamp of last fetched data for every collection during initial load internal var firstLoadContinueTimestamp = LastModified(LastModified.Collections()) // timestamp of last fetched data for every collection during initial load
internal var initialLoadFinished = false
private val serviceConnection: ServiceConnection = object : ServiceConnection {
override fun onServiceDisconnected(name: ComponentName) {
aapsLogger.debug(LTag.NSCLIENT, "Service is disconnected")
nsClientV3Service = null
}
override fun onServiceConnected(name: ComponentName, service: IBinder) {
aapsLogger.debug(LTag.NSCLIENT, "Service is connected")
val localBinder = service as NSClientV3Service.LocalBinder
nsClientV3Service = localBinder.serviceInstance
}
}
override fun onStart() { override fun onStart() {
super.onStart() super.onStart()
@ -192,13 +191,23 @@ class NSClientV3Plugin @Inject constructor(
setClient("START") setClient("START")
receiverDelegate.grabReceiversState() receiverDelegate.grabReceiversState()
disposable += rxBus
.toObservable(EventAppExit::class.java)
.observeOn(aapsSchedulers.io)
.subscribe({ if (nsClientV3Service != null) context.unbindService(serviceConnection) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
.toObservable(EventConnectivityOptionChanged::class.java) .toObservable(EventConnectivityOptionChanged::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe({ ev -> .subscribe({ ev ->
rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason)) rxBus.send(EventNSClientNewLog("● CONNECTIVITY", ev.blockingReason))
setClient("CONNECTIVITY") assert(nsClientV3Service != null)
if (isAllowed) executeLoop("CONNECTIVITY", forceNew = false) if (ev.connected) {
when {
isAllowed && nsClientV3Service?.storageSocket == null -> setClient("CONNECTIVITY") // socket must be created
!isAllowed && nsClientV3Service?.storageSocket != null -> shutdownWebsockets()
}
if (isAllowed) executeLoop("CONNECTIVITY", forceNew = false)
}
rxBus.send(EventNSClientUpdateGuiStatus()) rxBus.send(EventNSClientUpdateGuiStatus())
}, fabricPrivacy::logException) }, fabricPrivacy::logException)
disposable += rxBus disposable += rxBus
@ -211,8 +220,10 @@ class NSClientV3Plugin @Inject constructor(
ev.isChanged(rh.gs(R.string.key_ns_paused)) || ev.isChanged(rh.gs(R.string.key_ns_paused)) ||
ev.isChanged(rh.gs(app.aaps.core.utils.R.string.key_ns_alarms)) || ev.isChanged(rh.gs(app.aaps.core.utils.R.string.key_ns_alarms)) ||
ev.isChanged(rh.gs(app.aaps.core.utils.R.string.key_ns_announcements)) ev.isChanged(rh.gs(app.aaps.core.utils.R.string.key_ns_announcements))
) ) {
shutdownWebsockets()
setClient("SETTING CHANGE") setClient("SETTING CHANGE")
}
if (ev.isChanged(rh.gs(app.aaps.core.utils.R.string.key_local_profile_last_change))) if (ev.isChanged(rh.gs(app.aaps.core.utils.R.string.key_local_profile_last_change)))
executeUpload("PROFILE_CHANGE", forceNew = true) executeUpload("PROFILE_CHANGE", forceNew = true)
@ -299,10 +310,7 @@ class NSClientV3Plugin @Inject constructor(
override fun onStop() { override fun onStop() {
handler.removeCallbacksAndMessages(null) handler.removeCallbacksAndMessages(null)
disposable.clear() disposable.clear()
storageSocket?.disconnect() shutdownWebsockets()
alarmSocket?.disconnect()
storageSocket = null
alarmSocket = null
super.onStop() super.onStop()
} }
@ -331,270 +339,35 @@ class NSClientV3Plugin @Inject constructor(
} }
private fun setClient(reason: String) { private fun setClient(reason: String) {
nsAndroidClient = NSAndroidClientImpl( if (nsAndroidClient == null)
baseUrl = sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace("https://", "").replace(Regex("/$"), ""), nsAndroidClient = NSAndroidClientImpl(
accessToken = sp.getString(R.string.key_ns_client_token, ""), baseUrl = sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace("https://", "").replace(Regex("/$"), ""),
context = context, accessToken = sp.getString(R.string.key_ns_client_token, ""),
logging = true, context = context,
logger = { msg -> aapsLogger.debug(LTag.HTTP, msg) } logging = config.isEngineeringMode() || config.isDev(),
) logger = { msg -> aapsLogger.debug(LTag.HTTP, msg) }
if (wsConnected) { )
storageSocket?.disconnect()
alarmSocket?.disconnect()
storageSocket = null
alarmSocket = null
}
SystemClock.sleep(2000) SystemClock.sleep(2000)
initializeWebSockets(reason) initializeWebSockets(reason)
rxBus.send(EventSWSyncStatus(status)) rxBus.send(EventSWSyncStatus(status))
} }
/**********************
WS code
**********************/
private var storageSocket: Socket? = null
private var alarmSocket: Socket? = null
var wsConnected = false
internal var initialLoadFinished = false
private fun initializeWebSockets(reason: String) { private fun initializeWebSockets(reason: String) {
if (!sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true)) return if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true)) {
if (sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").isEmpty()) return context.bindService(Intent(context, NSClientV3Service::class.java), serviceConnection, Context.BIND_AUTO_CREATE)
val urlStorage = sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/storage" while (nsClientV3Service == null) {
val urlAlarm = sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/alarm" aapsLogger.debug(LTag.NSCLIENT, "Waiting for service start")
if (!isAllowed) { SystemClock.sleep(100)
rxBus.send(EventNSClientNewLog("● WS", blockingReason))
} else if (sp.getBoolean(R.string.key_ns_paused, false)) {
rxBus.send(EventNSClientNewLog("● WS", "paused"))
} else {
try {
// java io.client doesn't support multiplexing. create 2 sockets
storageSocket = IO.socket(urlStorage).also { socket ->
socket.on(Socket.EVENT_CONNECT, onConnectStorage)
socket.on(Socket.EVENT_DISCONNECT, onDisconnectStorage)
rxBus.send(EventNSClientNewLog("► WS", "do connect storage $reason"))
socket.connect()
socket.on("create", onDataCreateUpdate)
socket.on("update", onDataCreateUpdate)
socket.on("delete", onDataDelete)
}
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_announcements, config.NSCLIENT) ||
sp.getBoolean(app.aaps.core.utils.R.string.key_ns_alarms, config.NSCLIENT)
)
alarmSocket = IO.socket(urlAlarm).also { socket ->
socket.on(Socket.EVENT_CONNECT, onConnectAlarms)
socket.on(Socket.EVENT_DISCONNECT, onDisconnectAlarm)
rxBus.send(EventNSClientNewLog("► WS", "do connect alarm $reason"))
socket.connect()
socket.on("announcement", onAnnouncement)
socket.on("alarm", onAlarm)
socket.on("urgent_alarm", onUrgentAlarm)
socket.on("clear_alarm", onClearAlarm)
}
} catch (e: URISyntaxException) {
rxBus.send(EventNSClientNewLog("● WS", "Wrong URL syntax"))
} catch (e: RuntimeException) {
rxBus.send(EventNSClientNewLog("● WS", "RuntimeException"))
} }
nsClientV3Service?.initializeWebSockets(reason)
} }
} }
private val onConnectStorage = Emitter.Listener { private fun shutdownWebsockets() {
val socketId = storageSocket?.id() ?: "NULL" if (nsClientV3Service != null) context.unbindService(serviceConnection)
rxBus.send(EventNSClientNewLog("◄ WS", "connected storage ID: $socketId")) nsClientV3Service?.shutdownWebsockets()
if (storageSocket != null) {
val authMessage = JSONObject().also {
it.put("accessToken", sp.getString(R.string.key_ns_client_token, ""))
it.put("collections", JSONArray(arrayOf("devicestatus", "entries", "profile", "treatments", "foods", "settings")))
}
rxBus.send(EventNSClientNewLog("► WS", "requesting auth for storage"))
storageSocket?.emit("subscribe", authMessage, Ack { args ->
val response = args[0] as JSONObject
wsConnected = if (response.optBoolean("success")) {
rxBus.send(EventNSClientNewLog("◄ WS", "Subscribed for: ${response.optString("collections")}"))
// during disconnection updated data is not received
// thus run non WS load to get missing data
executeLoop("WS_CONNECT", forceNew = false)
true
} else {
rxBus.send(EventNSClientNewLog("◄ WS", "Auth failed"))
false
}
rxBus.send(EventNSClientUpdateGuiStatus())
})
}
} }
private val onConnectAlarms = Emitter.Listener {
val socket = alarmSocket
val socketId = socket?.id() ?: "NULL"
rxBus.send(EventNSClientNewLog("◄ WS", "connected alarms ID: $socketId"))
if (socket != null) {
val authMessage = JSONObject().also {
it.put("accessToken", sp.getString(R.string.key_ns_client_token, ""))
}
rxBus.send(EventNSClientNewLog("► WS", "requesting auth for alarms"))
socket.emit("subscribe", authMessage, Ack { args ->
val response = args[0] as JSONObject
wsConnected = if (response.optBoolean("success")) {
rxBus.send(EventNSClientNewLog("◄ WS", response.optString("message")))
true
} else {
rxBus.send(EventNSClientNewLog("◄ WS", "Auth failed"))
false
}
})
}
}
private val onDisconnectStorage = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect storage reason: ${args[0]}")
rxBus.send(EventNSClientNewLog("◄ WS", "disconnect storage event"))
wsConnected = false
initialLoadFinished = false
rxBus.send(EventNSClientUpdateGuiStatus())
}
private val onDisconnectAlarm = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect alarm reason: ${args[0]}")
rxBus.send(EventNSClientNewLog("◄ WS", "disconnect alarm event"))
}
private val onDataCreateUpdate = Emitter.Listener { args ->
val response = args[0] as JSONObject
aapsLogger.debug(LTag.NSCLIENT, "onDataCreateUpdate: $response")
val collection = response.getString("colName")
val docJson = response.getJSONObject("doc")
val docString = response.getString("doc")
rxBus.send(EventNSClientNewLog("◄ WS CREATE/UPDATE", "$collection <i>$docString</i>"))
val srvModified = docJson.getLong("srvModified")
lastLoadedSrvModified.set(collection, srvModified)
storeLastLoadedSrvModified()
when (collection) {
"devicestatus" -> docString.toNSDeviceStatus().let { nsDeviceStatusHandler.handleNewData(arrayOf(it)) }
"entries" -> docString.toNSSgvV3()?.let {
nsIncomingDataProcessor.processSgvs(listOf(it))
storeDataForDb.storeGlucoseValuesToDb()
}
"profile" ->
nsIncomingDataProcessor.processProfile(docJson)
"treatments" -> docString.toNSTreatment()?.let {
nsIncomingDataProcessor.processTreatments(listOf(it))
storeDataForDb.storeTreatmentsToDb()
}
"foods" -> docString.toNSFood()?.let {
nsIncomingDataProcessor.processFood(listOf(it))
storeDataForDb.storeFoodsToDb()
}
"settings" -> {}
}
}
private val onDataDelete = Emitter.Listener { args ->
val response = args[0] as JSONObject
aapsLogger.debug(LTag.NSCLIENT, "onDataDelete: $response")
val collection = response.optString("colName") ?: return@Listener
val identifier = response.optString("identifier") ?: return@Listener
rxBus.send(EventNSClientNewLog("◄ WS DELETE", "$collection $identifier"))
if (collection == "treatments") {
storeDataForDb.deleteTreatment.add(identifier)
storeDataForDb.updateDeletedTreatmentsInDb()
}
if (collection == "entries") {
storeDataForDb.deleteGlucoseValue.add(identifier)
storeDataForDb.updateDeletedGlucoseValuesInDb()
}
}
private val onAnnouncement = Emitter.Listener { args ->
/*
{
"level":0,
"title":"Announcement",
"message":"test",
"plugin":{"name":"treatmentnotify","label":"Treatment Notifications","pluginType":"notification","enabled":true},
"group":"Announcement",
"isAnnouncement":true,
"key":"9ac46ad9a1dcda79dd87dae418fce0e7955c68da"
}
*/
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ ANNOUNCEMENT", data.optString("message")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_announcements, config.NSCLIENT))
uiInteraction.addNotificationWithAction(injector, NSAlarmObject(data))
}
private val onAlarm = Emitter.Listener { args ->
/*
{
"level":1,
"title":"Warning HIGH",
"message":"BG Now: 5 -0.2 → mmol\/L\nRaw BG: 4.8 mmol\/L Čistý\nBG 15m: 4.8 mmol\/L\nIOB: -0.02U\nCOB: 0g",
"eventName":"high",
"plugin":{"name":"simplealarms","label":"Simple Alarms","pluginType":"notification","enabled":true},
"pushoverSound":"climb",
"debug":{"lastSGV":5,"thresholds":{"bgHigh":180,"bgTargetTop":75,"bgTargetBottom":72,"bgLow":70}},
"group":"default",
"key":"simplealarms_1"
}
*/
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ ALARM", data.optString("message")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_alarms, config.NSCLIENT)) {
val snoozedTo = sp.getLong(rh.gs(app.aaps.core.utils.R.string.key_snoozed_to) + data.optString("level"), 0L)
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo)
uiInteraction.addNotificationWithAction(injector, NSAlarmObject(data))
}
}
private val onUrgentAlarm = Emitter.Listener { args: Array<Any> ->
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ URGENT ALARM", data.optString("message")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_alarms, config.NSCLIENT)) {
val snoozedTo = sp.getLong(rh.gs(app.aaps.core.utils.R.string.key_snoozed_to) + data.optString("level"), 0L)
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo)
uiInteraction.addNotificationWithAction(injector, NSAlarmObject(data))
}
}
private val onClearAlarm = Emitter.Listener { args ->
/*
{
"clear":true,
"title":"All Clear",
"message":"default - Urgent was ack'd",
"group":"default"
}
*/
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ CLEARALARM", data.optString("title")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
override fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
if (!isEnabled()) return
if (!sp.getBoolean(R.string.key_ns_upload, true)) {
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
return
}
alarmSocket?.emit("ack", originalAlarm.level(), originalAlarm.group(), silenceTimeInMilliseconds)
rxBus.send(EventNSClientNewLog("► ALARMACK ", "${originalAlarm.level()} ${originalAlarm.group()} $silenceTimeInMilliseconds"))
}
/**********************
WS code end
**********************/
override fun resend(reason: String) { override fun resend(reason: String) {
// If WS is enabled, download is triggered by changes in NS. Thus uploadOnly // If WS is enabled, download is triggered by changes in NS. Thus uploadOnly
// Exception is after reset to full sync (initialLoadFinished == false), where // Exception is after reset to full sync (initialLoadFinished == false), where
@ -638,6 +411,15 @@ class NSClientV3Plugin @Inject constructor(
dataSyncSelectorV3.resetToNextFullSync() dataSyncSelectorV3.resetToNextFullSync()
} }
override fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
if (!isEnabled()) return
if (!sp.getBoolean(R.string.key_ns_upload, true)) {
aapsLogger.debug(LTag.NSCLIENT, "Upload disabled. Message dropped")
return
}
nsClientV3Service?.handleClearAlarm(originalAlarm, silenceTimeInMilliseconds)
}
override suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, profile: Profile?): Boolean = override suspend fun nsAdd(collection: String, dataPair: DataSyncSelector.DataPair, progress: String, profile: Profile?): Boolean =
dbOperation(collection, dataPair, progress, Operation.CREATE, profile) dbOperation(collection, dataPair, progress, Operation.CREATE, profile)
@ -700,6 +482,7 @@ class NSClientV3Plugin @Inject constructor(
} }
} catch (e: Exception) { } catch (e: Exception) {
aapsLogger.error(LTag.NSCLIENT, "Upload exception", e) aapsLogger.error(LTag.NSCLIENT, "Upload exception", e)
return false
} }
return true return true
} }
@ -930,7 +713,7 @@ class NSClientV3Plugin @Inject constructor(
sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified)) sp.putString(R.string.key_ns_client_v3_last_modified, Json.encodeToString(LastModified.serializer(), lastLoadedSrvModified))
} }
private fun executeLoop(origin: String, forceNew: Boolean) { internal fun executeLoop(origin: String, forceNew: Boolean) {
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true) && initialLoadFinished) return if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_use_ws, true) && initialLoadFinished) return
if (sp.getBoolean(R.string.key_ns_paused, false)) { if (sp.getBoolean(R.string.key_ns_paused, false)) {
rxBus.send(EventNSClientNewLog("● RUN", "paused $origin")) rxBus.send(EventNSClientNewLog("● RUN", "paused $origin"))

View file

@ -0,0 +1,337 @@
package app.aaps.plugins.sync.nsclientV3.services
import android.annotation.SuppressLint
import android.content.Context
import android.content.Intent
import android.os.Binder
import android.os.Handler
import android.os.HandlerThread
import android.os.IBinder
import android.os.PowerManager
import app.aaps.core.interfaces.configuration.Config
import app.aaps.core.interfaces.logging.AAPSLogger
import app.aaps.core.interfaces.logging.LTag
import app.aaps.core.interfaces.notifications.Notification
import app.aaps.core.interfaces.nsclient.NSAlarm
import app.aaps.core.interfaces.nsclient.StoreDataForDb
import app.aaps.core.interfaces.resources.ResourceHelper
import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.*
import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.ui.UiInteraction
import app.aaps.core.interfaces.utils.fabric.FabricPrivacy
import app.aaps.core.nssdk.mapper.toNSDeviceStatus
import app.aaps.core.nssdk.mapper.toNSFood
import app.aaps.core.nssdk.mapper.toNSSgvV3
import app.aaps.core.nssdk.mapper.toNSTreatment
import app.aaps.plugins.sync.R
import app.aaps.plugins.sync.nsShared.NSAlarmObject
import app.aaps.plugins.sync.nsShared.NsIncomingDataProcessor
import app.aaps.plugins.sync.nsShared.events.EventNSClientUpdateGuiStatus
import app.aaps.plugins.sync.nsclient.data.NSDeviceStatusHandler
import app.aaps.plugins.sync.nsclientV3.NSClientV3Plugin
import dagger.android.DaggerService
import dagger.android.HasAndroidInjector
import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.socket.client.Ack
import io.socket.client.IO
import io.socket.client.Socket
import io.socket.emitter.Emitter
import org.json.JSONArray
import org.json.JSONObject
import java.net.URISyntaxException
import java.util.*
import javax.inject.Inject
@Suppress("SpellCheckingInspection")
class NSClientV3Service : DaggerService() {
@Inject lateinit var injector: HasAndroidInjector
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBus
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var sp: SP
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
@Inject lateinit var config: Config
@Inject lateinit var nsIncomingDataProcessor: NsIncomingDataProcessor
@Inject lateinit var storeDataForDb: StoreDataForDb
@Inject lateinit var uiInteraction: UiInteraction
@Inject lateinit var nsDeviceStatusHandler: NSDeviceStatusHandler
private val disposable = CompositeDisposable()
private var wakeLock: PowerManager.WakeLock? = null
private val binder: IBinder = LocalBinder()
private val handler = Handler(HandlerThread(this::class.simpleName + "Handler").also { it.start() }.looper)
@SuppressLint("WakelockTimeout")
override fun onCreate() {
super.onCreate()
wakeLock = (getSystemService(Context.POWER_SERVICE) as PowerManager).newWakeLock(PowerManager.PARTIAL_WAKE_LOCK, "AndroidAPS:NSClientService")
wakeLock?.acquire()
}
override fun onDestroy() {
super.onDestroy()
disposable.clear()
if (wakeLock?.isHeld == true) wakeLock?.release()
}
inner class LocalBinder : Binder() {
val serviceInstance: NSClientV3Service
get() = this@NSClientV3Service
}
override fun onBind(intent: Intent): IBinder = binder
override fun onStartCommand(intent: Intent, flags: Int, startId: Int): Int = START_STICKY
internal var storageSocket: Socket? = null
private var alarmSocket: Socket? = null
internal var wsConnected = false
internal fun shutdownWebsockets() {
storageSocket?.on(Socket.EVENT_CONNECT, onConnectStorage)
storageSocket?.on(Socket.EVENT_DISCONNECT, onDisconnectStorage)
storageSocket?.on("create", onDataCreateUpdate)
storageSocket?.on("update", onDataCreateUpdate)
storageSocket?.on("delete", onDataDelete)
storageSocket?.disconnect()
alarmSocket?.on(Socket.EVENT_CONNECT, onConnectAlarms)
alarmSocket?.on(Socket.EVENT_DISCONNECT, onDisconnectAlarm)
alarmSocket?.on("announcement", onAnnouncement)
alarmSocket?.on("alarm", onAlarm)
alarmSocket?.on("urgent_alarm", onUrgentAlarm)
alarmSocket?.on("clear_alarm", onClearAlarm)
alarmSocket?.disconnect()
wsConnected = false
storageSocket = null
alarmSocket = null
}
internal fun initializeWebSockets(reason: String) {
if (sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").isEmpty()) return
val urlStorage = sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/storage"
val urlAlarm = sp.getString(app.aaps.core.utils.R.string.key_nsclientinternal_url, "").lowercase().replace(Regex("/$"), "") + "/alarm"
if (!nsClientV3Plugin.isAllowed) {
rxBus.send(EventNSClientNewLog("● WS", nsClientV3Plugin.blockingReason))
} else if (sp.getBoolean(R.string.key_ns_paused, false)) {
rxBus.send(EventNSClientNewLog("● WS", "paused"))
} else {
try {
// java io.client doesn't support multiplexing. create 2 sockets
storageSocket = IO.socket(urlStorage).also { socket ->
socket.on(Socket.EVENT_CONNECT, onConnectStorage)
socket.on(Socket.EVENT_DISCONNECT, onDisconnectStorage)
rxBus.send(EventNSClientNewLog("► WS", "do connect storage $reason"))
socket.connect()
socket.on("create", onDataCreateUpdate)
socket.on("update", onDataCreateUpdate)
socket.on("delete", onDataDelete)
}
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_announcements, config.NSCLIENT) ||
sp.getBoolean(app.aaps.core.utils.R.string.key_ns_alarms, config.NSCLIENT)
)
alarmSocket = IO.socket(urlAlarm).also { socket ->
socket.on(Socket.EVENT_CONNECT, onConnectAlarms)
socket.on(Socket.EVENT_DISCONNECT, onDisconnectAlarm)
rxBus.send(EventNSClientNewLog("► WS", "do connect alarm $reason"))
socket.connect()
socket.on("announcement", onAnnouncement)
socket.on("alarm", onAlarm)
socket.on("urgent_alarm", onUrgentAlarm)
socket.on("clear_alarm", onClearAlarm)
}
} catch (e: URISyntaxException) {
rxBus.send(EventNSClientNewLog("● WS", "Wrong URL syntax"))
} catch (e: RuntimeException) {
rxBus.send(EventNSClientNewLog("● WS", "RuntimeException"))
}
}
}
private val onConnectStorage = Emitter.Listener {
val socketId = storageSocket?.id() ?: "NULL"
rxBus.send(EventNSClientNewLog("◄ WS", "connected storage ID: $socketId"))
if (storageSocket != null) {
val authMessage = JSONObject().also {
it.put("accessToken", sp.getString(R.string.key_ns_client_token, ""))
it.put("collections", JSONArray(arrayOf("devicestatus", "entries", "profile", "treatments", "foods", "settings")))
}
rxBus.send(EventNSClientNewLog("► WS", "requesting auth for storage"))
storageSocket?.emit("subscribe", authMessage, Ack { args ->
val response = args[0] as JSONObject
wsConnected = if (response.optBoolean("success")) {
rxBus.send(EventNSClientNewLog("◄ WS", "Subscribed for: ${response.optString("collections")}"))
// during disconnection updated data is not received
// thus run non WS load to get missing data
nsClientV3Plugin.executeLoop("WS_CONNECT", forceNew = false)
true
} else {
rxBus.send(EventNSClientNewLog("◄ WS", "Auth failed"))
false
}
rxBus.send(EventNSClientUpdateGuiStatus())
})
}
}
private val onConnectAlarms = Emitter.Listener {
val socket = alarmSocket
val socketId = socket?.id() ?: "NULL"
rxBus.send(EventNSClientNewLog("◄ WS", "connected alarms ID: $socketId"))
if (socket != null) {
val authMessage = JSONObject().also {
it.put("accessToken", sp.getString(R.string.key_ns_client_token, ""))
}
rxBus.send(EventNSClientNewLog("► WS", "requesting auth for alarms"))
socket.emit("subscribe", authMessage, Ack { args ->
val response = args[0] as JSONObject
if (response.optBoolean("success")) rxBus.send(EventNSClientNewLog("◄ WS", response.optString("message")))
else rxBus.send(EventNSClientNewLog("◄ WS", "Auth failed"))
})
}
}
private val onDisconnectStorage = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect storage reason: ${args[0]}")
rxBus.send(EventNSClientNewLog("◄ WS", "disconnect storage event"))
wsConnected = false
nsClientV3Plugin.initialLoadFinished = false
rxBus.send(EventNSClientUpdateGuiStatus())
}
private val onDisconnectAlarm = Emitter.Listener { args ->
aapsLogger.debug(LTag.NSCLIENT, "disconnect alarm reason: ${args[0]}")
rxBus.send(EventNSClientNewLog("◄ WS", "disconnect alarm event"))
}
private val onDataCreateUpdate = Emitter.Listener { args ->
val response = args[0] as JSONObject
aapsLogger.debug(LTag.NSCLIENT, "onDataCreateUpdate: $response")
val collection = response.getString("colName")
val docJson = response.getJSONObject("doc")
val docString = response.getString("doc")
rxBus.send(EventNSClientNewLog("◄ WS CREATE/UPDATE", "$collection <i>$docString</i>"))
val srvModified = docJson.getLong("srvModified")
nsClientV3Plugin.lastLoadedSrvModified.set(collection, srvModified)
nsClientV3Plugin.storeLastLoadedSrvModified()
when (collection) {
"devicestatus" -> docString.toNSDeviceStatus().let { nsDeviceStatusHandler.handleNewData(arrayOf(it)) }
"entries" -> docString.toNSSgvV3()?.let {
nsIncomingDataProcessor.processSgvs(listOf(it))
storeDataForDb.storeGlucoseValuesToDb()
}
"profile" ->
nsIncomingDataProcessor.processProfile(docJson)
"treatments" -> docString.toNSTreatment()?.let {
nsIncomingDataProcessor.processTreatments(listOf(it))
storeDataForDb.storeTreatmentsToDb()
}
"foods" -> docString.toNSFood()?.let {
nsIncomingDataProcessor.processFood(listOf(it))
storeDataForDb.storeFoodsToDb()
}
"settings" -> {}
}
}
private val onDataDelete = Emitter.Listener { args ->
val response = args[0] as JSONObject
aapsLogger.debug(LTag.NSCLIENT, "onDataDelete: $response")
val collection = response.optString("colName") ?: return@Listener
val identifier = response.optString("identifier") ?: return@Listener
rxBus.send(EventNSClientNewLog("◄ WS DELETE", "$collection $identifier"))
if (collection == "treatments") {
storeDataForDb.deleteTreatment.add(identifier)
storeDataForDb.updateDeletedTreatmentsInDb()
}
if (collection == "entries") {
storeDataForDb.deleteGlucoseValue.add(identifier)
storeDataForDb.updateDeletedGlucoseValuesInDb()
}
}
private val onAnnouncement = Emitter.Listener { args ->
/*
{
"level":0,
"title":"Announcement",
"message":"test",
"plugin":{"name":"treatmentnotify","label":"Treatment Notifications","pluginType":"notification","enabled":true},
"group":"Announcement",
"isAnnouncement":true,
"key":"9ac46ad9a1dcda79dd87dae418fce0e7955c68da"
}
*/
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ ANNOUNCEMENT", data.optString("message")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_announcements, config.NSCLIENT))
uiInteraction.addNotificationWithAction(injector, NSAlarmObject(data))
}
private val onAlarm = Emitter.Listener { args ->
/*
{
"level":1,
"title":"Warning HIGH",
"message":"BG Now: 5 -0.2 → mmol\/L\nRaw BG: 4.8 mmol\/L Čistý\nBG 15m: 4.8 mmol\/L\nIOB: -0.02U\nCOB: 0g",
"eventName":"high",
"plugin":{"name":"simplealarms","label":"Simple Alarms","pluginType":"notification","enabled":true},
"pushoverSound":"climb",
"debug":{"lastSGV":5,"thresholds":{"bgHigh":180,"bgTargetTop":75,"bgTargetBottom":72,"bgLow":70}},
"group":"default",
"key":"simplealarms_1"
}
*/
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ ALARM", data.optString("message")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_alarms, config.NSCLIENT)) {
val snoozedTo = sp.getLong(rh.gs(app.aaps.core.utils.R.string.key_snoozed_to) + data.optString("level"), 0L)
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo)
uiInteraction.addNotificationWithAction(injector, NSAlarmObject(data))
}
}
private val onUrgentAlarm = Emitter.Listener { args: Array<Any> ->
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ URGENT ALARM", data.optString("message")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
if (sp.getBoolean(app.aaps.core.utils.R.string.key_ns_alarms, config.NSCLIENT)) {
val snoozedTo = sp.getLong(rh.gs(app.aaps.core.utils.R.string.key_snoozed_to) + data.optString("level"), 0L)
if (snoozedTo == 0L || System.currentTimeMillis() > snoozedTo)
uiInteraction.addNotificationWithAction(injector, NSAlarmObject(data))
}
}
private val onClearAlarm = Emitter.Listener { args ->
/*
{
"clear":true,
"title":"All Clear",
"message":"default - Urgent was ack'd",
"group":"default"
}
*/
val data = args[0] as JSONObject
rxBus.send(EventNSClientNewLog("◄ CLEARALARM", data.optString("title")))
aapsLogger.debug(LTag.NSCLIENT, data.toString())
rxBus.send(EventDismissNotification(Notification.NS_ALARM))
rxBus.send(EventDismissNotification(Notification.NS_URGENT_ALARM))
}
fun handleClearAlarm(originalAlarm: NSAlarm, silenceTimeInMilliseconds: Long) {
alarmSocket?.emit("ack", originalAlarm.level(), originalAlarm.group(), silenceTimeInMilliseconds)
rxBus.send(EventNSClientNewLog("► ALARMACK ", "${originalAlarm.level()} ${originalAlarm.group()} $silenceTimeInMilliseconds"))
}
}

View file

@ -23,14 +23,14 @@ class DataSyncWorker(
@Inject lateinit var nsClientV3Plugin: NSClientV3Plugin @Inject lateinit var nsClientV3Plugin: NSClientV3Plugin
override suspend fun doWorkAndLog(): Result { override suspend fun doWorkAndLog(): Result {
if (activePlugin.activeNsClient?.hasWritePermission == true || nsClientV3Plugin.wsConnected) { if (activePlugin.activeNsClient?.hasWritePermission == true || nsClientV3Plugin.nsClientV3Service?.wsConnected == true) {
rxBus.send(EventNSClientNewLog("► UPL", "Start")) rxBus.send(EventNSClientNewLog("► UPL", "Start"))
dataSyncSelectorV3.doUpload() dataSyncSelectorV3.doUpload()
rxBus.send(EventNSClientNewLog("► UPL", "End")) rxBus.send(EventNSClientNewLog("► UPL", "End"))
} else { } else {
if (activePlugin.activeNsClient?.hasWritePermission == true) if (activePlugin.activeNsClient?.hasWritePermission == true)
rxBus.send(EventNSClientNewLog("► ERROR", "No write permission")) rxBus.send(EventNSClientNewLog("► ERROR", "No write permission"))
else if (nsClientV3Plugin.wsConnected) else if (nsClientV3Plugin.nsClientV3Service?.wsConnected == true)
rxBus.send(EventNSClientNewLog("► ERROR", "Not connected")) rxBus.send(EventNSClientNewLog("► ERROR", "Not connected"))
// refresh token // refresh token
nsClientV3Plugin.scheduleIrregularExecution(refreshToken = true) nsClientV3Plugin.scheduleIrregularExecution(refreshToken = true)

View file

@ -1,4 +1,4 @@
package app.aaps.plugins.main.general.wear package app.aaps.plugins.sync.wear
import android.content.Intent import android.content.Intent
import android.os.Bundle import android.os.Bundle
@ -21,9 +21,9 @@ import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.utils.DateUtil import app.aaps.core.interfaces.utils.DateUtil
import app.aaps.core.interfaces.utils.fabric.FabricPrivacy import app.aaps.core.interfaces.utils.fabric.FabricPrivacy
import app.aaps.core.ui.toast.ToastUtils import app.aaps.core.ui.toast.ToastUtils
import app.aaps.plugins.main.R import app.aaps.plugins.sync.R
import app.aaps.plugins.main.databinding.WearFragmentBinding import app.aaps.plugins.sync.databinding.WearFragmentBinding
import app.aaps.plugins.main.general.wear.activities.CwfInfosActivity import app.aaps.plugins.sync.wear.activities.CwfInfosActivity
import dagger.android.support.DaggerFragment import dagger.android.support.DaggerFragment
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign

View file

@ -1,4 +1,4 @@
package app.aaps.plugins.main.general.wear package app.aaps.plugins.sync.wear
import android.content.Context import android.content.Context
import app.aaps.core.interfaces.logging.AAPSLogger import app.aaps.core.interfaces.logging.AAPSLogger
@ -11,7 +11,6 @@ import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventAutosensCalculationFinished import app.aaps.core.interfaces.rx.events.EventAutosensCalculationFinished
import app.aaps.core.interfaces.rx.events.EventDismissBolusProgressIfRunning import app.aaps.core.interfaces.rx.events.EventDismissBolusProgressIfRunning
import app.aaps.core.interfaces.rx.events.EventLoopUpdateGui import app.aaps.core.interfaces.rx.events.EventLoopUpdateGui
import app.aaps.core.interfaces.rx.events.EventMobileDataToWear
import app.aaps.core.interfaces.rx.events.EventMobileToWear import app.aaps.core.interfaces.rx.events.EventMobileToWear
import app.aaps.core.interfaces.rx.events.EventOverviewBolusProgress import app.aaps.core.interfaces.rx.events.EventOverviewBolusProgress
import app.aaps.core.interfaces.rx.events.EventPreferenceChange import app.aaps.core.interfaces.rx.events.EventPreferenceChange
@ -21,9 +20,9 @@ import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey
import app.aaps.core.interfaces.rx.weardata.EventData import app.aaps.core.interfaces.rx.weardata.EventData
import app.aaps.core.interfaces.sharedPreferences.SP import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.utils.fabric.FabricPrivacy import app.aaps.core.interfaces.utils.fabric.FabricPrivacy
import app.aaps.plugins.main.R import app.aaps.plugins.sync.R
import app.aaps.plugins.main.general.wear.wearintegration.DataHandlerMobile import app.aaps.plugins.sync.wear.wearintegration.DataHandlerMobile
import app.aaps.plugins.main.general.wear.wearintegration.DataLayerListenerServiceMobileHelper import app.aaps.plugins.sync.wear.wearintegration.DataLayerListenerServiceMobileHelper
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
@ -45,7 +44,7 @@ class WearPlugin @Inject constructor(
) : PluginBase( ) : PluginBase(
PluginDescription() PluginDescription()
.mainType(PluginType.GENERAL) .mainType(PluginType.SYNC)
.fragmentClass(WearFragment::class.java.name) .fragmentClass(WearFragment::class.java.name)
.pluginIcon(app.aaps.core.main.R.drawable.ic_watch) .pluginIcon(app.aaps.core.main.R.drawable.ic_watch)
.pluginName(app.aaps.core.ui.R.string.wear) .pluginName(app.aaps.core.ui.R.string.wear)
@ -112,12 +111,23 @@ class WearPlugin @Inject constructor(
fun checkCustomWatchfacePreferences() { fun checkCustomWatchfacePreferences() {
savedCustomWatchface?.let { cwf -> savedCustomWatchface?.let { cwf ->
val cwf_authorization = sp.getBoolean(app.aaps.core.utils.R.string.key_wear_custom_watchface_autorization, false) val cwfAuthorization = sp.getBoolean(app.aaps.core.utils.R.string.key_wear_custom_watchface_autorization, false)
if (cwf_authorization != cwf.metadata[CwfMetadataKey.CWF_AUTHORIZATION]?.toBooleanStrictOrNull()) { val cwfName = sp.getString(app.aaps.core.utils.R.string.key_wear_cwf_watchface_name, "")
// resend new customWatchface to Watch with updated authorization for preferences update val authorVersion = sp.getString(app.aaps.core.utils.R.string.key_wear_cwf_author_version, "")
val newCwf = cwf.copy() val fileName = sp.getString(app.aaps.core.utils.R.string.key_wear_cwf_filename, "")
newCwf.metadata[CwfMetadataKey.CWF_AUTHORIZATION] = sp.getBoolean(app.aaps.core.utils.R.string.key_wear_custom_watchface_autorization, false).toString() var toUpdate = false
rxBus.send(EventMobileDataToWear(EventData.ActionSetCustomWatchface(newCwf))) CwfData("", cwf.metadata, mutableMapOf()).also {
if (cwfAuthorization != cwf.metadata[CwfMetadataKey.CWF_AUTHORIZATION]?.toBooleanStrictOrNull()) {
it.metadata[CwfMetadataKey.CWF_AUTHORIZATION] = cwfAuthorization.toString()
toUpdate = true
}
if (cwfName == cwf.metadata[CwfMetadataKey.CWF_NAME] && authorVersion == cwf.metadata[CwfMetadataKey.CWF_AUTHOR_VERSION] && fileName != cwf.metadata[CwfMetadataKey.CWF_FILENAME]) {
it.metadata[CwfMetadataKey.CWF_FILENAME] = fileName
toUpdate = true
}
if (toUpdate)
rxBus.send(EventMobileToWear(EventData.ActionUpdateCustomWatchface(it)))
} }
} }
} }

View file

@ -1,4 +1,4 @@
package app.aaps.plugins.main.general.wear.activities package app.aaps.plugins.sync.wear.activities
import android.os.Bundle import android.os.Bundle
import android.view.LayoutInflater import android.view.LayoutInflater
@ -24,11 +24,11 @@ import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.utils.fabric.FabricPrivacy import app.aaps.core.interfaces.utils.fabric.FabricPrivacy
import app.aaps.core.interfaces.versionChecker.VersionCheckerUtils import app.aaps.core.interfaces.versionChecker.VersionCheckerUtils
import app.aaps.core.ui.activities.TranslatedDaggerAppCompatActivity import app.aaps.core.ui.activities.TranslatedDaggerAppCompatActivity
import app.aaps.plugins.main.R import app.aaps.plugins.sync.R
import app.aaps.plugins.main.databinding.CwfInfosActivityBinding import app.aaps.plugins.sync.databinding.CwfInfosActivityBinding
import app.aaps.plugins.main.databinding.CwfInfosActivityPrefItemBinding import app.aaps.plugins.sync.databinding.CwfInfosActivityPrefItemBinding
import app.aaps.plugins.main.databinding.CwfInfosActivityViewItemBinding import app.aaps.plugins.sync.databinding.CwfInfosActivityViewItemBinding
import app.aaps.plugins.main.general.wear.WearPlugin import app.aaps.plugins.sync.wear.WearPlugin
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import org.json.JSONObject import org.json.JSONObject
@ -192,7 +192,7 @@ class CwfInfosActivity : TranslatedDaggerAppCompatActivity() {
val visibleKeyPairs = mutableListOf<Pair<ViewKeys, Boolean>>() val visibleKeyPairs = mutableListOf<Pair<ViewKeys, Boolean>>()
for (viewKey in ViewKeys.values()) { for (viewKey in ViewKeys.entries) {
try { try {
val jsonValue = json.optJSONObject(viewKey.key) val jsonValue = json.optJSONObject(viewKey.key)
if (jsonValue != null) { if (jsonValue != null) {

View file

@ -1,4 +1,4 @@
package app.aaps.plugins.main.general.wear.wearintegration package app.aaps.plugins.sync.wear.wearintegration
import android.app.NotificationManager import android.app.NotificationManager
import android.content.Context import android.content.Context
@ -31,6 +31,7 @@ import app.aaps.core.interfaces.rx.AapsSchedulers
import app.aaps.core.interfaces.rx.bus.RxBus import app.aaps.core.interfaces.rx.bus.RxBus
import app.aaps.core.interfaces.rx.events.EventMobileToWear import app.aaps.core.interfaces.rx.events.EventMobileToWear
import app.aaps.core.interfaces.rx.events.EventWearUpdateGui import app.aaps.core.interfaces.rx.events.EventWearUpdateGui
import app.aaps.core.interfaces.rx.weardata.CwfMetadataKey
import app.aaps.core.interfaces.rx.weardata.EventData import app.aaps.core.interfaces.rx.weardata.EventData
import app.aaps.core.interfaces.sharedPreferences.SP import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.ui.UiInteraction import app.aaps.core.interfaces.ui.UiInteraction
@ -66,7 +67,7 @@ import app.aaps.database.impl.AppRepository
import app.aaps.database.impl.transactions.CancelCurrentTemporaryTargetIfAnyTransaction import app.aaps.database.impl.transactions.CancelCurrentTemporaryTargetIfAnyTransaction
import app.aaps.database.impl.transactions.InsertAndCancelCurrentTemporaryTargetTransaction import app.aaps.database.impl.transactions.InsertAndCancelCurrentTemporaryTargetTransaction
import app.aaps.database.impl.transactions.InsertOrUpdateHeartRateTransaction import app.aaps.database.impl.transactions.InsertOrUpdateHeartRateTransaction
import app.aaps.plugins.main.R import app.aaps.plugins.sync.R
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
@ -1266,10 +1267,19 @@ class DataHandlerMobile @Inject constructor(
private fun handleGetCustomWatchface(command: EventData.ActionGetCustomWatchface) { private fun handleGetCustomWatchface(command: EventData.ActionGetCustomWatchface) {
val customWatchface = command.customWatchface val customWatchface = command.customWatchface
aapsLogger.debug(LTag.WEAR, "Custom Watchface received from ${command.sourceNodeId}: ${customWatchface.customWatchfaceData.json}") aapsLogger.debug(LTag.WEAR, "Custom Watchface received from ${command.sourceNodeId}")
rxBus.send(EventWearUpdateGui(customWatchface.customWatchfaceData, command.exportFile)) val cwfData = customWatchface.customWatchfaceData
rxBus.send(EventWearUpdateGui(cwfData, command.exportFile))
val watchfaceName = sp.getString(app.aaps.core.utils.R.string.key_wear_cwf_watchface_name, "")
val authorVersion = sp.getString(app.aaps.core.utils.R.string.key_wear_cwf_author_version, "")
if (cwfData.metadata[CwfMetadataKey.CWF_NAME] != watchfaceName || cwfData.metadata[CwfMetadataKey.CWF_AUTHOR_VERSION] != authorVersion) {
sp.putString(app.aaps.core.utils.R.string.key_wear_cwf_watchface_name, cwfData.metadata[CwfMetadataKey.CWF_NAME] ?:"")
sp.putString(app.aaps.core.utils.R.string.key_wear_cwf_author_version, cwfData.metadata[CwfMetadataKey.CWF_AUTHOR_VERSION] ?:"")
sp.putString(app.aaps.core.utils.R.string.key_wear_cwf_filename, cwfData.metadata[CwfMetadataKey.CWF_FILENAME] ?:"")
}
if (command.exportFile) if (command.exportFile)
importExportPrefs.exportCustomWatchface(customWatchface.customWatchfaceData, command.withDate) importExportPrefs.exportCustomWatchface(cwfData, command.withDate)
} }
} }

View file

@ -1,4 +1,4 @@
package app.aaps.plugins.main.general.wear.wearintegration package app.aaps.plugins.sync.wear.wearintegration
import android.os.Binder import android.os.Binder
import android.os.Handler import android.os.Handler
@ -20,8 +20,8 @@ import app.aaps.core.interfaces.rx.weardata.EventData
import app.aaps.core.interfaces.sharedPreferences.SP import app.aaps.core.interfaces.sharedPreferences.SP
import app.aaps.core.interfaces.utils.fabric.FabricPrivacy import app.aaps.core.interfaces.utils.fabric.FabricPrivacy
import app.aaps.database.impl.AppRepository import app.aaps.database.impl.AppRepository
import app.aaps.plugins.main.R import app.aaps.plugins.sync.R
import app.aaps.plugins.main.general.wear.WearPlugin import app.aaps.plugins.sync.wear.WearPlugin
import com.google.android.gms.tasks.Tasks import com.google.android.gms.tasks.Tasks
import com.google.android.gms.wearable.CapabilityClient import com.google.android.gms.wearable.CapabilityClient
import com.google.android.gms.wearable.CapabilityInfo import com.google.android.gms.wearable.CapabilityInfo
@ -93,7 +93,7 @@ class DataLayerListenerServiceMobile : WearableListenerService() {
disposable += rxBus disposable += rxBus
.toObservable(EventMobileDataToWear::class.java) .toObservable(EventMobileDataToWear::class.java)
.observeOn(aapsSchedulers.io) .observeOn(aapsSchedulers.io)
.subscribe { sendMessage(rxDataPath, it.payload.serializeByte()) } .subscribe { sendMessage(rxDataPath, it.payload) }
} }
override fun onCapabilityChanged(p0: CapabilityInfo) { override fun onCapabilityChanged(p0: CapabilityInfo) {

View file

@ -1,4 +1,4 @@
package app.aaps.plugins.main.general.wear.wearintegration package app.aaps.plugins.sync.wear.wearintegration
import android.content.ComponentName import android.content.ComponentName
import android.content.Context import android.content.Context

View file

@ -6,7 +6,7 @@
android:scrollbarStyle="outsideOverlay" android:scrollbarStyle="outsideOverlay"
android:scrollbars="vertical" android:scrollbars="vertical"
android:paddingTop="2dp" android:paddingTop="2dp"
tools:context=".general.wear.activities.CwfInfosActivity"> tools:context="app.aaps.plugins.sync.wear.activities.CwfInfosActivity">
<androidx.core.widget.NestedScrollView <androidx.core.widget.NestedScrollView
android:layout_width="match_parent" android:layout_width="match_parent"
@ -58,7 +58,8 @@
android:text="Author: Name" android:text="Author: Name"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?attr/importListFileNameColor" android:textColor="?attr/importListFileNameColor"
android:textSize="18sp" /> android:textSize="18sp"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/created_at" android:id="@+id/created_at"
@ -71,7 +72,8 @@
android:text="created at: " android:text="created at: "
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?attr/importListFileNameColor" android:textColor="?attr/importListFileNameColor"
android:textSize="18sp" /> android:textSize="18sp"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/cwf_version" android:id="@+id/cwf_version"
@ -85,7 +87,8 @@
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?attr/importListFileNameColor" android:textColor="?attr/importListFileNameColor"
android:textSize="18sp" /> android:textSize="18sp"
tools:ignore="HardcodedText" />
<TextView <TextView
android:id="@+id/cwf_comment" android:id="@+id/cwf_comment"
@ -99,7 +102,8 @@
android:textAlignment="viewStart" android:textAlignment="viewStart"
android:textAppearance="?android:attr/textAppearanceSmall" android:textAppearance="?android:attr/textAppearanceSmall"
android:textColor="?attr/importListFileNameColor" android:textColor="?attr/importListFileNameColor"
android:textSize="18sp" /> android:textSize="18sp"
tools:ignore="HardcodedText" />
<LinearLayout <LinearLayout
android:id="@+id/pref_layout" android:id="@+id/pref_layout"

View file

@ -26,7 +26,7 @@
<TextView <TextView
android:id="@+id/pref_label" android:id="@+id/pref_label"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginTop="0dp" android:layout_marginTop="0dp"

View file

@ -3,7 +3,6 @@
xmlns:android="http://schemas.android.com/apk/res/android" xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools" xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/careportal_cardview"
style="@style/Widget.MaterialComponents.CardView" style="@style/Widget.MaterialComponents.CardView"
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="wrap_content" android:layout_height="wrap_content"
@ -43,7 +42,7 @@
<TextView <TextView
android:id="@+id/view_comment" android:id="@+id/view_comment"
android:layout_width="wrap_content" android:layout_width="0dp"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="3dp" android:layout_marginStart="3dp"
android:layout_marginTop="0dp" android:layout_marginTop="0dp"

Some files were not shown because too many files have changed in this diff Show more