migrate out of app module

This commit is contained in:
Milos Kozak 2022-11-04 14:34:05 +01:00
parent 732f2b4b40
commit c5ae87d344
58 changed files with 594 additions and 254 deletions

View file

@ -90,18 +90,10 @@
android:name=".activities.TreatmentsActivity" android:name=".activities.TreatmentsActivity"
android:exported="false" android:exported="false"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity
android:name=".activities.SurveyActivity"
android:exported="false"
android:theme="@style/AppTheme" />
<activity <activity
android:name=".activities.ProfileHelperActivity" android:name=".activities.ProfileHelperActivity"
android:exported="false" android:exported="false"
android:theme="@style/AppTheme" /> android:theme="@style/AppTheme" />
<activity
android:name=".activities.StatsActivity"
android:exported="false"
android:theme="@style/AppTheme" />
<!-- Receive new BG readings from other local apps --> <!-- Receive new BG readings from other local apps -->
<receiver <receiver
@ -212,7 +204,7 @@
android:name=".plugins.general.maintenance.activities.LogSettingActivity" android:name=".plugins.general.maintenance.activities.LogSettingActivity"
android:exported="false" /> android:exported="false" />
<activity <activity
android:name=".activities.RequestDexcomPermissionActivity" android:name=".plugins.source.activities.RequestDexcomPermissionActivity"
android:exported="false" /> android:exported="false" />
<uses-library <uses-library

View file

@ -30,7 +30,12 @@ import com.google.android.material.tabs.TabLayoutMediator
import com.google.firebase.crashlytics.FirebaseCrashlytics import com.google.firebase.crashlytics.FirebaseCrashlytics
import com.joanzapata.iconify.Iconify import com.joanzapata.iconify.Iconify
import com.joanzapata.iconify.fonts.FontAwesomeModule import com.joanzapata.iconify.fonts.FontAwesomeModule
import info.nightscout.androidaps.activities.* import info.nightscout.androidaps.activities.HistoryBrowseActivity
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.activities.ProfileHelperActivity
import info.nightscout.androidaps.activities.SingleFragmentActivity
import info.nightscout.androidaps.activities.TreatmentsActivity
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.databinding.ActivityMainBinding import info.nightscout.androidaps.databinding.ActivityMainBinding
@ -38,9 +43,17 @@ import info.nightscout.androidaps.events.EventAppExit
import info.nightscout.androidaps.events.EventInitializationChanged import info.nightscout.androidaps.events.EventInitializationChanged
import info.nightscout.androidaps.events.EventPreferenceChange import info.nightscout.androidaps.events.EventPreferenceChange
import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.events.EventRebuildTabs
import info.nightscout.androidaps.interfaces.* import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.interfaces.AndroidPermission
import info.nightscout.androidaps.interfaces.BuildHelper
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.Constraints import info.nightscout.androidaps.interfaces.Constraints
import info.nightscout.androidaps.interfaces.IconsProvider
import info.nightscout.androidaps.interfaces.Loop
import info.nightscout.androidaps.interfaces.PluginBase
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.SmsCommunicator
import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin import info.nightscout.androidaps.plugins.constraints.signatureVerifier.SignatureVerifierPlugin
import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils import info.nightscout.androidaps.plugins.constraints.versionChecker.VersionCheckerUtils
import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus import info.nightscout.androidaps.plugins.general.nsclient.data.NSSettingsStatus
@ -56,9 +69,10 @@ import info.nightscout.androidaps.utils.tabs.TabPageAdapter
import info.nightscout.androidaps.utils.ui.UIRunnable import info.nightscout.androidaps.utils.ui.UIRunnable
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.ui.activities.StatsActivity
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
import java.util.* import java.util.Locale
import javax.inject.Inject import javax.inject.Inject
import kotlin.system.exitProcess import kotlin.system.exitProcess

View file

@ -41,13 +41,13 @@ import info.nightscout.androidaps.receivers.KeepAliveWorker
import info.nightscout.androidaps.receivers.NetworkChangeReceiver import info.nightscout.androidaps.receivers.NetworkChangeReceiver
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
import info.nightscout.androidaps.services.AlarmSoundServiceHelper import info.nightscout.androidaps.services.AlarmSoundServiceHelper
import info.nightscout.androidaps.utils.ActivityMonitor
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.ProcessLifecycleListener import info.nightscout.androidaps.utils.ProcessLifecycleListener
import info.nightscout.androidaps.utils.locale.LocaleHelper import info.nightscout.androidaps.utils.locale.LocaleHelper
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.ui.utils.ActivityMonitor
import info.nightscout.ui.widget.Widget import info.nightscout.ui.widget.Widget
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.exceptions.UndeliverableException import io.reactivex.rxjava3.exceptions.UndeliverableException
@ -55,7 +55,6 @@ import io.reactivex.rxjava3.kotlin.plusAssign
import io.reactivex.rxjava3.plugins.RxJavaPlugins import io.reactivex.rxjava3.plugins.RxJavaPlugins
import rxdogtag2.RxDogTag import rxdogtag2.RxDogTag
import java.io.IOException import java.io.IOException
import java.net.SocketException
import java.util.concurrent.TimeUnit import java.util.concurrent.TimeUnit
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Provider import javax.inject.Provider
@ -76,7 +75,7 @@ class MainApp : DaggerApplication() {
@Inject lateinit var compatDBHelper: CompatDBHelper @Inject lateinit var compatDBHelper: CompatDBHelper
@Inject lateinit var repository: AppRepository @Inject lateinit var repository: AppRepository
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize @Suppress("unused") @Inject lateinit var staticInjector: StaticInjector// TODO avoid , here fake only to initialize
@Inject lateinit var uel: UserEntryLogger @Inject lateinit var uel: UserEntryLogger
@Inject lateinit var alarmSoundServiceHelper: AlarmSoundServiceHelper @Inject lateinit var alarmSoundServiceHelper: AlarmSoundServiceHelper
@Inject lateinit var notificationStore: NotificationStore @Inject lateinit var notificationStore: NotificationStore
@ -166,7 +165,7 @@ class MainApp : DaggerApplication() {
if (e is UndeliverableException) { if (e is UndeliverableException) {
e = e.cause!! e = e.cause!!
} }
if (e is IOException || e is SocketException) { if (e is IOException) {
// fine, irrelevant network problem or API that throws on cancellation // fine, irrelevant network problem or API that throws on cancellation
return@setErrorHandler return@setErrorHandler
} }

View file

@ -25,10 +25,10 @@ import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.defaultProfile.DefaultProfile import info.nightscout.ui.defaultProfile.DefaultProfile
import info.nightscout.androidaps.utils.defaultProfile.DefaultProfileDPV import info.nightscout.ui.defaultProfile.DefaultProfileDPV
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.androidaps.interfaces.stats.TddCalculator
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
@ -183,25 +183,25 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
for (i in 0..1) { for (i in 0..1) {
if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) { if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) {
if (ageUsed[i] < 1 || ageUsed[i] > 18) { if (ageUsed[i] < 1 || ageUsed[i] > 18) {
ToastUtils.warnToast(this, R.string.invalidage) ToastUtils.warnToast(this, R.string.invalid_age)
return@setOnClickListener return@setOnClickListener
} }
if ((weightUsed[i] < 5 || weightUsed[i] > 150) && tddUsed[i] == 0.0) { if ((weightUsed[i] < 5 || weightUsed[i] > 150) && tddUsed[i] == 0.0) {
ToastUtils.warnToast(this, R.string.invalidweight) ToastUtils.warnToast(this, R.string.invalid_weight)
return@setOnClickListener return@setOnClickListener
} }
if ((tddUsed[i] < 5 || tddUsed[i] > 150) && weightUsed[i] == 0.0) { if ((tddUsed[i] < 5 || tddUsed[i] > 150) && weightUsed[i] == 0.0) {
ToastUtils.warnToast(this, R.string.invalidweight) ToastUtils.warnToast(this, R.string.invalid_weight)
return@setOnClickListener return@setOnClickListener
} }
} }
if (typeSelected[i] == ProfileType.DPV_DEFAULT) { if (typeSelected[i] == ProfileType.DPV_DEFAULT) {
if (ageUsed[i] < 1 || ageUsed[i] > 18) { if (ageUsed[i] < 1 || ageUsed[i] > 18) {
ToastUtils.warnToast(this, R.string.invalidage) ToastUtils.warnToast(this, R.string.invalid_age)
return@setOnClickListener return@setOnClickListener
} }
if (tddUsed[i] < 5 || tddUsed[i] > 150) { if (tddUsed[i] < 5 || tddUsed[i] > 150) {
ToastUtils.warnToast(this, R.string.invalidweight) ToastUtils.warnToast(this, R.string.invalid_weight)
return@setOnClickListener return@setOnClickListener
} }
if ((pctUsed[i] < 32 || pctUsed[i] > 37)) { if ((pctUsed[i] < 32 || pctUsed[i] > 37)) {

View file

@ -3,10 +3,14 @@ package info.nightscout.androidaps.di
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.MainActivity import info.nightscout.androidaps.MainActivity
import info.nightscout.androidaps.activities.*
import info.nightscout.androidaps.activities.HistoryBrowseActivity import info.nightscout.androidaps.activities.HistoryBrowseActivity
import info.nightscout.androidaps.activities.PreferencesActivity
import info.nightscout.androidaps.activities.ProfileHelperActivity
import info.nightscout.androidaps.activities.SingleFragmentActivity
import info.nightscout.androidaps.activities.TreatmentsActivity
import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity import info.nightscout.androidaps.plugins.general.maintenance.activities.LogSettingActivity
import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity import info.nightscout.androidaps.plugins.general.overview.activities.QuickWizardListActivity
import info.nightscout.androidaps.plugins.source.activities.RequestDexcomPermissionActivity
import info.nightscout.androidaps.setupwizard.SetupWizardActivity import info.nightscout.androidaps.setupwizard.SetupWizardActivity
@Module @Module
@ -22,8 +26,6 @@ abstract class ActivitiesModule {
@ContributesAndroidInjector abstract fun contributesRequestDexcomPermissionActivity(): RequestDexcomPermissionActivity @ContributesAndroidInjector abstract fun contributesRequestDexcomPermissionActivity(): RequestDexcomPermissionActivity
@ContributesAndroidInjector abstract fun contributesSetupWizardActivity(): SetupWizardActivity @ContributesAndroidInjector abstract fun contributesSetupWizardActivity(): SetupWizardActivity
@ContributesAndroidInjector abstract fun contributesSingleFragmentActivity(): SingleFragmentActivity @ContributesAndroidInjector abstract fun contributesSingleFragmentActivity(): SingleFragmentActivity
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
@ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity @ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity
} }

View file

@ -34,6 +34,9 @@ import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.SmsCommunicator import info.nightscout.androidaps.interfaces.SmsCommunicator
import info.nightscout.androidaps.interfaces.TrendCalculator import info.nightscout.androidaps.interfaces.TrendCalculator
import info.nightscout.androidaps.interfaces.XDripBroadcast import info.nightscout.androidaps.interfaces.XDripBroadcast
import info.nightscout.androidaps.interfaces.stats.DexcomTirCalculator
import info.nightscout.androidaps.interfaces.stats.TddCalculator
import info.nightscout.androidaps.interfaces.stats.TirCalculator
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin
import info.nightscout.androidaps.plugins.bus.RxBus import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
@ -65,24 +68,31 @@ import info.nightscout.implementation.TrendCalculatorImpl
import info.nightscout.implementation.XDripBroadcastImpl import info.nightscout.implementation.XDripBroadcastImpl
import info.nightscout.implementation.constraints.ConstraintsImpl import info.nightscout.implementation.constraints.ConstraintsImpl
import info.nightscout.implementation.queue.CommandQueueImplementation import info.nightscout.implementation.queue.CommandQueueImplementation
import info.nightscout.implementation.stats.DexcomTirCalculatorImpl
import info.nightscout.implementation.stats.TddCalculatorImpl
import info.nightscout.implementation.stats.TirCalculatorImpl
import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin import info.nightscout.plugins.general.smsCommunicator.SmsCommunicatorPlugin
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import javax.inject.Singleton import javax.inject.Singleton
@Suppress("unused") @Suppress("unused")
@Module(includes = [ @Module(
AppModule.AppBindings::class includes = [
]) AppModule.AppBindings::class
]
)
open class AppModule { open class AppModule {
@Provides @Provides
fun providesPlugins(config: Config, buildHelper: BuildHelper, fun providesPlugins(
@PluginsModule.AllConfigs allConfigs: Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>, config: Config, buildHelper: BuildHelper,
@PluginsModule.PumpDriver pumpDrivers: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>, @PluginsModule.AllConfigs allConfigs: Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>,
@PluginsModule.NotNSClient notNsClient: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>, @PluginsModule.PumpDriver pumpDrivers: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
@PluginsModule.APS aps: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>, @PluginsModule.NotNSClient notNsClient: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
@PluginsModule.Unfinished unfinished: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>) @PluginsModule.APS aps: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
@PluginsModule.Unfinished unfinished: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>
)
: List<@JvmSuppressWildcards PluginBase> { : List<@JvmSuppressWildcards PluginBase> {
val plugins = allConfigs.toMutableMap() val plugins = allConfigs.toMutableMap()
if (config.PUMPDRIVERS) plugins += pumpDrivers.get() if (config.PUMPDRIVERS) plugins += pumpDrivers.get()
@ -120,6 +130,7 @@ open class AppModule {
@Provides @Provides
@Singleton @Singleton
internal fun provideConstraints(activePlugin: ActivePlugin): Constraints = ConstraintsImpl(activePlugin) internal fun provideConstraints(activePlugin: ActivePlugin): Constraints = ConstraintsImpl(activePlugin)
@Module @Module
interface AppBindings { interface AppBindings {
@ -146,6 +157,9 @@ open class AppModule {
@Binds fun bindLocalAlertUtilsInterface(localAlertUtils: LocalAlertUtilsImpl): LocalAlertUtils @Binds fun bindLocalAlertUtilsInterface(localAlertUtils: LocalAlertUtilsImpl): LocalAlertUtils
@Binds fun bindActivityNamesInterface(activityNames: ActivityNamesImpl): ActivityNames @Binds fun bindActivityNamesInterface(activityNames: ActivityNamesImpl): ActivityNames
@Binds fun bindTrendCalculatorInterface(trendCalculator: TrendCalculatorImpl): TrendCalculator @Binds fun bindTrendCalculatorInterface(trendCalculator: TrendCalculatorImpl): TrendCalculator
@Binds fun bindTddCalculatorInterface(tddCalculator: TddCalculatorImpl): TddCalculator
@Binds fun bindTirCalculatorInterface(tirCalculator: TirCalculatorImpl): TirCalculator
@Binds fun bindDexcomTirCalculatorInterface(dexcomTirCalculator: DexcomTirCalculatorImpl): DexcomTirCalculator
} }
} }

View file

@ -23,7 +23,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.Round import info.nightscout.androidaps.utils.Round
import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.androidaps.interfaces.stats.TddCalculator
import info.nightscout.shared.SafeParse import info.nightscout.shared.SafeParse
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag

View file

@ -9,7 +9,7 @@ import androidx.work.WorkerParameters
import androidx.work.workDataOf import androidx.work.workDataOf
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.activities.RequestDexcomPermissionActivity import info.nightscout.androidaps.plugins.source.activities.RequestDexcomPermissionActivity
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.entities.GlucoseValue import info.nightscout.androidaps.database.entities.GlucoseValue
import info.nightscout.androidaps.database.entities.TherapyEvent import info.nightscout.androidaps.database.entities.TherapyEvent

View file

@ -1,11 +1,10 @@
package info.nightscout.androidaps.activities package info.nightscout.androidaps.plugins.source.activities
import android.os.Bundle import android.os.Bundle
import info.nightscout.androidaps.activities.DialogAppCompatActivity
import info.nightscout.androidaps.plugins.source.DexcomPlugin import info.nightscout.androidaps.plugins.source.DexcomPlugin
import javax.inject.Inject
class RequestDexcomPermissionActivity : DialogAppCompatActivity() { class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
@Inject lateinit var dexcomPlugin: DexcomPlugin
private val requestCode = "AndroidAPS <3".map { it.code }.sum() private val requestCode = "AndroidAPS <3".map { it.code }.sum()

View file

@ -253,7 +253,6 @@
<string name="short_tabtitles">Shorten tab titles</string> <string name="short_tabtitles">Shorten tab titles</string>
<string name="always_use_shortavg">Always use short average delta instead of simple delta</string> <string name="always_use_shortavg">Always use short average delta instead of simple delta</string>
<string name="always_use_shortavg_summary">Useful when data from unfiltered sources like xDrip+ gets noisy.</string> <string name="always_use_shortavg_summary">Useful when data from unfiltered sources like xDrip+ gets noisy.</string>
<string name="profile">Profile</string>
<string name="openapsama_max_daily_safety_multiplier_summary">Default value: 3 This is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware thats what is discussed about “3x max daily; 4x current” for safety caps.</string> <string name="openapsama_max_daily_safety_multiplier_summary">Default value: 3 This is a key OpenAPS safety cap. What this does is limit your basals to be 3x (in this people) your biggest basal rate. You likely will not need to change this, but you should be aware thats what is discussed about “3x max daily; 4x current” for safety caps.</string>
<string name="openapsama_current_basal_safety_multiplier_summary">Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.</string> <string name="openapsama_current_basal_safety_multiplier_summary">Default value: 4 This is the other half of the key OpenAPS safety caps, and the other half of “3x max daily; 4x current” of the safety caps. This means your basal, regardless of max basal set on your pump, cannot be any higher than this number times the current level of your basal. This is to prevent people from getting into dangerous territory by setting excessively high max basals before understanding how the algorithm works. Again, the default is 4x; most people will never need to adjust this and are instead more likely to need to adjust other settings if they feel like they are “running into” this safety cap.</string>
<string name="openapsama_autosens_max_summary">Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20%% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.</string> <string name="openapsama_autosens_max_summary">Default value: 1.2\nThis is a multiplier cap for autosens (and soon autotune) to set a 20%% max limit on how high the autosens ratio can be, which in turn determines how high autosens can adjust basals, how low it can adjust ISF, and how low it can set the BG target.</string>
@ -589,7 +588,6 @@
<string name="smbnotallowedinopenloopmode">SMB not allowed in open loop mode</string> <string name="smbnotallowedinopenloopmode">SMB not allowed in open loop mode</string>
<string name="food_short">Food</string> <string name="food_short">Food</string>
<string name="iobcobcalculator" translatable="false">IobCobCalculator</string> <string name="iobcobcalculator" translatable="false">IobCobCalculator</string>
<string name="reset">reset</string>
<string name="key_openapssmb_max_iob" translatable="false">openapsmb_max_iob</string> <string name="key_openapssmb_max_iob" translatable="false">openapsmb_max_iob</string>
<string name="openapssmb_maxiob_title">Maximum total IOB OpenAPS can\'t go over [U]</string> <string name="openapssmb_maxiob_title">Maximum total IOB OpenAPS can\'t go over [U]</string>
<string name="openapssmb_maxiob_summary">This value is called Max IOB in OpenAPS context\nOpenAPS will not add more insulin if current IOB is greater than this value</string> <string name="openapssmb_maxiob_summary">This value is called Max IOB in OpenAPS context\nOpenAPS will not add more insulin if current IOB is greater than this value</string>
@ -802,25 +800,7 @@
<string name="profilenamecontainsdot">Profile name contains dots.\nThis is not supported by NS.\nProfile is not uploaded to NS.</string> <string name="profilenamecontainsdot">Profile name contains dots.\nThis is not supported by NS.\nProfile is not uploaded to NS.</string>
<string name="low_mark_comment">Lower value of in range area (display only)</string> <string name="low_mark_comment">Lower value of in range area (display only)</string>
<string name="high_mark_comment">Higher value of in range area (display only)</string> <string name="high_mark_comment">Higher value of in range area (display only)</string>
<string name="age">Age</string>
<string name="weight_label">Weight</string>
<string name="id">ID:</string>
<string name="submit">Submit</string>
<string name="mostcommonprofile">Most common profile:</string>
<string name="survey_comment">Note: Only data visible on this screen will be anonymously uploaded. ID is assigned to this installation of AAPS. You can submit data again if your main profile get changed but let it running at least for a week to make result visible in time in range. Your help is appreciated.</string>
<string name="invalidage">Invalid age entry</string>
<string name="invalidweight">Invalid weight entry</string>
<string name="invalidpct">Invalid % entry</string> <string name="invalidpct">Invalid % entry</string>
<string name="average">Average</string>
<string name="tir">TIR</string>
<string name="day_tir">Day TIR</string>
<string name="night_tir">Night TIR</string>
<string name="detailed_14_days">Detailed 14 days</string>
<string name="std_deviation">SD: %1$s</string>
<string name="hba1c">HbA1c: </string>
<string name="activitymonitor">Activity monitor</string>
<string name="doyouwantresetstats">Do you want to reset activity stats?</string>
<string name="statistics">Statistics</string>
<string name="randombg">Random BG</string> <string name="randombg">Random BG</string>
<string name="description_source_randombg">Generate random BG data (Demo mode only)</string> <string name="description_source_randombg">Generate random BG data (Demo mode only)</string>
<string name="randombg_short">BG</string> <string name="randombg_short">BG</string>
@ -927,7 +907,6 @@
<string name="key_ns_receive_cgm" translatable="false">ns_receive_cgm</string> <string name="key_ns_receive_cgm" translatable="false">ns_receive_cgm</string>
<string name="ns_receive_cgm">Receive/backfill CGM data</string> <string name="ns_receive_cgm">Receive/backfill CGM data</string>
<string name="ns_receive_cgm_summary">Accept CGM data from NS</string> <string name="ns_receive_cgm_summary">Accept CGM data from NS</string>
<string name="calculation_in_progress">Calculation in progress</string>
<string name="missing_profile_name">Missing profile name</string> <string name="missing_profile_name">Missing profile name</string>
<string name="error_in_ic_values">Error in IC values</string> <string name="error_in_ic_values">Error in IC values</string>
<string name="error_in_basal_values">Error in basal values</string> <string name="error_in_basal_values">Error in basal values</string>
@ -1023,13 +1002,6 @@
<string name="show_loop">Show loop</string> <string name="show_loop">Show loop</string>
<string name="count_selected">%1$d selected</string> <string name="count_selected">%1$d selected</string>
<string name="sort_label">Sort</string> <string name="sort_label">Sort</string>
<string name="veryLow" comment="below 3.1">Very low</string>
<string name="low" comment="3.1-3.9">Low</string>
<string name="high" comment="10.0-13.9">High</string>
<string name="veryHigh" comment="above 13.9">Very high</string>
<string name="below" comment="below &quot;in range&quot;">Below</string>
<string name="in_range">In range</string>
<string name="above" comment="above &quot;in range&quot;">Above</string>
<string name="show_loop_records">Show loop records</string> <string name="show_loop_records">Show loop records</string>
<string name="show_hide_records">Hide loop records</string> <string name="show_hide_records">Hide loop records</string>
<string name="loop_status">Loop status</string> <string name="loop_status">Loop status</string>

View file

@ -1,79 +0,0 @@
package info.nightscout.androidaps.plugins.treatments
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.database.AppRepository
import info.nightscout.shared.sharedPreferences.SP
import org.junit.Test
import org.mockito.Mock
@Suppress("SpellCheckingInspection")
class TreatmentsPluginTest : TestBaseWithProfile() {
@Mock lateinit var sp: SP
@Mock lateinit var repository: AppRepository
val injector = HasAndroidInjector {
AndroidInjector {
}
}
@Test fun dummy() {}
/*
private lateinit var insulinOrefRapidActingPlugin: InsulinOrefRapidActingPlugin
private lateinit var sot: TreatmentsPlugin
@Before
fun prepare() {
insulinOrefRapidActingPlugin = InsulinOrefRapidActingPlugin(profileInjector, rh, profileFunction, rxBus, aapsLogger)
`when`(profileFunction.getProfile(ArgumentMatchers.anyLong())).thenReturn(validProfile)
`when`(activePluginProvider.activeInsulin).thenReturn(insulinOrefRapidActingPlugin)
sot = TreatmentsPlugin(profileInjector, aapsLogger, rxBus, aapsSchedulers, rh, context, sp, profileFunction, activePluginProvider, nsUpload, fabricPrivacy, dateUtil, databaseHelper, repository)
sot.service = treatmentService
}
@Test
fun `zero TBR should produce zero absolute insulin`() {
val now = dateUtil._now()
val tbrs: MutableList<TemporaryBasal> = ArrayList()
tbrs.add(TemporaryBasal(injector).date(now - T.hours(30).msecs()).duration(10000).percent(0))
`when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs)
sot.initializeData(T.hours(30).msecs())
val iob = sot.getAbsoluteIOBTempBasals(now)
Assert.assertEquals(0.0, iob.iob, 0.0)
}
@Test
fun `90pct TBR and should produce less absolute insulin`() {
val now = dateUtil._now()
val tbrs: MutableList<TemporaryBasal> = ArrayList()
`when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs)
sot.initializeData(T.hours(30).msecs())
val iob100pct = sot.getAbsoluteIOBTempBasals(now)
tbrs.add(TemporaryBasal(injector).date(now - T.hours(30).msecs()).duration(10000).percent(90))
sot.initializeData(T.hours(30).msecs())
val iob90pct = sot.getAbsoluteIOBTempBasals(now)
Assert.assertTrue(iob100pct.basaliob > iob90pct.basaliob)
}
@Test
fun `110pct TBR and should produce 10pct more absolute insulin`() {
val now = dateUtil._now()
val tbrs: MutableList<TemporaryBasal> = ArrayList()
`when`(databaseHelper.getTemporaryBasalsDataFromTime(ArgumentMatchers.anyLong(), ArgumentMatchers.anyBoolean())).thenReturn(tbrs)
sot.initializeData(T.hours(30).msecs())
val iob100pct = sot.getAbsoluteIOBTempBasals(now)
tbrs.add(TemporaryBasal(injector).date(now - T.hours(30).msecs()).duration(10000).percent(110))
sot.initializeData(T.hours(30).msecs())
val iob110pct = sot.getAbsoluteIOBTempBasals(now)
Assert.assertEquals(1.1, iob110pct.basaliob / iob100pct.basaliob, 0.0001)
}
*/
}

View file

@ -0,0 +1,17 @@
package info.nightscout.androidaps.interfaces.stats
import android.content.Context
import android.widget.TableRow
import android.widget.TextView
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
interface DexcomTIR {
fun calculateSD(): Double
fun toHbA1cView(context: Context, rh: ResourceHelper): TextView
fun toSDView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView
fun toRangeHeaderView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView
fun toTableRowHeader(context: Context, rh: ResourceHelper): TableRow
fun toTableRow(context: Context, rh: ResourceHelper): TableRow
}

View file

@ -0,0 +1,10 @@
package info.nightscout.androidaps.interfaces.stats
import android.content.Context
import android.widget.TableLayout
interface DexcomTirCalculator {
fun calculate(): DexcomTIR
fun stats(context: Context): TableLayout
}

View file

@ -0,0 +1,25 @@
package info.nightscout.androidaps.interfaces.stats
import android.content.Context
import android.widget.TableRow
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.DateUtil
interface TIR {
val date: Long
val lowThreshold: Double
val highThreshold: Double
var below: Int
var inRange: Int
var above: Int
var error: Int
var count: Int
fun error()
fun below()
fun inRange()
fun above()
fun toTableRow(context: Context, rh: ResourceHelper, dateUtil: DateUtil): TableRow
fun toTableRow(context: Context, rh: ResourceHelper, days: Int): TableRow
}

View file

@ -0,0 +1,16 @@
package info.nightscout.androidaps.interfaces.stats
import android.content.Context
import android.util.LongSparseArray
import android.widget.TableLayout
import info.nightscout.androidaps.database.entities.TotalDailyDose
interface TddCalculator {
fun calculate(days: Long): LongSparseArray<TotalDailyDose>
fun calculateToday(): TotalDailyDose
fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose
fun calculate(startTime: Long, endTime: Long): TotalDailyDose
fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose?
fun stats(context: Context): TableLayout
}

View file

@ -0,0 +1,11 @@
package info.nightscout.androidaps.interfaces.stats
import android.content.Context
import android.util.LongSparseArray
import android.widget.TableLayout
interface TirCalculator {
fun calculate(days: Long, lowMgdl: Double, highMgdl: Double): LongSparseArray<TIR>
fun stats(context: Context): TableLayout
}

View file

@ -225,6 +225,9 @@
<string name="a11y_high">high</string> <string name="a11y_high">high</string>
<string name="a11y_inrange">in range</string> <string name="a11y_inrange">in range</string>
<string name="a11y_low">low</string> <string name="a11y_low">low</string>
<string name="average">Average</string>
<string name="tir">TIR</string>
<string name="tdd_total">TDD Total</string>
<!-- Constraints--> <!-- Constraints-->
<string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string> <string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string>

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils.stats package info.nightscout.implementation.stats
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
@ -7,6 +7,8 @@ import android.widget.TableLayout
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.stats.DexcomTIR
import info.nightscout.androidaps.interfaces.stats.DexcomTirCalculator
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
@ -14,26 +16,27 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class DexcomTirCalculator @Inject constructor( class DexcomTirCalculatorImpl @Inject constructor(
private val rh: ResourceHelper, private val rh: ResourceHelper,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val repository: AppRepository private val repository: AppRepository
) { ) : DexcomTirCalculator {
val days = 14L val days = 14L
fun calculate(): DexcomTIR { override fun calculate(): DexcomTIR {
val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
val endTime = MidnightTime.calc(dateUtil.now()) val endTime = MidnightTime.calc(dateUtil.now())
val bgReadings = repository.compatGetBgReadingsDataFromTime(startTime, endTime, true).blockingGet() val bgReadings = repository.compatGetBgReadingsDataFromTime(startTime, endTime, true).blockingGet()
val result = DexcomTIR() val result = DexcomTirImpl()
for (bg in bgReadings) result.add(bg.timestamp, bg.value) for (bg in bgReadings) result.add(bg.timestamp, bg.value)
return result return result
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun stats(context: Context): TableLayout = override fun stats(context: Context): TableLayout =
TableLayout(context).also { layout -> TableLayout(context).also { layout ->
val tir = calculate() val tir = calculate()
layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils.stats package info.nightscout.implementation.stats
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
@ -7,16 +7,17 @@ import android.view.Gravity
import android.widget.TableRow import android.widget.TableRow
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.stats.DexcomTIR
import info.nightscout.implementation.R
import java.util.* import java.util.*
import kotlin.math.pow import kotlin.math.pow
import kotlin.math.roundToInt import kotlin.math.roundToInt
import kotlin.math.sqrt import kotlin.math.sqrt
class DexcomTIR { class DexcomTirImpl : DexcomTIR {
private var veryLow = 0 private var veryLow = 0
private var low = 0 private var low = 0
@ -26,7 +27,7 @@ class DexcomTIR {
private var error = 0 private var error = 0
private var count = 0 private var count = 0
var sum = 0.0 private var sum = 0.0
val values = mutableListOf<Double>() val values = mutableListOf<Double>()
private val veryLowTirMgdl = Constants.STATS_RANGE_VERY_LOW_MMOL * Constants.MMOLL_TO_MGDL private val veryLowTirMgdl = Constants.STATS_RANGE_VERY_LOW_MMOL * Constants.MMOLL_TO_MGDL
@ -65,14 +66,14 @@ class DexcomTIR {
private fun veryHighPct() = if (count > 0) veryHigh.toDouble() / count * 100.0 else 0.0 private fun veryHighPct() = if (count > 0) veryHigh.toDouble() / count * 100.0 else 0.0
private fun mean() = sum / count private fun mean() = sum / count
fun calculateSD(): Double { override fun calculateSD(): Double {
if (count == 0) return 0.0 if (count == 0) return 0.0
var standardDeviation = 0.0 var standardDeviation = 0.0
for (num in values) standardDeviation += (num - mean()).pow(2.0) for (num in values) standardDeviation += (num - mean()).pow(2.0)
return sqrt(standardDeviation / count) return sqrt(standardDeviation / count)
} }
fun toHbA1cView(context: Context, rh: ResourceHelper): TextView = override fun toHbA1cView(context: Context, rh: ResourceHelper): TextView =
TextView(context).apply { TextView(context).apply {
text = text =
if (count == 0) "" if (count == 0) ""
@ -86,7 +87,7 @@ class DexcomTIR {
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun toSDView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView = override fun toSDView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView =
TextView(context).apply { TextView(context).apply {
val sd = calculateSD() val sd = calculateSD()
text = "\n" + rh.gs(R.string.std_deviation, Profile.toUnitsString(sd, sd * Constants.MGDL_TO_MMOLL, profileFunction.getUnits())) text = "\n" + rh.gs(R.string.std_deviation, Profile.toUnitsString(sd, sd * Constants.MGDL_TO_MMOLL, profileFunction.getUnits()))
@ -94,7 +95,7 @@ class DexcomTIR {
gravity = Gravity.CENTER_HORIZONTAL gravity = Gravity.CENTER_HORIZONTAL
} }
fun toRangeHeaderView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView = override fun toRangeHeaderView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView =
TextView(context).apply { TextView(context).apply {
text = StringBuilder() text = StringBuilder()
.append(rh.gs(R.string.detailed_14_days)) .append(rh.gs(R.string.detailed_14_days))
@ -129,7 +130,7 @@ class DexcomTIR {
setTextAppearance(android.R.style.TextAppearance_Material_Medium) setTextAppearance(android.R.style.TextAppearance_Material_Medium)
} }
fun toTableRowHeader(context: Context, rh: ResourceHelper): TableRow = override fun toTableRowHeader(context: Context, rh: ResourceHelper): TableRow =
TableRow(context).also { header -> TableRow(context).also { header ->
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT) val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)
header.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) header.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT)
@ -142,7 +143,7 @@ class DexcomTIR {
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun toTableRow(context: Context, rh: ResourceHelper): TableRow = override fun toTableRow(context: Context, rh: ResourceHelper): TableRow =
TableRow(context).also { row -> TableRow(context).also { row ->
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f) val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)
row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT)

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils.stats package info.nightscout.implementation.stats
import android.content.Context import android.content.Context
import android.graphics.Typeface import android.graphics.Typeface
@ -8,27 +8,29 @@ import android.view.ViewGroup
import android.widget.TableLayout import android.widget.TableLayout
import android.widget.TableRow import android.widget.TableRow
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.database.ValueWrapper import info.nightscout.androidaps.database.ValueWrapper
import info.nightscout.androidaps.database.embedments.InterfaceIDs import info.nightscout.androidaps.database.embedments.InterfaceIDs
import info.nightscout.androidaps.database.entities.Bolus import info.nightscout.androidaps.database.entities.Bolus
import info.nightscout.androidaps.database.entities.TotalDailyDose import info.nightscout.androidaps.database.entities.TotalDailyDose
import info.nightscout.androidaps.extensions.convertedToAbsolute
import info.nightscout.androidaps.extensions.toTableRow import info.nightscout.androidaps.extensions.toTableRow
import info.nightscout.androidaps.extensions.toTableRowHeader import info.nightscout.androidaps.extensions.toTableRowHeader
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.IobCobCalculator import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.stats.TddCalculator
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.implementation.R
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton
class TddCalculator @Inject constructor( @Singleton
class TddCalculatorImpl @Inject constructor(
private val aapsLogger: AAPSLogger, private val aapsLogger: AAPSLogger,
private val rh: ResourceHelper, private val rh: ResourceHelper,
private val activePlugin: ActivePlugin, private val activePlugin: ActivePlugin,
@ -36,9 +38,9 @@ class TddCalculator @Inject constructor(
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val iobCobCalculator: IobCobCalculator, private val iobCobCalculator: IobCobCalculator,
private val repository: AppRepository private val repository: AppRepository
) { ) : TddCalculator {
fun calculate(days: Long): LongSparseArray<TotalDailyDose> { override fun calculate(days: Long): LongSparseArray<TotalDailyDose> {
var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) var startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
val endTime = MidnightTime.calc(dateUtil.now()) val endTime = MidnightTime.calc(dateUtil.now())
val stepSize = T.hours(24).msecs() val stepSize = T.hours(24).msecs()
@ -69,19 +71,19 @@ class TddCalculator @Inject constructor(
return result return result
} }
fun calculateToday(): TotalDailyDose { override fun calculateToday(): TotalDailyDose {
val startTime = MidnightTime.calc(dateUtil.now()) val startTime = MidnightTime.calc(dateUtil.now())
val endTime = dateUtil.now() val endTime = dateUtil.now()
return calculate(startTime, endTime) return calculate(startTime, endTime)
} }
fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose { override fun calculateDaily(startHours: Long, endHours: Long): TotalDailyDose {
val startTime = dateUtil.now() + T.hours(hour = startHours).msecs() val startTime = dateUtil.now() + T.hours(hour = startHours).msecs()
val endTime = dateUtil.now() + T.hours(hour = endHours).msecs() val endTime = dateUtil.now() + T.hours(hour = endHours).msecs()
return calculate(startTime, endTime) return calculate(startTime, endTime)
} }
fun calculate(startTime: Long, endTime: Long): TotalDailyDose { override fun calculate(startTime: Long, endTime: Long): TotalDailyDose {
val startTimeAligned = startTime - startTime % (5 * 60 * 1000) val startTimeAligned = startTime - startTime % (5 * 60 * 1000)
val endTimeAligned = endTime - endTime % (5 * 60 * 1000) val endTimeAligned = endTime - endTime % (5 * 60 * 1000)
val tdd = TotalDailyDose(timestamp = startTimeAligned) val tdd = TotalDailyDose(timestamp = startTimeAligned)
@ -112,7 +114,7 @@ class TddCalculator @Inject constructor(
return tdd return tdd
} }
fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose? { override fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose? {
val totalTdd = TotalDailyDose(timestamp = dateUtil.now()) val totalTdd = TotalDailyDose(timestamp = dateUtil.now())
if (tdds.size() == 0) return null if (tdds.size() == 0) return null
for (i in 0 until tdds.size()) { for (i in 0 until tdds.size()) {
@ -129,7 +131,7 @@ class TddCalculator @Inject constructor(
return totalTdd return totalTdd
} }
fun stats(context: Context): TableLayout { override fun stats(context: Context): TableLayout {
val tdds = calculate(7) val tdds = calculate(7)
val averageTdd = averageTDD(tdds) val averageTdd = averageTDD(tdds)
val todayTdd = calculateToday() val todayTdd = calculateToday()

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils.stats package info.nightscout.implementation.stats
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
@ -9,26 +9,28 @@ import android.view.ViewGroup
import android.widget.TableLayout import android.widget.TableLayout
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.Constants import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.R
import info.nightscout.androidaps.database.AppRepository import info.nightscout.androidaps.database.AppRepository
import info.nightscout.androidaps.interfaces.Profile import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.stats.TIR
import info.nightscout.androidaps.interfaces.stats.TirCalculator
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.MidnightTime import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.implementation.R
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@Singleton @Singleton
class TirCalculator @Inject constructor( class TirCalculatorImpl @Inject constructor(
private val rh: ResourceHelper, private val rh: ResourceHelper,
private val profileFunction: ProfileFunction, private val profileFunction: ProfileFunction,
private val dateUtil: DateUtil, private val dateUtil: DateUtil,
private val repository: AppRepository private val repository: AppRepository
) { ) : TirCalculator {
fun calculate(days: Long, lowMgdl: Double, highMgdl: Double): LongSparseArray<TIR> { override fun calculate(days: Long, lowMgdl: Double, highMgdl: Double): LongSparseArray<TIR> {
if (lowMgdl < 39) throw RuntimeException("Low below 39") if (lowMgdl < 39) throw RuntimeException("Low below 39")
if (lowMgdl > highMgdl) throw RuntimeException("Low > High") if (lowMgdl > highMgdl) throw RuntimeException("Low > High")
val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs()) val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
@ -40,7 +42,7 @@ class TirCalculator @Inject constructor(
val midnight = MidnightTime.calc(bg.timestamp) val midnight = MidnightTime.calc(bg.timestamp)
var tir = result[midnight] var tir = result[midnight]
if (tir == null) { if (tir == null) {
tir = TIR(midnight, lowMgdl, highMgdl) tir = TirImpl(midnight, lowMgdl, highMgdl)
result.append(midnight, tir) result.append(midnight, tir)
} }
if (bg.value < 39) tir.error() if (bg.value < 39) tir.error()
@ -53,9 +55,9 @@ class TirCalculator @Inject constructor(
private fun averageTIR(tirs: LongSparseArray<TIR>): TIR { private fun averageTIR(tirs: LongSparseArray<TIR>): TIR {
val totalTir = if (tirs.size() > 0) { val totalTir = if (tirs.size() > 0) {
TIR(tirs.valueAt(0).date, tirs.valueAt(0).lowThreshold, tirs.valueAt(0).highThreshold) TirImpl(tirs.valueAt(0).date, tirs.valueAt(0).lowThreshold, tirs.valueAt(0).highThreshold)
} else { } else {
TIR(7, 70.0, 180.0) TirImpl(7, 70.0, 180.0)
} }
for (i in 0 until tirs.size()) { for (i in 0 until tirs.size()) {
val tir = tirs.valueAt(i) val tir = tirs.valueAt(i)
@ -69,7 +71,7 @@ class TirCalculator @Inject constructor(
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun stats(context: Context): TableLayout = override fun stats(context: Context): TableLayout =
TableLayout(context).also { layout -> TableLayout(context).also { layout ->
val lowTirMgdl = Constants.STATS_RANGE_LOW_MMOL * Constants.MMOLL_TO_MGDL val lowTirMgdl = Constants.STATS_RANGE_LOW_MMOL * Constants.MMOLL_TO_MGDL
val highTirMgdl = Constants.STATS_RANGE_HIGH_MMOL * Constants.MMOLL_TO_MGDL val highTirMgdl = Constants.STATS_RANGE_HIGH_MMOL * Constants.MMOLL_TO_MGDL
@ -92,7 +94,7 @@ class TirCalculator @Inject constructor(
gravity = Gravity.CENTER_HORIZONTAL gravity = Gravity.CENTER_HORIZONTAL
setTextAppearance(android.R.style.TextAppearance_Material_Medium) setTextAppearance(android.R.style.TextAppearance_Material_Medium)
}) })
layout.addView(TIR.toTableRowHeader(context, rh)) layout.addView(TirImpl.toTableRowHeader(context, rh))
for (i in 0 until tir7.size()) layout.addView(tir7.valueAt(i).toTableRow(context, rh, dateUtil)) for (i in 0 until tir7.size()) layout.addView(tir7.valueAt(i).toTableRow(context, rh, dateUtil))
layout.addView( layout.addView(
TextView(context).apply { TextView(context).apply {

View file

@ -1,26 +1,38 @@
package info.nightscout.androidaps.utils.stats package info.nightscout.implementation.stats
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.content.Context import android.content.Context
import android.view.Gravity import android.view.Gravity
import android.widget.TableRow import android.widget.TableRow
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.interfaces.stats.TIR
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.implementation.R
class TIR(val date: Long, val lowThreshold: Double, val highThreshold: Double) { class TirImpl(override val date: Long, override val lowThreshold: Double, override val highThreshold: Double) : TIR {
internal var below = 0 override var below = 0
internal var inRange = 0 override var inRange = 0
internal var above = 0 override var above = 0
internal var error = 0 override var error = 0
internal var count = 0 override var count = 0
fun error() = run { error++ } override fun error() {
fun below() = run { below++; count++ } error++
fun inRange() = run { inRange++; count++ } }
fun above() = run { above++; count++ }
override fun below() {
below++; count++
}
override fun inRange() {
inRange++; count++
}
override fun above() {
above++; count++
}
private fun belowPct() = if (count > 0) below.toDouble() / count * 100.0 else 0.0 private fun belowPct() = if (count > 0) below.toDouble() / count * 100.0 else 0.0
private fun inRangePct() = if (count > 0) 100 - belowPct() - abovePct() else 0.0 private fun inRangePct() = if (count > 0) 100 - belowPct() - abovePct() else 0.0
@ -40,7 +52,7 @@ class TIR(val date: Long, val lowThreshold: Double, val highThreshold: Double) {
} }
} }
fun toTableRow(context: Context, rh: ResourceHelper, dateUtil: DateUtil): TableRow = override fun toTableRow(context: Context, rh: ResourceHelper, dateUtil: DateUtil): TableRow =
TableRow(context).also { row -> TableRow(context).also { row ->
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f) val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)
row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT)
@ -52,7 +64,7 @@ class TIR(val date: Long, val lowThreshold: Double, val highThreshold: Double) {
} }
@SuppressLint("SetTextI18n") @SuppressLint("SetTextI18n")
fun toTableRow(context: Context, rh: ResourceHelper, days: Int): TableRow = override fun toTableRow(context: Context, rh: ResourceHelper, days: Int): TableRow =
TableRow(context).also { row -> TableRow(context).also { row ->
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f) val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT, 1f)
row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT) row.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT)

View file

@ -23,4 +23,18 @@
<string name="error_asking_for_permissions">Error asking for permissions</string> <string name="error_asking_for_permissions">Error asking for permissions</string>
<string name="alert_dialog_permission_battery_optimization_failed">This device does not appear to support battery optimization whitelisting - you may experience performance issues.</string> <string name="alert_dialog_permission_battery_optimization_failed">This device does not appear to support battery optimization whitelisting - you may experience performance issues.</string>
<!-- Stats -->
<string name="veryLow" comment="below 3.1">Very low</string>
<string name="low" comment="3.1-3.9">Low</string>
<string name="high" comment="10.0-13.9">High</string>
<string name="veryHigh" comment="above 13.9">Very high</string>
<string name="below" comment="below &quot;in range&quot;">Below</string>
<string name="in_range">In range</string>
<string name="above" comment="above &quot;in range&quot;">Above</string>
<string name="hba1c">HbA1c: </string>
<string name="std_deviation">SD: %1$s</string>
<string name="detailed_14_days">Detailed 14 days</string>
<string name="day_tir">Day TIR</string>
<string name="night_tir">Night TIR</string>
</resources> </resources>

View file

@ -17,7 +17,6 @@
<string name="not_inserted">Not inserted</string> <string name="not_inserted">Not inserted</string>
<string name="tdd_bolus">TDD Bolus</string> <string name="tdd_bolus">TDD Bolus</string>
<string name="tdd_basal">TDD Basal</string> <string name="tdd_basal">TDD Basal</string>
<string name="tdd_total">TDD Total</string>
<string name="tbr_formatter">%1$d%% for %2$d / %3$d min</string> <string name="tbr_formatter">%1$d%% for %2$d / %3$d min</string>
<string name="multiwave_bolus">Multiwave bolus</string> <string name="multiwave_bolus">Multiwave bolus</string>
<string name="eb_formatter">%1$.2f / %2$.2f U for %3$d min</string> <string name="eb_formatter">%1$.2f / %2$.2f U for %3$d min</string>

View file

@ -35,6 +35,14 @@
android:name=".activities.ErrorHelperActivity" android:name=".activities.ErrorHelperActivity"
android:exported="false" android:exported="false"
android:theme="@style/Theme.MaterialComponents.Translucent" /> android:theme="@style/Theme.MaterialComponents.Translucent" />
<activity
android:name=".activities.SurveyActivity"
android:exported="false"
android:theme="@style/AppTheme" />
<activity
android:name=".activities.StatsActivity"
android:exported="false"
android:theme="@style/AppTheme" />
</application> </application>

View file

@ -1,20 +1,21 @@
package info.nightscout.androidaps.activities package info.nightscout.ui.activities
import android.annotation.SuppressLint import android.annotation.SuppressLint
import android.os.Bundle import android.os.Bundle
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.database.entities.UserEntry.Action import info.nightscout.androidaps.database.entities.UserEntry.Action
import info.nightscout.androidaps.database.entities.UserEntry.Sources import info.nightscout.androidaps.database.entities.UserEntry.Sources
import info.nightscout.androidaps.databinding.ActivityStatsBinding import info.nightscout.androidaps.interfaces.stats.DexcomTirCalculator
import info.nightscout.androidaps.interfaces.stats.TddCalculator
import info.nightscout.androidaps.interfaces.stats.TirCalculator
import info.nightscout.androidaps.logging.UserEntryLogger import info.nightscout.androidaps.logging.UserEntryLogger
import info.nightscout.androidaps.utils.ActivityMonitor
import info.nightscout.androidaps.utils.FabricPrivacy import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.utils.alertDialogs.OKDialog import info.nightscout.androidaps.utils.alertDialogs.OKDialog
import info.nightscout.androidaps.utils.rx.AapsSchedulers import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.stats.DexcomTirCalculator import info.nightscout.ui.R
import info.nightscout.androidaps.utils.stats.TddCalculator import info.nightscout.ui.databinding.ActivityStatsBinding
import info.nightscout.androidaps.utils.stats.TirCalculator import info.nightscout.ui.utils.ActivityMonitor
import io.reactivex.rxjava3.core.Single import io.reactivex.rxjava3.core.Single
import io.reactivex.rxjava3.disposables.CompositeDisposable import io.reactivex.rxjava3.disposables.CompositeDisposable
import io.reactivex.rxjava3.kotlin.plusAssign import io.reactivex.rxjava3.kotlin.plusAssign
@ -41,7 +42,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
binding.tdds.addView(TextView(this).apply { text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) }) binding.tdds.addView(TextView(this).apply { text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress) })
binding.tir.addView(TextView(this).apply { text = getString(R.string.tir) + ": " + rh.gs(R.string.calculation_in_progress) }) binding.tir.addView(TextView(this).apply { text = getString(R.string.tir) + ": " + rh.gs(R.string.calculation_in_progress) })
binding.activity.addView(TextView(this).apply { text = getString(R.string.activitymonitor) + ": " + rh.gs(R.string.calculation_in_progress) }) binding.activity.addView(TextView(this).apply { text = getString(R.string.activity_monitor) + ": " + rh.gs(R.string.calculation_in_progress) })
disposable += Single.fromCallable { tddCalculator.stats(this) } disposable += Single.fromCallable { tddCalculator.stats(this) }
.subscribeOn(aapsSchedulers.io) .subscribeOn(aapsSchedulers.io)
@ -74,7 +75,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
binding.ok.setOnClickListener { finish() } binding.ok.setOnClickListener { finish() }
binding.reset.setOnClickListener { binding.reset.setOnClickListener {
OKDialog.showConfirmation(this, rh.gs(R.string.doyouwantresetstats)) { OKDialog.showConfirmation(this, rh.gs(R.string.do_you_want_reset_stats)) {
uel.log(Action.STAT_RESET, Sources.Stats) uel.log(Action.STAT_RESET, Sources.Stats)
activityMonitor.reset() activityMonitor.reset()
recreate() recreate()

View file

@ -1,32 +1,29 @@
package info.nightscout.androidaps.activities package info.nightscout.ui.activities
import android.os.Bundle import android.os.Bundle
import android.widget.ArrayAdapter import android.widget.ArrayAdapter
import com.google.firebase.auth.FirebaseAuth import com.google.firebase.auth.FirebaseAuth
import com.google.firebase.database.FirebaseDatabase import com.google.firebase.database.FirebaseDatabase
import info.nightscout.androidaps.R import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
import info.nightscout.androidaps.databinding.ActivitySurveyBinding
import info.nightscout.androidaps.dialogs.ProfileViewerDialog import info.nightscout.androidaps.dialogs.ProfileViewerDialog
import info.nightscout.androidaps.interfaces.ActivePlugin import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.ProfileFunction import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.utils.ActivityMonitor import info.nightscout.androidaps.interfaces.stats.TddCalculator
import info.nightscout.androidaps.utils.DateUtil import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.InstanceId import info.nightscout.androidaps.utils.InstanceId
import info.nightscout.androidaps.utils.ToastUtils import info.nightscout.androidaps.utils.ToastUtils
import info.nightscout.androidaps.utils.defaultProfile.DefaultProfile
import info.nightscout.androidaps.utils.stats.TddCalculator
import info.nightscout.androidaps.utils.stats.TirCalculator
import info.nightscout.shared.SafeParse import info.nightscout.shared.SafeParse
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import info.nightscout.ui.R
import info.nightscout.ui.databinding.ActivitySurveyBinding
import info.nightscout.ui.defaultProfile.DefaultProfile
import javax.inject.Inject import javax.inject.Inject
class SurveyActivity : NoSplashAppCompatActivity() { class SurveyActivity : NoSplashAppCompatActivity() {
@Inject lateinit var activePlugin: ActivePlugin @Inject lateinit var activePlugin: ActivePlugin
@Inject lateinit var tddCalculator: TddCalculator @Inject lateinit var tddCalculator: TddCalculator
@Inject lateinit var tirCalculator: TirCalculator
@Inject lateinit var profileFunction: ProfileFunction @Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var activityMonitor: ActivityMonitor
@Inject lateinit var defaultProfile: DefaultProfile @Inject lateinit var defaultProfile: DefaultProfile
@Inject lateinit var dateUtil: DateUtil @Inject lateinit var dateUtil: DateUtil
@ -43,24 +40,20 @@ class SurveyActivity : NoSplashAppCompatActivity() {
val profileList = profileStore?.getProfileList() ?: return val profileList = profileStore?.getProfileList() ?: return
binding.spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList) binding.spinner.adapter = ArrayAdapter(this, R.layout.spinner_centered, profileList)
//binding.tdds.text = tddCalculator.stats()
//binding.tir.text = tirCalculator.stats()
//binding.activity.text = activityMonitor.stats()
binding.profile.setOnClickListener { binding.profile.setOnClickListener {
val age = SafeParse.stringToDouble(binding.age.text.toString()) val age = SafeParse.stringToDouble(binding.age.text.toString())
val weight = SafeParse.stringToDouble(binding.weight.text.toString()) val weight = SafeParse.stringToDouble(binding.weight.text.toString())
val tdd = SafeParse.stringToDouble(binding.tdd.text.toString()) val tdd = SafeParse.stringToDouble(binding.tdd.text.toString())
if (age < 1 || age > 120) { if (age < 1 || age > 120) {
ToastUtils.warnToast(this, R.string.invalidage) ToastUtils.warnToast(this, R.string.invalid_age)
return@setOnClickListener return@setOnClickListener
} }
if ((weight < 5 || weight > 150) && tdd == 0.0) { if ((weight < 5 || weight > 150) && tdd == 0.0) {
ToastUtils.warnToast(this, R.string.invalidweight) ToastUtils.warnToast(this, R.string.invalid_weight)
return@setOnClickListener return@setOnClickListener
} }
if ((tdd < 5 || tdd > 150) && weight == 0.0) { if ((tdd < 5 || tdd > 150) && weight == 0.0) {
ToastUtils.warnToast(this, R.string.invalidweight) ToastUtils.warnToast(this, R.string.invalid_weight)
return@setOnClickListener return@setOnClickListener
} }
profileFunction.getProfile()?.let { runningProfile -> profileFunction.getProfile()?.let { runningProfile ->
@ -84,11 +77,11 @@ class SurveyActivity : NoSplashAppCompatActivity() {
r.age = SafeParse.stringToInt(binding.age.text.toString()) r.age = SafeParse.stringToInt(binding.age.text.toString())
r.weight = SafeParse.stringToInt(binding.weight.text.toString()) r.weight = SafeParse.stringToInt(binding.weight.text.toString())
if (r.age < 1 || r.age > 120) { if (r.age < 1 || r.age > 120) {
ToastUtils.warnToast(this, R.string.invalidage) ToastUtils.warnToast(this, R.string.invalid_age)
return@setOnClickListener return@setOnClickListener
} }
if (r.weight < 5 || r.weight > 150) { if (r.weight < 5 || r.weight > 150) {
ToastUtils.warnToast(this, R.string.invalidweight) ToastUtils.warnToast(this, R.string.invalid_weight)
return@setOnClickListener return@setOnClickListener
} }

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils.defaultProfile package info.nightscout.ui.defaultProfile
import info.nightscout.androidaps.data.PureProfile import info.nightscout.androidaps.data.PureProfile
import info.nightscout.androidaps.extensions.pureProfileFromJson import info.nightscout.androidaps.extensions.pureProfileFromJson
@ -13,31 +13,32 @@ import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
import kotlin.math.abs import kotlin.math.abs
@Suppress("LocalVariableName")
@Singleton @Singleton
class DefaultProfile @Inject constructor(val dateUtil: DateUtil) { class DefaultProfile @Inject constructor(val dateUtil: DateUtil) {
var oneToFive: TreeMap<Double, Array<Double>> = TreeMap() private var oneToFive: TreeMap<Double, Array<Double>> = TreeMap()
var sixToEleven: TreeMap<Double, Array<Double>> = TreeMap() private var sixToEleven: TreeMap<Double, Array<Double>> = TreeMap()
var twelveToSeventeen: TreeMap<Double, Array<Double>> = TreeMap() private var twelveToSeventeen: TreeMap<Double, Array<Double>> = TreeMap()
var eighteenToTwentyFour: TreeMap<Double, Array<Double>> = TreeMap() @Suppress("unused") var eighteenToTwentyFour: TreeMap<Double, Array<Double>> = TreeMap()
fun profile(age: Double, tdd: Double, weight: Double, units: GlucoseUnit): PureProfile? { fun profile(age: Double, tdd: Double, weight: Double, units: GlucoseUnit): PureProfile? {
val profile = JSONObject() val profile = JSONObject()
if (age >= 1 && age < 6) { if (age in 1.0..5.0) {
val _tdd = if (tdd == 0.0) 0.6 * weight else tdd val _tdd = if (tdd == 0.0) 0.6 * weight else tdd
closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) } closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) }
val ic = Round.roundTo(250.0 / _tdd, 1.0) val ic = Round.roundTo(250.0 / _tdd, 1.0)
profile.put("carbratio", singleValueArray(ic, arrayOf(0.0, -4.0, -1.0, -2.0, -4.0, 0.0, -4.0))) profile.put("carbratio", singleValueArray(ic, arrayOf(0.0, -4.0, -1.0, -2.0, -4.0, 0.0, -4.0)))
val isf = Round.roundTo(200.0 / _tdd, 0.1) val isf = Round.roundTo(200.0 / _tdd, 0.1)
profile.put("sens", singleValueArrayFromMmolToUnits(isf, arrayOf(0.0, -2.0, -0.0, -0.0, -2.0, 0.0, -2.0),units)) profile.put("sens", singleValueArrayFromMmolToUnits(isf, arrayOf(0.0, -2.0, -0.0, -0.0, -2.0, 0.0, -2.0),units))
} else if (age >= 6 && age < 12) { } else if (age in 6.0..11.0) {
val _tdd = if (tdd == 0.0) 0.8 * weight else tdd val _tdd = if (tdd == 0.0) 0.8 * weight else tdd
closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) } closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) }
val ic = Round.roundTo(375.0 / _tdd, 1.0) val ic = Round.roundTo(375.0 / _tdd, 1.0)
profile.put("carbratio", singleValueArray(ic, arrayOf(0.0, -3.0, 0.0, -1.0, -3.0, 0.0, -2.0))) profile.put("carbratio", singleValueArray(ic, arrayOf(0.0, -3.0, 0.0, -1.0, -3.0, 0.0, -2.0)))
val isf = Round.roundTo(170.0 / _tdd, 0.1) val isf = Round.roundTo(170.0 / _tdd, 0.1)
profile.put("sens", singleValueArrayFromMmolToUnits(isf, arrayOf(0.0, -1.0, -0.0, -0.0, -1.0, 0.0, -1.0),units)) profile.put("sens", singleValueArrayFromMmolToUnits(isf, arrayOf(0.0, -1.0, -0.0, -0.0, -1.0, 0.0, -1.0),units))
} else if (age >= 12 && age <= 18) { } else if (age in 12.0..18.0) {
val _tdd = if (tdd == 0.0) 1.0 * weight else tdd val _tdd = if (tdd == 0.0) 1.0 * weight else tdd
closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) } closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) }
val ic = Round.roundTo(500.0 / _tdd, 1.0) val ic = Round.roundTo(500.0 / _tdd, 1.0)

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils.defaultProfile package info.nightscout.ui.defaultProfile
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.PureProfile import info.nightscout.androidaps.data.PureProfile
@ -15,22 +15,22 @@ import javax.inject.Singleton
@Singleton @Singleton
class DefaultProfileDPV @Inject constructor(val injector: HasAndroidInjector, val dateUtil: DateUtil) { class DefaultProfileDPV @Inject constructor(val injector: HasAndroidInjector, val dateUtil: DateUtil) {
var oneToFive = arrayOf(3.97, 3.61, 3.46, 3.70, 3.76, 3.87, 4.18, 4.01, 3.76, 3.54, 3.15, 2.80, 2.86, 3.21, 3.61, 3.97, 4.43, 4.96, 5.10, 5.50, 5.81, 6.14, 5.52, 5.10) private var oneToFive = arrayOf(3.97, 3.61, 3.46, 3.70, 3.76, 3.87, 4.18, 4.01, 3.76, 3.54, 3.15, 2.80, 2.86, 3.21, 3.61, 3.97, 4.43, 4.96, 5.10, 5.50, 5.81, 6.14, 5.52, 5.10)
var sixToEleven = arrayOf(4.20, 4.27, 4.41, 4.62, 4.92, 5.09, 5.01, 4.47, 3.89, 3.33, 3.10, 2.91, 2.97, 3.08, 3.36, 3.93, 4.52, 4.76, 4.69, 4.63, 4.63, 4.47, 4.47, 4.31) private var sixToEleven = arrayOf(4.20, 4.27, 4.41, 4.62, 4.92, 5.09, 5.01, 4.47, 3.89, 3.33, 3.10, 2.91, 2.97, 3.08, 3.36, 3.93, 4.52, 4.76, 4.69, 4.63, 4.63, 4.47, 4.47, 4.31)
var twelveToEighteen = arrayOf(3.47, 3.80, 4.31, 4.95, 5.59, 6.11, 5.89, 5.11, 4.31, 3.78, 3.55, 3.39, 3.35, 3.39, 3.64, 3.97, 4.53, 4.59, 4.50, 4.00, 3.69, 3.39, 3.35, 3.35) private var twelveToEighteen = arrayOf(3.47, 3.80, 4.31, 4.95, 5.59, 6.11, 5.89, 5.11, 4.31, 3.78, 3.55, 3.39, 3.35, 3.39, 3.64, 3.97, 4.53, 4.59, 4.50, 4.00, 3.69, 3.39, 3.35, 3.35)
fun profile(age: Double, tdd: Double, basalSumPct: Double, units: GlucoseUnit): PureProfile? { fun profile(age: Double, tdd: Double, basalSumPct: Double, units: GlucoseUnit): PureProfile? {
val basalSum = tdd * basalSumPct val basalSum = tdd * basalSumPct
val profile = JSONObject() val profile = JSONObject()
if (age >= 1 && age < 6) { if (age in 1.0..5.0) {
profile.put("basal", arrayToJson(oneToFive, basalSum)) profile.put("basal", arrayToJson(oneToFive, basalSum))
profile.put("carbratio", singleValueArray(0.0)) profile.put("carbratio", singleValueArray(0.0))
profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units)) profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units))
} else if (age >= 6 && age < 12) { } else if (age in 6.0..11.0) {
profile.put("basal", arrayToJson(sixToEleven, basalSum)) profile.put("basal", arrayToJson(sixToEleven, basalSum))
profile.put("carbratio", singleValueArray(0.0)) profile.put("carbratio", singleValueArray(0.0))
profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units)) profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units))
} else if (age >= 12 && age <= 18) { } else if (age in 12.0..18.0) {
profile.put("basal", arrayToJson(twelveToEighteen, basalSum)) profile.put("basal", arrayToJson(twelveToEighteen, basalSum))
profile.put("carbratio", singleValueArray(0.0)) profile.put("carbratio", singleValueArray(0.0))
profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units)) profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units))
@ -56,12 +56,14 @@ class DefaultProfileDPV @Inject constructor(val injector: HasAndroidInjector, va
return basals return basals
} }
@Suppress("SameParameterValue")
private fun singleValueArray(value: Double): JSONArray { private fun singleValueArray(value: Double): JSONArray {
val array = JSONArray() val array = JSONArray()
array.put(JSONObject().put("time", "00:00").put("value", value).put("timeAsSeconds", 0 * 3600)) array.put(JSONObject().put("time", "00:00").put("value", value).put("timeAsSeconds", 0 * 3600))
return array return array
} }
@Suppress("SameParameterValue")
private fun singleValueArrayFromMmolToUnits(value: Double, units: GlucoseUnit): JSONArray { private fun singleValueArrayFromMmolToUnits(value: Double, units: GlucoseUnit): JSONArray {
val array = JSONArray() val array = JSONArray()
array.put(JSONObject().put("time", "00:00").put("value", Profile.fromMmolToUnits(value, units)).put("timeAsSeconds", 0 * 3600)) array.put(JSONObject().put("time", "00:00").put("value", Profile.fromMmolToUnits(value, units)).put("timeAsSeconds", 0 * 3600))

View file

@ -2,8 +2,10 @@ package info.nightscout.ui.di
import dagger.Module import dagger.Module
import dagger.android.ContributesAndroidInjector import dagger.android.ContributesAndroidInjector
import info.nightscout.ui.activities.SurveyActivity
import info.nightscout.ui.activities.BolusProgressHelperActivity import info.nightscout.ui.activities.BolusProgressHelperActivity
import info.nightscout.ui.activities.ErrorHelperActivity import info.nightscout.ui.activities.ErrorHelperActivity
import info.nightscout.ui.activities.StatsActivity
import info.nightscout.ui.activities.TDDStatsActivity import info.nightscout.ui.activities.TDDStatsActivity
import info.nightscout.ui.dialogs.CalibrationDialog import info.nightscout.ui.dialogs.CalibrationDialog
import info.nightscout.ui.dialogs.CarbsDialog import info.nightscout.ui.dialogs.CarbsDialog
@ -18,5 +20,7 @@ abstract class UiModule {
@ContributesAndroidInjector abstract fun contributesTDDStatsActivity(): TDDStatsActivity @ContributesAndroidInjector abstract fun contributesTDDStatsActivity(): TDDStatsActivity
@ContributesAndroidInjector abstract fun contributeBolusProgressHelperActivity(): BolusProgressHelperActivity @ContributesAndroidInjector abstract fun contributeBolusProgressHelperActivity(): BolusProgressHelperActivity
@ContributesAndroidInjector abstract fun contributeErrorHelperActivity(): ErrorHelperActivity @ContributesAndroidInjector abstract fun contributeErrorHelperActivity(): ErrorHelperActivity
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
} }

View file

@ -1,4 +1,4 @@
package info.nightscout.androidaps.utils package info.nightscout.ui.utils
import android.app.Activity import android.app.Activity
import android.app.Application import android.app.Application
@ -10,12 +10,14 @@ import android.view.ViewGroup
import android.widget.TableLayout import android.widget.TableLayout
import android.widget.TableRow import android.widget.TableRow
import android.widget.TextView import android.widget.TextView
import info.nightscout.androidaps.R
import info.nightscout.androidaps.interfaces.ResourceHelper import info.nightscout.androidaps.interfaces.ResourceHelper
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import info.nightscout.shared.SafeParse import info.nightscout.shared.SafeParse
import info.nightscout.shared.logging.AAPSLogger import info.nightscout.shared.logging.AAPSLogger
import info.nightscout.shared.logging.LTag import info.nightscout.shared.logging.LTag
import info.nightscout.shared.sharedPreferences.SP import info.nightscout.shared.sharedPreferences.SP
import info.nightscout.ui.R
import javax.inject.Inject import javax.inject.Inject
import javax.inject.Singleton import javax.inject.Singleton
@ -69,7 +71,7 @@ class ActivityMonitor @Inject constructor(
layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f) layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)
layout.addView( layout.addView(
TextView(context).apply { TextView(context).apply {
text = rh.gs(R.string.activitymonitor) text = rh.gs(R.string.activity_monitor)
setTypeface(typeface, Typeface.BOLD) setTypeface(typeface, Typeface.BOLD)
gravity = Gravity.CENTER_HORIZONTAL gravity = Gravity.CENTER_HORIZONTAL
setTextAppearance(android.R.style.TextAppearance_Material_Medium) setTextAppearance(android.R.style.TextAppearance_Material_Medium)

View file

@ -5,7 +5,7 @@
android:layout_width="match_parent" android:layout_width="match_parent"
android:layout_height="match_parent" android:layout_height="match_parent"
android:orientation="vertical" android:orientation="vertical"
tools:context=".activities.StatsActivity"> tools:context="info.nightscout.ui.activities.StatsActivity">
<LinearLayout <LinearLayout
android:layout_width="match_parent" android:layout_width="match_parent"

View file

@ -68,7 +68,7 @@
android:layout_height="match_parent"> android:layout_height="match_parent">
<TextView <TextView
android:id="@+id/weigth_label" android:id="@+id/weight_label"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
@ -124,7 +124,7 @@
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_marginStart="10dp" android:layout_marginStart="10dp"
android:layout_marginEnd="20dp" android:layout_marginEnd="20dp"
android:text="@string/mostcommonprofile" android:text="@string/most_common_profile"
android:textAppearance="@style/TextAppearance.AppCompat.Medium" /> android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
<Spinner <Spinner

View file

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View file

Before

Width:  |  Height:  |  Size: 7.2 KiB

After

Width:  |  Height:  |  Size: 7.2 KiB

View file

Before

Width:  |  Height:  |  Size: 4.7 KiB

After

Width:  |  Height:  |  Size: 4.7 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 4.1 KiB

After

Width:  |  Height:  |  Size: 4.1 KiB

View file

Before

Width:  |  Height:  |  Size: 3.1 KiB

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 7.4 KiB

After

Width:  |  Height:  |  Size: 7.4 KiB

View file

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View file

Before

Width:  |  Height:  |  Size: 7 KiB

After

Width:  |  Height:  |  Size: 7 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 12 KiB

After

Width:  |  Height:  |  Size: 12 KiB

View file

Before

Width:  |  Height:  |  Size: 17 KiB

After

Width:  |  Height:  |  Size: 17 KiB

View file

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 18 KiB

After

Width:  |  Height:  |  Size: 18 KiB

View file

Before

Width:  |  Height:  |  Size: 26 KiB

After

Width:  |  Height:  |  Size: 26 KiB

View file

Before

Width:  |  Height:  |  Size: 20 KiB

After

Width:  |  Height:  |  Size: 20 KiB

View file

@ -19,4 +19,21 @@
<string name="configure">Configure opacity</string> <string name="configure">Configure opacity</string>
<string name="widget_description">AAPS widget</string> <string name="widget_description">AAPS widget</string>
<!-- Activities-->
<string name="activity_monitor">Activity monitor</string>
<string name="do_you_want_reset_stats">Do you want to reset activity stats?</string>
<string name="statistics">Statistics</string>
<string name="calculation_in_progress">Calculation in progress</string>
<string name="invalid_age">Invalid age entry</string>
<string name="invalid_weight">Invalid weight entry</string>
<string name="reset">reset</string>
<string name="id">ID:</string>
<string name="submit">Submit</string>
<string name="profile">Profile</string>
<string name="age">Age</string>
<string name="weight_label">Weight</string>
<string name="most_common_profile">Most common profile:</string>
<string name="survey_comment">Note: Only data visible on this screen will be anonymously uploaded. ID is assigned to this installation of AAPS. You can submit data again if your main profile get changed but let it running at least for a week to make result visible in time in range. Your help is appreciated.</string>
</resources> </resources>

View file

@ -0,0 +1,39 @@
package info.nightscout.androidaps
import info.nightscout.shared.logging.AAPSLoggerTest
import info.nightscout.androidaps.utils.rx.AapsSchedulers
import info.nightscout.androidaps.utils.rx.TestAapsSchedulers
import org.junit.Before
import org.junit.Rule
import org.mockito.Mockito
import org.mockito.junit.MockitoJUnit
import org.mockito.junit.MockitoRule
import java.util.*
open class TestBase {
val aapsLogger = AAPSLoggerTest()
val aapsSchedulers: AapsSchedulers = TestAapsSchedulers()
// Add a JUnit rule that will setup the @Mock annotated vars and log.
// Another possibility would be to add `MockitoAnnotations.initMocks(this) to the setup method.
@get:Rule
val mockitoRule: MockitoRule = MockitoJUnit.rule()
@Before
fun setupLocale() {
Locale.setDefault(Locale.ENGLISH)
System.setProperty("disableFirebase", "true")
}
// Workaround for Kotlin nullability.
// https://medium.com/@elye.project/befriending-kotlin-and-mockito-1c2e7b0ef791
// https://stackoverflow.com/questions/30305217/is-it-possible-to-use-mockito-in-kotlin
fun <T> anyObject(): T {
Mockito.any<T>()
return uninitialized()
}
@Suppress("Unchecked_Cast")
fun <T> uninitialized(): T = null as T
}

View file

@ -0,0 +1,177 @@
package info.nightscout.androidaps
import android.content.Context
import dagger.android.AndroidInjector
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.database.embedments.InsulinConfiguration
import info.nightscout.androidaps.database.entities.EffectiveProfileSwitch
import info.nightscout.androidaps.extensions.pureProfileFromJson
import info.nightscout.androidaps.interfaces.ActivePlugin
import info.nightscout.androidaps.interfaces.Config
import info.nightscout.androidaps.interfaces.IobCobCalculator
import info.nightscout.androidaps.interfaces.ProfileFunction
import info.nightscout.androidaps.interfaces.ProfileStore
import info.nightscout.androidaps.plugins.bus.RxBus
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.FabricPrivacy
import info.nightscout.androidaps.interfaces.ResourceHelper
import org.json.JSONObject
import org.junit.Before
import org.mockito.ArgumentMatchers.anyDouble
import org.mockito.ArgumentMatchers.anyInt
import org.mockito.ArgumentMatchers.anyString
import org.mockito.Mock
import org.mockito.Mockito
import org.mockito.Mockito.`when`
import org.mockito.invocation.InvocationOnMock
@Suppress("SpellCheckingInspection")
open class TestBaseWithProfile : TestBase() {
@Mock lateinit var activePluginProvider: ActivePlugin
@Mock lateinit var rh: ResourceHelper
@Mock lateinit var iobCobCalculator: IobCobCalculator
@Mock lateinit var fabricPrivacy: FabricPrivacy
@Mock lateinit var profileFunction: ProfileFunction
@Mock lateinit var config: Config
@Mock lateinit var context: Context
lateinit var dateUtil: DateUtil
val rxBus = RxBus(aapsSchedulers, aapsLogger)
val profileInjector = HasAndroidInjector { AndroidInjector { } }
private lateinit var validProfileJSON: String
lateinit var validProfile: ProfileSealed.Pure
lateinit var effectiveProfileSwitch: EffectiveProfileSwitch
@Suppress("PropertyName") val TESTPROFILENAME = "someProfile"
@Before
fun prepareMock() {
validProfileJSON = "{\"dia\":\"5\",\"carbratio\":[{\"time\":\"00:00\",\"value\":\"30\"}],\"carbs_hr\":\"20\",\"delay\":\"20\",\"sens\":[{\"time\":\"00:00\",\"value\":\"3\"}," +
"{\"time\":\"2:00\",\"value\":\"3.4\"}],\"timezone\":\"UTC\",\"basal\":[{\"time\":\"00:00\",\"value\":\"1\"}],\"target_low\":[{\"time\":\"00:00\",\"value\":\"4.5\"}]," +
"\"target_high\":[{\"time\":\"00:00\",\"value\":\"7\"}],\"startDate\":\"1970-01-01T00:00:00.000Z\",\"units\":\"mmol\"}"
dateUtil = Mockito.spy(DateUtil(context))
`when`(dateUtil.now()).thenReturn(1656358822000)
validProfile = ProfileSealed.Pure(pureProfileFromJson(JSONObject(validProfileJSON), dateUtil)!!)
effectiveProfileSwitch = EffectiveProfileSwitch(
timestamp = dateUtil.now(),
basalBlocks = validProfile.basalBlocks,
isfBlocks = validProfile.isfBlocks,
icBlocks = validProfile.icBlocks,
targetBlocks = validProfile.targetBlocks,
glucoseUnit = EffectiveProfileSwitch.GlucoseUnit.MMOL,
originalProfileName = "",
originalCustomizedName = "",
originalTimeshift = 0,
originalPercentage = 100,
originalDuration = 0,
originalEnd = 0,
insulinConfiguration = InsulinConfiguration("", 0, 0)
)
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Int?>(1)
String.format(rh.gs(string), arg1)
}.`when`(rh).gs(anyInt(), anyInt())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Double?>(1)
String.format(rh.gs(string), arg1)
}.`when`(rh).gs(anyInt(), anyDouble())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<String?>(1)
String.format(rh.gs(string), arg1)
}.`when`(rh).gs(anyInt(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<String?>(1)
val arg2 = invocation.getArgument<String?>(2)
String.format(rh.gs(string), arg1, arg2)
}.`when`(rh).gs(anyInt(), anyString(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<String?>(1)
val arg2 = invocation.getArgument<Int?>(2)
String.format(rh.gs(string), arg1, arg2)
}.`when`(rh).gs(anyInt(), anyString(), anyInt())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Double?>(1)
val arg2 = invocation.getArgument<String?>(2)
String.format(rh.gs(string), arg1, arg2)
}.`when`(rh).gs(anyInt(), anyDouble(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Double?>(1)
val arg2 = invocation.getArgument<Int?>(2)
String.format(rh.gs(string), arg1, arg2)
}.`when`(rh).gs(anyInt(), anyDouble(), anyInt())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Int?>(1)
val arg2 = invocation.getArgument<Int?>(2)
String.format(rh.gs(string), arg1, arg2)
}.`when`(rh).gs(anyInt(), anyInt(), anyInt())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Int?>(1)
val arg2 = invocation.getArgument<String?>(2)
String.format(rh.gs(string), arg1, arg2)
}.`when`(rh).gs(anyInt(), anyInt(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Int?>(1)
val arg2 = invocation.getArgument<Int?>(2)
val arg3 = invocation.getArgument<String?>(3)
String.format(rh.gs(string), arg1, arg2, arg3)
}.`when`(rh).gs(anyInt(), anyInt(), anyInt(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Int?>(1)
val arg2 = invocation.getArgument<String?>(2)
val arg3 = invocation.getArgument<String?>(3)
String.format(rh.gs(string), arg1, arg2, arg3)
}.`when`(rh).gs(anyInt(), anyInt(), anyString(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<Double?>(1)
val arg2 = invocation.getArgument<Int?>(2)
val arg3 = invocation.getArgument<String?>(3)
String.format(rh.gs(string), arg1, arg2, arg3)
}.`when`(rh).gs(anyInt(), anyDouble(), anyInt(), anyString())
Mockito.doAnswer { invocation: InvocationOnMock ->
val string = invocation.getArgument<Int>(0)
val arg1 = invocation.getArgument<String?>(1)
val arg2 = invocation.getArgument<Int?>(2)
val arg3 = invocation.getArgument<String?>(3)
String.format(rh.gs(string), arg1, arg2, arg3)
}.`when`(rh).gs(anyInt(), anyString(), anyInt(), anyString())
}
fun getValidProfileStore(): ProfileStore {
val json = JSONObject()
val store = JSONObject()
store.put(TESTPROFILENAME, JSONObject(validProfileJSON))
json.put("defaultProfile", TESTPROFILENAME)
json.put("store", store)
return ProfileStore(profileInjector, json, dateUtil)
}
}

View file

@ -0,0 +1,68 @@
package info.nightscout.androidaps
import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.data.DetailedBolusInfo
import info.nightscout.androidaps.interfaces.Profile
import info.nightscout.androidaps.data.PumpEnactResult
import info.nightscout.androidaps.interfaces.PumpDescription
import info.nightscout.androidaps.interfaces.Pump
import info.nightscout.androidaps.interfaces.PumpSync
import info.nightscout.androidaps.plugins.common.ManufacturerType
import info.nightscout.androidaps.plugins.pump.common.defs.PumpType
import info.nightscout.androidaps.utils.TimeChangeType
import org.json.JSONObject
@Suppress("MemberVisibilityCanBePrivate")
class TestPumpPlugin(val injector: HasAndroidInjector) : Pump {
var connected = false
var isProfileSet = true
override fun isConnected() = connected
override fun isConnecting() = false
override fun isHandshakeInProgress() = false
val lastData = 0L
val baseBasal = 0.0
override val pumpDescription = PumpDescription()
override fun isInitialized(): Boolean = true
override fun isSuspended(): Boolean = false
override fun isBusy(): Boolean = false
override fun connect(reason: String) {
connected = true
}
override fun disconnect(reason: String) {
connected = false
}
override fun stopConnecting() {
connected = false
}
override fun waitForDisconnectionInSeconds(): Int = 0
override fun getPumpStatus(reason: String) {}
override fun setNewBasalProfile(profile: Profile): PumpEnactResult = PumpEnactResult(injector)
override fun isThisProfileSet(profile: Profile): Boolean = isProfileSet
override fun lastDataTime(): Long = lastData
override val baseBasalRate: Double = baseBasal
override val reservoirLevel: Double = 0.0
override val batteryLevel: Int = 0
override fun deliverTreatment(detailedBolusInfo: DetailedBolusInfo): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun stopBolusDelivering() {}
override fun setTempBasalAbsolute(absoluteRate: Double, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun setTempBasalPercent(percent: Int, durationInMinutes: Int, profile: Profile, enforceNew: Boolean, tbrType: PumpSync.TemporaryBasalType): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun setExtendedBolus(insulin: Double, durationInMinutes: Int): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun cancelTempBasal(enforceNew: Boolean): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun cancelExtendedBolus(): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun getJSONStatus(profile: Profile, profileName: String, version: String): JSONObject = JSONObject()
override fun manufacturer(): ManufacturerType = ManufacturerType.AAPS
override fun model(): PumpType = PumpType.GENERIC_AAPS
override fun serialNumber(): String = "1"
override fun shortStatus(veryShort: Boolean): String = ""
override val isFakingTempsByExtendedBoluses: Boolean = false
override fun loadTDDs(): PumpEnactResult = PumpEnactResult(injector).success(true)
override fun canHandleDST(): Boolean = true
override fun timezoneOrDSTChanged(timeChangeType: TimeChangeType) {}
}

View file

@ -1,8 +1,8 @@
package info.nightscout.androidaps.utils.defaultProfile package info.nightscout.ui.defaultProfile
import info.nightscout.androidaps.TestBaseWithProfile
import info.nightscout.androidaps.data.ProfileSealed import info.nightscout.androidaps.data.ProfileSealed
import info.nightscout.androidaps.interfaces.GlucoseUnit import info.nightscout.androidaps.interfaces.GlucoseUnit
import info.nightscout.androidaps.TestBaseWithProfile
import org.junit.Assert.assertEquals import org.junit.Assert.assertEquals
import org.junit.Test import org.junit.Test