Merge remote-tracking branch 'Nightscout/dev' into Autotune/TuneWeekDaysClean
This commit is contained in:
commit
0ce6d8d0d6
315 changed files with 11286 additions and 2626 deletions
|
@ -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.
|
||||
|
@ -45,4 +45,4 @@ workflows:
|
|||
# For more details on extending your workflow, see the configuration docs: https://circleci.com/docs/2.0/configuration-reference/#workflows
|
||||
dotests:
|
||||
jobs:
|
||||
- build-and-test
|
||||
- build-and-test
|
||||
|
|
|
@ -34,7 +34,7 @@ dependencies {
|
|||
api 'org.slf4j:slf4j-api:1.7.36' // 2.0.x breaks logging. Code change needed
|
||||
api 'com.github.tony19:logback-android:2.0.0'
|
||||
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version"
|
||||
api "org.apache.commons:commons-lang3:$commonslang3_version"
|
||||
|
||||
//RxBus
|
||||
|
|
|
@ -3,6 +3,7 @@ package info.nightscout.rx.weardata
|
|||
import info.nightscout.rx.events.Event
|
||||
import kotlinx.serialization.Serializable
|
||||
import kotlinx.serialization.json.Json
|
||||
import org.joda.time.DateTime
|
||||
import java.util.Objects
|
||||
|
||||
@Serializable
|
||||
|
@ -90,6 +91,16 @@ sealed class EventData : Event() {
|
|||
@Serializable
|
||||
data class ActionQuickWizardPreCheck(val guid: String) : EventData()
|
||||
|
||||
@Serializable
|
||||
data class ActionHeartRate(
|
||||
val duration: Long,
|
||||
val timestamp: Long,
|
||||
val beatsPerMinute: Double,
|
||||
val device: String): EventData() {
|
||||
override fun toString() =
|
||||
"HR ${beatsPerMinute.toInt()} at ${DateTime(timestamp)} for ${duration / 1000.0}sec $device"
|
||||
}
|
||||
|
||||
@Serializable
|
||||
data class ActionTempTargetPreCheck(
|
||||
val command: TempTargetCommand,
|
||||
|
|
|
@ -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> =
|
||||
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)
|
||||
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
|
||||
|
|
|
@ -16,8 +16,6 @@ import androidx.annotation.RawRes
|
|||
import androidx.annotation.StringRes
|
||||
|
||||
interface ResourceHelper {
|
||||
fun updateContext(ctx: Context?)
|
||||
|
||||
fun gs(@StringRes id: Int): String
|
||||
fun gs(@StringRes id: Int, vararg args: Any?): String
|
||||
fun gq(@PluralsRes id: Int, quantity: Int, vararg args: Any?): String
|
||||
|
|
|
@ -111,7 +111,7 @@ android {
|
|||
defaultConfig {
|
||||
multiDexEnabled true
|
||||
versionCode 1500
|
||||
version "3.1.0.3-dev-h"
|
||||
version "3.2.0-dev-j"
|
||||
buildConfigField "String", "VERSION", '"' + version + '"'
|
||||
buildConfigField "String", "BUILDVERSION", '"' + generateGitBuild() + '-' + generateDate() + '"'
|
||||
buildConfigField "String", "REMOTE", '"' + generateGitRemote() + '"'
|
||||
|
@ -234,7 +234,7 @@ dependencies {
|
|||
kapt "com.google.dagger:dagger-compiler:$dagger_version"
|
||||
|
||||
// MainApp
|
||||
api "com.uber.rxdogtag2:rxdogtag:2.0.1"
|
||||
api "com.uber.rxdogtag2:rxdogtag:2.0.2"
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -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)
|
||||
|
@ -477,4 +478,4 @@ class MainActivity : DaggerAppCompatActivityWithResult() {
|
|||
ToastUtils.okToast(context, context.getString(info.nightscout.core.ui.R.string.password_set))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -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
|
||||
|
@ -327,6 +327,7 @@ class HistoryBrowseActivity : DaggerAppCompatActivity() {
|
|||
var useRatioForScale = false
|
||||
var useDSForScale = false
|
||||
var useBGIForScale = false
|
||||
var useHRForScale = false
|
||||
when {
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.ABS.ordinal] -> useABSForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.IOB.ordinal] -> useIobForScale = true
|
||||
|
@ -335,6 +336,7 @@ class HistoryBrowseActivity : DaggerAppCompatActivity() {
|
|||
menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal] -> useBGIForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal] -> useRatioForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] -> useDSForScale = true
|
||||
menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal] -> useHRForScale = true
|
||||
}
|
||||
val alignDevBgiScale = menuChartSettings[g + 1][OverviewMenus.CharType.DEV.ordinal] && menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]
|
||||
|
||||
|
@ -345,6 +347,7 @@ class HistoryBrowseActivity : DaggerAppCompatActivity() {
|
|||
if (menuChartSettings[g + 1][OverviewMenus.CharType.BGI.ordinal]) secondGraphData.addMinusBGI(useBGIForScale, if (alignDevBgiScale) 1.0 else 0.8)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.SEN.ordinal]) secondGraphData.addRatio(useRatioForScale, if (useRatioForScale) 1.0 else 0.8)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.DEVSLOPE.ordinal] && config.isDev()) secondGraphData.addDeviationSlope(useDSForScale, 1.0)
|
||||
if (menuChartSettings[g + 1][OverviewMenus.CharType.HR.ordinal] && config.isDev()) secondGraphData.addHeartRate(useHRForScale, 1.0)
|
||||
|
||||
// set manual x bounds to have nice steps
|
||||
secondGraphData.formatAxis(historyBrowserData.overviewData.fromTime, historyBrowserData.overviewData.endTime)
|
||||
|
|
|
@ -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 -> {
|
||||
|
|
|
@ -44,6 +44,8 @@ class ConfigImpl @Inject constructor(
|
|||
engineeringMode = engineeringModeSemaphore.exists() && engineeringModeSemaphore.isFile
|
||||
unfinishedMode = unfinishedModeSemaphore.exists() && unfinishedModeSemaphore.isFile
|
||||
devBranch = BuildConfig.VERSION.contains("-") || BuildConfig.VERSION.matches(Regex(".*[a-zA-Z]+.*"))
|
||||
if (BuildConfig.VERSION.contains("-beta") || BuildConfig.VERSION.contains("-rc"))
|
||||
devBranch = false
|
||||
}
|
||||
|
||||
override fun isEngineeringModeOrRelease(): Boolean =
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -21,7 +21,7 @@
|
|||
<string name="ns_announcements">Създаване на известия от NS съобщения</string>
|
||||
<string name="ns_alarm_stale_data_value_label">Когато няма данни повече от [мин]</string>
|
||||
<string name="ns_alarm_urgent_stale_data_value_label">Много стари данни при повече от [мин]</string>
|
||||
<string name="sensitivity_warning">Когато включите Autosense feature трябва да въвеждате ВСИЧКИ въглехидрати. В противен случай те ще се изчисляват грешно като повишена чувствителност!!</string>
|
||||
<string name="sensitivity_warning">Когато включите Autosense, трябва да въвеждате ВСИЧКИ въглехидрати. В противен случай те ще се изчисляват грешно, като повишена чувствителност!!</string>
|
||||
<string name="notloadedplugins">Не всички профили са заредени!</string>
|
||||
<string name="valuesnotstored">Стойностите не са запазени!</string>
|
||||
<string name="invalid">НЕВАЛИДНО</string>
|
||||
|
|
39
build.gradle
39
build.gradle
|
@ -2,41 +2,40 @@
|
|||
|
||||
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.0'
|
||||
lifecycle_version = '2.5.1'
|
||||
dagger_version = '2.45'
|
||||
coroutines_version = '1.6.4'
|
||||
activity_version = '1.6.1'
|
||||
fragmentktx_version = '1.5.5'
|
||||
room_version = '2.5.1'
|
||||
lifecycle_version = '2.6.1'
|
||||
dagger_version = '2.46.1'
|
||||
coroutines_version = '1.7.1'
|
||||
activity_version = '1.7.2'
|
||||
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'
|
||||
commonslang3_version = '3.12.0'
|
||||
commonscodec_version = '1.15'
|
||||
jodatime_version = '2.10.14'
|
||||
work_version = '2.8.0'
|
||||
tink_version = '1.8.0'
|
||||
work_version = '2.8.1'
|
||||
tink_version = '1.9.0'
|
||||
json_version = '20220320'
|
||||
serialization_version = '1.4.1'
|
||||
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'
|
||||
|
@ -50,7 +49,7 @@ buildscript {
|
|||
play_services_location_version = '21.0.1'
|
||||
|
||||
kotlinx_datetime_version = '0.4.0'
|
||||
kotlinx_serialization_core_version = '1.4.1'
|
||||
kotlinx_serialization_version = '1.5.1'
|
||||
}
|
||||
repositories {
|
||||
google()
|
||||
|
@ -58,9 +57,9 @@ buildscript {
|
|||
maven { url "https://plugins.gradle.org/m2/" } // jacoco 0.2
|
||||
}
|
||||
dependencies {
|
||||
classpath 'com.android.tools.build:gradle:7.4.1'
|
||||
classpath 'com.google.gms:google-services:4.3.14'
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.4'
|
||||
classpath 'com.android.tools.build:gradle:7.4.2'
|
||||
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
|
||||
|
@ -76,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.2.0"
|
||||
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
|
||||
}
|
||||
|
|
|
@ -150,4 +150,7 @@ interface OverviewData {
|
|||
val dsMinScale: Scale
|
||||
var dsMaxSeries: LineGraphSeries<ScaledDataPoint>
|
||||
var dsMinSeries: LineGraphSeries<ScaledDataPoint>
|
||||
}
|
||||
var heartRateScale: Scale
|
||||
var heartRateGraphSeries: LineGraphSeries<DataPointWithLabelInterface>
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,24 @@
|
|||
package info.nightscout.core.graph.data
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Paint
|
||||
import info.nightscout.database.entities.HeartRate
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
|
||||
class HeartRateDataPoint(
|
||||
private val data: HeartRate,
|
||||
private val rh: ResourceHelper,
|
||||
) : DataPointWithLabelInterface {
|
||||
|
||||
override fun getX(): Double = (data.timestamp - data.duration).toDouble()
|
||||
override fun getY(): Double = data.beatsPerMinute
|
||||
override fun setY(y: Double) {}
|
||||
|
||||
override val label: String = ""
|
||||
override val duration = data.duration
|
||||
override val shape = PointsWithLabelGraphSeries.Shape.HEARTRATE
|
||||
override val size = 1f
|
||||
override val paintStyle: Paint.Style = Paint.Style.FILL
|
||||
|
||||
override fun color(context: Context?): Int = rh.gac(context, info.nightscout.core.ui.R.attr.heartRateColor)
|
||||
}
|
|
@ -54,7 +54,8 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
|
|||
GENERAL_WITH_DURATION,
|
||||
COB_FAIL_OVER,
|
||||
IOB_PREDICTION,
|
||||
BUCKETED_BG
|
||||
BUCKETED_BG,
|
||||
HEARTRATE,
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -324,6 +325,10 @@ public class PointsWithLabelGraphSeries<E extends DataPointWithLabelInterface> e
|
|||
mPaint.setStrokeWidth(5);
|
||||
canvas.drawRect(endX - 3, bounds.top + py - 3, xPlusLength + 3, bounds.bottom + py + 3, mPaint);
|
||||
}
|
||||
} else if (value.getShape() == Shape.HEARTRATE) {
|
||||
mPaint.setStyle(Paint.Style.FILL_AND_STROKE);
|
||||
mPaint.setStrokeWidth(0);
|
||||
canvas.drawCircle(endX, endY, 1F, mPaint);
|
||||
}
|
||||
// set values above point
|
||||
}
|
||||
|
|
|
@ -9,6 +9,8 @@ import info.nightscout.interfaces.userEntry.ValueWithUnitMapper
|
|||
|
||||
interface UserEntryLogger {
|
||||
|
||||
fun log(action: Action, source: Sources, note: String?, timestamp: Long, vararg listValues: ValueWithUnit?)
|
||||
fun log(action: Action, source: Sources, note: String?, timestamp: Long, listValues: List<ValueWithUnit?>)
|
||||
fun log(action: Action, source: Sources, note: String? = "", vararg listValues: ValueWithUnit?)
|
||||
fun log(action: Action, source: Sources, vararg listValues: ValueWithUnit?)
|
||||
fun log(action: Action, source: Sources, note: String? = "", listValues: List<ValueWithUnit?> = listOf())
|
||||
|
|
|
@ -133,6 +133,7 @@ open class Notification {
|
|||
const val EOELOW_PATCH_ALERTS = 79
|
||||
const val COMBO_PUMP_SUSPENDED = 80
|
||||
const val COMBO_UNKNOWN_TBR = 81
|
||||
const val BLUETOOTH_NOT_ENABLED = 82
|
||||
|
||||
const val USER_MESSAGE = 1000
|
||||
|
||||
|
|
|
@ -43,7 +43,12 @@ interface StoreDataForDb {
|
|||
val nsIdDeviceStatuses: MutableList<DeviceStatus>
|
||||
val nsIdFoods: MutableList<Food>
|
||||
|
||||
val deleteTreatment: MutableList<String>
|
||||
val deleteGlucoseValue: MutableList<String>
|
||||
|
||||
fun updateDeletedGlucoseValuesInDb()
|
||||
fun storeTreatmentsToDb()
|
||||
fun updateDeletedTreatmentsInDb()
|
||||
fun storeGlucoseValuesToDb()
|
||||
fun storeFoodsToDb()
|
||||
fun scheduleNsIdUpdate()
|
||||
|
|
|
@ -15,7 +15,8 @@ interface OverviewMenus {
|
|||
BGI,
|
||||
SEN,
|
||||
ACT,
|
||||
DEVSLOPE
|
||||
DEVSLOPE,
|
||||
HR,
|
||||
}
|
||||
|
||||
val setting: List<Array<Boolean>>
|
||||
|
@ -23,4 +24,4 @@ interface OverviewMenus {
|
|||
fun setupChartMenu(context: Context, chartButton: ImageButton)
|
||||
fun enabledTypes(graph: Int): String
|
||||
fun isEnabledIn(type: CharType): Int
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -23,7 +23,7 @@ dependencies {
|
|||
|
||||
api "org.jetbrains.kotlin:kotlin-stdlib-jdk8:$kotlin_version"
|
||||
|
||||
api 'com.google.guava:guava:31.1-jre'
|
||||
api 'com.google.guava:guava:32.0.0-jre'
|
||||
|
||||
api "androidx.activity:activity-ktx:$activity_version"
|
||||
api "androidx.appcompat:appcompat:$appcompat_version"
|
||||
|
|
|
@ -34,5 +34,5 @@ dependencies {
|
|||
api "org.jetbrains.kotlinx:kotlinx-coroutines-android:$coroutines_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-coroutines-rx3:$coroutines_version"
|
||||
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$serialization_version"
|
||||
api "org.jetbrains.kotlinx:kotlinx-serialization-json:$kotlinx_serialization_version"
|
||||
}
|
||||
|
|
|
@ -292,14 +292,11 @@ class NSAndroidClientImpl(
|
|||
lastModified = response.body()?.lastModified
|
||||
)
|
||||
} else throw UnknownResponseNightscoutException()
|
||||
} else if (response.code() in 400..499) {
|
||||
return@callWrapper CreateUpdateResponse(
|
||||
response = response.code(),
|
||||
identifier = null,
|
||||
errorResponse = response.errorBody()?.string() ?: response.message()
|
||||
)
|
||||
} else
|
||||
throw UnsuccessfullNightscoutException(response.errorBody()?.string() ?: response.message())
|
||||
} else return@callWrapper CreateUpdateResponse(
|
||||
response = response.code(),
|
||||
identifier = null,
|
||||
errorResponse = response.errorBody()?.string() ?: response.message()
|
||||
)
|
||||
}
|
||||
|
||||
override suspend fun createTreatment(nsTreatment: NSTreatment): CreateUpdateResponse = callWrapper(dispatcher) {
|
||||
|
|
|
@ -45,7 +45,7 @@ internal fun RemoteTreatment.toTreatment(): NSTreatment? {
|
|||
subject = this.subject,
|
||||
isReadOnly = this.isReadOnly ?: false,
|
||||
isValid = this.isValid ?: true,
|
||||
eventType = this.eventType,
|
||||
eventType = this.eventType ?: EventType.MEAL_BOLUS,
|
||||
notes = this.notes,
|
||||
pumpId = this.pumpId,
|
||||
endId = this.endId,
|
||||
|
@ -68,7 +68,7 @@ internal fun RemoteTreatment.toTreatment(): NSTreatment? {
|
|||
subject = this.subject,
|
||||
isReadOnly = this.isReadOnly ?: false,
|
||||
isValid = this.isValid ?: true,
|
||||
eventType = this.eventType,
|
||||
eventType = this.eventType ?: EventType.CARBS_CORRECTION,
|
||||
notes = this.notes,
|
||||
pumpId = this.pumpId,
|
||||
endId = this.endId,
|
||||
|
|
|
@ -29,7 +29,7 @@ internal data class RemoteTreatment(
|
|||
@SerializedName("modifiedBy") val modifiedBy: String? = null, // string Name of the security subject (within Nightscout scope) which has patched or deleted the document for the last time. This field is automatically set by the server.
|
||||
@SerializedName("isValid") val isValid: Boolean? = null, // boolean A flag set by the server only for deleted documents. This field appears only within history operation and for documents which were deleted by API v3 (and they always have a false value)
|
||||
@SerializedName("isReadOnly") val isReadOnly: Boolean? = null, // boolean A flag set by client that locks the document from any changes. Every document marked with isReadOnly=true is forever immutable and cannot even be deleted.
|
||||
@SerializedName("eventType") val eventType: EventType, // string "BG Check", "Snack Bolus", "Meal Bolus", "Correction Bolus", "Carb Correction", "Combo Bolus", "Announcement", "Note", "Question", "Exercise", "Site Change", "Sensor Start", "Sensor Change", "Pump Battery Change", "Insulin Change", "Temp Basal", "Profile Switch", "D.A.D. Alert", "Temporary Target", "OpenAPS Offline", "Bolus Wizard"
|
||||
@SerializedName("eventType") val eventType: EventType?, // string "BG Check", "Snack Bolus", "Meal Bolus", "Correction Bolus", "Carb Correction", "Combo Bolus", "Announcement", "Note", "Question", "Exercise", "Site Change", "Sensor Start", "Sensor Change", "Pump Battery Change", "Insulin Change", "Temp Basal", "Profile Switch", "D.A.D. Alert", "Temporary Target", "OpenAPS Offline", "Bolus Wizard"
|
||||
@SerializedName("glucose") val glucose: Double? = null, // double Current glucose
|
||||
@SerializedName("glucoseType") val glucoseType: String? = null, // string example: "Sensor", "Finger", "Manual"
|
||||
@SerializedName("units") val units: String? = null, // string The units for the glucose value, mg/dl or mmol/l. It is strongly recommended to fill in this field.
|
||||
|
|
|
@ -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))
|
||||
}
|
|
@ -2,19 +2,21 @@ package info.nightscout.core.ui.locale
|
|||
|
||||
import android.content.Context
|
||||
import android.content.ContextWrapper
|
||||
import android.content.res.Configuration
|
||||
import android.os.LocaleList
|
||||
import androidx.preference.PreferenceManager
|
||||
import info.nightscout.core.ui.R
|
||||
import java.util.Locale
|
||||
|
||||
object LocaleHelper {
|
||||
|
||||
private fun selectedLanguage(context: Context): String =
|
||||
PreferenceManager.getDefaultSharedPreferences(context).getString(context.getString(R.string.key_language), "default")
|
||||
?: "default"
|
||||
// injection not possible because of use in attachBaseContext
|
||||
//SP.getString(R.string.key_language, Locale.getDefault().language)
|
||||
|
||||
private fun currentLocale(context: Context): Locale {
|
||||
fun currentLocale(context: Context): Locale {
|
||||
val language = selectedLanguage(context)
|
||||
if (language == "default") return Locale.getDefault()
|
||||
|
||||
|
@ -34,18 +36,13 @@ object LocaleHelper {
|
|||
|
||||
val locale = currentLocale(context)
|
||||
Locale.setDefault(locale)
|
||||
val resources = context.resources
|
||||
val configuration = resources.configuration
|
||||
context.createConfigurationContext(configuration)
|
||||
configuration.setLocale(locale)
|
||||
}
|
||||
|
||||
fun wrap(ctx: Context): Context {
|
||||
// no action for system default language
|
||||
if (selectedLanguage(ctx) == "default") return ctx
|
||||
|
||||
val res = ctx.resources
|
||||
val configuration = res.configuration
|
||||
val configuration = Configuration()
|
||||
val newLocale = currentLocale(ctx)
|
||||
configuration.setLocale(newLocale)
|
||||
val localeList = LocaleList(newLocale)
|
||||
|
|
|
@ -164,7 +164,6 @@
|
|||
<string name="isf_short">Чувств</string>
|
||||
<string name="canceling_tbr_failed">Отмяната на временния базал е неуспешно</string>
|
||||
<string name="canceling_eb_failed">Неуспешно спиране на удължен болус</string>
|
||||
<string name="virtualpump_uploadstatus_title">Качване на статус в NS или Tidepool</string>
|
||||
<string name="suspendloop_label">Изключен/забранен цикъл</string>
|
||||
<string name="iob_label">Активен Инсулин (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
@ -298,7 +297,6 @@
|
|||
<string name="uel_site_change">СМЯНА КАНЮЛА</string>
|
||||
<string name="uel_reservoir_change">СМЯНА НА РЕЗЕРВОАР</string>
|
||||
<string name="uel_calibration">КАЛИБРАЦИЯ</string>
|
||||
<string name="uel_prime_bolus">БОЛУС ПЪЛНЕНЕНЕ</string>
|
||||
<string name="uel_treatment">ЛЕЧЕНИЕ</string>
|
||||
<string name="uel_careportal_ns_refresh">ОБНОВИ ПОРТАЛА ЗА ЛЕЧЕНИЯ NS</string>
|
||||
<string name="uel_profile_switch_ns_refresh">ОБНОВИ СМЯНАТА НА ПРОФИЛ NS</string>
|
||||
|
@ -463,10 +461,10 @@
|
|||
<string name="wizard_carbs_constraint">Нарушение на въхлехидратните ограничения!</string>
|
||||
<string name="wizard_explain_calc">Изчисляване (въглехидратно число: %1$.1f, инсулинова чувствителност: %2$.1f)</string>
|
||||
<string name="wizard_explain_carbs">Въглехидрати: %1$.2fЕ</string>
|
||||
<string name="wizard_explain_cob">Остатъчни въглехидрати: %1$.0fg %2$.2fU</string>
|
||||
<string name="wizard_explain_bg">Кръвна захар: %1$.2fU</string>
|
||||
<string name="wizard_explain_cob">Активни въглехидрати: %1$.0fгр %2$.2fЕ</string>
|
||||
<string name="wizard_explain_bg">КЗ: %1$.2fЕ</string>
|
||||
<string name="wizard_explain_iob">Остатъчен инсулин: %1$.2fU</string>
|
||||
<string name="wizard_explain_superbolus">Суперболус: %1$.2fU</string>
|
||||
<string name="wizard_explain_superbolus">Суперболус: %1$.2fЕ</string>
|
||||
<string name="wizard_explain_trend">15\' тенденция: %1$.2fЕ</string>
|
||||
<string name="wizard_explain_percent">Проценти: %1$.2fЕ x %2$d%% ≈ %3$.2fЕ</string>
|
||||
<string name="wizard_constraint_bolus_size">Нарушение в ограниичението на инсулин!\nНе може да бъде доставен %1$.2fЕ</string>
|
||||
|
@ -572,7 +570,7 @@
|
|||
<item quantity="other">%1$d минути</item>
|
||||
</plurals>
|
||||
<!-- Maintenance-->
|
||||
<string name="cleanup_db_confirm">Искате ли да почистите базата данни\nТова ще премахне проследените промени и историята на данните, по-стари от 3 месеца.</string>
|
||||
<string name="cleanup_db_confirm">Искате ли да изтриете базата данни\nТова ще премахне проследените промени и историята на данните, по-стари от 3 месеца.</string>
|
||||
<string name="cleanup_db_confirm_sync">Искате ли да изтриете базата данни?\nТова ще премахне проследените промени и историята на данните, по-стари от 3 месеца.\nИзвършването му ще ускори драстично пълната синхронизация.</string>
|
||||
<string name="cleared_entries">Изчистени записи</string>
|
||||
</resources>
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Rušení dočasného bazálu selhalo</string>
|
||||
<string name="canceling_eb_failed">Zastavení prodlouženého bolusu selhalo</string>
|
||||
<string name="virtualpump_uploadstatus_title">Nahrát stav do NS nebo Tidepoolu</string>
|
||||
<string name="virtualpump_uploadstatus_title">Nahrávat stav pumpy do NS nebo Tidepoolu</string>
|
||||
<string name="suspendloop_label">Zakázaná/pozastavená smyčka</string>
|
||||
<string name="iob_label">Aktivní inzulín (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,6 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Abbruch der temporären Basalrate fehlgeschlagen</string>
|
||||
<string name="canceling_eb_failed">Der Abbruch des erweiterten Bolus ist fehlgeschlagen</string>
|
||||
<string name="virtualpump_uploadstatus_title">Status zu NS oder Tidepool hochladen</string>
|
||||
<string name="suspendloop_label">Deaktiviere/Pausiere den Loop</string>
|
||||
<string name="iob_label">Aktives Insulin (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Error cancelando la basal temporal</string>
|
||||
<string name="canceling_eb_failed">Error cancelando el bolo extendido</string>
|
||||
<string name="virtualpump_uploadstatus_title">Subir estado a NS o Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Subir estado de la bomba a NS o Tidepool</string>
|
||||
<string name="suspendloop_label">Desactiva/suspende el bucle</string>
|
||||
<string name="iob_label">Insulina a bordo (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">SI</string>
|
||||
<string name="canceling_tbr_failed">Echec de l\'annulation du basal temporaire</string>
|
||||
<string name="canceling_eb_failed">Échec de l\'annulation du Bolus étendu</string>
|
||||
<string name="virtualpump_uploadstatus_title">Transférer le statut vers NS ou Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Télécharger l\'état de la pompe sur NS ou Tidepool</string>
|
||||
<string name="suspendloop_label">Boucle désactivée/suspendue</string>
|
||||
<string name="iob_label">Insuline Active (IA)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Basale temporanea: cancellazione fallita</string>
|
||||
<string name="canceling_eb_failed">Bolo esteso: cancellazione fallita</string>
|
||||
<string name="virtualpump_uploadstatus_title">Carica stato su NS o Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Carica stato micro su NS o Tidepool</string>
|
||||
<string name="suspendloop_label">Loop disabilitato/sospeso</string>
|
||||
<string name="iob_label">Insulina attiva (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
@ -449,6 +449,7 @@
|
|||
<string name="info">INFO</string>
|
||||
<!-- BolusWizard -->
|
||||
<string name="bolus_advisor">Consiglio bolo</string>
|
||||
<string name="bolus_advisor_message">Hai una glicemia alta. Invece di mangiare ora, si consiglia di attendere una glicemia migliore. Vuoi fare adesso un bolo di correzione ed essere ricordato quando è il momento di mangiare? In questo caso non verranno registrati carboidrati e dovrai usare di nuovo il calcolatore quando ti verrà mostrato il promemoria.</string>
|
||||
<string name="cobvsiob">COB vs IOB</string>
|
||||
<string name="slowabsorptiondetected"><![CDATA[<font color=\'%1$s\'>!!!!! Rilevato assorbimento lento dei carboidrati: %2$d%% del tempo. Ricontrolla il tuo calcolo. COB potrebbero essere sovrastimati e potrebbe essere somministrata più insulina !!!!!</font>]]></string>
|
||||
<string name="partialboluswizard">Eroga parte del risultato del calcolatore [%]</string>
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">ביטול בזאלי זמני נכשל</string>
|
||||
<string name="canceling_eb_failed">ביטול בולוס ממושך נכשל</string>
|
||||
<string name="virtualpump_uploadstatus_title">סטטוס העלאה לנייטסקאוט או ל-Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">העלה את סטטוס המשאבה לנייטסקאוט או ל-Tidepool</string>
|
||||
<string name="suspendloop_label">השבתת \\ השהיית לולאה</string>
|
||||
<string name="iob_label">אינסולין פעיל בגוף (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -23,7 +23,7 @@
|
|||
<string name="mgdl">mg/dl</string>
|
||||
<string name="mmol">mmol/l</string>
|
||||
<string name="save">Išsaugoti</string>
|
||||
<string name="snooze">Snausti</string>
|
||||
<string name="snooze">Nutildyti</string>
|
||||
<string name="virtual_pump">Virtuali pompa</string>
|
||||
<string name="constraints">Apribojimai</string>
|
||||
<string name="superbolus">Superbolus</string>
|
||||
|
@ -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>
|
||||
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">JIF</string>
|
||||
<string name="canceling_tbr_failed">Laikinos bazės atšaukti nepavyko</string>
|
||||
<string name="canceling_eb_failed">Ištęsto boluso atšaukti nepavyko</string>
|
||||
<string name="virtualpump_uploadstatus_title">Įkelti statusą į NS arba Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Įkelti pompos statusą į NS arba Tidepool</string>
|
||||
<string name="suspendloop_label">Ciklas išjungtas/sustabdytas</string>
|
||||
<string name="iob_label">Aktyvus insulinas organizme (AIO)</string>
|
||||
<!-- Protection-->
|
||||
|
@ -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>
|
||||
|
@ -288,7 +288,7 @@
|
|||
<string name="uel_resume">ATNAUJINTI</string>
|
||||
<string name="uel_suspend">SUSTABDYTI</string>
|
||||
<string name="uel_hw_pump_allowed">HW POMPA LEIDŽIAMA</string>
|
||||
<string name="uel_clear_pairing_keys">IŠVALYTI PORAVIMO KODUS</string>
|
||||
<string name="uel_clear_pairing_keys">IŠVALYTI SUSIEJIMO KODUS</string>
|
||||
<string name="uel_accepts_temp_basal">PRIIMTI LAIKINĄ BAZĘ</string>
|
||||
<string name="uel_cancel_temp_basal">ATŠAUKTI LAIKINĄ BAZĘ</string>
|
||||
<string name="uel_cancel_bolus">ATŠAUKTI BOLUSĄ</string>
|
||||
|
@ -387,7 +387,7 @@
|
|||
<string name="temp_basal_percent">LAIKINA BAZĖ %1$d%% %2$d min</string>
|
||||
<string name="insight_set_tbr_over_notification">INSIGHT NUSTATYTI LAIKINĄ BAZĘ PRANEŠIMU</string>
|
||||
<string name="read_status" comment="10 characters max for READSTATUS translation">STATUSAS %1$s</string>
|
||||
<string name="keepalive_status_outdated" comment="26 characters max for translation">Tęsti. Būklė per sena.</string>
|
||||
<string name="keepalive_status_outdated" comment="26 characters max for translation">Tęsti. Statusas senas.</string>
|
||||
<string name="keepalive_basal_outdated" comment="26 characters max for translation">Tęsti. Bazė per sena.</string>
|
||||
<string name="sms" comment="26 characters max for translation">SMS</string>
|
||||
<string name="formatPercent">%1$.0f%%</string>
|
||||
|
@ -513,7 +513,7 @@
|
|||
<string name="connection_error">Pompos prisijungimo klaida</string>
|
||||
<string name="reading_pump_history">Skaitoma pompos istorija</string>
|
||||
<string name="password_cleared">Slaptažodis išvalytas!</string>
|
||||
<string name="pairing">Sujungiama</string>
|
||||
<string name="pairing">Susiejimas</string>
|
||||
<string name="initializing">Inicijuojama ...</string>
|
||||
<!-- Constraints-->
|
||||
<string name="limitingbasalratio">Ribojamas maksimalus bazės dydis%1$.2f vv/val dėl %2$s</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>
|
||||
|
@ -544,13 +544,13 @@
|
|||
<string name="need_connect_permission">Programai reikalinga Bluetooth prieigos teisė</string>
|
||||
<!-- Combo-->
|
||||
<string name="user_request" comment="26 characters max for translation">Vartotojo užklausa</string>
|
||||
<string name="pump_paired" comment="26 characters max for translation">Pompa suporuota</string>
|
||||
<string name="pump_paired" comment="26 characters max for translation">Pompa susieta</string>
|
||||
<!-- BlePreCheck-->
|
||||
<string name="ble_not_supported">Bluetooth Low Energy nepalaikoma.</string>
|
||||
<string name="ble_not_supported_or_not_paired">Nepalaikomas Bluetooth Low Energy arba įrenginys nesuporuotas.</string>
|
||||
<string name="ble_not_supported_or_not_paired">Nepalaikomas BLE arba įrenginys nesusietas.</string>
|
||||
<string name="ble_not_enabled">Bluetooth neįjungta.</string>
|
||||
<string name="location_not_found_title">Vietovės nustatymas neįjungtas</string>
|
||||
<string name="location_not_found_message">Vietos nustatymo paslauga turi būti įjungta, kad Bluetooth aptikimas veiktų naujesniuose įrenginiuose. AAPS neseka Jūsų lokacijos, o vietos nustatymo paslauga gali būti išjungta po sėkmingo įrenginių suporavimo.</string>
|
||||
<string name="location_not_found_message">Vietos nustatymo paslauga turi būti įjungta, kad Bluetooth aptikimas veiktų naujesniuose įrenginiuose. AAPS neseka Jūsų lokacijos, o vietos nustatymo paslauga gali būti išjungta po sėkmingo įrenginių susiejimo.</string>
|
||||
<!-- Preferences -->
|
||||
<string name="nav_plugin_preferences">Įskiepių nustatymai</string>
|
||||
<!-- SmsCommunicator -->
|
||||
|
|
|
@ -216,6 +216,7 @@
|
|||
<item name="inRangeBackground">@color/inRangeBackground</item>
|
||||
<item name="devSlopePosColor">@color/devSlopePos</item>
|
||||
<item name="devSlopeNegColor">@color/devSlopeNeg</item>
|
||||
<item name="heartRateColor">@color/heartRate</item>
|
||||
<item name="deviationGreyColor">@color/deviationGrey</item>
|
||||
<item name="deviationBlackColor">@color/deviationBlack</item>
|
||||
<item name="deviationGreenColor">@color/deviationGreen</item>
|
||||
|
|
|
@ -164,7 +164,6 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Annuleren van tijdelijke basaal mislukt</string>
|
||||
<string name="canceling_eb_failed">Annuleren van vertraagde bolus is mislukt</string>
|
||||
<string name="virtualpump_uploadstatus_title">Upload status naar NS of Tidepool</string>
|
||||
<string name="suspendloop_label">Uitgeschakelde/onderbroken loop</string>
|
||||
<string name="iob_label">Insuline aan boord (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Kunne ikke avbryte midlertidig basal</string>
|
||||
<string name="canceling_eb_failed">Kunne ikke avbryte forlenget bolus</string>
|
||||
<string name="virtualpump_uploadstatus_title">Last opp status til NS eller Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Last opp pumpestatus til NS eller Tidepool</string>
|
||||
<string name="suspendloop_label">Deaktivert/pauset loop</string>
|
||||
<string name="iob_label">Aktivt insulin (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Anulowanie bazy tymczasowej nie powiodło się</string>
|
||||
<string name="canceling_eb_failed">Anulowanie przedłużonego bolusa nie powiodło się</string>
|
||||
<string name="virtualpump_uploadstatus_title">Prześlij status do NS lub Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Prześlij status pompy do NS lub Tidepool</string>
|
||||
<string name="suspendloop_label">Wyłączona/zawieszona pętla</string>
|
||||
<string name="iob_label">Aktywna insulina (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
@ -532,7 +532,7 @@
|
|||
<string name="no">Nie</string>
|
||||
<string name="close">Zamknij</string>
|
||||
<!-- TwoMessagesDialog -->
|
||||
<string name="password_preferences_decrypt_prompt">Zostaniesz poproszony o hasło główne, które jest potrzebne do odszyfrowania zaimportowanych preferencji.</string>
|
||||
<string name="password_preferences_decrypt_prompt">Zostaniesz poproszony o hasło główne, które jest potrzebne do odszyfrowania zaimportowanych ustawień.</string>
|
||||
<!-- NumberPicker -->
|
||||
<string name="a11y_min_button_description">zmniejszenie %1$s o %2$s</string>
|
||||
<string name="a11y_plus_button_description">zwiększenie %1$s o %2$s</string>
|
||||
|
|
|
@ -164,7 +164,6 @@
|
|||
<string name="isf_short">FSI</string>
|
||||
<string name="canceling_tbr_failed">Cancelamento do basal temporário falhou</string>
|
||||
<string name="canceling_eb_failed">Falhou o cancelamento do bolus extendido</string>
|
||||
<string name="virtualpump_uploadstatus_title">Carregar status para NS ou Tidepool</string>
|
||||
<string name="suspendloop_label">Loop Desativado/Suspenso</string>
|
||||
<string name="iob_label">Insulina ativa (IA)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF (чувствительность к инсулину)</string>
|
||||
<string name="canceling_tbr_failed">Отмена врем базала не состоялась</string>
|
||||
<string name="canceling_eb_failed">Сбой отмены пролонгированного болюса</string>
|
||||
<string name="virtualpump_uploadstatus_title">Статус dsuheprb в NS или Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Передавать статус помпы в NS или Tidepool</string>
|
||||
<string name="suspendloop_label">Отключенный/приостановленный цикл</string>
|
||||
<string name="iob_label">Активный инсулин (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Zrušenie dočasného bazálu zlyhalo</string>
|
||||
<string name="canceling_eb_failed">Zastavenie predĺženého bolusu zlyhalo</string>
|
||||
<string name="virtualpump_uploadstatus_title">Nahrať stav do NS, alebo Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Nahrávať stav pumpy do NS, alebo Tidepoolu</string>
|
||||
<string name="suspendloop_label">Deaktivovaný/pozastavený uzavretý okruh</string>
|
||||
<string name="iob_label">Aktívny inzulín (IOB)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -164,7 +164,7 @@
|
|||
<string name="isf_short">IDF İnsülin Duyarlılık Faktörü</string>
|
||||
<string name="canceling_tbr_failed">Geçici bazal iptali başarısız oldu</string>
|
||||
<string name="canceling_eb_failed">Yayma bolusun iptal edilmesi başarısız oldu</string>
|
||||
<string name="virtualpump_uploadstatus_title">Durumu NS\'a veya Tidepool\'a yükleyin</string>
|
||||
<string name="virtualpump_uploadstatus_title">Pompa durumunu NS veya Tidepool\'a yükleyin</string>
|
||||
<string name="suspendloop_label">Döngüyü Devre Dışı bırakma/Askıya alma</string>
|
||||
<string name="iob_label">Aktif İnsülin (AİNS)</string>
|
||||
<!-- Protection-->
|
||||
|
|
|
@ -181,6 +181,7 @@
|
|||
<attr name="bolusDataPointColor" format="reference|color" />
|
||||
<attr name="profileSwitchColor" format="reference|color" />
|
||||
<attr name="originalBgValueColor" format="reference|color" />
|
||||
<attr name="heartRateColor" format="reference|color" />
|
||||
<attr name="therapyEvent_NS_MBG" format="reference|color" />
|
||||
<attr name="therapyEvent_FINGER_STICK_BG_VALUE" format="reference|color" />
|
||||
<attr name="therapyEvent_EXERCISE" format="reference|color" />
|
||||
|
@ -221,4 +222,4 @@
|
|||
<attr name="crossTargetColor" format="reference|color" />
|
||||
<!---Custom button -->
|
||||
<attr name="customBtnStyle" format="reference"/>
|
||||
</resources>
|
||||
</resources>
|
||||
|
|
|
@ -153,6 +153,7 @@
|
|||
<color name="bgi">#00EEEE</color>
|
||||
<color name="devSlopePos">#FFFFFF00</color>
|
||||
<color name="devSlopeNeg">#FFFF00FF</color>
|
||||
<color name="heartRate">#FFFFFF66</color>
|
||||
<color name="actionsConfirm">#F6CE22</color>
|
||||
<color name="deviations">#FF0000</color>
|
||||
<color name="cobAlert">#7484E2</color>
|
||||
|
|
|
@ -165,7 +165,7 @@
|
|||
<string name="isf_short">ISF</string>
|
||||
<string name="canceling_tbr_failed">Canceling of temporary basal failed</string>
|
||||
<string name="canceling_eb_failed">Canceling of extended bolus failed</string>
|
||||
<string name="virtualpump_uploadstatus_title">Upload status to NS or Tidepool</string>
|
||||
<string name="virtualpump_uploadstatus_title">Upload pump status to NS or Tidepool</string>
|
||||
<string name="suspendloop_label">Disabled/Suspended loop</string>
|
||||
<string name="iob_label">Insulin on Board (IOB)</string>
|
||||
|
||||
|
|
|
@ -219,6 +219,7 @@
|
|||
<item name="inRangeBackground">@color/inRangeBackground</item>
|
||||
<item name="devSlopePosColor">@color/devSlopePos</item>
|
||||
<item name="devSlopeNegColor">@color/devSlopeNeg</item>
|
||||
<item name="heartRateColor">@color/heartRate</item>
|
||||
<item name="deviationGreyColor">@color/deviationGrey</item>
|
||||
<item name="deviationBlackColor">@color/deviationBlack</item>
|
||||
<item name="deviationGreenColor">@color/deviationGreen</item>
|
||||
|
|
|
@ -22,7 +22,7 @@ dependencies {
|
|||
implementation project(':app-wear-shared:shared')
|
||||
|
||||
//Firebase
|
||||
api platform('com.google.firebase:firebase-bom:31.2.2')
|
||||
api platform('com.google.firebase:firebase-bom:32.1.0')
|
||||
api "com.google.firebase:firebase-analytics-ktx"
|
||||
api "com.google.firebase:firebase-crashlytics-ktx"
|
||||
// StatsActivity not in use now
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -7,6 +7,7 @@ plugins {
|
|||
}
|
||||
|
||||
apply from: "${project.rootDir}/core/main/android_dependencies.gradle"
|
||||
apply from: "${project.rootDir}/core/main/test_dependencies.gradle"
|
||||
|
||||
android {
|
||||
|
||||
|
@ -30,4 +31,4 @@ dependencies {
|
|||
allOpen {
|
||||
// allows mocking for classes w/o directly opening them for release builds
|
||||
annotation 'info.nightscout.database.annotations.DbOpenForTesting'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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"
|
||||
|
|
|
@ -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>,
|
||||
)
|
||||
|
|
|
@ -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",
|
||||
)
|
||||
}
|
||||
}
|
|
@ -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,9 +49,11 @@ 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 {
|
||||
// allows mocking for classes w/o directly opening them for release builds
|
||||
annotation 'info.nightscout.database.annotations.DbOpenForTesting'
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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
|
@ -0,0 +1,126 @@
|
|||
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())
|
||||
}
|
||||
}
|
||||
|
||||
@Test
|
||||
fun getFromTimeToTime() {
|
||||
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)
|
||||
val hr3 = createHeartRate(timestamp = timestamp + 2, beatsPerMinute = 160.0)
|
||||
dao.insertNewEntry(hr1)
|
||||
dao.insertNewEntry(hr2)
|
||||
dao.insertNewEntry(hr3)
|
||||
|
||||
assertEquals(listOf(hr1, hr2, hr3), dao.getFromTimeToTime(timestamp, timestamp + 2))
|
||||
assertEquals(listOf(hr1, hr2), dao.getFromTimeToTime(timestamp, timestamp + 1))
|
||||
assertEquals(listOf(hr2), dao.getFromTimeToTime(timestamp + 1, timestamp + 1))
|
||||
assertTrue(dao.getFromTimeToTime(timestamp + 3, timestamp + 10).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",
|
||||
)
|
||||
|
||||
}
|
||||
}
|
|
@ -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))
|
||||
}
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
|
@ -143,8 +145,8 @@ import kotlin.math.roundToInt
|
|||
.subscribeOn(Schedulers.io())
|
||||
|
||||
//BG READINGS -- including invalid/history records
|
||||
fun findBgReadingByNSIdSingle(nsId: String): Single<ValueWrapper<GlucoseValue>> =
|
||||
database.glucoseValueDao.findByNSIdMaybe(nsId).toWrappedSingle()
|
||||
fun findBgReadingByNSId(nsId: String): GlucoseValue? =
|
||||
database.glucoseValueDao.findByNSId(nsId)
|
||||
|
||||
fun getModifiedBgReadingsDataFromId(lastId: Long): Single<List<GlucoseValue>> =
|
||||
database.glucoseValueDao.getModifiedFrom(lastId)
|
||||
|
@ -186,6 +188,9 @@ import kotlin.math.roundToInt
|
|||
.subscribeOn(Schedulers.io())
|
||||
|
||||
// TEMP TARGETS
|
||||
fun findTemporaryTargetByNSId(nsId: String): TemporaryTarget? =
|
||||
database.temporaryTargetDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
|
@ -253,6 +258,9 @@ import kotlin.math.roundToInt
|
|||
|
||||
// PROFILE SWITCH
|
||||
|
||||
fun findProfileSwitchByNSId(nsId: String): ProfileSwitch? =
|
||||
database.profileSwitchDao.findByNSId(nsId)
|
||||
|
||||
fun getNextSyncElementProfileSwitch(id: Long): Maybe<Pair<ProfileSwitch, ProfileSwitch>> =
|
||||
database.profileSwitchDao.getNextModifiedOrNewAfter(id)
|
||||
.flatMap { nextIdElement ->
|
||||
|
@ -309,6 +317,9 @@ import kotlin.math.roundToInt
|
|||
database.profileSwitchDao.getLastId()
|
||||
|
||||
// EFFECTIVE PROFILE SWITCH
|
||||
fun findEffectiveProfileSwitchByNSId(nsId: String): EffectiveProfileSwitch? =
|
||||
database.effectiveProfileSwitchDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
|
@ -373,6 +384,9 @@ import kotlin.math.roundToInt
|
|||
*
|
||||
* It is a Maybe as there might be no next element.
|
||||
* */
|
||||
fun findTherapyEventByNSId(nsId: String): TherapyEvent? =
|
||||
database.therapyEventDao.findByNSId(nsId)
|
||||
|
||||
fun getNextSyncElementTherapyEvent(id: Long): Maybe<Pair<TherapyEvent, TherapyEvent>> =
|
||||
database.therapyEventDao.getNextModifiedOrNewAfter(id)
|
||||
.flatMap { nextIdElement ->
|
||||
|
@ -431,6 +445,9 @@ import kotlin.math.roundToInt
|
|||
database.therapyEventDao.getLastId()
|
||||
|
||||
// FOOD
|
||||
fun findFoodByNSId(nsId: String): Food? =
|
||||
database.foodDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
|
@ -465,6 +482,9 @@ import kotlin.math.roundToInt
|
|||
database.foodDao.getLastId()
|
||||
|
||||
// BOLUS
|
||||
fun findBolusByNSId(nsId: String): Bolus? =
|
||||
database.bolusDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
|
@ -531,6 +551,9 @@ import kotlin.math.roundToInt
|
|||
database.bolusDao.getLastId()
|
||||
// CARBS
|
||||
|
||||
fun findCarbsByNSId(nsId: String): Carbs? =
|
||||
database.carbsDao.findByNSId(nsId)
|
||||
|
||||
private fun expandCarbs(carbs: Carbs): List<Carbs> =
|
||||
if (carbs.duration == 0L) {
|
||||
listOf(carbs)
|
||||
|
@ -646,6 +669,9 @@ import kotlin.math.roundToInt
|
|||
database.carbsDao.getLastId()
|
||||
|
||||
// BOLUS CALCULATOR RESULT
|
||||
fun findBolusCalculatorResultByNSId(nsId: String): BolusCalculatorResult? =
|
||||
database.bolusCalculatorResultDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
|
@ -709,13 +735,16 @@ import kotlin.math.roundToInt
|
|||
database.deviceStatusDao.getLastId()
|
||||
|
||||
// TEMPORARY BASAL
|
||||
fun findTemporaryBasalByNSId(nsId: String): TemporaryBasal? =
|
||||
database.temporaryBasalDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
* of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully.
|
||||
*
|
||||
* It is a Maybe as there might be no next element.
|
||||
* */
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
* of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully.
|
||||
*
|
||||
* It is a Maybe as there might be no next element.
|
||||
* */
|
||||
|
||||
fun getNextSyncElementTemporaryBasal(id: Long): Maybe<Pair<TemporaryBasal, TemporaryBasal>> =
|
||||
database.temporaryBasalDao.getNextModifiedOrNewAfter(id)
|
||||
|
@ -773,13 +802,16 @@ import kotlin.math.roundToInt
|
|||
database.temporaryBasalDao.getLastId()
|
||||
|
||||
// EXTENDED BOLUS
|
||||
fun findExtendedBolusByNSId(nsId: String): ExtendedBolus? =
|
||||
database.extendedBolusDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
* of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully.
|
||||
*
|
||||
* It is a Maybe as there might be no next element.
|
||||
* */
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
* of the update ("historic") entry. The sync counter should be incremented to that id if it was synced successfully.
|
||||
*
|
||||
* It is a Maybe as there might be no next element.
|
||||
* */
|
||||
|
||||
fun getNextSyncElementExtendedBolus(id: Long): Maybe<Pair<ExtendedBolus, ExtendedBolus>> =
|
||||
database.extendedBolusDao.getNextModifiedOrNewAfter(id)
|
||||
|
@ -844,6 +876,9 @@ import kotlin.math.roundToInt
|
|||
}
|
||||
|
||||
// OFFLINE EVENT
|
||||
fun findOfflineEventByNSId(nsId: String): OfflineEvent? =
|
||||
database.offlineEventDao.findByNSId(nsId)
|
||||
|
||||
/*
|
||||
* returns a Pair of the next entity to sync and the ID of the "update".
|
||||
* The update id might either be the entry id itself if it is a new entry - or the id
|
||||
|
@ -897,6 +932,11 @@ import kotlin.math.roundToInt
|
|||
fun getLastOfflineEventId(): Long? =
|
||||
database.offlineEventDao.getLastId()
|
||||
|
||||
fun getHeartRatesFromTime(timeMillis: Long) = database.heartRateDao.getFromTime(timeMillis)
|
||||
|
||||
fun getHeartRatesFromTimeToTime(startMillis: Long, endMillis: Long) =
|
||||
database.heartRateDao.getFromTimeToTime(startMillis, endMillis)
|
||||
|
||||
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),
|
||||
|
@ -915,6 +955,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),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -923,4 +964,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()
|
||||
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ internal interface GlucoseValueDao : TraceableDao<GlucoseValue> {
|
|||
fun getLastId(): Long?
|
||||
|
||||
@Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE nightscoutId = :nsId AND referenceId IS NULL")
|
||||
fun findByNSIdMaybe(nsId: String): Maybe<GlucoseValue>
|
||||
fun findByNSId(nsId: String): GlucoseValue?
|
||||
|
||||
@Query("SELECT * FROM $TABLE_GLUCOSE_VALUES WHERE timestamp = :timestamp AND sourceSensor = :sourceSensor AND referenceId IS NULL")
|
||||
fun findByTimestampAndSensor(timestamp: Long, sourceSensor: GlucoseValue.SourceSensor): GlucoseValue?
|
||||
|
|
|
@ -0,0 +1,31 @@
|
|||
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 BETWEEN :startMillis AND :endMillis ORDER BY timestamp")
|
||||
fun getFromTimeToTime(startMillis: Long, endMillis: 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>
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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>)
|
||||
}
|
|
@ -8,10 +8,11 @@ class InvalidateBolusCalculatorResultTransaction(val id: Long) : Transaction<Inv
|
|||
val result = TransactionResult()
|
||||
val bolusCalculatorResult = database.bolusCalculatorResultDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such BolusCalculatorResult with the specified ID.")
|
||||
|
||||
bolusCalculatorResult.isValid = false
|
||||
database.bolusCalculatorResultDao.updateExistingEntry(bolusCalculatorResult)
|
||||
result.invalidated.add(bolusCalculatorResult)
|
||||
if (bolusCalculatorResult.isValid) {
|
||||
bolusCalculatorResult.isValid = false
|
||||
database.bolusCalculatorResultDao.updateExistingEntry(bolusCalculatorResult)
|
||||
result.invalidated.add(bolusCalculatorResult)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ class InvalidateBolusTransaction(val id: Long) : Transaction<InvalidateBolusTran
|
|||
val result = TransactionResult()
|
||||
val bolus = database.bolusDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such Bolus with the specified ID.")
|
||||
bolus.isValid = false
|
||||
database.bolusDao.updateExistingEntry(bolus)
|
||||
result.invalidated.add(bolus)
|
||||
if (bolus.isValid) {
|
||||
bolus.isValid = false
|
||||
database.bolusDao.updateExistingEntry(bolus)
|
||||
result.invalidated.add(bolus)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ class InvalidateCarbsTransaction(val id: Long) : Transaction<InvalidateCarbsTran
|
|||
val result = TransactionResult()
|
||||
val carbs = database.carbsDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such Carbs with the specified ID.")
|
||||
carbs.isValid = false
|
||||
database.carbsDao.updateExistingEntry(carbs)
|
||||
result.invalidated.add(carbs)
|
||||
if (carbs.isValid) {
|
||||
carbs.isValid = false
|
||||
database.carbsDao.updateExistingEntry(carbs)
|
||||
result.invalidated.add(carbs)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,23 @@
|
|||
package info.nightscout.database.impl.transactions
|
||||
|
||||
import info.nightscout.database.entities.EffectiveProfileSwitch
|
||||
|
||||
class InvalidateEffectiveProfileSwitchTransaction(val id: Long) : Transaction<InvalidateEffectiveProfileSwitchTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
val effectiveProfileSwitch = database.effectiveProfileSwitchDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such EffectiveProfileSwitch with the specified ID.")
|
||||
if (effectiveProfileSwitch.isValid) {
|
||||
effectiveProfileSwitch.isValid = false
|
||||
database.effectiveProfileSwitchDao.updateExistingEntry(effectiveProfileSwitch)
|
||||
result.invalidated.add(effectiveProfileSwitch)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
|
||||
val invalidated = mutableListOf<EffectiveProfileSwitch>()
|
||||
}
|
||||
}
|
|
@ -8,9 +8,11 @@ class InvalidateExtendedBolusTransaction(val id: Long) : Transaction<InvalidateE
|
|||
val result = TransactionResult()
|
||||
val extendedBolus = database.extendedBolusDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such Extended Bolus with the specified ID.")
|
||||
extendedBolus.isValid = false
|
||||
database.extendedBolusDao.updateExistingEntry(extendedBolus)
|
||||
result.invalidated.add(extendedBolus)
|
||||
if (extendedBolus.isValid) {
|
||||
extendedBolus.isValid = false
|
||||
database.extendedBolusDao.updateExistingEntry(extendedBolus)
|
||||
result.invalidated.add(extendedBolus)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -5,7 +5,9 @@ class InvalidateFoodTransaction(val id: Long) : Transaction<Unit>() {
|
|||
override fun run() {
|
||||
val food = database.foodDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such Food with the specified ID.")
|
||||
food.isValid = false
|
||||
database.foodDao.updateExistingEntry(food)
|
||||
if (food.isValid) {
|
||||
food.isValid = false
|
||||
database.foodDao.updateExistingEntry(food)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -11,9 +11,11 @@ class InvalidateGlucoseValueTransaction(val id: Long) : Transaction<InvalidateGl
|
|||
val result = TransactionResult()
|
||||
val glucoseValue = database.glucoseValueDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such GlucoseValue with the specified ID.")
|
||||
glucoseValue.isValid = false
|
||||
database.glucoseValueDao.updateExistingEntry(glucoseValue)
|
||||
result.invalidated.add(glucoseValue)
|
||||
if (glucoseValue.isValid) {
|
||||
glucoseValue.isValid = false
|
||||
database.glucoseValueDao.updateExistingEntry(glucoseValue)
|
||||
result.invalidated.add(glucoseValue)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -1,22 +0,0 @@
|
|||
package info.nightscout.database.impl.transactions
|
||||
|
||||
import info.nightscout.database.entities.ProfileSwitch
|
||||
|
||||
class InvalidateNsIdProfileSwitchTransaction(val nsId: String) : Transaction<InvalidateNsIdProfileSwitchTransaction.TransactionResult>() {
|
||||
|
||||
override fun run() : TransactionResult{
|
||||
val result = TransactionResult()
|
||||
val current = database.profileSwitchDao.findByNSId(nsId)
|
||||
if (current != null) {
|
||||
current.isValid = false
|
||||
database.profileSwitchDao.updateExistingEntry(current)
|
||||
result.invalidated.add(current)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
val invalidated = mutableListOf<ProfileSwitch>()
|
||||
}
|
||||
|
||||
}
|
|
@ -1,10 +1,23 @@
|
|||
package info.nightscout.database.impl.transactions
|
||||
|
||||
class InvalidateOfflineEventTransaction(val id: Long) : Transaction<Unit>() {
|
||||
override fun run() {
|
||||
import info.nightscout.database.entities.OfflineEvent
|
||||
|
||||
class InvalidateOfflineEventTransaction(val id: Long) : Transaction<InvalidateOfflineEventTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
val offlineEvent = database.offlineEventDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such OfflineEvent with the specified ID.")
|
||||
offlineEvent.isValid = false
|
||||
database.offlineEventDao.updateExistingEntry(offlineEvent)
|
||||
if (offlineEvent.isValid) {
|
||||
offlineEvent.isValid = false
|
||||
database.offlineEventDao.updateExistingEntry(offlineEvent)
|
||||
result.invalidated.add(offlineEvent)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
|
||||
val invalidated = mutableListOf<OfflineEvent>()
|
||||
}
|
||||
}
|
|
@ -8,9 +8,11 @@ class InvalidateProfileSwitchTransaction(val id: Long) : Transaction<InvalidateP
|
|||
val result = TransactionResult()
|
||||
val profileSwitch = database.profileSwitchDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such ProfileSwitch with the specified ID.")
|
||||
profileSwitch.isValid = false
|
||||
database.profileSwitchDao.updateExistingEntry(profileSwitch)
|
||||
result.invalidated.add(profileSwitch)
|
||||
if (profileSwitch.isValid) {
|
||||
profileSwitch.isValid = false
|
||||
database.profileSwitchDao.updateExistingEntry(profileSwitch)
|
||||
result.invalidated.add(profileSwitch)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ class InvalidateTemporaryBasalTransaction(val id: Long) : Transaction<Invalidate
|
|||
val result = TransactionResult()
|
||||
val temporaryBasal = database.temporaryBasalDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such Temporary Basal with the specified ID.")
|
||||
temporaryBasal.isValid = false
|
||||
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
|
||||
result.invalidated.add(temporaryBasal)
|
||||
if (temporaryBasal.isValid) {
|
||||
temporaryBasal.isValid = false
|
||||
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
|
||||
result.invalidated.add(temporaryBasal)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -10,9 +10,11 @@ class InvalidateTemporaryBasalTransactionWithPumpId(val pumpId: Long, val pumpTy
|
|||
val result = TransactionResult()
|
||||
val temporaryBasal = database.temporaryBasalDao.findByPumpIds(pumpId, pumpType, pumpSerial)
|
||||
?: throw IllegalArgumentException("There is no such Temporary Basal with the specified temp ID.")
|
||||
temporaryBasal.isValid = false
|
||||
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
|
||||
result.invalidated.add(temporaryBasal)
|
||||
if (temporaryBasal.isValid) {
|
||||
temporaryBasal.isValid = false
|
||||
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
|
||||
result.invalidated.add(temporaryBasal)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -8,9 +8,11 @@ class InvalidateTemporaryBasalWithTempIdTransaction(val tempId: Long) : Transact
|
|||
val result = TransactionResult()
|
||||
val temporaryBasal = database.temporaryBasalDao.findByTempId(tempId)
|
||||
?: throw IllegalArgumentException("There is no such Temporary Basal with the specified temp ID.")
|
||||
temporaryBasal.isValid = false
|
||||
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
|
||||
result.invalidated.add(temporaryBasal)
|
||||
if (temporaryBasal.isValid) {
|
||||
temporaryBasal.isValid = false
|
||||
database.temporaryBasalDao.updateExistingEntry(temporaryBasal)
|
||||
result.invalidated.add(temporaryBasal)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -1,10 +1,23 @@
|
|||
package info.nightscout.database.impl.transactions
|
||||
|
||||
class InvalidateTemporaryTargetTransaction(val id: Long) : Transaction<Unit>() {
|
||||
override fun run() {
|
||||
import info.nightscout.database.entities.TemporaryTarget
|
||||
|
||||
class InvalidateTemporaryTargetTransaction(val id: Long) : Transaction<InvalidateTemporaryTargetTransaction.TransactionResult>() {
|
||||
|
||||
override fun run(): TransactionResult {
|
||||
val result = TransactionResult()
|
||||
val temporaryTarget = database.temporaryTargetDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such TemporaryTarget with the specified ID.")
|
||||
temporaryTarget.isValid = false
|
||||
database.temporaryTargetDao.updateExistingEntry(temporaryTarget)
|
||||
if (temporaryTarget.isValid) {
|
||||
temporaryTarget.isValid = false
|
||||
database.temporaryTargetDao.updateExistingEntry(temporaryTarget)
|
||||
result.invalidated.add(temporaryTarget)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
class TransactionResult {
|
||||
|
||||
val invalidated = mutableListOf<TemporaryTarget>()
|
||||
}
|
||||
}
|
|
@ -8,9 +8,11 @@ class InvalidateTherapyEventTransaction(val id: Long) : Transaction<InvalidateTh
|
|||
val result = TransactionResult()
|
||||
val therapyEvent = database.therapyEventDao.findById(id)
|
||||
?: throw IllegalArgumentException("There is no such TherapyEvent with the specified ID.")
|
||||
therapyEvent.isValid = false
|
||||
database.therapyEventDao.updateExistingEntry(therapyEvent)
|
||||
result.invalidated.add(therapyEvent)
|
||||
if (therapyEvent.isValid) {
|
||||
therapyEvent.isValid = false
|
||||
database.therapyEventDao.updateExistingEntry(therapyEvent)
|
||||
result.invalidated.add(therapyEvent)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -29,16 +29,14 @@ class UserEntryLoggerImpl @Inject constructor(
|
|||
|
||||
private val compositeDisposable = CompositeDisposable()
|
||||
|
||||
override fun log(action: Action, source: Sources, note: String?, vararg listValues: ValueWithUnit?) = log(action, source, note, listValues.toList())
|
||||
override fun log(action: Action, source: Sources, note: String?, timestamp: Long, vararg listValues: ValueWithUnit?) = log(action, source, note, timestamp, listValues.toList())
|
||||
|
||||
override fun log(action: Action, source: Sources, vararg listValues: ValueWithUnit?) = log(action, source, "", listValues.toList())
|
||||
|
||||
override fun log(action: Action, source: Sources, note: String?, listValues: List<ValueWithUnit?>) {
|
||||
override fun log(action: Action, source: Sources, note: String?, timestamp: Long, listValues: List<ValueWithUnit?>) {
|
||||
val filteredValues = listValues.toList().filterNotNull()
|
||||
log(
|
||||
listOf(
|
||||
UserEntry(
|
||||
timestamp = dateUtil.now(),
|
||||
timestamp = timestamp,
|
||||
action = action,
|
||||
source = source,
|
||||
note = note ?: "",
|
||||
|
@ -48,6 +46,12 @@ class UserEntryLoggerImpl @Inject constructor(
|
|||
)
|
||||
}
|
||||
|
||||
override fun log(action: Action, source: Sources, note: String?, vararg listValues: ValueWithUnit?) = log(action, source, note, listValues.toList())
|
||||
|
||||
override fun log(action: Action, source: Sources, vararg listValues: ValueWithUnit?) = log(action, source, "", listValues.toList())
|
||||
|
||||
override fun log(action: Action, source: Sources, note: String?, listValues: List<ValueWithUnit?>) = log(action, source, note, dateUtil.now(), listValues)
|
||||
|
||||
override fun log(entries: List<UserEntry>) {
|
||||
compositeDisposable += repository.runTransactionForResult(UserEntryTransaction(entries))
|
||||
.subscribeOn(aapsSchedulers.io)
|
||||
|
|
|
@ -87,6 +87,7 @@ class OverviewDataImpl @Inject constructor(
|
|||
dsMinSeries = LineGraphSeries()
|
||||
treatmentsSeries = PointsWithLabelGraphSeries()
|
||||
epsSeries = PointsWithLabelGraphSeries()
|
||||
heartRateGraphSeries = LineGraphSeries()
|
||||
}
|
||||
|
||||
override fun initRange() {
|
||||
|
@ -322,4 +323,6 @@ class OverviewDataImpl @Inject constructor(
|
|||
override val dsMinScale = Scale()
|
||||
override var dsMaxSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
override var dsMinSeries: LineGraphSeries<ScaledDataPoint> = LineGraphSeries()
|
||||
override var heartRateScale = Scale()
|
||||
override var heartRateGraphSeries: LineGraphSeries<DataPointWithLabelInterface> = LineGraphSeries()
|
||||
}
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -273,7 +273,13 @@ class PumpSyncImplementation @Inject constructor(
|
|||
pumpSerial = pumpSerial
|
||||
)
|
||||
)
|
||||
uel.log(UserEntry.Action.CAREPORTAL, pumpType.source.toDbSource(), note, ValueWithUnit.Timestamp(timestamp), ValueWithUnit.TherapyEventType(type.toDBbEventType()))
|
||||
uel.log(
|
||||
action = UserEntry.Action.CAREPORTAL,
|
||||
source = pumpType.source.toDbSource(),
|
||||
note = note,
|
||||
timestamp = timestamp,
|
||||
ValueWithUnit.Timestamp(timestamp), ValueWithUnit.TherapyEventType(type.toDBbEventType())
|
||||
)
|
||||
repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent))
|
||||
.doOnError {
|
||||
aapsLogger.error(LTag.DATABASE, "Error while saving TherapyEvent", it)
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -19,6 +19,7 @@ import androidx.appcompat.app.AppCompatDelegate
|
|||
import androidx.appcompat.view.ContextThemeWrapper
|
||||
import androidx.core.content.ContextCompat
|
||||
import info.nightscout.core.ui.getThemeColor
|
||||
import info.nightscout.core.ui.locale.LocaleHelper
|
||||
import info.nightscout.core.utils.fabric.FabricPrivacy
|
||||
import info.nightscout.shared.interfaces.ResourceHelper
|
||||
import java.util.Locale
|
||||
|
@ -29,15 +30,12 @@ import javax.inject.Inject
|
|||
*/
|
||||
class ResourceHelperImpl @Inject constructor(var context: Context, private val fabricPrivacy: FabricPrivacy) : ResourceHelper {
|
||||
|
||||
override fun updateContext(ctx: Context?) {
|
||||
ctx?.let { context = it }
|
||||
}
|
||||
|
||||
override fun gs(@StringRes id: Int): String = context.getString(id)
|
||||
override fun gs(@StringRes id: Int): String =
|
||||
context.createConfigurationContext(Configuration().apply { setLocale(LocaleHelper.currentLocale(context)) }).resources.getString(id)
|
||||
|
||||
override fun gs(@StringRes id: Int, vararg args: Any?): String {
|
||||
return try {
|
||||
context.getString(id, *args)
|
||||
context.createConfigurationContext(Configuration().apply { setLocale(LocaleHelper.currentLocale(context)) }).resources.getString(id, *args)
|
||||
} catch (exception: Exception) {
|
||||
val resourceName = context.resources.getResourceEntryName(id)
|
||||
val resourceValue = context.getString(id)
|
||||
|
|
|
@ -3,21 +3,21 @@
|
|||
<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>
|
||||
<string name="alert_m20_description">Įdėkite rezervuarą.</string>
|
||||
<string name="alert_m21_description">Pakeiskite rezervuarą.</string>
|
||||
<string name="alert_m22_description">Pakeiskite bateriją.</string>
|
||||
<string name="alert_m23_description">Patikrinkite pompos būseną.</string>
|
||||
<string name="alert_m23_description">Patikrinkite pompos statusą.</string>
|
||||
<string name="alert_m24_description">Pakeiskite infuzijos rinkinį.</string>
|
||||
<string name="alert_m25_description">Kreipkitės į Accu-Chek palaikymo tarnybą.</string>
|
||||
<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 būseną.</string>
|
||||
<string name="alert_m29_description">Nustatykite baterijos tipą.</string>
|
||||
<string name="alert_m30_description">Nustatykite rezervuaro tipą.</string>
|
||||
<string name="alert_m28_description">Patikrinkite pompos statusą.</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>
|
||||
|
|
|
@ -4,7 +4,7 @@
|
|||
<string name="disable_tbr_over_notification">Išjungti pranešimus apie LBD pabaigą\n(pompos nustatymai)</string>
|
||||
<string name="not_paired">Nesusieta</string>
|
||||
<string name="recovering">Atstatoma</string>
|
||||
<string name="insight_status">Būsena</string>
|
||||
<string name="insight_status">Statusas</string>
|
||||
<string name="recovery_duration">Atkūrimo trukmė</string>
|
||||
<string name="last_connected">Paskutinis prisijungimas</string>
|
||||
<string name="start_pump">Paleisti pompą</string>
|
||||
|
@ -21,9 +21,9 @@
|
|||
<string name="eb_formatter">%1$.2f / %2$.2f vv per %3$d min</string>
|
||||
<string name="insight_last_bolus">Paskutinis bolusas</string>
|
||||
<string name="searching_for_devices">Ieškoma įrenginių…</string>
|
||||
<string name="pairing_completed">Sujungimas sėkmingas</string>
|
||||
<string name="pairing_completed">Sėkmingai susieta</string>
|
||||
<string name="code_compare">Ar kodas, kurį matote įrenginyje, sutampa su pompos kodu?</string>
|
||||
<string name="insight_pairing">Insight sujungimas</string>
|
||||
<string name="insight_pairing">Insight susiejimas</string>
|
||||
<string name="insight_local">Accu-Chek Insight</string>
|
||||
<string name="insight_alert_formatter">%1$s: %2$s</string>
|
||||
<string name="tube_changed">Kateteris pakeistas</string>
|
||||
|
@ -36,7 +36,7 @@
|
|||
<string name="timeout_during_handshake">Ryšio užmezgimui skirtas laikas baigėsi - iš naujo nustatykite bluetooth</string>
|
||||
<string name="pump_stopped">Pompa sustabdyta</string>
|
||||
<string name="pump_started">Pompa paleista</string>
|
||||
<string name="short_status_last_connected">Paskutinis prisijungimas: prieš %1$d min</string>
|
||||
<string name="short_status_last_connected">Pask. prijung: prieš %1$d min</string>
|
||||
<string name="short_status_tbr">LBD: %1$d%% - %2$d / %3$d min</string>
|
||||
<string name="short_status_extended">Ištęstas: %1$.2f / %2$.2f V %3$d min</string>
|
||||
<string name="short_status_multiwave">Daugiabangis: %1$.2f / %2$.2f vv %3$d min</string>
|
||||
|
@ -52,7 +52,7 @@
|
|||
<string name="bluetooth_address">Bluetooth adresas</string>
|
||||
<string name="system_id_appendix">Sistemos ID priedėlis</string>
|
||||
<string name="manufacturing_date">Pagaminimo data</string>
|
||||
<string name="delete_pairing">Panaikinti sąsają</string>
|
||||
<string name="delete_pairing">Panaikinti susiejimą</string>
|
||||
<string name="log_site_changes">Įrašyti adatos pakeitimą</string>
|
||||
<string name="log_reservoir_changes">Įrašyti rezervuaro keitimus</string>
|
||||
<string name="log_tube_changes">Įrašyti infuzijos vamzdelio pakeitimą</string>
|
||||
|
@ -65,6 +65,6 @@
|
|||
<string name="max_recovery_duration">Didž. atkūrimo trukmė [s]</string>
|
||||
<string name="min_recovery_duration">Min. atkūrimo trukmė [s]</string>
|
||||
<string name="pump_alert">Pompos aliarmas</string>
|
||||
<string name="pairing_information">Sąsajos informacija</string>
|
||||
<string name="insight_refresh_button" comment="26 characters max for translation">Insight Mygtukas Naujinti</string>
|
||||
<string name="pairing_information">Susiejimo informacija</string>
|
||||
<string name="insight_refresh_button" comment="26 characters max for translation">Naujinti Insight mygtukas </string>
|
||||
</resources>
|
||||
|
|
|
@ -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 =
|
||||
|
|
|
@ -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 =
|
||||
|
@ -169,4 +170,4 @@ class LoopFragment : DaggerFragment(), MenuProvider {
|
|||
binding.smbsetbypump.text = ""
|
||||
binding.swipeRefresh.isRefreshing = false
|
||||
}
|
||||
}
|
||||
}
|
|
@ -25,7 +25,7 @@
|
|||
<string name="description_ama">2017 m. algoritmas</string>
|
||||
<string name="description_smb">Naujausias algoritmas patyrusiems vartotojams</string>
|
||||
<string name="description_smb_dynamic_isf">Naujausias algoritmas patyrusiems naudotojams su dinaminiu/automatiniu JIF</string>
|
||||
<string name="openapsama_bolus_snooze_dia_divisor">Boluso snaudimo daliklis</string>
|
||||
<string name="openapsama_bolus_snooze_dia_divisor">Atidėjimo po boluso IVT daliklis</string>
|
||||
<string name="openapsma_run">Paleisti dabar</string>
|
||||
<string name="openapsma_last_run_label">Paskutinis veiksmas</string>
|
||||
<string name="openapsma_input_parameters_label">Įvesties parametrai</string>
|
||||
|
@ -48,7 +48,7 @@
|
|||
<string name="openapsama_min_5m_carb_impact_summary">Numatytoji reikšmė: 3.0 (AMA) arba 8.0 (SMB). Tai parametras, nurodantis angliavandenių poveikį glikemijai kas 5 minutes nuo jų suvartojimo. Numatytoji reikšmė yra 3 mg/dl per 5min. Šis skaičius turi įtakos apskaičiavimams, kaip greitai mažės AAO, kokia bus glikemijos kitimo prognozė, ypač kai ji krenta daugiau nei tikėtasi, arba nedidėja tiek, kiek tikėtasi.</string>
|
||||
<string name="openapsama_max_daily_safety_multiplier_summary">Numatytoji reikšmė: 3 tai pagrindinis OpenAPS saugiklis. Jis apriboja Jūsų valandinę bazę iki trigubos maksimalios valandinės bazės (standartiniu atveju). Jums greičiausiai neprireiks šios reikšmės keisti, tačiau turėtumėte žinoti, kad ji naudojama kaip saugiklis apskaičiuojant \"3x maksimali dienos bazė; 4x dabartinė valandinė bazė\".</string>
|
||||
<string name="openapsama_current_basal_safety_multiplier_summary">Numatytoji reikšmė: 4 tai antras pagrindinis OpenAPS saugiklis, apskaičiuojant \"3x maksimali dienos bazė; 4x dabartinė valandinė bazė\". Jis reiškia, kad jūsų valandinė bazė, nepriklausomai nuo to, kokia maksimali valandinė bazė suprogramuota pompoje, negali būti didesnė, nei keturguba dabartinė valandinė bazė. Tai apsaugo Jus nuo pavojingų situacijų, kai nustatoma pernelyg didelė valandinė bazė, pilnai nesuprantant, kaip veikia algoritmas. Numatytoji reikšmė yra 4x; daugumai vartotojų niekada neprireikia šio skaičiaus keisti, o pajutus, kad \"atsitrenkiama\" į saugiklį, rekomenduojama peržiūrėti kitus nustatymus.</string>
|
||||
<string name="openapsama_bolus_snooze_dia_divisor_summary">Numatytoji reikšmė: 2\nBoluso snaudimas aktyvuojamas iškart po to, kai susileidžiate bolusą maistui. Ši funkcija neleidžia sistemai nustatyti mažų LBD iškart po valgio. Pvz.: jei IVT yra 3 val, tai boluso snaudimas pamažu deaktyvuojamas per 1,5 val (3 val. / 2).</string>
|
||||
<string name="openapsama_bolus_snooze_dia_divisor_summary">Numatytoji reikšmė: 2\nAtidėjimas po boluso aktyvuojamas iškart po to, kai susileidžiate bolusą maistui. Ši funkcija neleidžia sistemai nustatyti mažų laikinų bazių iškart po valgio. Pvz.: jei IVT yra 3 val, tai atidėjimas po boluso pamažu deaktyvuojamas per 1,5 val (3 val. / 2).</string>
|
||||
<string name="openapsama_link_to_preference_json_doc_txt">Dėmesio!\nPaprastai neturėtumėte keisti šių, žemiau esančių, reikšmių. Prašome PASPAUSTI ČIA ir PERSKAITYKITE tekstą ir įsitikinkite, kad SUPRANTATE prieš keisdami bet kurią iš šių verčių.</string>
|
||||
<string name="always_use_short_avg">Visada naudoti trumpo laikotarpio vidutinį pokyti vietoj paprasto pokyčio</string>
|
||||
<string name="always_use_short_avg_summary">Naudinga, kai duomenys, gaunami iš nefiltruoto šaltinio, tokio kaip xDrip+, tampa nestabilūs.</string>
|
||||
|
|
|
@ -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
|
||||
|
@ -61,7 +62,6 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener, MenuProvider {
|
|||
|
||||
const val ID_MENU_ADD = 504
|
||||
const val ID_MENU_RUN = 505
|
||||
const val ID_MENU_EDIT_MOVE = 506
|
||||
}
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
@ -98,8 +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.add(Menu.FIRST, ID_MENU_EDIT_MOVE, 0, rh.gs(R.string.remove_sort)).setShowAsAction(MenuItem.SHOW_AS_ACTION_NEVER)
|
||||
menu.setGroupDividerEnabled(true)
|
||||
MenuCompat.setGroupDividerEnabled(menu, true)
|
||||
}
|
||||
|
||||
override fun onMenuItemSelected(item: MenuItem): Boolean =
|
||||
|
@ -115,11 +114,6 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener, MenuProvider {
|
|||
true
|
||||
}
|
||||
|
||||
ID_MENU_EDIT_MOVE -> {
|
||||
actionHelper.startAction()
|
||||
true
|
||||
}
|
||||
|
||||
else -> super.onContextItemSelected(item)
|
||||
}
|
||||
|
||||
|
@ -316,4 +310,4 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener, MenuProvider {
|
|||
}
|
||||
}.show(childFragmentManager, "EditEventDialog")
|
||||
}
|
||||
}
|
||||
}
|
|
@ -116,7 +116,6 @@
|
|||
<string name="system_automation">Системна автомация</string>
|
||||
<string name="run_automations">Стартирай автомаций</string>
|
||||
<string name="add_automation">Добавяне на правило</string>
|
||||
<string name="remove_sort">Премахни/сортирай</string>
|
||||
<string name="stop_processing">Спри изпълнението</string>
|
||||
<!-- WeekdayPicker -->
|
||||
<string name="monday_short">П</string>
|
||||
|
|
|
@ -116,7 +116,6 @@
|
|||
<string name="system_automation">Automatizace systému</string>
|
||||
<string name="run_automations">Spustit automatizace</string>
|
||||
<string name="add_automation">Přidat pravidlo</string>
|
||||
<string name="remove_sort">Odstranit/řadit</string>
|
||||
<string name="stop_processing">Zastavit zpracovávání</string>
|
||||
<!-- WeekdayPicker -->
|
||||
<string name="monday_short">Po</string>
|
||||
|
|
|
@ -116,7 +116,6 @@
|
|||
<string name="system_automation">System automatisering</string>
|
||||
<string name="run_automations">Kør automatisering</string>
|
||||
<string name="add_automation">Tilføj regel</string>
|
||||
<string name="remove_sort">Fjern/sorter</string>
|
||||
<string name="stop_processing">Stop afvikling</string>
|
||||
<!-- WeekdayPicker -->
|
||||
<string name="monday_short">Ma</string>
|
||||
|
|
|
@ -116,7 +116,6 @@
|
|||
<string name="system_automation">System-Automatisierung</string>
|
||||
<string name="run_automations">Automatisierungen ausführen</string>
|
||||
<string name="add_automation">Regel hinzufügen</string>
|
||||
<string name="remove_sort">Entfernen/sortieren</string>
|
||||
<string name="stop_processing">Verarbeitung beenden</string>
|
||||
<!-- WeekdayPicker -->
|
||||
<string name="monday_short">Mo</string>
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue