Merge remote-tracking branch 'nightscout/dev' into medtrum-activate-patch2

This commit is contained in:
jbr7rr 2023-05-25 15:48:13 +02:00
commit 404365aed2
152 changed files with 4993 additions and 510 deletions

View file

@ -5,7 +5,7 @@ version: 2.1
# Orbs are reusable packages of CircleCI configuration that you may share across projects, enabling you to create encapsulated, parameterized commands, jobs, and executors that can be used across multiple projects.
orbs:
android: circleci/android@1.0.3
codecov: codecov/codecov@1.2.0
codecov: codecov/codecov@3.2.4
jobs:
# Below is the definition of your job to build and test your app, you can rename and customize it as you want.

View file

@ -16,8 +16,12 @@ fun PackageManager.safeGetInstalledPackages(flags: Int): List<PackageInfo> =
* Safe version of queryBroadcastReceivers depending on Android version running
*/
fun PackageManager.safeQueryBroadcastReceivers(intent: Intent, flags: Int): List<ResolveInfo> =
try {
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.TIRAMISU) queryBroadcastReceivers(intent, PackageManager.ResolveInfoFlags.of(flags.toLong()))
else @Suppress("DEPRECATION") queryBroadcastReceivers(intent, flags)
} catch (ignored: Exception) {
emptyList()
}
/**
* Safe version of getPackageInfo depending on Android version running

View file

@ -111,7 +111,7 @@ android {
defaultConfig {
multiDexEnabled true
versionCode 1500
version "3.2.0-dev-i-medtrum"
version "3.2.0-dev-j-medtrum"
buildConfigField "String", "VERSION", '"' + version + '"'
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'

View file

@ -24,6 +24,7 @@ import android.widget.TextView
import androidx.appcompat.app.ActionBarDrawerToggle
import androidx.appcompat.widget.Toolbar
import androidx.core.view.GravityCompat
import androidx.core.view.MenuCompat
import androidx.viewpager2.widget.ViewPager2
import com.google.android.material.dialog.MaterialAlertDialogBuilder
import com.google.android.material.tabs.TabLayoutMediator
@ -302,7 +303,7 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
override fun onCreateOptionsMenu(menu: Menu): Boolean {
super.onCreateOptionsMenu(menu)
menu.setGroupDividerEnabled(true)
MenuCompat.setGroupDividerEnabled(menu, true)
this.menu = menu
menuInflater.inflate(R.menu.menu_main, menu)
pluginPreferencesMenuItem = menu.findItem(R.id.nav_plugin_preferences)

View file

@ -11,9 +11,9 @@ import android.widget.TextView
import com.google.android.material.datepicker.MaterialDatePicker
import com.jjoe64.graphview.GraphView
import dagger.android.HasAndroidInjector
import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.androidaps.databinding.ActivityHistorybrowseBinding
import info.nightscout.core.events.EventIobCalculationProgress
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
import info.nightscout.core.utils.fabric.FabricPrivacy
import info.nightscout.core.workflow.CalculationWorkflow
import info.nightscout.interfaces.Config
@ -42,7 +42,7 @@ import java.util.GregorianCalendar
import javax.inject.Inject
import kotlin.math.min
class HistoryBrowseActivity : DaggerAppCompatActivity() {
class HistoryBrowseActivity : TranslatedDaggerAppCompatActivity() {
@Inject lateinit var historyBrowserData: HistoryBrowserData
@Inject lateinit var injector: HasAndroidInjector

View file

@ -1,6 +1,5 @@
package info.nightscout.androidaps.activities
import android.content.Context
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
@ -10,7 +9,6 @@ import androidx.preference.PreferenceScreen
import info.nightscout.androidaps.R
import info.nightscout.androidaps.databinding.ActivityPreferencesBinding
import info.nightscout.configuration.activities.DaggerAppCompatActivityWithResult
import info.nightscout.core.ui.locale.LocaleHelper
class PreferencesActivity : DaggerAppCompatActivityWithResult(), PreferenceFragmentCompat.OnPreferenceStartScreenCallback {
@ -66,10 +64,6 @@ class PreferencesActivity : DaggerAppCompatActivityWithResult(), PreferenceFragm
return true
}
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
override fun onOptionsItemSelected(item: MenuItem): Boolean =
when (item.itemId) {
android.R.id.home -> {

View file

@ -191,7 +191,7 @@ class KeepAliveWorker(
}
if (loop.isDisconnected) {
// do nothing if pump is disconnected
} else if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile)) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
} else if (runningProfile == null || ((!pump.isThisProfileSet(requestedProfile) || !requestedProfile.isEqual(runningProfile) || (runningProfile is ProfileSealed.EPS && runningProfile.value.originalEnd < dateUtil.now())) && !commandQueue.isRunning(Command.CommandType.BASAL_PROFILE))) {
rxBus.send(EventProfileSwitchChanged())
} else if (isStatusOutdated && !pump.isBusy()) {
lastReadStatus = now

View file

@ -2,22 +2,22 @@
buildscript {
ext {
kotlin_version = '1.8.10'
core_version = '1.9.0'
kotlin_version = '1.8.21'
core_version = '1.10.1'
rxjava_version = '3.1.6'
rxandroid_version = '3.0.2'
rxkotlin_version = '3.0.1'
room_version = '2.5.1'
lifecycle_version = '2.5.1'
dagger_version = '2.45'
coroutines_version = '1.6.4'
activity_version = '1.6.1'
fragmentktx_version = '1.5.6'
lifecycle_version = '2.6.1'
dagger_version = '2.46.1'
coroutines_version = '1.7.1'
activity_version = '1.7.1'
fragmentktx_version = '1.5.7'
ormLite_version = '4.46'
gson_version = '2.10.1'
nav_version = '2.5.3'
appcompat_version = '1.6.1'
material_version = '1.8.0'
material_version = '1.9.0'
gridlayout_version = '1.0.0'
constraintlayout_version = '2.1.4'
preferencektx_version = '1.2.0'
@ -25,17 +25,17 @@ buildscript {
commonscodec_version = '1.15'
jodatime_version = '2.10.14'
work_version = '2.8.1'
tink_version = '1.8.0'
tink_version = '1.9.0'
json_version = '20220320'
joda_version = '2.12.1.1'
joda_version = '2.12.5'
swipe_version = '1.1.0'
junit_version = '4.13.2'
junit_jupiter_version = '5.9.2'
junit_jupiter_version = '5.9.3'
mockito_version = '4.6.1'
dexmaker_version = '1.2'
retrofit2_version = '2.9.0'
okhttp3_version = '4.10.0'
okhttp3_version = '4.11.0'
byteBuddy_version = '1.12.8'
androidx_junit_version = '1.1.4'
@ -49,7 +49,7 @@ buildscript {
play_services_location_version = '21.0.1'
kotlinx_datetime_version = '0.4.0'
kotlinx_serialization_version = '1.5.0'
kotlinx_serialization_version = '1.5.1'
}
repositories {
google()
@ -58,8 +58,8 @@ buildscript {
}
dependencies {
classpath 'com.android.tools.build:gradle:7.4.2'
classpath 'com.google.gms:google-services:4.3.14'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.4'
classpath 'com.google.gms:google-services:4.3.15'
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.5'
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
@ -75,7 +75,7 @@ buildscript {
plugins {
// Test Gradle build, keep disabled under normal circumstances
// id "com.osacky.doctor" version "0.8.1"
id "org.jlleitschuh.gradle.ktlint" version "11.3.1"
id "org.jlleitschuh.gradle.ktlint" version "11.3.2"
id 'org.barfuin.gradle.jacocolog' version '3.1.0'
id 'org.jetbrains.kotlin.android' version "$kotlin_version" apply false
}

View file

@ -25,7 +25,6 @@ interface CommandQueue {
fun extendedBolus(insulin: Double, durationInMinutes: Int, callback: Callback?): Boolean
fun cancelTempBasal(enforceNew: Boolean, callback: Callback?): Boolean
fun cancelExtended(callback: Callback?): Boolean
fun setProfile(profile: Profile, hasNsId: Boolean, callback: Callback?): Boolean
fun readStatus(reason: String, callback: Callback?): Boolean
fun statusInQueue(): Boolean
fun loadHistory(type: Byte, callback: Callback?): Boolean

View file

@ -292,14 +292,11 @@ class NSAndroidClientImpl(
lastModified = response.body()?.lastModified
)
} else throw UnknownResponseNightscoutException()
} else if (response.code() in 400..499) {
return@callWrapper CreateUpdateResponse(
} else return@callWrapper CreateUpdateResponse(
response = response.code(),
identifier = null,
errorResponse = response.errorBody()?.string() ?: response.message()
)
} else
throw UnsuccessfullNightscoutException(response.errorBody()?.string() ?: response.message())
}
override suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) {

View file

@ -4,7 +4,7 @@ import android.content.Context
import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.core.ui.locale.LocaleHelper
open class DialogAppCompatActivity : DaggerAppCompatActivity() {
open class TranslatedDaggerAppCompatActivity : DaggerAppCompatActivity() {
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}

View file

@ -82,7 +82,7 @@
<string name="bluetooth">Bluetooth</string>
<string name="btwatchdog_title">BT Watchdog</string>
<string name="btwatchdog_summary">Vienai sekundei išjungia telefono bluetooth, jei ryšys su pompa nutrūksta. Gali būti veiksminga kai kuriems telefonų modeliams, turintiems BT problemų.</string>
<string name="virtualpump_resultok">Gerai</string>
<string name="virtualpump_resultok">OK</string>
<string name="pump_time_updated">Pompos laikas pakeistas</string>
<string name="exit">Išeiti</string>
<string name="removerecord">Ištrinti įrašą</string>
@ -232,7 +232,7 @@
<string name="hypo">Hipo</string>
<string name="activity">Aktyvumas</string>
<string name="wear">Išmanieji laikrodžiai</string>
<string name="automation">Automatiškai</string>
<string name="automation">Automatizacija</string>
<string name="custom">Pasirinktinis</string>
<string name="loop">Ciklas</string>
<string name="ns">NS</string>
@ -525,7 +525,7 @@
<!-- Dialogs-->
<string name="confirmation">Patvirtinimas</string>
<string name="message">Pranešimas</string>
<string name="ok">Gerai</string>
<string name="ok">OK</string>
<string name="cancel">Atšaukti</string>
<string name="dismiss">ATMESTI</string>
<string name="yes">Taip</string>

View file

@ -22,7 +22,7 @@ dependencies {
implementation project(':app-wear-shared:shared')
//Firebase
api platform('com.google.firebase:firebase-bom:31.2.3')
api platform('com.google.firebase:firebase-bom:32.0.0')
api "com.google.firebase:firebase-analytics-ktx"
api "com.google.firebase:firebase-crashlytics-ktx"
// StatsActivity not in use now

View file

@ -5,6 +5,7 @@ import android.view.ActionMode
import android.view.Menu
import android.view.MenuInflater
import android.view.MenuItem
import androidx.core.view.MenuCompat
import androidx.fragment.app.Fragment
import androidx.fragment.app.FragmentActivity
import info.nightscout.shared.interfaces.ResourceHelper
@ -68,7 +69,7 @@ class ActionModeHelper<T>(val rh: ResourceHelper, val activity: FragmentActivity
} else if (fragment?.isResumed == true) {
menu.add(Menu.FIRST, R.id.nav_remove_items, 0, rh.gs(R.string.remove_items)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.add(Menu.FIRST, R.id.nav_sort_items, 0, rh.gs(R.string.sort_items)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.setGroupDividerEnabled(true)
MenuCompat.setGroupDividerEnabled(menu, true)
}
}

View file

@ -7,6 +7,7 @@ plugins {
}
apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
android {

View file

@ -0,0 +1,44 @@
package info.nightscout.database.entities
import androidx.room.Embedded
import androidx.room.Entity
import androidx.room.Index
import androidx.room.PrimaryKey
import info.nightscout.database.entities.embedments.InterfaceIDs
import info.nightscout.database.entities.interfaces.DBEntryWithTimeAndDuration
import info.nightscout.database.entities.interfaces.TraceableDBEntry
import java.util.*
/** Heart rate values measured by a user smart watch or the like. */
@Entity(
tableName = TABLE_HEART_RATE,
indices = [Index("id"), Index("timestamp")]
)
data class HeartRate(
@PrimaryKey(autoGenerate = true)
override var id: Long = 0,
/** Duration milliseconds */
override var duration: Long,
/** Milliseconds since the epoch. End of the sampling period, i.e. the value is
* sampled from timestamp-duration to timestamp. */
override var timestamp: Long,
var beatsPerMinute: Double,
/** Source device that measured the heart rate. */
var device: String,
override var utcOffset: Long = TimeZone.getDefault().getOffset(timestamp).toLong(),
override var version: Int = 0,
override var dateCreated: Long = -1,
override var isValid: Boolean = true,
override var referenceId: Long? = null,
@Embedded
override var interfaceIDs_backing: InterfaceIDs? = null
) : TraceableDBEntry, DBEntryWithTimeAndDuration {
fun contentEqualsTo(other: HeartRate): Boolean {
return this === other || (
duration == other.duration &&
timestamp == other.timestamp &&
beatsPerMinute == other.beatsPerMinute &&
isValid == other.isValid)
}
}

View file

@ -8,6 +8,7 @@ const val TABLE_CARBS = "carbs"
const val TABLE_DEVICE_STATUS = "deviceStatus"
const val TABLE_EFFECTIVE_PROFILE_SWITCHES = "effectiveProfileSwitches"
const val TABLE_EXTENDED_BOLUSES = "extendedBoluses"
const val TABLE_HEART_RATE = "heartRate"
const val TABLE_GLUCOSE_VALUES = "glucoseValues"
const val TABLE_FOODS = "foods"
const val TABLE_MULTIWAVE_BOLUS_LINKS = "multiwaveBolusLinks"

View file

@ -8,6 +8,7 @@ import info.nightscout.database.entities.Carbs
import info.nightscout.database.entities.EffectiveProfileSwitch
import info.nightscout.database.entities.ExtendedBolus
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.entities.HeartRate
import info.nightscout.database.entities.MultiwaveBolusLink
import info.nightscout.database.entities.OfflineEvent
import info.nightscout.database.entities.PreferenceChange
@ -35,5 +36,6 @@ data class NewEntries(
val temporaryTarget: List<TemporaryTarget>,
val therapyEvents: List<TherapyEvent>,
val totalDailyDoses: List<TotalDailyDose>,
val versionChanges: List<VersionChange>
val versionChanges: List<VersionChange>,
val heartRates: List<HeartRate>,
)

View file

@ -0,0 +1,36 @@
package info.nightscout.database.entities
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.jupiter.api.Test
class HeartRateTest {
@Test
fun contentEqualsTo_equals() {
val hr1 = createHeartRate()
assertTrue(hr1.contentEqualsTo(hr1))
assertTrue(hr1.contentEqualsTo(hr1.copy()))
assertTrue(hr1.contentEqualsTo(hr1.copy (id = 2, version = 2, dateCreated = 1L, referenceId = 4L)))
}
@Test
fun contentEqualsTo_notEquals() {
val hr1 = createHeartRate()
assertFalse(hr1.contentEqualsTo(hr1.copy(duration = 60_001L)))
assertFalse(hr1.contentEqualsTo(hr1.copy(timestamp = 2L)))
assertFalse(hr1.contentEqualsTo(hr1.copy(duration = 60_001L)))
assertFalse(hr1.contentEqualsTo(hr1.copy(beatsPerMinute = 100.0)))
assertFalse(hr1.contentEqualsTo(hr1.copy(isValid = false)))
}
companion object {
fun createHeartRate(timestamp: Long? = null, beatsPerMinute: Double = 80.0) =
HeartRate(
timestamp = timestamp ?: System.currentTimeMillis(),
duration = 60_0000L,
beatsPerMinute = beatsPerMinute,
device = "T",
)
}
}

View file

@ -8,6 +8,8 @@ plugins {
apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
apply from: "${project.rootDir}/core/main/android_module_dependencies.gradle"
apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
apply from: "${project.rootDir}/core/main/jacoco_global.gradle"
android {
@ -20,6 +22,9 @@ android {
}
}
}
sourceSets {
androidTest.assets.srcDirs += files("$projectDir/schemas")
}
}
dependencies {
@ -44,6 +49,8 @@ dependencies {
api "com.google.dagger:dagger-android:$dagger_version"
api "com.google.dagger:dagger-android-support:$dagger_version"
androidTestImplementation "androidx.room:room-testing:$room_version"
}
allOpen {

View file

@ -2,7 +2,7 @@
"formatVersion": 1,
"database": {
"version": 23,
"identityHash": "173734db5f4f35f6295ed953d8124794",
"identityHash": "a3ee37800b6cda170d0ea64799ed7876",
"entities": [
{
"tableName": "apsResults",
@ -3689,12 +3689,153 @@
]
}
]
},
{
"tableName": "heartRate",
"createSql": "CREATE TABLE IF NOT EXISTS `${TABLE_NAME}` (`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL, `duration` INTEGER NOT NULL, `timestamp` INTEGER NOT NULL, `beatsPerMinute` REAL NOT NULL, `device` TEXT NOT NULL, `utcOffset` INTEGER NOT NULL, `version` INTEGER NOT NULL, `dateCreated` INTEGER NOT NULL, `isValid` INTEGER NOT NULL, `referenceId` INTEGER, `nightscoutSystemId` TEXT, `nightscoutId` TEXT, `pumpType` TEXT, `pumpSerial` TEXT, `temporaryId` INTEGER, `pumpId` INTEGER, `startId` INTEGER, `endId` INTEGER)",
"fields": [
{
"fieldPath": "id",
"columnName": "id",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "duration",
"columnName": "duration",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "timestamp",
"columnName": "timestamp",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "beatsPerMinute",
"columnName": "beatsPerMinute",
"affinity": "REAL",
"notNull": true
},
{
"fieldPath": "device",
"columnName": "device",
"affinity": "TEXT",
"notNull": true
},
{
"fieldPath": "utcOffset",
"columnName": "utcOffset",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "version",
"columnName": "version",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "dateCreated",
"columnName": "dateCreated",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "isValid",
"columnName": "isValid",
"affinity": "INTEGER",
"notNull": true
},
{
"fieldPath": "referenceId",
"columnName": "referenceId",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.nightscoutSystemId",
"columnName": "nightscoutSystemId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.nightscoutId",
"columnName": "nightscoutId",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.pumpType",
"columnName": "pumpType",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.pumpSerial",
"columnName": "pumpSerial",
"affinity": "TEXT",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.temporaryId",
"columnName": "temporaryId",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.pumpId",
"columnName": "pumpId",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.startId",
"columnName": "startId",
"affinity": "INTEGER",
"notNull": false
},
{
"fieldPath": "interfaceIDs_backing.endId",
"columnName": "endId",
"affinity": "INTEGER",
"notNull": false
}
],
"primaryKey": {
"autoGenerate": true,
"columnNames": [
"id"
]
},
"indices": [
{
"name": "index_heartRate_id",
"unique": false,
"columnNames": [
"id"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_heartRate_id` ON `${TABLE_NAME}` (`id`)"
},
{
"name": "index_heartRate_timestamp",
"unique": false,
"columnNames": [
"timestamp"
],
"orders": [],
"createSql": "CREATE INDEX IF NOT EXISTS `index_heartRate_timestamp` ON `${TABLE_NAME}` (`timestamp`)"
}
],
"foreignKeys": []
}
],
"views": [],
"setupQueries": [
"CREATE TABLE IF NOT EXISTS room_master_table (id INTEGER PRIMARY KEY,identity_hash TEXT)",
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, '173734db5f4f35f6295ed953d8124794')"
"INSERT OR REPLACE INTO room_master_table (id,identity_hash) VALUES(42, 'a3ee37800b6cda170d0ea64799ed7876')"
]
}
}

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,108 @@
package info.nightscout.database.impl
import android.content.Context
import androidx.room.Room
import androidx.room.testing.MigrationTestHelper
import androidx.sqlite.db.SupportSQLiteDatabase
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import androidx.test.platform.app.InstrumentationRegistry
import info.nightscout.database.entities.HeartRate
import info.nightscout.database.entities.TABLE_HEART_RATE
import org.junit.Assert.assertEquals
import org.junit.Assert.assertFalse
import org.junit.Assert.assertTrue
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
internal class HeartRateDaoTest {
private val context = ApplicationProvider.getApplicationContext<Context>()
private fun createDatabase() =
Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build()
private fun getDbObjects(supportDb: SupportSQLiteDatabase, type: String): Set<String> {
val names = mutableSetOf<String>()
supportDb.query("SELECT name FROM sqlite_master WHERE type = '$type'").use { c ->
while (c.moveToNext()) names.add(c.getString(0))
}
return names
}
private fun getTableNames(db: SupportSQLiteDatabase) = getDbObjects(db, "table")
private fun getIndexNames(db: SupportSQLiteDatabase) = getDbObjects(db, "index")
private fun insertAndFind(database: AppDatabase) {
val hr1 = createHeartRate()
val id = database.heartRateDao.insert(hr1)
val hr2 = database.heartRateDao.findById(id)
assertTrue(hr1.contentEqualsTo(hr2!!))
}
@Test
fun new_insertAndFind() {
createDatabase().use { db -> insertAndFind(db) }
}
@Test
fun migrate_createsTableAndIndices() {
val helper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java
)
val startVersion = 22
val supportDb = helper.createDatabase(TEST_DB_NAME, startVersion)
assertFalse(getTableNames(supportDb).contains(TABLE_HEART_RATE))
DatabaseModule().migrations.filter { m -> m.startVersion >= startVersion }.forEach { m -> m.migrate(supportDb) }
assertTrue(getTableNames(supportDb).contains(TABLE_HEART_RATE))
assertTrue(getIndexNames(supportDb).contains("index_heartRate_id"))
assertTrue(getIndexNames(supportDb).contains("index_heartRate_timestamp"))
}
@Test
fun migrate_insertAndFind() {
val helper = MigrationTestHelper(
InstrumentationRegistry.getInstrumentation(),
AppDatabase::class.java
)
// Create the database for version 22 (that's missing the heartRate table).
// helper.createDatabase removes the db file if it already exists.
val supportDb = helper.createDatabase(TEST_DB_NAME, 22)
assertFalse(getTableNames(supportDb).contains(TABLE_HEART_RATE))
// Room.databaseBuilder will use the previously created db file that has version 22.
Room.databaseBuilder(ApplicationProvider.getApplicationContext(), AppDatabase::class.java, TEST_DB_NAME)
.addMigrations(*DatabaseModule().migrations)
.build().use { db -> insertAndFind(db) }
}
@Test
fun getFromTime() {
createDatabase().use { db ->
val dao = db.heartRateDao
val timestamp = System.currentTimeMillis()
val hr1 = createHeartRate(timestamp = timestamp, beatsPerMinute = 80.0)
val hr2 = createHeartRate(timestamp = timestamp + 1, beatsPerMinute = 150.0)
dao.insertNewEntry(hr1)
dao.insertNewEntry(hr2)
assertEquals(listOf(hr1, hr2), dao.getFromTime(timestamp))
assertEquals(listOf(hr2), dao.getFromTime(timestamp + 1))
assertTrue(dao.getFromTime(timestamp + 2).isEmpty())
}
}
companion object {
private const val TEST_DB_NAME = "testDatabase"
fun createHeartRate(timestamp: Long? = null, beatsPerMinute: Double = 80.0) =
HeartRate(
timestamp = timestamp ?: System.currentTimeMillis(),
duration = 60_0000L,
beatsPerMinute = beatsPerMinute,
device = "T",
)
}
}

View file

@ -0,0 +1,57 @@
package info.nightscout.database.impl.transactions
import android.content.Context
import androidx.room.Room
import androidx.test.core.app.ApplicationProvider
import androidx.test.ext.junit.runners.AndroidJUnit4
import info.nightscout.database.impl.AppDatabase
import info.nightscout.database.impl.AppRepository
import info.nightscout.database.impl.HeartRateDaoTest
import org.junit.After
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotEquals
import org.junit.Assert.assertTrue
import org.junit.Before
import org.junit.Test
import org.junit.runner.RunWith
@RunWith(AndroidJUnit4::class)
class InsertOrUpdateHeartRateTransactionTest {
private val context = ApplicationProvider.getApplicationContext<Context>()
private lateinit var db: AppDatabase
private lateinit var repo: AppRepository
@Before
fun setupUp() {
db = Room.inMemoryDatabaseBuilder(context, AppDatabase::class.java).build()
repo = AppRepository(db)
}
@After
fun shutdown() {
db.close()
}
@Test
fun createNewEntry() {
val hr1 = HeartRateDaoTest.createHeartRate()
val result = repo.runTransactionForResult(InsertOrUpdateHeartRateTransaction(hr1)).blockingGet()
assertEquals(listOf(hr1), result.inserted)
assertTrue(result.updated.isEmpty())
}
@Test
fun updateEntry() {
val hr1 = HeartRateDaoTest.createHeartRate()
val id = db.heartRateDao.insertNewEntry(hr1)
assertNotEquals(0, id)
val hr2 = hr1.copy(id = id, beatsPerMinute = 181.0)
val result = repo.runTransactionForResult(InsertOrUpdateHeartRateTransaction(hr2)).blockingGet()
assertEquals(listOf(hr2), result.updated)
assertTrue(result.inserted.isEmpty())
val hr3 = db.heartRateDao.findById(id)!!
assertTrue(hr2.contentEqualsTo(hr3))
}
}

View file

@ -33,6 +33,7 @@ import info.nightscout.database.entities.EffectiveProfileSwitch
import info.nightscout.database.entities.ExtendedBolus
import info.nightscout.database.entities.Food
import info.nightscout.database.entities.GlucoseValue
import info.nightscout.database.entities.HeartRate
import info.nightscout.database.entities.MultiwaveBolusLink
import info.nightscout.database.entities.OfflineEvent
import info.nightscout.database.entities.PreferenceChange
@ -43,18 +44,20 @@ import info.nightscout.database.entities.TherapyEvent
import info.nightscout.database.entities.TotalDailyDose
import info.nightscout.database.entities.UserEntry
import info.nightscout.database.entities.VersionChange
import info.nightscout.database.impl.daos.HeartRateDao
import java.io.Closeable
const val DATABASE_VERSION = 23
const val DATABASE_VERSION = 24
@Database(version = DATABASE_VERSION,
entities = [APSResult::class, Bolus::class, BolusCalculatorResult::class, Carbs::class,
EffectiveProfileSwitch::class, ExtendedBolus::class, GlucoseValue::class, ProfileSwitch::class,
TemporaryBasal::class, TemporaryTarget::class, TherapyEvent::class, TotalDailyDose::class, APSResultLink::class,
MultiwaveBolusLink::class, PreferenceChange::class, VersionChange::class, UserEntry::class,
Food::class, DeviceStatus::class, OfflineEvent::class],
Food::class, DeviceStatus::class, OfflineEvent::class, HeartRate::class],
exportSchema = true)
@TypeConverters(Converters::class)
internal abstract class AppDatabase : RoomDatabase() {
internal abstract class AppDatabase : Closeable, RoomDatabase() {
abstract val glucoseValueDao: GlucoseValueDao
@ -96,4 +99,5 @@ internal abstract class AppDatabase : RoomDatabase() {
abstract val offlineEventDao: OfflineEventDao
abstract val heartRateDao: HeartRateDao
}

View file

@ -101,6 +101,7 @@ import kotlin.math.roundToInt
//database.foodDao.deleteOlderThan(than)
removed.add(Pair("DeviceStatus", database.deviceStatusDao.deleteOlderThan(than)))
removed.add(Pair("OfflineEvent", database.offlineEventDao.deleteOlderThan(than)))
removed.add(Pair("HeartRate", database.heartRateDao.deleteOlderThan(than)))
if (deleteTrackedChanges) {
removed.add(Pair("GlucoseValue", database.glucoseValueDao.deleteTrackedChanges()))
@ -119,6 +120,7 @@ import kotlin.math.roundToInt
removed.add(Pair("ApsResult", database.apsResultDao.deleteTrackedChanges()))
//database.foodDao.deleteHistory()
removed.add(Pair("OfflineEvent", database.offlineEventDao.deleteTrackedChanges()))
removed.add(Pair("HeartRate", database.heartRateDao.deleteTrackedChanges()))
}
val ret = StringBuilder()
removed
@ -930,6 +932,8 @@ import kotlin.math.roundToInt
fun getLastOfflineEventId(): Long? =
database.offlineEventDao.getLastId()
fun getHeartRatesFromTime(timeMillis: Long) = database.heartRateDao.getFromTime(timeMillis)
suspend fun collectNewEntriesSince(since: Long, until: Long, limit: Int, offset: Int) = NewEntries(
apsResults = database.apsResultDao.getNewEntriesSince(since, until, limit, offset),
apsResultLinks = database.apsResultLinkDao.getNewEntriesSince(since, until, limit, offset),
@ -948,6 +952,7 @@ import kotlin.math.roundToInt
therapyEvents = database.therapyEventDao.getNewEntriesSince(since, until, limit, offset),
totalDailyDoses = database.totalDailyDoseDao.getNewEntriesSince(since, until, limit, offset),
versionChanges = database.versionChangeDao.getNewEntriesSince(since, until, limit, offset),
heartRates = database.heartRateDao.getNewEntriesSince(since, until, limit, offset),
)
}
@ -956,4 +961,3 @@ inline fun <reified T : Any> Maybe<T>.toWrappedSingle(): Single<ValueWrapper<T>>
this.map { ValueWrapper.Existing(it) as ValueWrapper<T> }
.switchIfEmpty(Maybe.just(ValueWrapper.Absent()))
.toSingle()

View file

@ -1,12 +1,14 @@
package info.nightscout.database.impl
import android.content.Context
import androidx.annotation.VisibleForTesting
import androidx.room.Room
import androidx.room.RoomDatabase.Callback
import androidx.room.migration.Migration
import androidx.sqlite.db.SupportSQLiteDatabase
import dagger.Module
import dagger.Provides
import info.nightscout.database.entities.TABLE_HEART_RATE
import javax.inject.Qualifier
import javax.inject.Singleton
@ -22,13 +24,7 @@ open class DatabaseModule {
internal fun provideAppDatabase(context: Context, @DbFileName fileName: String) =
Room
.databaseBuilder(context, AppDatabase::class.java, fileName)
// .addMigrations(migration5to6)
// .addMigrations(migration6to7)
// .addMigrations(migration7to8)
// .addMigrations(migration11to12)
.addMigrations(migration20to21)
.addMigrations(migration21to22)
.addMigrations(migration22to23)
.addMigrations(*migrations)
.addCallback(object : Callback() {
override fun onOpen(db: SupportSQLiteDatabase) {
super.onOpen(db)
@ -89,4 +85,36 @@ open class DatabaseModule {
}
}
private val migration23to24 = object : Migration(23, 24) {
override fun migrate(database: SupportSQLiteDatabase) {
database.execSQL(
"""CREATE TABLE IF NOT EXISTS `$TABLE_HEART_RATE` (
`id` INTEGER PRIMARY KEY AUTOINCREMENT NOT NULL,
`duration` INTEGER NOT NULL,
`timestamp` INTEGER NOT NULL,
`beatsPerMinute` REAL NOT NULL,
`device` TEXT NOT NULL,
`utcOffset` INTEGER NOT NULL,
`version` INTEGER NOT NULL,
`dateCreated` INTEGER NOT NULL,
`isValid` INTEGER NOT NULL,
`referenceId` INTEGER,
`nightscoutSystemId` TEXT,
`nightscoutId` TEXT,
`pumpType` TEXT,
`pumpSerial` TEXT,
`temporaryId` INTEGER,
`pumpId` INTEGER, `startId` INTEGER,
`endId` INTEGER)""".trimIndent()
)
database.execSQL("""CREATE INDEX IF NOT EXISTS `index_heartRate_id` ON `$TABLE_HEART_RATE` (`id`)""")
database.execSQL("""CREATE INDEX IF NOT EXISTS `index_heartRate_timestamp` ON `$TABLE_HEART_RATE` (`timestamp`)""")
// Custom indexes must be dropped on migration to pass room schema checking after upgrade
dropCustomIndexes(database)
}
}
/** List of all migrations for easy reply in tests. */
@VisibleForTesting
internal val migrations = arrayOf(migration20to21, migration21to22, migration22to23, migration23to24)
}

View file

@ -41,6 +41,8 @@ import info.nightscout.database.impl.daos.delegated.DelegatedTotalDailyDoseDao
import info.nightscout.database.impl.daos.delegated.DelegatedUserEntryDao
import info.nightscout.database.impl.daos.delegated.DelegatedVersionChangeDao
import info.nightscout.database.entities.interfaces.DBEntry
import info.nightscout.database.impl.daos.HeartRateDao
import info.nightscout.database.impl.daos.delegated.DelegatedHeartRateDao
internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, val database: AppDatabase) {
@ -64,5 +66,6 @@ internal class DelegatedAppDatabase(val changes: MutableList<DBEntry>, val datab
val foodDao: FoodDao = DelegatedFoodDao(changes, database.foodDao)
val deviceStatusDao: DeviceStatusDao = DelegatedDeviceStatusDao(changes, database.deviceStatusDao)
val offlineEventDao: OfflineEventDao = DelegatedOfflineEventDao(changes, database.offlineEventDao)
val heartRateDao: HeartRateDao = DelegatedHeartRateDao(changes, database.heartRateDao)
fun clearAllTables() = database.clearAllTables()
}

View file

@ -0,0 +1,28 @@
package info.nightscout.database.impl.daos
import androidx.room.Dao
import androidx.room.Query
import info.nightscout.database.entities.HeartRate
import info.nightscout.database.entities.TABLE_HEART_RATE
@Dao
internal interface HeartRateDao : TraceableDao<HeartRate> {
@Query("SELECT * FROM $TABLE_HEART_RATE WHERE id = :id")
override fun findById(id: Long): HeartRate?
@Query("DELETE FROM $TABLE_HEART_RATE")
override fun deleteAllEntries()
@Query("DELETE FROM $TABLE_HEART_RATE WHERE timestamp < :than")
override fun deleteOlderThan(than: Long): Int
@Query("DELETE FROM $TABLE_HEART_RATE WHERE referenceId IS NOT NULL")
override fun deleteTrackedChanges(): Int
@Query("SELECT * FROM $TABLE_HEART_RATE WHERE timestamp >= :timestamp ORDER BY timestamp")
fun getFromTime(timestamp: Long): List<HeartRate>
@Query("SELECT * FROM $TABLE_HEART_RATE WHERE timestamp > :since AND timestamp <= :until LIMIT :limit OFFSET :offset")
fun getNewEntriesSince(since: Long, until: Long, limit: Int, offset: Int): List<HeartRate>
}

View file

@ -0,0 +1,20 @@
package info.nightscout.database.impl.daos.delegated
import info.nightscout.database.entities.HeartRate
import info.nightscout.database.entities.interfaces.DBEntry
import info.nightscout.database.impl.daos.HeartRateDao
internal class DelegatedHeartRateDao(
changes: MutableList<DBEntry>,
private val dao:HeartRateDao): DelegatedDao(changes), HeartRateDao by dao {
override fun insertNewEntry(entry: HeartRate): Long {
changes.add(entry)
return dao.insertNewEntry(entry)
}
override fun updateExistingEntry(entry: HeartRate): Long {
changes.add(entry)
return dao.updateExistingEntry(entry)
}
}

View file

@ -0,0 +1,20 @@
package info.nightscout.database.impl.transactions
import info.nightscout.database.entities.HeartRate
class InsertOrUpdateHeartRateTransaction(private val heartRate: HeartRate):
Transaction<InsertOrUpdateHeartRateTransaction.TransactionResult>() {
override fun run(): TransactionResult {
val existing = if (heartRate.id == 0L) null else database.heartRateDao.findById(heartRate.id)
return if (existing == null) {
database.heartRateDao.insertNewEntry(heartRate).let {
TransactionResult(listOf(heartRate), emptyList()) }
} else {
database.heartRateDao.updateExistingEntry(heartRate)
TransactionResult(emptyList(), listOf(heartRate))
}
}
data class TransactionResult(val inserted: List<HeartRate>, val updated: List<HeartRate>)
}

View file

@ -24,3 +24,11 @@ android.useAndroidX=true
android.nonTransitiveRClass=true
# Cache is causeing issues with CircleCI nad maybe Studio 2021
# org.gradle.unsafe.configuration-cache=true
# After migration to kotlin 1.8.21
#e: org.jetbrains.kotlin.backend.common.BackendException: Backend Internal error: Exception during psi2ir
# File being compiled: (37,18) in /home/circleci/project/core/interfaces/src/main/java/info/nightscout/interfaces/pump/defs/PumpCapability.kt
# The root cause org.jetbrains.kotlin.psi2ir.generators.ErrorExpressionException was thrown at: org.jetbrains.kotlin.psi2ir.generators.ErrorExpressionGenerator.generateErrorCall(ErrorExpressionGenerator.kt:100)
# null: KtCallExpression
# https://youtrack.jetbrains.com/issue/KT-58027
kapt.use.jvm.ir=false

View file

@ -71,7 +71,7 @@ class ProfileFunctionImpl @Inject constructor(
override fun getProfileNameWithRemainingTime(): String =
getProfileName(System.currentTimeMillis(), customized = true, showRemainingTime = true)
fun getProfileName(time: Long, customized: Boolean, showRemainingTime: Boolean): String {
private fun getProfileName(time: Long, customized: Boolean, showRemainingTime: Boolean): String {
var profileName = rh.gs(info.nightscout.core.ui.R.string.no_profile_set)
val profileSwitch = repository.getEffectiveProfileSwitchActiveAt(time).blockingGet()

View file

@ -113,12 +113,13 @@ class CommandQueueImplementation @Inject constructor(
return@subscribe
}
aapsLogger.debug(LTag.PROFILE, "onEventProfileSwitchChanged")
val effective = repository.getEffectiveProfileSwitchActiveAt(dateUtil.now()).blockingGet()
profileFunction.getRequestedProfile()?.let {
setProfile(ProfileSealed.PS(it), it.interfaceIDs.nightscoutId != null, object : Callback() {
override fun run() {
if (!result.success) {
uiInteraction.runAlarm(result.comment, rh.gs(info.nightscout.core.ui.R.string.failed_update_basal_profile), info.nightscout.core.ui.R.raw.boluserror)
} else if (result.enacted) {
} else if (result.enacted || effective is ValueWrapper.Existing && effective.value.originalEnd < dateUtil.now() && effective.value.originalDuration != 0L) {
val nonCustomized = ProfileSealed.PS(it).convertToNonCustomizedProfile(dateUtil)
EffectiveProfileSwitch(
timestamp = dateUtil.now(),
@ -421,7 +422,7 @@ class CommandQueueImplementation @Inject constructor(
}
// returns true if command is queued
override fun setProfile(profile: Profile, hasNsId: Boolean, callback: Callback?): Boolean {
fun setProfile(profile: ProfileSealed, hasNsId: Boolean, callback: Callback?): Boolean {
if (isRunning(CommandType.BASAL_PROFILE)) {
aapsLogger.debug(LTag.PUMPQUEUE, "Command is already executed")
callback?.result(PumpEnactResult(injector).success(true).enacted(false))?.run()

View file

@ -3,7 +3,7 @@
<string name="alert_r7_description"><![CDATA[Kiekis: <b>%1$d%%</b>\nTrukmė: <b>%2$s h</b>]]></string>
<string name="alert_w31_description"><![CDATA[Rezervuaro tūris: <b>%1$s U</b>]]></string>
<string name="alert_w32_description">Pakeiskite bateriją.</string>
<string name="alert_w33_description">Nustatykite laiką/datą.</string>
<string name="alert_w33_description">Nustatyti laiką/datą.</string>
<string name="alert_w34_description">Kreipkitės į Accu-Chek palaikymo tarnybą.</string>
<string name="alert_w36_description"><![CDATA[Kiekis: <b>%1$d%%</b><br/>Trukmė: <b>%2$s h</b>]]></string>
<string name="alert_w38_description"><![CDATA[Suprogramuota: <b>%1$s U</b><br/>Suleista: <b>%2$s U</b>]]></string>
@ -16,8 +16,8 @@
<string name="alert_m26_description">Pakeiskite rezervuarą.</string>
<string name="alert_m27_description">Iš naujo paleiskite duomenų atsisiuntimą.</string>
<string name="alert_m28_description">Patikrinkite pompos statusą.</string>
<string name="alert_m29_description">Nustatykite baterijos tipą.</string>
<string name="alert_m30_description">Nustatykite rezervuaro tipą.</string>
<string name="alert_m29_description">Nustatyti baterijos tipą.</string>
<string name="alert_m30_description">Nustatyti rezervuaro tipą.</string>
<string name="alert_e6_description">Pakeiskite bateriją ir rezervuarą.</string>
<string name="alert_e10_description">Pakeiskite rezervuarą.</string>
<string name="alert_e13_description">Pakeiskite kalbą.</string>

View file

@ -10,6 +10,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.MenuCompat
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import dagger.android.support.DaggerFragment
@ -72,7 +73,7 @@ class OpenAPSFragment : DaggerFragment(), MenuProvider {
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
menu.add(Menu.FIRST, ID_MENU_RUN, 0, rh.gs(R.string.openapsma_run)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.setGroupDividerEnabled(true)
MenuCompat.setGroupDividerEnabled(menu, true)
}
override fun onMenuItemSelected(item: MenuItem): Boolean =

View file

@ -9,6 +9,7 @@ import android.view.MenuInflater
import android.view.MenuItem
import android.view.View
import android.view.ViewGroup
import androidx.core.view.MenuCompat
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import dagger.android.support.DaggerFragment
@ -74,7 +75,7 @@ class LoopFragment : DaggerFragment(), MenuProvider {
override fun onCreateMenu(menu: Menu, inflater: MenuInflater) {
menu.add(Menu.FIRST, ID_MENU_RUN, 0, rh.gs(R.string.run_now)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.setGroupDividerEnabled(true)
MenuCompat.setGroupDividerEnabled(menu, true)
}
override fun onMenuItemSelected(item: MenuItem): Boolean =

View file

@ -16,6 +16,7 @@ import android.widget.ImageView
import android.widget.LinearLayout
import androidx.annotation.DrawableRes
import androidx.core.util.forEach
import androidx.core.view.MenuCompat
import androidx.core.view.MenuProvider
import androidx.lifecycle.Lifecycle
import androidx.recyclerview.widget.ItemTouchHelper
@ -97,7 +98,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener, MenuProvider {
actionHelper.onCreateOptionsMenu(menu, inflater)
menu.add(Menu.FIRST, ID_MENU_ADD, 0, rh.gs(R.string.add_automation)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.add(Menu.FIRST, ID_MENU_RUN, 0, rh.gs(R.string.run_automations)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
menu.setGroupDividerEnabled(true)
MenuCompat.setGroupDividerEnabled(menu, true)
}
override fun onMenuItemSelected(item: MenuItem): Boolean =

View file

@ -27,13 +27,13 @@
<string name="sendsmsactionlabel">Siųsti SMS: %1$s</string>
<string name="sendsmsactiondescription">Siųsti SMS į visus numerius</string>
<string name="sendsmsactiontext">Išsiųsti SMS žinutę su tekstu</string>
<string name="starttemptarget">Nustatykite laikiną tikslą</string>
<string name="islesser">mažesnis nei</string>
<string name="isequalorlesser">lygus arba mažesnis nei</string>
<string name="isequal">yra lygus</string>
<string name="isequalorgreater">yra lygus arba didesnis nei</string>
<string name="isgreater">didesnis nei</string>
<string name="isnotavailable">negalimas</string>
<string name="starttemptarget">Pradėti laikiną tikslą</string>
<string name="islesser">mažiau nei</string>
<string name="isequalorlesser">lygu arba mažiau nei</string>
<string name="isequal">lygu</string>
<string name="isequalorgreater">lygu arba daugiau nei</string>
<string name="isgreater">daugiau nei</string>
<string name="isnotavailable">nėra duomenų</string>
<string name="glucoseisnotavailable">Glikemija nepasiekiama</string>
<string name="glucosecomparedmgdl">Glikemija %1$s %2$.0f %3$s</string>
<string name="glucosecomparedmmol">Glikemija %1$s %2$.1f %3$s</string>

View file

@ -22,16 +22,16 @@ class TriggerWifiSsidTest : TriggerTestBase() {
@Test fun shouldRunTest() {
val e = EventNetworkChange()
`when`(receiverStatusStore.lastNetworkEvent).thenReturn(e)
var t: TriggerWifiSsid = TriggerWifiSsid(injector).setValue("aSSID").comparator(Comparator.Compare.IS_EQUAL)
var t: TriggerWifiSsid = TriggerWifiSsid(injector).setValue("aSSID 1").comparator(Comparator.Compare.IS_EQUAL)
e.wifiConnected = false
Assert.assertFalse(t.shouldRun())
e.wifiConnected = true
e.ssid = "otherSSID"
Assert.assertFalse(t.shouldRun())
e.wifiConnected = true
e.ssid = "aSSID"
e.ssid = "aSSID 1"
Assert.assertTrue(t.shouldRun())
t = TriggerWifiSsid(injector).setValue("aSSID").comparator(Comparator.Compare.IS_NOT_AVAILABLE)
t = TriggerWifiSsid(injector).setValue("aSSID 1").comparator(Comparator.Compare.IS_NOT_AVAILABLE)
e.wifiConnected = false
Assert.assertTrue(t.shouldRun())

View file

@ -1,12 +1,10 @@
package info.nightscout.configuration.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.Menu
import android.view.MenuItem
import info.nightscout.configuration.R
import info.nightscout.core.ui.locale.LocaleHelper
import info.nightscout.interfaces.plugin.ActivePlugin
import info.nightscout.interfaces.plugin.PluginBase
import info.nightscout.interfaces.protection.ProtectionCheck
@ -60,8 +58,4 @@ class SingleFragmentActivity : DaggerAppCompatActivityWithResult() {
if (plugin?.preferencesId != -1) menuInflater.inflate(R.menu.menu_single_fragment, menu)
return super.onCreateOptionsMenu(menu)
}
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
}

View file

@ -5,14 +5,14 @@ import android.view.View
import android.widget.CheckBox
import android.widget.LinearLayout
import android.widget.TextView
import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.configuration.R
import info.nightscout.configuration.databinding.ActivityLogsettingBinding
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
import info.nightscout.rx.interfaces.L
import info.nightscout.rx.interfaces.LogElement
import javax.inject.Inject
class LogSettingActivity : DaggerAppCompatActivity() {
class LogSettingActivity : TranslatedDaggerAppCompatActivity() {
@Inject lateinit var l: L

View file

@ -1,6 +1,5 @@
package info.nightscout.configuration.maintenance.activities
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.view.LayoutInflater
@ -10,12 +9,11 @@ import android.view.ViewGroup
import androidx.fragment.app.FragmentActivity
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.configuration.R
import info.nightscout.configuration.databinding.MaintenanceImportListActivityBinding
import info.nightscout.configuration.databinding.MaintenanceImportListItemBinding
import info.nightscout.configuration.maintenance.PrefsFileContract
import info.nightscout.core.ui.locale.LocaleHelper
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
import info.nightscout.interfaces.maintenance.PrefFileListProvider
import info.nightscout.interfaces.maintenance.PrefsFile
import info.nightscout.interfaces.maintenance.PrefsMetadataKey
@ -23,7 +21,7 @@ import info.nightscout.interfaces.maintenance.PrefsStatus
import info.nightscout.shared.interfaces.ResourceHelper
import javax.inject.Inject
class PrefImportListActivity : DaggerAppCompatActivity() {
class PrefImportListActivity : TranslatedDaggerAppCompatActivity() {
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var prefFileListProvider: PrefFileListProvider
@ -116,8 +114,4 @@ class PrefImportListActivity : DaggerAppCompatActivity() {
}
return super.onOptionsItemSelected(item)
}
override fun attachBaseContext(newBase: Context) {
super.attachBaseContext(LocaleHelper.wrap(newBase))
}
}

View file

@ -9,6 +9,7 @@ import android.widget.TextView
import dagger.android.HasAndroidInjector
import info.nightscout.configuration.setupwizard.SWNumberValidator
import info.nightscout.core.ui.elements.NumberPicker
import info.nightscout.interfaces.Constants
import info.nightscout.interfaces.GlucoseUnit
import info.nightscout.interfaces.profile.Profile
import info.nightscout.interfaces.profile.ProfileFunction
@ -16,12 +17,15 @@ import info.nightscout.shared.SafeParse
import java.text.DecimalFormat
import javax.inject.Inject
class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Double, private val min: Double, private val max: Double) : SWItem(injector, Type.UNIT_NUMBER) {
class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Double, private val minMmol: Double, private val maxMmol: Double) : SWItem(injector, Type.UNIT_NUMBER) {
@Inject lateinit var profileFunction: ProfileFunction
private val validator: SWNumberValidator =
SWNumberValidator { value -> value in min..max }
if (profileFunction.getUnits() == GlucoseUnit.MMOL)
SWNumberValidator { value -> value in minMmol..maxMmol }
else
SWNumberValidator { value -> value in minMmol * Constants.MMOLL_TO_MGDL..maxMmol * Constants.MMOLL_TO_MGDL }
private var updateDelay = 0
override fun generateDialog(layout: LinearLayout) {
@ -44,7 +48,10 @@ class SWEditNumberWithUnits(injector: HasAndroidInjector, private val init: Doub
var initValue = sp.getDouble(preferenceId, init)
initValue = Profile.toCurrentUnits(profileFunction.getUnits(), initValue)
val numberPicker = NumberPicker(context)
if (profileFunction.getUnits() == GlucoseUnit.MMOL) numberPicker.setParams(initValue, min, max, 0.1, DecimalFormat("0.0"), false, null, watcher) else numberPicker.setParams(initValue, min * 18, max * 18, 1.0, DecimalFormat("0"), false, null, watcher)
if (profileFunction.getUnits() == GlucoseUnit.MMOL)
numberPicker.setParams(initValue, minMmol, maxMmol, 0.1, DecimalFormat("0.0"), false, null, watcher)
else
numberPicker.setParams(initValue, minMmol * Constants.MMOLL_TO_MGDL, maxMmol * Constants.MMOLL_TO_MGDL, 1.0, DecimalFormat("0"), false, null, watcher)
layout.addView(numberPicker)
val c = TextView(context)

View file

@ -3,7 +3,7 @@
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".constraints.objectives.ObjectivesFragment">
tools:context="info.nightscout.plugins.constraints.objectives.ObjectivesFragment">
<LinearLayout
android:layout_width="match_parent"

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Pas basale en verhoudings aan as nodig, en dan aktiveer auto-sens</string>
<string name="objectives_autosens_gate">1 week suksesvolle dagtyd lus met gereelde karb toevoegings</string>
<string name="objectives_smb_objective">Skakel bykomende nutsfunskies aan vir bedags gebruik, soos bv. SMB</string>
<string name="objectives_smb_gate">Jy moet asb die wiki lees en verhoog maksIAB om SMBs te laat werk! \'n Goeie begin is maksIAB = gemiddelde ete bolus + 3 x maks daaglikse basale</string>
<string name="objectives_manualenacts">Per hand aksies</string>
<string name="accomplished">Bereik: %1$s</string>
<string name="objectives_useprofileswitch">Stel profiel 90% vir 10 min (Lang-pers profiel naam op Oorsig)</string>

View file

@ -24,7 +24,6 @@
<string name="objectives_autosens_gate">Една седмица успешно дневно използване с редовно въвеждане на въглехидрати</string>
<string name="objectives_autosens_learned">Ако вашият резултат от autosens не се колебае около 100%, вашият профил вероятно е грешен.</string>
<string name="objectives_smb_objective">Добавяне на допълнителни функции за използване през деня, като SMB</string>
<string name="objectives_smb_gate">Трябва да прочетете wiki и увеличите maxIOB за да може SMB да работи добре! Добро начало е maxIOB = средния болус за хранене + 3 пъти най-големия базал от профила</string>
<string name="objectives_smb_learned">Използването на SMB трябва да е вашата основна цел. Алгоритъмът Oref1 е създаден, за да ви помогне и с вашите болуси. Не трябва да давате пълен болус за вашата храна, а само част от него и оставете AAPS да ви даде останалото, ако е необходимо. По този начин имате по-голям диапазон за грешно изчислени въглехидрати. Знаете ли, че можете да зададете процент от резултата от болус калкулатора, за да намалите размера на болуса?</string>
<string name="objectives_auto_objective">Разрешаване на автоматизация</string>
<string name="objectives_auto_gate">Прочетете документацията за това как работи автоматизацията. Настройте първите си прости правила. Нека AAPS показва само известия. Когато сте сигурни, автоматизацията се задейства в точното време, за да заменете известяването с реални действия. (https: //androidaps.readthedocs.io/en/latest/EN/Usage/Automation.html)</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Ajustar basals i ràtios si cal, i després activar auto-sens</string>
<string name="objectives_autosens_gate">1 setmana d\'èxit en mode llaç tancat durant el dia, amb introducció regular de carbohidrats</string>
<string name="objectives_smb_objective">Activant funcions addicionals d\'ús diurn, com l\'SMB (super micro bolus)</string>
<string name="objectives_smb_gate">Heu de llegir la wiki i augmentar la maxIOB per a què l\'SMB funcioni correctament! Una bona manera de començar és amb maxIOB = bolus d\'àpat mig + 3 x màxima basal diària</string>
<string name="objectives_auto_objective">Activant l\'automatització</string>
<string name="objectives_manualenacts">Activació manual</string>
<string name="accomplished">Completat: %1$s</string>

View file

@ -24,7 +24,7 @@
<string name="objectives_autosens_gate">Jeden týden úspěšného používání s běžným příjmem sacharidů</string>
<string name="objectives_autosens_learned">Pokud váš výsledek autosens neosciluje kolem 100%, nastavení Vašeho profilu pravděpodobně špatné.</string>
<string name="objectives_smb_objective">Povolit další funkce pro běžné používání jako SMB</string>
<string name="objectives_smb_gate">Přečíst si dokumentaci a zvýšit maximální IOB, aby mohlo SMB fungovat. Pro začátek se dá použít velikost běžného bolusu + 3x maximální denní bazál</string>
<string name="objectives_smb_gate">Přečíst si dokumentaci a zvýšit maximání IOB, aby mohlo SMB fungovat. Pro začátek se dá použít velikost běžného bolusu + 3x maximální denní bazál</string>
<string name="objectives_smb_learned">Použití SMB je vaším cílem. Oref1 algoritmus byl navržen tak, aby vám pomohl i s vašimi bolusy. Neměli byste dávat úplný bolus pro vaše jídlo, ale jen jeho část a nechtat AAPS v případě potřeby dát zbytek. Takto máte větší rezervu pro špatně vypočtené sacharidy. Věděli jste, že můžete nastavit procento bolusové kalkulačky pro snížení velikosti bolusu?</string>
<string name="objectives_auto_objective">Povolení automatizace</string>
<string name="objectives_auto_gate">Přečtěte si na wiki, jak automatizace funguje. Nejdříve nastavte pouze jednoduchá pravidla. Namísto provádění akcí nechte AAPS zobrazovat pouze oznámení. Pokud jste si jistí, že je automatizace spouštěna v pravý čas, můžete oznámení nahradit prováděním akce. (https://wiki.aaps.app/cs/latest/Usage/Automation.html)</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Justér om nødvendigt basaler og forhold og aktivér derefter auto-sens</string>
<string name="objectives_autosens_gate">1 uges vellykket looping i dagtimerne med alle måltider tastet ind</string>
<string name="objectives_smb_objective">Aktivering af yderligere funktioner til brug i dagtimerne, såsom SMB</string>
<string name="objectives_smb_gate">Du skal læse wikien og hæve maxIOB for at få SMB\'er til at fungere fint! En god start er maxIOB=gennemsnitlig måltidsbolus + 3 x max daglig basal</string>
<string name="objectives_auto_objective">Aktiverer automatisering</string>
<string name="objectives_manualenacts">Manuelle handlinger</string>
<string name="accomplished">Udført: %1$s</string>

View file

@ -24,8 +24,6 @@
<string name="objectives_autosens_gate">Loope eine Woche tagsüber mit regelmäßiger Kohlenhydrat-Eingabe</string>
<string name="objectives_autosens_learned">Wenn Ihr Autosens Ergebnis nicht stündlich schwankt, um die angestrebten 100 % ist das verwendete Profil wahrscheinlich falsch.</string>
<string name="objectives_smb_objective">Aktiviere zusätzliche Funktionen für die Nutzung tagsüber wie z. B. SMB</string>
<string name="objectives_smb_gate">Lies das Wiki und erhöhe maxIOB, damit der SMB gut funktioniert. Ein guter Anfang ist
die Formel maxIOB = durchschnittlicher Essensbolus + 3 x höchste Basalrate</string>
<string name="objectives_smb_learned">Die Verwendung von SMB ist Dein Ziel. Der Oref1-Algorithmus wurde entwickelt, um Dir auch mit Boli zu helfen. Du solltest nicht den vollen Bolus für Dein Essen geben, sondern nur einen Teil davon abgeben und es AAPS überlassen bei Bedarf den notwendigen Rest entsprechend dem Blutzuckerverlauf zugeben zu lassen. Auf diese Weise hast Du mehr Platz für falsch berechnete Kohlenhydrate. Wusstest Du, dass Du einen Prozentsatz bei Verwendung des Bolusrechners festlegen kannst, um die Größe des Bolus zu reduzieren?</string>
<string name="objectives_auto_objective">Automatisierung aktivieren</string>
<string name="objectives_auto_gate">Lies in der Dokumentation nach, wie die Automation funktioniert. Richte Dir erst einfache Regeln ein. Zunächst sollte AAPS keine Änderungen vornehmen, sondern Dir nur eine Benachrichtigung anzeigen. Wenn Du Dir sicher bist, dass die Automation im richtigen Moment angetriggert wird, dann kannst Du die Benachrichtigung durch eine Aktion ersetzen (https://androidaps.readthedocs.io/de/latest/CROWDIN/de/Usage/Automation.html)</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Ρυθμίστε τον βασικό ρυθμό και τις αναλογίες αν χρειάζεται, και μετά ενεργοποιήστε το auto-sens</string>
<string name="objectives_autosens_gate">1 επιτυχής εβδομάδα ημερήσιου κυκλώματος με κανονική εισαγωγή υδατανθράκων</string>
<string name="objectives_smb_objective">Ενεργοποιώντας επιπρόσθετα χαρακτηριστικά για χρήση κατά την ημέρα, όπως το SMB</string>
<string name="objectives_smb_gate">Πρέπει να διαβάσετε τον οδηγό wiki και να αυξήσετε το ανώτατο όριο του IOB για να μπορέσει να λειτουργήσει σωστά το SMB! Μια καλή αρχή είναι μέγιστο IOB= μέσο bolus γεύματος + 3 x το μέγιστο ημερήσιο βασικού ρυθμού</string>
<string name="objectives_manualenacts">Ξεκινήστε χειροκίνητα</string>
<string name="accomplished">Επιτεύχθηκε: %1$s</string>
<string name="objectives_useprofileswitch">Θέστε το προφίλ στο 90% για 10 λεπτά (Παρατεταμένο πάτημα του προφίλ στην Επισκόπηση)</string>

View file

@ -24,7 +24,7 @@
<string name="objectives_autosens_gate">Una semana con éxito en bucle cerrado durante el día con entrada regular de carbohidratos</string>
<string name="objectives_autosens_learned">Si el resultado de tu autosens no oscila en torno al 100% es probable que tu perfil esté equivocado.</string>
<string name="objectives_smb_objective">Habilitar funciones adicionales para uso durante el día como SMB</string>
<string name="objectives_smb_gate">¡Debes leer el wiki y subir maxIOB para que SMB funcione bien! Para comenzar un buen valor sería maxIOB = bolo de comida medio + 3 x máximo basal diario</string>
<string name="objectives_smb_gate">Debes leer la wiki y aumentar el valor de maxIOB para que SMB funcione bien. Un buen comienzo sería maxIOB = bolo de comida promedio + 3x máxima basal diaria</string>
<string name="objectives_smb_learned">Utilizar SMB es su objetivo. El algoritmo Oref1 fue diseñado para ayudarle también con sus bolos. No debe dar un bolo completo para su comida, sino sólo una parte y dejar que AAPS le dé el resto si es necesario. De esta forma tendrás más espacio para los carbohidratos mal calculados. ¿Sabías que puedes establecer un porcentaje del resultado de la calculadora de bolo para reducir el tamaño del bolo?</string>
<string name="objectives_auto_objective">Activar automatización</string>
<string name="objectives_auto_gate">Lee la documentación sobre el funcionamiento de la automatización. Configure sus primeras reglas simples. En lugar de una acción, deja que AAPS muestre sólo una notificación. Cuando esté seguro de que la automatización se activa en el momento adecuado, sustituya la notificación por una acción real. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>

View file

@ -24,7 +24,6 @@
<string name="objectives_autosens_gate">1 semaine de Boucle Fermée en journée en saisissant régulièrement les glucides</string>
<string name="objectives_autosens_learned">Si le résultat de votre autosens n\'est pas autour de 100%, votre profil est probablement erroné.</string>
<string name="objectives_smb_objective">Activation de fonctionnalités supplémentaires pour l\'utilisation en journée, telles que la fonction SMB</string>
<string name="objectives_smb_gate">Lisez le wiki et augmentez le maxIA pour que les SMBs fonctionnent correctement ! Un bon début est maxIA = moyenne des Bolus Repas + 3 x maximum débit Basal quotidien</string>
<string name="objectives_smb_learned">L\'utilisation de SMB est votre objectif. L\'algorithme Oref1 a été conçu pour vous aider également avec vos bolus. Vous ne devriez pas donner un bolus complet pour votre nourriture, mais seulement une partie de celui-ci et laisser AAPS vous donner le reste si nécessaire. De cette façon, vous avez plus de latitude pour les glucides mal calculés. Saviez-vous que vous pouvez définir un pourcentage à appliquer au résultat de la calculatrice de bolus pour réduire la taille du bolus ?</string>
<string name="objectives_auto_objective">Activation de l\'automatisation</string>
<string name="objectives_auto_gate">Lisez la documentation sur le fonctionnement de l\'automatisation fonctionne. Configurez vos premières règles simples. Au lieu de mettre une action, configurez une notification. Quand vous êtes sûr que l\'automatisation est déclenchée au bon moment, remplacez la notification par une action réelle. (https://wiki.aaps.app/fr/latest/Usage/Automation.html)</string>

View file

@ -24,7 +24,7 @@
<string name="objectives_autosens_gate">שבוע של הפעלה מוצלחת של הלולאה במשך שעות היום, עם רישום ערכי פחמימות בקביעות</string>
<string name="objectives_autosens_learned">אם תוצאת הזיהוי האוטומטי שלכם לא מתנודדת סביב 100%, כנראה שהפרופיל טעון שיפור.</string>
<string name="objectives_smb_objective">הפעלת פונקציות נוספות לשימוש במשך היום, כגון סופר מיקרו בולוסים (SMB)</string>
<string name="objectives_smb_gate">חובה לקרוא את הויקי ולהעלות את ערך ה-maxIOB כדי להפעיל את ה- SMB כראוי. התחלה טובה תהיה maxIOB=בולוס ממוצע + 3 פעמים ערך הבזאלי היומי המקסימלי</string>
<string name="objectives_smb_gate">חובה לקרוא את הויקי ולהעלות את ערך האינסולין הפעיל המרבי (maxIOB) כדי להפעיל את ה- SMB כראוי. התחלה טובה תהיה maxIOB=בולוס ארוחה טיפוסי + 3 פעמים ערך הבזאלי המקסימלי ביממה</string>
<string name="objectives_smb_learned">שימוש ב-SMB הוא המטרה שלכם. אלגוריתם Oref1 תוכנן לעזור גם עם הבולוסים שלכם. אתם לא צריכים להזריק בולוס מלא למזון שלכם אלא רק על חלק ממנו ולתת ל-AAPS לטפל בשאר במידת הצורך. כך קל יותר להכיל טעויות בספירת פחמימות. הידעתם שאפשר להגדיר אחוז מתוצאת מחשבון הבולוס כדי להקטין את גודל הבולוס?</string>
<string name="objectives_auto_objective">הפעלת אוטומציה</string>
<string name="objectives_auto_gate">קראו את המסמכים על אופן הפעולה של אוטומציות. הגדירו את התנאים הפשוטים הראשונים שלכם. במקום פעולה תנו ל-AAPS להציג הודעה בלבד. כאשר אתם בטוחים שהאוטומציה מופעלת בזמן הנכון, החליפו את ההודעה בפעולה אמיתית. (https://wiki.aaps.app/he/latest/Usage/Automation.html)</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">필요하면 Basal과 비율을 조절하고, auto-sens를 활성화합니다</string>
<string name="objectives_autosens_gate">섭취한 탄수화물양을 입력하고 1주일동안 낮시간대에 loop를 성공적으로 사용하여 봅니다</string>
<string name="objectives_smb_objective">낮시간대에 SMB(Super Micro Bolus)같은 추가기능을 활성화해 사용해봅니다</string>
<string name="objectives_smb_gate">SMB가 잘 작동하게 하기위해서 wiki를 반드시 읽은 다음 maxIOB 값을 올려보세요! maxIOB=평균 식사 Bolus + 3 x 최대하루 Basal이면 적당한 시작값입니다</string>
<string name="objectives_auto_objective">자동화 사용</string>
<string name="objectives_manualenacts">수동 주입</string>
<string name="accomplished">완료: %1$s</string>

View file

@ -24,7 +24,6 @@
<string name="objectives_autosens_gate">1 savaitę praleiskite sėkmingai naudodami uždarąjį ciklą dienos metu ir įvesdami visus valgomus angliavandenius</string>
<string name="objectives_autosens_learned">Jei Jūsų autosens rezultatai nesvyruoja apie 100%, tikėtina, kad profilis turi klaidų.</string>
<string name="objectives_smb_objective">Dienos metu aktyvuokite papildomas funkcijas, tokias kaip SMB (Super Mikro Bolusas)</string>
<string name="objectives_smb_gate">Norėdami, kad SMB veiktų gerai, turite perskaityti dokumentaciją ir padidinti max AIO! Pradžiai patartina skaičiuoti taip: maxAIO=(didžiausia valandinė bazė x 3) + vidutinis bolusas</string>
<string name="objectives_smb_learned">SMB yra Jūsų tikslas. Oref1 algoritmas sukurtas taip, kad taptų Jums pagalba su bolusavimu. Jūs galite nesileisti viso boluso maistui, susileiskite dalį, o AAPS padarys likusį darbą, jei reikės. Taip išvengsite klaidų dėl neteisingai apskaičiuotų AV. Ar žinote, kad galite skaičiuotuve nurodyti, kiek % apskaičiuoto boluso suleisti?</string>
<string name="objectives_auto_objective">Automatizavimo įjungimas</string>
<string name="objectives_auto_gate">Perskaitykite dokumentaciją apie automatizacijos veikimą. Nustatykite kelias paprastas taisykles. Nustatykite, kad AAPS tik parodytų pranešimą, o ne atliktų realų veiksmą. Kai įsitikinsite, kad automatizacija suveikia reikalingu metu, vietoj pranešimo įjunkite veiksmą. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>
@ -40,7 +39,7 @@
<string name="objectives_usedisconnectpump">Imituokite maudynes duše. Atjunkite pompą 1 valandai (ilgai paspauskite Atviras Ciklas)</string>
<string name="objectives_usereconnectpump">... ir iš naujo prisijunkite tuo pačiu būdu</string>
<string name="objectives_usetemptarget">Nustatykite 10 min trukmės laikiną tikslą (ilgai spausti ant dabartinio tikslo)</string>
<string name="objectives_useactions">Konfigūracijoje įjunkite Veiksmų įskiepį, nustatykite jį matomą ir jo turinio rodymą viršutiniame meniu</string>
<string name="objectives_useactions">Konfigūracijoje įjunkite Veiksmų įskiepį, padarykite jį ir jo turinį matomą viršutiniame meniu</string>
<string name="objectives_useloop">Parodyti Ciklo įskiepio turinį</string>
<string name="objectives_usescale">Panaudokite vaizdo dydžio keitimo funkciją ilgai spaudžiant ant glikemijos kreivės</string>
<string name="objectives_exam_objective">Patvirtinkite savo žinias</string>

View file

@ -24,7 +24,6 @@
<string name="objectives_autosens_gate">Gedurende 1 week succesvol overdag loopen met regelmatige invoer van koolhydraten</string>
<string name="objectives_autosens_learned">Als het resultaat van autosens zich niet rond de 100% beweegt dan is je profiel waarschijnlijk niet juist.</string>
<string name="objectives_smb_objective">Activeren van extra functies overdag zoals SMB (super micro bolus)</string>
<string name="objectives_smb_gate">Lees de wiki en verhoog maxIOB om SMB goed werkend te krijgen. Een goed begin is maxIOB=gemiddelde maaltijdbolus + 3 x max dagelijkse basaal</string>
<string name="objectives_smb_learned">Het gebruik van SMB is het uiteindelijke doel. Het Oref1 algoritme is ontworpen om je ook te helpen met je bolussen. Je hoeft geen volledige bolus te geven voor jouw voeding, maar slechts een deel ervan en AAPS zal de rest geven als dat nodig is. Op deze manier heb je meer ruimte voor verkeerd berekende koolhydraten. Wist je dat je een percentage in de bolus calculator kan instellen om de hoeveelheid bolus te verminderen?</string>
<string name="objectives_auto_objective">Automatisering inschakelen</string>
<string name="objectives_auto_gate">Lees eerst de documentatie over hoe automatisering werkt. Maak daarna je eerste simpele regels, waarbij je in plaats van acties eerst gebruikt maakt van de notificaties. Wanneer je er dan zeker van bent, dat je automatisering op de goede momenten wordt geactiveerd, kan je de noticifcatie omzetten naar een echte actie.

View file

@ -24,7 +24,6 @@
<string name="objectives_autosens_gate">1 tydzień sukcesu w działaniu pętli w ciągu dnia z regularnym wprowadzaniem spożywanych węglowodanów</string>
<string name="objectives_autosens_learned">Jeśli wynik autosens nie oscyluje w okolicach 100%, prawdopodobnie Twój profil nie jest poprawny.</string>
<string name="objectives_smb_objective">Włączanie dodatkowych funkcji do użytku, jak SMB (Super Mikro Bolusy)</string>
<string name="objectives_smb_gate">Musisz przeczytać wiki i zwiększyć maxIOB, aby SMB działało dobrze! Dobrym początkiem jest maxIOB = średni bolus + 3 x maks. dzienna dawka bazowa</string>
<string name="objectives_smb_learned">Używanie SMB jest Twoim celem. Algorytm Oref1 został zaprojektowany, aby pomóc Ci również w bolusach. Nie należy podawać pełnego bolusa do jedzenia, ale tylko jego część, a w razie potrzeby pozostawić resztę AAPS. W ten sposób masz więcej miejsca na błędnie obliczone węglowodany. Czy wiesz, że można w kalkulatorze ustawić procent wyniku bolusa, aby zmniejszyć rozmiar bolusa?</string>
<string name="objectives_auto_objective">Włączanie automatyzacji</string>
<string name="objectives_auto_gate">Przeczytaj dokumentację dotyczącą działania automatyzacji. Skonfiguruj swoje pierwsze proste zasady. Zamiast wykonania działania niech AAPS wyświetli tylko powiadomienie. Gdy masz pewność, że automatyzacja zostaje uruchomiona we właściwym czasie, zastąp powiadomienie rzeczywistą akcją. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>

View file

@ -24,7 +24,6 @@
<string name="objectives_autosens_gate">1 semana de looping durante o dia com sucesso com entrada regular de carboidratos</string>
<string name="objectives_autosens_learned">Se o resultado do seu autosens não está oscilando por volta de 100% seu perfil provavelmente está errado.</string>
<string name="objectives_smb_objective">Activando recursos adicionais para uso durante o dia, como SMB</string>
<string name="objectives_smb_gate">Deverá ler a wiki e aumentar a IA máx para que os SMBs funcionem corretamente! Inicialmente poderá considerar maxIA=média dos bólus + 3 x a basal diária máxima</string>
<string name="objectives_smb_learned">Usar SMB é o seu objetivo. O algoritmo Oref1 foi projetado para ajudá-lo também com seus bolus. Você não deve dar bolus completo para sua comida, apenas parte dela e deixar o AAPS lhe dar o resto, se necessário. Desta forma, você tem mais espaço para carboidratos mal calculado. Você sabia que pode definir uma porcentagem do resultado da calculadora de bolus para reduzir o tamanho do bolus?</string>
<string name="objectives_auto_objective">Ativando a automação</string>
<string name="objectives_auto_gate">Leia os documentos de como a automação funciona. Configure suas primeiras regras simples. Em vez de efetuar uma ação deixe AAPS apresentar apenas uma notificação. Quando você tiver certeza de que a automação é acionada no momento certo substitua a notificação por uma ação real. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Ajuste as basais e os rácios, se necessário, e, em seguida, active o auto-sens</string>
<string name="objectives_autosens_gate">1 semana de looping durante o dia com sucesso com entrada regular de hidratos de carbono</string>
<string name="objectives_smb_objective">Activando recursos adicionais para uso durante o dia, como SMB</string>
<string name="objectives_smb_gate">Deverá ler a wiki e aumentar a IA máx para que os SMBs funcionem devidamente! Inicialmente poderá considerar maxIA=média dos bólus + 3 x a basal máxima</string>
<string name="objectives_auto_objective">A ativar a automatização</string>
<string name="objectives_manualenacts">Execução manual</string>
<string name="accomplished">Concluído: %1$s</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Ajustarea bazalelor și a factorilor dacă este necesar și apoi activarea auto-sens</string>
<string name="objectives_autosens_gate">O săptămână de buclă închisă încheiată cu succes în condițiile introducerii regulate a carbohidraților</string>
<string name="objectives_smb_objective">Se activează opțiuni pentru uzul în timpul zilei, cum ar fi SMB</string>
<string name="objectives_smb_gate">Trebuie sa citiți wiki și să măriți maxIOB pentru a obține SMB corect! Un start bun este maxIOB=media bolusurilor + 3x maxima bazalei din zi</string>
<string name="objectives_auto_objective">Activarea automatizării</string>
<string name="objectives_manualenacts">Acțiuni manuale</string>
<string name="accomplished">Îndeplinit: %1$s</string>

View file

@ -5,8 +5,8 @@
<string name="nth_objective">Цель %1$d</string>
<string name="objectivenotstarted">Цель %1$d не начата</string>
<string name="objectivenotfinished">Цель %1$d не завершена</string>
<string name="objectives_0_objective">Настройка визуализации и мониторинга, анализ базала и коэффициентов</string>
<string name="objectives_0_gate">Убедитесь, что величина ГК и данные по инсулину помпы передаются в Nightscout</string>
<string name="objectives_0_objective">Настройка интеграции с Nightscout, анализ базала и коэффициентов</string>
<string name="objectives_0_gate">Убедитесь, что данные о гликемии и подаваемом AAPSом инсулине отображаются в Nightscout и актуальны</string>
<string name="objectives_0_learned">Вы сделали базовую настройку экосистемы AAPS. Nightscout не нужен для работы AAPS, но может быть полезен для отчетов и мониторинга других пациентов. Необходимости в постоянном подключении к NS нет, если вы используете NS только для себя. Вы можете установить загрузку, например, только на домашний wifi, чтобы сэкономить заряд батареи.</string>
<string name="objectives_openloop_objective">Старт незамкнутого цикла</string>
<string name="objectives_openloop_gate">Начинайте работу в режиме незамкнутого цикла и ручной подстройки величины временного базала. Установите и применяйте временные цели и временные цели по умолчанию (напр. углеводы при нагрузке или купировании гипо)</string>
@ -14,9 +14,9 @@
<string name="objectives_maxbasal_objective">Глубже понимаем работу системы в режиме незамкнутого цикла, включая ее рекомендации по временным базалам</string>
<string name="objectives_maxbasal_gate">На основе накопленного опыта, определяем максимальную величину базала и задаем ее в помпе и в настройки AndroidAPS</string>
<string name="objectives_maxbasal_learned">Примите меры предосторожности и корректируйте, если необходимо, параметры безопасности.</string>
<string name="objectives_maxiobzero_objective">Начинаем замыкать цикл с прекращением подачи инсулина при низком значении Ск (режим Low Glucose Suspend)</string>
<string name="objectives_maxiobzero_objective">Начинаем замыкать цикл с прекращением подачи инсулина при низком значении ГК (режим Low Glucose Suspend)</string>
<string name="objectives_maxiobzero_gate">Работа в замкнутом цикле с макс активным инсулином IOB = 0 на протяжении нескольких дней избегая событий типа приостановка на низких ГК Low Suspend</string>
<string name="objectives_maxiobzero_learned">Установка MaxIOB на нуль предотвращает от гипо и не добавит инсулина выше базальной скорости (за исключением отрицательных значений IOB)</string>
<string name="objectives_maxiobzero_learned">Установка MaxIOB на нуль предотвращает гипо и не добавит инсулина выше базальной скорости (за исключением отрицательных значений IOB)</string>
<string name="objectives_maxiob_objective">Настройка замкнутого цикла с поднятием макс величины IOB выше 0 и постепенным понижением целевой ГК</string>
<string name="objectives_maxiob_gate">Работа несколько дней и по кр мере одну ночь без срабатывания оповещений о низкой ГК</string>
<string name="objectives_maxiob_learned">Обновляйте MaxIOB по мере взросления ребенка. Не допускайте, чтобы система подавала больше инсулина, чем вы можете покрыть едой = действительно, плохая идея выставлять высокие значения.</string>
@ -24,7 +24,7 @@
<string name="objectives_autosens_gate">1 неделя успешной дневной работы с регулярным введением углеводов</string>
<string name="objectives_autosens_learned">Если результаты autosense не колеблются около 100%, то возможно ваш профиль неверный.</string>
<string name="objectives_smb_objective">Активация таких доп функций для дневного времени как супер микро болюс SMB</string>
<string name="objectives_smb_gate">Прочтите wiki и увеличьте maxIOB чтобы супер микро болюс SMB заработал как положено! Хорошее начало maxIOB = средний болюс на еду + троекратный максимальный суточный базал</string>
<string name="objectives_smb_gate">Прочтите статью wiki и увеличивайте maxIOB так, чтобы SMB заработал как положено! Для начала рассчитайте maxIOB как средний болюс на еду + макс. суточная базальная скорость*3</string>
<string name="objectives_smb_learned">Ваша цель - это использование СМБ. Алгоритм Oref1 предназначен также, чтобы помочь вам с болюсами. Вы не должны подавать полный болюс на еду, а только часть его, предоставив AAPS подать при необходимости остальную часть болюса. Таким образом вы можете иметь большее пространство для ошибки в подсчетах углеводов. Вы знаете, что можно установить проценты для уменьшения размера болюса?</string>
<string name="objectives_auto_objective">Включение автоматизации</string>
<string name="objectives_auto_gate">Прочтите документацию по автоматизации. Настройте свои первые простые правила. Вместо действия позвольте AAPS только выводить уведомления. Если вы уверены, что автоматизация инициируется в нужное время, замените уведомление реальными действиями. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>
@ -49,9 +49,9 @@
<string name="objectives_exam_learned_prerequisites2">AAPS может работать в автономном режиме.</string>
<string name="objectives_exam_learned_basaltest">Следует пересмотреть и обновить профиль. Лучший профиль = лучшие результаты.</string>
<string name="objectives_exam_learned_dia">Продолжительность действия инсулина DIA в AAPS имеет иное значение (время до полного поглощения инсулина), чем в классической помповой терапии (время до поглощения основной массы инсулина).</string>
<string name="objectives_exam_learned_isf">Вы изучили понятие чувствительность к инсулину ISF, и как она влияет на коррекцию ГК.</string>
<string name="objectives_exam_learned_ic">Вы изучили понятие углеводный коэффициент IC и как он влияет на количество инсулина, необходимого для покрытия углеводов.</string>
<string name="objectives_exam_learned_hypott">Временная цель Hypo используется только для предотвращения чрезмерной коррекции после гипо, когда накапливается отрицательный IOB. Необходимо принять дополнительные меры, чтобы предотвратить ситуацию в будущем.</string>
<string name="objectives_exam_learned_isf">Вы изучили понятие чувствительность к инсулину ISF и то, как она влияет на коррекцию ГК.</string>
<string name="objectives_exam_learned_ic">Вы изучили понятие углеводный коэффициент IC и то, как он влияет на количество инсулина, необходимого для покрытия углеводов.</string>
<string name="objectives_exam_learned_hypott">Временная цель Гипо используется только для предотвращения чрезмерной коррекции после гипо, когда накапливается отрицательный IOB. Необходимо принять дополнительные меры, чтобы предотвратить ситуацию в будущем.</string>
<string name="objectives_exam_learned_profileswitch">Использование процентов не повлияет на целевую ГК, а только на базу, ISF и IC таким образом, чтобы дать больше инсулина (выше 100%%) или меньше инсулина (ниже 100%%).</string>
<string name="objectives_exam_learned_profileswitchtime">Используя сдвиг по времени, можно адаптировать профиль к нерегулярным событиям типа позднего пробуждения.</string>
<string name="objectives_exam_learned_profileswitch4">Редактирование профиля не является достаточным для внесения изменений. Все еще нужно переключиться на этот профиль и активировать изменения.</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">Justera basaler och kvoter om det behövs. Aktivera sedan autosens</string>
<string name="objectives_autosens_gate">1 veckas lyckad looping dagtid, där alla måltider lagts in</string>
<string name="objectives_smb_objective">Aktiverar ytterligare funktioner för användning dagtid, t ex SMB</string>
<string name="objectives_smb_gate">Du måste läsa på wikin och öka max IOB för att få SMB att fungera bra. En bra start är att sätta max IOB till din genomsnittliga måltidsbolus plus 3 gånger den högsta basalen du har under ett dygn</string>
<string name="objectives_auto_objective">Aktivera automatisering</string>
<string name="objectives_manualenacts">Manuella justeringar</string>
<string name="accomplished">Utfört: %1$s</string>

View file

@ -18,7 +18,6 @@
<string name="objectives_autosens_objective">必要时调整胰岛素基础率和比率然后再启用auto-sens胰岛素敏感系数自动调整功能</string>
<string name="objectives_autosens_gate">规律的进行碳水记录,成功在一个星期的白天开启闭环</string>
<string name="objectives_smb_objective">在白天启用额外的功能,例如微型大剂量 SMB</string>
<string name="objectives_smb_gate">你应该阅读wiki指南以调整 maxIOB(活性胰岛素的最大值) 设置让SMB(微型大剂量) 更好的工作。建议是 maxIOB值=餐时剂量的平均值+基础率的最大值的3倍。</string>
<string name="objectives_auto_objective">启用自动操作功能插件</string>
<string name="objectives_manualenacts">手动执行</string>
<string name="accomplished">已完成: %1$s</string>

View file

@ -26,7 +26,7 @@
<string name="objectives_autosens_gate">1 week successful daytime looping with regular carb entry</string>
<string name="objectives_autosens_learned">If your autosens result is not oscillating around 100% your profile probably wrong.</string>
<string name="objectives_smb_objective">Enabling additional features for daytime use, such as SMB</string>
<string name="objectives_smb_gate">You must read the wiki and rise maxIOB to get SMBs working fine! A good start is maxIOB=average mealbolus + 3 x max daily basal</string>
<string name="objectives_smb_gate">You must read the wiki and raise maxIOB to get SMBs working fine! A good start is maxIOB=average mealbolus + 3 x max daily basal</string>
<string name="objectives_smb_learned">Using SMB is your goal. Oref1 algorithm was designed to help you with your boluses as well. You should not give full bolus for your food but only part of it and let AAPS give you the rest if needed. This way you have more space for miscalculated carbs. Did you know that you can set a percentage of bolus calculator result to reduce the size of bolus?</string>
<string name="objectives_auto_objective">Enabling automation</string>
<string name="objectives_auto_gate">Read the docs on how automation works. Set up your first simple rules. Instead of action let AAPS display only notification. When you are sure automation is triggered at the right time replace notification by real action. (https://wiki.aaps.app/en/latest/Usage/Automation.html)</string>

View file

@ -1,9 +1,7 @@
package info.nightscout.plugins.general.actions
import android.content.Context
import android.content.Intent
import android.os.Bundle
import android.util.DisplayMetrics
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
@ -59,7 +57,6 @@ class ActionsFragment : DaggerFragment() {
@Inject lateinit var sp: SP
@Inject lateinit var dateUtil: DateUtil
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var ctx: Context
@Inject lateinit var rh: ResourceHelper
@Inject lateinit var statusLightHandler: StatusLightHandler
@Inject lateinit var fabricPrivacy: FabricPrivacy
@ -78,31 +75,22 @@ class ActionsFragment : DaggerFragment() {
private val pumpCustomActions = HashMap<String, CustomAction>()
private val pumpCustomButtons = ArrayList<SingleClickButton>()
private lateinit var dm: DisplayMetrics
private var _binding: ActionsFragmentBinding? = null
// This property is only valid between onCreateView and onDestroyView.
private val binding get() = _binding!!
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
//check screen width
dm = DisplayMetrics()
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.R) {
@Suppress("DEPRECATION")
activity?.display?.getRealMetrics(dm)
} else {
@Suppress("DEPRECATION")
activity?.windowManager?.defaultDisplay?.getMetrics(dm)
}
_binding = ActionsFragmentBinding.inflate(inflater, container, false)
return binding.root
}
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View =
ActionsFragmentBinding.inflate(inflater, container, false).also { _binding = it }.root
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
skinProvider.activeSkin().preProcessLandscapeActionsLayout(dm, binding)
val screenWidth = activity?.window?.decorView?.width ?: 0
val screenHeight = activity?.window?.decorView?.height ?: 0
val isLandscape = screenHeight < screenWidth
skinProvider.activeSkin().preProcessLandscapeActionsLayout(isLandscape, binding)
binding.profileSwitch.setOnClickListener {
activity?.let { activity ->
@ -285,7 +273,7 @@ class ActionsFragment : DaggerFragment() {
binding.tddStats.visibility = pump.pumpDescription.supportsTDDs.toVisibility()
val isPatchPump = pump.pumpDescription.isPatchPump
binding.status.apply {
cannulaOrPatch.text = if (isPatchPump) rh.gs(R.string.patch_pump) else rh.gs(R.string.cannula)
cannulaOrPatch.text = if (cannulaOrPatch.text.isEmpty()) "" else if (isPatchPump) rh.gs(R.string.patch_pump) else rh.gs(R.string.cannula)
val imageResource = if (isPatchPump) info.nightscout.core.main.R.drawable.ic_patch_pump_outline else R.drawable.ic_cp_age_cannula
cannulaOrPatch.setCompoundDrawablesWithIntrinsicBounds(imageResource, 0, 0, 0)
batteryLayout.visibility = (!isPatchPump || pump.pumpDescription.useHardwareLink).toVisibility()
@ -293,7 +281,11 @@ class ActionsFragment : DaggerFragment() {
cannulaUsage.visibility = isPatchPump.not().toVisibility()
if (!config.NSCLIENT) {
statusLightHandler.updateStatusLights(cannulaAge, cannulaUsage, insulinAge, reservoirLevel, sensorAge, sensorLevel, pbAge, batteryLevel)
statusLightHandler.updateStatusLights(
cannulaAge, cannulaUsage, insulinAge,
reservoirLevel, sensorAge, sensorLevel,
pbAge, pbLevel
)
sensorLevelLabel.text = if (activeBgSource.sensorBatteryLevel == -1) "" else rh.gs(R.string.level_label)
} else {
statusLightHandler.updateStatusLights(cannulaAge, cannulaUsage, insulinAge, null, sensorAge, null, pbAge, null)

View file

@ -188,7 +188,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
smallHeight = screenHeight <= Constants.SMALL_HEIGHT
val landscape = screenHeight < screenWidth
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(dm, binding, landscape, rh.gb(info.nightscout.shared.R.bool.isTablet), smallHeight)
skinProvider.activeSkin().preProcessLandscapeOverviewLayout(binding, landscape, rh.gb(info.nightscout.shared.R.bool.isTablet), smallHeight)
binding.nsclientCard.visibility = config.NSCLIENT.toVisibility()
binding.notifications.setHasFixedSize(false)
@ -841,11 +841,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L)
info.nightscout.core.ui.R.attr.ribbonWarningColor
else info.nightscout.core.ui.R.attr.ribbonDefaultColor
} else if (it is ProfileSealed.PS) {
info.nightscout.core.ui.R.attr.ribbonDefaultColor
} else {
info.nightscout.core.ui.R.attr.ribbonDefaultColor
}
} else info.nightscout.core.ui.R.attr.ribbonDefaultColor
} ?: info.nightscout.core.ui.R.attr.ribbonCriticalColor
val profileTextColor = profile?.let {
@ -853,11 +849,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
if (it.value.originalPercentage != 100 || it.value.originalTimeshift != 0L || it.value.originalDuration != 0L)
info.nightscout.core.ui.R.attr.ribbonTextWarningColor
else info.nightscout.core.ui.R.attr.ribbonTextDefaultColor
} else if (it is ProfileSealed.PS) {
info.nightscout.core.ui.R.attr.ribbonTextDefaultColor
} else {
info.nightscout.core.ui.R.attr.ribbonTextDefaultColor
}
} else info.nightscout.core.ui.R.attr.ribbonTextDefaultColor
} ?: info.nightscout.core.ui.R.attr.ribbonTextDefaultColor
setRibbon(binding.activeProfile, profileTextColor, profileBackgroundColor, profileFunction.getProfileNameWithRemainingTime())
}
@ -899,14 +891,12 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.statusLightsLayout.apply {
cannulaOrPatch.setImageResource(if (isPatchPump) info.nightscout.core.main.R.drawable.ic_patch_pump_outline else R.drawable.ic_cp_age_cannula)
cannulaOrPatch.contentDescription = rh.gs(if (isPatchPump) R.string.statuslights_patch_pump_age else R.string.statuslights_cannula_age)
cannulaOrPatch.scaleX = if (isPatchPump) 1.4f else 2f
cannulaOrPatch.scaleY = cannulaOrPatch.scaleX
insulinAge.visibility = isPatchPump.not().toVisibility()
batteryLayout.visibility = (!isPatchPump || pump.pumpDescription.useHardwareLink).toVisibility()
pbAge.visibility = (pump.pumpDescription.isBatteryReplaceable || pump.isBatteryChangeLoggingEnabled()).toVisibility()
val useBatteryLevel = (pump.model() == PumpType.OMNIPOD_EROS)
|| (pump.model() != PumpType.ACCU_CHEK_COMBO && pump.model() != PumpType.OMNIPOD_DASH)
batteryLevel.visibility = useBatteryLevel.toVisibility()
pbLevel.visibility = useBatteryLevel.toVisibility()
statusLightsLayout.visibility = (sp.getBoolean(R.string.key_show_statuslights, true) || config.NSCLIENT).toVisibility()
}
statusLightHandler.updateStatusLights(
@ -917,7 +907,7 @@ class OverviewFragment : DaggerFragment(), View.OnClickListener, OnLongClickList
binding.statusLightsLayout.sensorAge,
null,
binding.statusLightsLayout.pbAge,
binding.statusLightsLayout.batteryLevel
binding.statusLightsLayout.pbLevel
)
}

View file

@ -12,7 +12,7 @@ import android.view.View
import android.view.WindowManager
import com.google.common.primitives.Ints.min
import com.google.zxing.qrcode.decoder.ErrorCorrectionLevel
import dagger.android.support.DaggerAppCompatActivity
import info.nightscout.core.ui.activities.TranslatedDaggerAppCompatActivity
import info.nightscout.core.ui.dialogs.OKDialog
import info.nightscout.core.ui.toast.ToastUtils
import info.nightscout.core.utils.fabric.FabricPrivacy
@ -28,7 +28,7 @@ import info.nightscout.shared.interfaces.ResourceHelper
import net.glxn.qrgen.android.QRCode
import javax.inject.Inject
class SmsCommunicatorOtpActivity : DaggerAppCompatActivity() {
class SmsCommunicatorOtpActivity : TranslatedDaggerAppCompatActivity() {
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var smsCommunicator: SmsCommunicator

View file

@ -255,6 +255,7 @@ class ProfilePlugin @Inject constructor(
isEdited = false
createAndStoreConvertedProfile()
aapsLogger.debug(LTag.PROFILE, "Accepted ${profiles.size} profiles")
storeSettings()
rxBus.send(EventLocalProfileChanged())
} else
aapsLogger.debug(LTag.PROFILE, "ProfileStore not accepted")

View file

@ -1,6 +1,5 @@
package info.nightscout.plugins.skins
import android.util.DisplayMetrics
import info.nightscout.interfaces.Config
import info.nightscout.plugins.R
import info.nightscout.plugins.databinding.OverviewFragmentBinding
@ -14,8 +13,8 @@ class SkinClassic @Inject constructor(private val config: Config) : SkinInterfac
override val mainGraphHeight: Int get() = 200
override val secondaryGraphHeight: Int get() = 100
override fun preProcessLandscapeOverviewLayout(dm: DisplayMetrics, binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
super.preProcessLandscapeOverviewLayout(dm, binding, isLandscape, isTablet, isSmallHeight)
override fun preProcessLandscapeOverviewLayout(binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
super.preProcessLandscapeOverviewLayout(binding, isLandscape, isTablet, isSmallHeight)
if (!config.NSCLIENT && (isSmallHeight || isLandscape)) moveButtonsLayout(binding.root)
}
}

View file

@ -1,6 +1,5 @@
package info.nightscout.plugins.skins
import android.util.DisplayMetrics
import android.util.TypedValue.COMPLEX_UNIT_PX
import android.view.View
import android.widget.LinearLayout
@ -18,16 +17,11 @@ interface SkinInterface {
val secondaryGraphHeight: Int // in dp
// no pre processing by default
fun preProcessLandscapeActionsLayout(dm: DisplayMetrics, binding: ActionsFragmentBinding) {
fun preProcessLandscapeActionsLayout(isLandscape: Boolean, binding: ActionsFragmentBinding) {
}
fun preProcessLandscapeOverviewLayout(dm: DisplayMetrics, binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
// pre-process landscape mode
val screenWidth = dm.widthPixels
val screenHeight = dm.heightPixels
val landscape = screenHeight < screenWidth
if (landscape) {
fun preProcessLandscapeOverviewLayout(binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
if (isLandscape) {
val iobLayout = binding.infoLayout.iobLayout
val iobLayoutParams = iobLayout.layoutParams as ConstraintLayout.LayoutParams
val timeLayout = binding.infoLayout.timeLayout
@ -59,7 +53,7 @@ interface SkinInterface {
for (v in texts) v.setTextSize(COMPLEX_UNIT_PX, v.textSize * 1.3f)
}
binding.statusLightsLayout.apply {
val texts = listOf(cannulaAge, insulinAge, reservoirLevel, sensorAge, pbAge, batteryLevel)
val texts = listOf(cannulaAge, insulinAge, reservoirLevel, sensorAge, pbAge, pbLevel)
for (v in texts) v.setTextSize(COMPLEX_UNIT_PX, v.textSize * 1.3f)
}
timeLayout.orientation = LinearLayout.HORIZONTAL

View file

@ -1,6 +1,5 @@
package info.nightscout.plugins.skins
import android.util.DisplayMetrics
import info.nightscout.interfaces.Config
import info.nightscout.plugins.R
import info.nightscout.plugins.databinding.OverviewFragmentBinding
@ -14,8 +13,8 @@ class SkinLargeDisplay @Inject constructor(private val config: Config) : SkinInt
override val mainGraphHeight: Int get() = 400
override val secondaryGraphHeight: Int get() = 150
override fun preProcessLandscapeOverviewLayout(dm: DisplayMetrics, binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
super.preProcessLandscapeOverviewLayout(dm, binding, isLandscape, isTablet, isSmallHeight)
override fun preProcessLandscapeOverviewLayout(binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
super.preProcessLandscapeOverviewLayout(binding, isLandscape, isTablet, isSmallHeight)
if (!config.NSCLIENT && (isSmallHeight || isLandscape)) moveButtonsLayout(binding.root)
}
}

View file

@ -1,6 +1,5 @@
package info.nightscout.plugins.skins
import android.util.DisplayMetrics
import android.view.View.GONE
import android.view.ViewGroup
import info.nightscout.interfaces.Config
@ -17,27 +16,26 @@ class SkinLowRes @Inject constructor(private val config: Config) : SkinInterface
override val mainGraphHeight: Int get() = 200
override val secondaryGraphHeight: Int get() = 100
override fun preProcessLandscapeActionsLayout(dm: DisplayMetrics, binding: ActionsFragmentBinding) {
val screenWidth = dm.widthPixels
val screenHeight = dm.heightPixels
val isLandscape = screenHeight < screenWidth
override fun preProcessLandscapeActionsLayout(isLandscape: Boolean, binding: ActionsFragmentBinding) {
if (!isLandscape) {
binding.status.apply {
sensorAgeLabel.visibility = GONE
sensorLabel.text = ""
sensorAgeLabel.visibility = GONE
sensorLevelLabel.visibility = GONE
insulinAgeLabel.visibility = GONE
insulinLabel.text = ""
insulinLevelLabel.visibility = GONE
cannulaOrPatch.text = ""
cannulaAgeLabel.visibility = GONE
cannulaUsageLabel.visibility = GONE
pbLabel.text = ""
pbAgeLabel.visibility = GONE
pbLevelLabel.visibility = GONE
}
}
}
override fun preProcessLandscapeOverviewLayout(dm: DisplayMetrics, binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
override fun preProcessLandscapeOverviewLayout(binding: OverviewFragmentBinding, isLandscape: Boolean, isTablet: Boolean, isSmallHeight: Boolean) {
if (!config.NSCLIENT && isLandscape) moveButtonsLayout(binding.root)
binding.apply {

View file

@ -12,6 +12,7 @@
android:focusable="true">
<TextView
android:id="@+id/sensor_label"
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center_vertical"
@ -84,6 +85,7 @@
android:focusable="true">
<TextView
android:id="@+id/insulin_label"
android:layout_width="wrap_content"
android:layout_height="25dp"
android:gravity="center_vertical"
@ -272,7 +274,7 @@
android:textSize="14sp" />
<TextView
android:id="@+id/battery_level"
android:id="@+id/pb_level"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="20dp"

View file

@ -127,7 +127,7 @@
app:alignItems="stretch"
app:flexDirection="row"
app:flexWrap="wrap"
app:justifyContent="center">
app:justifyContent="space_around">
<TextView
android:id="@+id/pump"

View file

@ -1,32 +1,32 @@
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
<com.google.android.flexbox.FlexboxLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/status_lights_layout"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="3dp"
android:layout_marginBottom="3dp"
android:orientation="horizontal"
android:layout_marginTop="-3dp"
android:layout_marginBottom="-3dp"
android:paddingTop="4dp"
android:paddingBottom="4dp"
android:baselineAligned="false">
app:alignContent="stretch"
app:alignItems="stretch"
app:flexDirection="row"
app:flexWrap="wrap"
app:justifyContent="space_around">
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_weight="1"
android:focusable="true"
android:gravity="center_horizontal"
android:gravity="center"
tools:ignore="UseCompoundDrawables">
<ImageView
android:id="@+id/cannula_or_patch"
android:layout_width="38dp"
android:layout_height="fill_parent"
android:layout_width="28dp"
android:layout_height="28dp"
android:contentDescription="@string/statuslights_cannula_age"
android:scaleX="2"
android:scaleY="2"
app:srcCompat="@drawable/ic_cp_age_cannula" />
<TextView
@ -40,23 +40,20 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:focusable="true"
android:gravity="center_horizontal">
android:gravity="center">
<ImageView
android:layout_width="26dp"
android:layout_height="fill_parent"
android:layout_width="28dp"
android:layout_height="28dp"
android:contentDescription="@string/a11y_insulin_label"
android:scaleX="1.7"
android:scaleY="1.7"
app:srcCompat="@drawable/ic_cp_age_insulin" />
<TextView
android:id="@+id/insulin_age"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_height="wrap_content"
android:lines="1"
tools:text="12h" />
@ -73,18 +70,15 @@
<LinearLayout
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:focusable="true"
android:gravity="center_horizontal"
android:gravity="center"
tools:ignore="UseCompoundDrawables">
<ImageView
android:layout_width="28dp"
android:layout_height="fill_parent"
android:layout_height="28dp"
android:contentDescription="@string/sensor_label"
android:scaleX="1.6"
android:scaleY="1.6"
app:srcCompat="@drawable/ic_cp_age_sensor" />
<TextView
@ -99,31 +93,28 @@
<LinearLayout
android:id="@+id/battery_layout"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_weight="1"
android:layout_height="wrap_content"
android:focusable="true"
android:gravity="center_horizontal">
android:gravity="center">
<ImageView
android:layout_width="32dp"
android:layout_height="wrap_content"
android:layout_width="28dp"
android:layout_height="28dp"
android:contentDescription="@string/battery_label"
android:scaleX="1.8"
android:scaleY="1.8"
app:srcCompat="@drawable/ic_cp_age_battery" />
<TextView
android:id="@+id/pb_age"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_height="wrap_content"
android:lines="1"
android:text="-"
tools:ignore="HardcodedText" />
<TextView
android:id="@+id/battery_level"
android:id="@+id/pb_level"
android:layout_width="wrap_content"
android:layout_height="fill_parent"
android:layout_height="wrap_content"
android:lines="1"
android:paddingStart="2dp"
android:paddingEnd="0dp"
@ -131,4 +122,4 @@
</LinearLayout>
</LinearLayout>
</com.google.android.flexbox.FlexboxLayout>

View file

@ -141,7 +141,6 @@
<string name="error_in_basal_values">Грешка в базалните стойности</string>
<string name="error_in_target_values">Грешка в стойностите за цел</string>
<string name="error_in_isf_values">Грешка в стойностите за чувствителност (ISF)</string>
<string name="profile_name_contains_dot">Името на профила съдържа точка.\nТова не се поддържа от НС.\nПрофилът не е качен в НС.</string>
<string name="invalid_profile_not_accepted">Невалиден профил %1$s не приет от NS</string>
<string name="view">Изглед</string>
<string name="errors">Грешки</string>

View file

@ -128,7 +128,6 @@
<string name="error_in_basal_values">Error en els valors de basal</string>
<string name="error_in_target_values">Error en els valors de l\'objectiu </string>
<string name="error_in_isf_values">Error en els valors de ISF</string>
<string name="profile_name_contains_dot">El nom del perfil conté punts.\nAixò NS no ho permet.\nPerfil no enviat a NS.</string>
<string name="invalid_profile_not_accepted">Perfil invàlid %1$s no acceptat de NS</string>
<string name="view">Vista</string>
<string name="errors">Errors</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Chyba v hodnotách bazálu</string>
<string name="error_in_target_values">Chyba v hodnotách cílové gl.</string>
<string name="error_in_isf_values">Chyba v hodnotách inz. citlivosti</string>
<string name="profile_name_contains_dot">Název profilu obsahuje tečky.\nToto není v NS podporováno.\nProfil není přenesen do NS.</string>
<string name="profile_name_contains_dot">Některý název profilu obsahuje tečky.\nToto není v NS podporováno.\nProfily nebudou přeneseny do NS.</string>
<string name="invalid_profile_not_accepted">Neplatný profil %1$s nebyl přijat z NS</string>
<string name="view">Zobrazit</string>
<string name="errors">Chyby</string>

View file

@ -137,7 +137,6 @@
<string name="error_in_basal_values">Fejl i basal rate værdier</string>
<string name="error_in_target_values">Fejl i målværdier</string>
<string name="error_in_isf_values">Fejl i ISF-værdier</string>
<string name="profile_name_contains_dot">Profilnavn indeholder punktum.\nDette understøttes ikke af NS.\nProfilen er ikke uploadet til NS.</string>
<string name="invalid_profile_not_accepted">Ugyldig profil %1$s blev ikke accepteret fra NS</string>
<string name="view">Vis</string>
<string name="errors">Fejl</string>

View file

@ -141,7 +141,6 @@
<string name="error_in_basal_values">Fehler in den Basalwerten</string>
<string name="error_in_target_values">Fehler in den Zielwerten</string>
<string name="error_in_isf_values">Fehler in ISF-Werten</string>
<string name="profile_name_contains_dot">Profilname enthält Punkte.\nDies wird von NS nicht unterstützt.\nProfil wird nicht zu NS hochgeladen.</string>
<string name="invalid_profile_not_accepted">Ungültiges Profil %1$s wurde von NS nicht akzeptiert</string>
<string name="view">Ansicht</string>
<string name="errors">Fehler</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Error en valores basales</string>
<string name="error_in_target_values">Error en los valores de objetivo</string>
<string name="error_in_isf_values">Error en valores ISF</string>
<string name="profile_name_contains_dot">El nombre de perfil contiene puntos.\nEsto no está permitido por NS.\nEl perfil no se cargará en NS.</string>
<string name="profile_name_contains_dot">Algunos nombres de perfiles contienen puntos.\nEsto no está soportado por NS.\nLos perfiles no serán subidos a NS.</string>
<string name="invalid_profile_not_accepted">Perfil no válido %1$s no aceptado desde Nightscout</string>
<string name="view">Vista</string>
<string name="errors">Errores</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Erreur dans les valeurs de basal</string>
<string name="error_in_target_values">Erreur dans les valeurs cibles</string>
<string name="error_in_isf_values">Erreur dans les valeurs de SI</string>
<string name="profile_name_contains_dot">Le nom du profil contient des points.\nCe n\'est pas pris en charge par NS.\nLe profil n\'est pas remonté dans NS.</string>
<string name="profile_name_contains_dot">Certains noms de profil contiennent des points.\nCeci n\'est pas supporté par NS.\nLes profils ne seront pas téléchargés vers NS.</string>
<string name="invalid_profile_not_accepted">Profil %1$s non valide, refusé par NS</string>
<string name="view">Vue</string>
<string name="errors">Erreurs</string>

View file

@ -94,7 +94,6 @@
<string name="error_in_basal_values">Pogreška u bazalnim vrijednostima</string>
<string name="error_in_target_values">Pogreška u ciljanim vrijednostima</string>
<string name="error_in_isf_values">Pogreška u ISF vrijednostima</string>
<string name="profile_name_contains_dot">Naziv profila sadrži točke.\nNS to ne podržava.\nProfil nije učitan u NS.</string>
<string name="invalid_profile_not_accepted">Nevažeći profil %1$s nije prihvaćen od NS-a</string>
<string name="view">Pogled</string>
<string name="errors">Greške</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Errore nei valori della basale</string>
<string name="error_in_target_values">Errore nei valori del target</string>
<string name="error_in_isf_values">Errore nei valori ISF</string>
<string name="profile_name_contains_dot">Il nome profilo contiene dei punti.\nQuesto non è supportato da NS.\nIl profilo non viene caricato in NS.</string>
<string name="profile_name_contains_dot">Alcuni nomi profilo contengono punti.\nQuesto non è supportato da NS.\nI profili non verranno caricati su NS.</string>
<string name="invalid_profile_not_accepted">Profilo %1$s non valido - non accettato da NS</string>
<string name="view">Vista</string>
<string name="errors">Errori</string>

View file

@ -141,7 +141,6 @@
<string name="error_in_basal_values">שגיאה בערכי המינון הבזאלי</string>
<string name="error_in_target_values">שגיאה בערכי המטרה</string>
<string name="error_in_isf_values">שגיאה בערכי יחס התיקון</string>
<string name="profile_name_contains_dot">שם הפרופיל מכיל נקודות.\nשם כזה אינו נתמך ע\"י Nightscout \n הפרופיל לא הועלה ל-Nightscout.</string>
<string name="invalid_profile_not_accepted">הפרופיל הבלתי חוקי %1$s מ-Nightscout לא מאושר</string>
<string name="view">תצוגה</string>
<string name="errors">שגיאות</string>

View file

@ -123,7 +123,6 @@
<string name="save_or_reset_changes_first">우선 현재 변경사항을을 저장하거나 재설정하세요</string>
<string name="delete_current_profile">현재 프로파일을 삭제 하시겠습니까?</string>
<string name="units_colon">단위:</string>
<string name="profile_name_contains_dot">프로파일명에 점을 포함하고 있습니다.\n이는 NS에서 지원하지 않습니다.\n프로파일이 NS에 업로드되지 않습니다.</string>
<string name="errors">에러</string>
<string name="profile_name">프로파일명:</string>
<string name="a11y_delete_current_profile">현재 프로파일을 삭제 하시겠습니까</string>

View file

@ -130,7 +130,7 @@
<!-- Profile -->
<string name="localprofile">Profilis</string>
<string name="localprofile_shortname">VP</string>
<string name="description_profile_local">Nustatykite vietinį profilį.</string>
<string name="description_profile_local">Nustatyti vietinį profilį.</string>
<string name="a11y_add_new_to_list">pridėti naują į sąrašą</string>
<string name="do_you_want_switch_profile">Ar norite pakeisti profilį ir atsisakyti pakeitimų, atliktų dabartiniame profilyje?</string>
<string name="save_or_reset_changes_first">Pirmiausia išsaugoti arba anuliuoti dabartinius pokyčius</string>
@ -141,7 +141,7 @@
<string name="error_in_basal_values">Bazės reikšmių klaida</string>
<string name="error_in_target_values">Tikslinės glikemijos reikšmės klaida</string>
<string name="error_in_isf_values">JIF reikšmės klaida</string>
<string name="profile_name_contains_dot">Profilio pavadinime yra taškų.\nŠios funkcijos NS nepalaiko.\nProfilis neįkeltas į NS.</string>
<string name="profile_name_contains_dot">Profilio pavadinime yra taškų.\nŠios funkcijos NS nepalaiko.\nProfilis nebus įkeltas į NS.</string>
<string name="invalid_profile_not_accepted">Neteisingas profilis %1$s nepriimtas iš NS</string>
<string name="view">Rodymas</string>
<string name="errors">Klaidos</string>
@ -206,7 +206,7 @@
<string name="dexcom_app_not_installed">Dexcom app neįdiegta.</string>
<string name="dexcom_app_not_detected">Atnaujinkite savo Dexcom programėlės versiją</string>
<string name="error_starting_cgm">Nepavyko paleisti NGJ programos. Įsitikinkite, kad ji įdiegta.</string>
<string name="not_available_full">Negalimas</string>
<string name="not_available_full">Nėra duomenų</string>
<string name="constraints_violation">Apribojimų pažeidimas</string>
<string name="change_your_input">Pakeiskite įvestus duomenis!</string>
<string name="openaps">AtviraDKS</string>

View file

@ -141,7 +141,6 @@
<string name="error_in_basal_values">Fout in basaal waarden</string>
<string name="error_in_target_values">Fout in streefdoel</string>
<string name="error_in_isf_values">Fout in ISF waarden</string>
<string name="profile_name_contains_dot">Profielnaam bevat punten.\nDit wordt niet ondersteund door NS.\nProfiel is niet geüpload naar NS.</string>
<string name="invalid_profile_not_accepted">Ongeldig profiel %1$s niet geaccepteerd door NS</string>
<string name="view">Weergeven</string>
<string name="errors">Foutmeldingen</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Feil i basalverdiene</string>
<string name="error_in_target_values">Feil i BS målverdier</string>
<string name="error_in_isf_values">Feil i IF verdien</string>
<string name="profile_name_contains_dot">Profilnavnet inneholder prikker.\nDette støttes ikke av NS.\nProfilen er ikke lastet opp til NS.</string>
<string name="profile_name_contains_dot">Noen av profilnavnene inneholder punktum.\nDette støttes ikke av NS.\nProfilen er ikke lastet opp til NS.</string>
<string name="invalid_profile_not_accepted">Ugyldig profil %1$s ikke akseptert fra NS</string>
<string name="view">Visning</string>
<string name="errors">Feil</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Błąd w wartościach bazy</string>
<string name="error_in_target_values">Błąd w wartościach docelowych</string>
<string name="error_in_isf_values">Błąd w wartościach ISF</string>
<string name="profile_name_contains_dot">Nazwa profilu zawiera kropki.\nTo nie jest obsługiwane przez NS.\nProfil nie zostanie przesyłany do NS.</string>
<string name="profile_name_contains_dot">Nazwa któregoś z profili zawiera kropki.\nTo nie jest obsługiwane przez NS.\nProfile nie zostaną przesłane do NS.</string>
<string name="invalid_profile_not_accepted">Błędny profil %1$s nie został zaakceptowany z NS</string>
<string name="view">Podgląd</string>
<string name="errors">Błędy</string>

View file

@ -138,7 +138,6 @@
<string name="error_in_basal_values">Erro nos valores da basal</string>
<string name="error_in_target_values">Erro nos valores de alvo</string>
<string name="error_in_isf_values">Erro nos valores de FSI</string>
<string name="profile_name_contains_dot">Nome do perfil contém pontos.\nIsso não é suportado pelo NS.\nPerfil não foi enviado para o NS.</string>
<string name="invalid_profile_not_accepted">Perfil inválido %1$s não aceito do NS</string>
<string name="view">Visualização</string>
<string name="errors">Erros</string>

View file

@ -128,7 +128,6 @@
<string name="error_in_basal_values">Erro nos valores da basal</string>
<string name="error_in_target_values">Erros no valor alvo</string>
<string name="error_in_isf_values">Erro nos valores do FSI</string>
<string name="profile_name_contains_dot">Nome do perfil contém pontos.\nIsso não é suportado pelo NS.\nPerfil não é enviado para o NS.</string>
<string name="invalid_profile_not_accepted">Perfil inválido %1$s não aceite do NS</string>
<string name="view">Ver</string>
<string name="errors">Erros</string>

View file

@ -129,7 +129,6 @@
<string name="error_in_basal_values">Eroare in valorile ratei bazale</string>
<string name="error_in_target_values">Eroare in valorile tinta</string>
<string name="error_in_isf_values">Eroare in valorile ISF</string>
<string name="profile_name_contains_dot">Numele profilului conține puncte.\nAcest lucru nu este permis de NS.\nProfilul nu a fost înregistrat în NS.</string>
<string name="invalid_profile_not_accepted">Profilul invalid din NS %1$s nu este acceptat</string>
<string name="view">Vizualizare</string>
<string name="errors">Erori</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Ошибка в величине базала</string>
<string name="error_in_target_values">Ошибка в целевых значениях</string>
<string name="error_in_isf_values">Ошибка в значении фактора чувствительности к инсулину ISF</string>
<string name="profile_name_contains_dot">Имя профиля содержит точки.\nЭто не поддерживается NS.\nПрофиль не выгружен в NS.</string>
<string name="profile_name_contains_dot">В некоторых наименованиях профиля содержатся точки.\nЭто не поддерживается NS.\nПрофиль не выгружен в NS.</string>
<string name="invalid_profile_not_accepted">Неверный профиль %1$s не принят из NS</string>
<string name="view">Смотреть</string>
<string name="errors">Ошибки</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Chyba v hodnotách bazálu</string>
<string name="error_in_target_values">Chyba v cieľových hodnotách</string>
<string name="error_in_isf_values">Chyba v hodnotách citlivosti</string>
<string name="profile_name_contains_dot">Názov profilu obsahuje bodky.\nToto nie je v NS podporované.\nProfil nie je prenesený do NS.</string>
<string name="profile_name_contains_dot">Názov profilu obsahuje bodky.\nToto nie je v NS podporované.\nProfil nebude prenesený do NS.</string>
<string name="invalid_profile_not_accepted">Neplatný profil %1$s nebol akceptovaný z NS</string>
<string name="view">Zobraziť</string>
<string name="errors">Chyby</string>

View file

@ -129,7 +129,6 @@
<string name="error_in_basal_values">Fel i basaldoser</string>
<string name="error_in_target_values">Fel i målvärden</string>
<string name="error_in_isf_values">Fel i korrektionskvoter</string>
<string name="profile_name_contains_dot">Profilnamnet innehåller punkter.\nDetta stöds inte av NS.\nProfil överförs inte till NS.</string>
<string name="invalid_profile_not_accepted">Ogiltig profil %1$s från NS accepteras inte</string>
<string name="view">Visa</string>
<string name="errors">Fel</string>

View file

@ -141,7 +141,7 @@
<string name="error_in_basal_values">Bazal değerlerde hata</string>
<string name="error_in_target_values">Hedef değerlerde hata</string>
<string name="error_in_isf_values">ISF değerinde hata</string>
<string name="profile_name_contains_dot">Profil adı noktalar içeriyor.\nBu NS tarafından desteklenmiyor.\n Profil NS\'a yüklenmez.</string>
<string name="profile_name_contains_dot">Profil adlarından bazıları noktalar içeriyor.\nBu, NS tarafından desteklenmiyor.\nProfiller NS\'ye yüklenmeyecek.</string>
<string name="invalid_profile_not_accepted">Geçersiz profil %1$s NS tarafından kabul edilmiyor</string>
<string name="view">Görünüm</string>
<string name="errors">Hatalar</string>

View file

@ -135,7 +135,6 @@
<string name="error_in_basal_values">基础率数值错误</string>
<string name="error_in_target_values">目标数值错误</string>
<string name="error_in_isf_values">ISF数值错误</string>
<string name="profile_name_contains_dot">配置文件名称包含点。\n这不受 NS 支持。\n配置未上载到 NS。</string>
<string name="invalid_profile_not_accepted">不接受来自NS的无效配置文件%1$s</string>
<string name="view">查看</string>
<string name="errors">错误</string>

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