migrate out of app module
|
@ -90,18 +90,10 @@
|
|||
android:name=".activities.TreatmentsActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity
|
||||
android:name=".activities.SurveyActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity
|
||||
android:name=".activities.ProfileHelperActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme" />
|
||||
<activity
|
||||
android:name=".activities.StatsActivity"
|
||||
android:exported="false"
|
||||
android:theme="@style/AppTheme" />
|
||||
|
||||
<!-- Receive new BG readings from other local apps -->
|
||||
<receiver
|
||||
|
@ -212,7 +204,7 @@
|
|||
android:name=".plugins.general.maintenance.activities.LogSettingActivity"
|
||||
android:exported="false" />
|
||||
<activity
|
||||
android:name=".activities.RequestDexcomPermissionActivity"
|
||||
android:name=".plugins.source.activities.RequestDexcomPermissionActivity"
|
||||
android:exported="false" />
|
||||
|
||||
<uses-library
|
||||
|
|
|
@ -30,7 +30,12 @@ import com.google.android.material.tabs.TabLayoutMediator
|
|||
import com.google.firebase.crashlytics.FirebaseCrashlytics
|
||||
import com.joanzapata.iconify.Iconify
|
||||
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.Sources
|
||||
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.EventPreferenceChange
|
||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||
import info.nightscout.androidaps.interfaces.*
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
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.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.versionChecker.VersionCheckerUtils
|
||||
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.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.ui.activities.StatsActivity
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
import java.util.*
|
||||
import java.util.Locale
|
||||
import javax.inject.Inject
|
||||
import kotlin.system.exitProcess
|
||||
|
||||
|
|
|
@ -41,13 +41,13 @@ import info.nightscout.androidaps.receivers.KeepAliveWorker
|
|||
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
|
||||
import info.nightscout.androidaps.receivers.TimeDateOrTZChangeReceiver
|
||||
import info.nightscout.androidaps.services.AlarmSoundServiceHelper
|
||||
import info.nightscout.androidaps.utils.ActivityMonitor
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.ProcessLifecycleListener
|
||||
import info.nightscout.androidaps.utils.locale.LocaleHelper
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.ui.utils.ActivityMonitor
|
||||
import info.nightscout.ui.widget.Widget
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.exceptions.UndeliverableException
|
||||
|
@ -55,7 +55,6 @@ import io.reactivex.rxjava3.kotlin.plusAssign
|
|||
import io.reactivex.rxjava3.plugins.RxJavaPlugins
|
||||
import rxdogtag2.RxDogTag
|
||||
import java.io.IOException
|
||||
import java.net.SocketException
|
||||
import java.util.concurrent.TimeUnit
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Provider
|
||||
|
@ -76,7 +75,7 @@ class MainApp : DaggerApplication() {
|
|||
@Inject lateinit var compatDBHelper: CompatDBHelper
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@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 alarmSoundServiceHelper: AlarmSoundServiceHelper
|
||||
@Inject lateinit var notificationStore: NotificationStore
|
||||
|
@ -166,7 +165,7 @@ class MainApp : DaggerApplication() {
|
|||
if (e is UndeliverableException) {
|
||||
e = e.cause!!
|
||||
}
|
||||
if (e is IOException || e is SocketException) {
|
||||
if (e is IOException) {
|
||||
// fine, irrelevant network problem or API that throws on cancellation
|
||||
return@setErrorHandler
|
||||
}
|
||||
|
|
|
@ -25,10 +25,10 @@ import info.nightscout.androidaps.utils.FabricPrivacy
|
|||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.defaultProfile.DefaultProfile
|
||||
import info.nightscout.androidaps.utils.defaultProfile.DefaultProfileDPV
|
||||
import info.nightscout.ui.defaultProfile.DefaultProfile
|
||||
import info.nightscout.ui.defaultProfile.DefaultProfileDPV
|
||||
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.disposables.CompositeDisposable
|
||||
import io.reactivex.rxjava3.kotlin.plusAssign
|
||||
|
@ -183,25 +183,25 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
|
|||
for (i in 0..1) {
|
||||
if (typeSelected[i] == ProfileType.MOTOL_DEFAULT) {
|
||||
if (ageUsed[i] < 1 || ageUsed[i] > 18) {
|
||||
ToastUtils.warnToast(this, R.string.invalidage)
|
||||
ToastUtils.warnToast(this, R.string.invalid_age)
|
||||
return@setOnClickListener
|
||||
}
|
||||
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
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
if (typeSelected[i] == ProfileType.DPV_DEFAULT) {
|
||||
if (ageUsed[i] < 1 || ageUsed[i] > 18) {
|
||||
ToastUtils.warnToast(this, R.string.invalidage)
|
||||
ToastUtils.warnToast(this, R.string.invalid_age)
|
||||
return@setOnClickListener
|
||||
}
|
||||
if (tddUsed[i] < 5 || tddUsed[i] > 150) {
|
||||
ToastUtils.warnToast(this, R.string.invalidweight)
|
||||
ToastUtils.warnToast(this, R.string.invalid_weight)
|
||||
return@setOnClickListener
|
||||
}
|
||||
if ((pctUsed[i] < 32 || pctUsed[i] > 37)) {
|
||||
|
|
|
@ -3,10 +3,14 @@ package info.nightscout.androidaps.di
|
|||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.androidaps.MainActivity
|
||||
import info.nightscout.androidaps.activities.*
|
||||
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.overview.activities.QuickWizardListActivity
|
||||
import info.nightscout.androidaps.plugins.source.activities.RequestDexcomPermissionActivity
|
||||
import info.nightscout.androidaps.setupwizard.SetupWizardActivity
|
||||
|
||||
@Module
|
||||
|
@ -22,8 +26,6 @@ abstract class ActivitiesModule {
|
|||
@ContributesAndroidInjector abstract fun contributesRequestDexcomPermissionActivity(): RequestDexcomPermissionActivity
|
||||
@ContributesAndroidInjector abstract fun contributesSetupWizardActivity(): SetupWizardActivity
|
||||
@ContributesAndroidInjector abstract fun contributesSingleFragmentActivity(): SingleFragmentActivity
|
||||
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
|
||||
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
|
||||
@ContributesAndroidInjector abstract fun contributesDefaultProfileActivity(): ProfileHelperActivity
|
||||
|
||||
}
|
|
@ -34,6 +34,9 @@ import info.nightscout.androidaps.interfaces.ResourceHelper
|
|||
import info.nightscout.androidaps.interfaces.SmsCommunicator
|
||||
import info.nightscout.androidaps.interfaces.TrendCalculator
|
||||
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.bus.RxBus
|
||||
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.constraints.ConstraintsImpl
|
||||
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.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Suppress("unused")
|
||||
@Module(includes = [
|
||||
@Module(
|
||||
includes = [
|
||||
AppModule.AppBindings::class
|
||||
])
|
||||
]
|
||||
)
|
||||
open class AppModule {
|
||||
|
||||
@Provides
|
||||
fun providesPlugins(config: Config, buildHelper: BuildHelper,
|
||||
fun providesPlugins(
|
||||
config: Config, buildHelper: BuildHelper,
|
||||
@PluginsModule.AllConfigs allConfigs: Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>,
|
||||
@PluginsModule.PumpDriver pumpDrivers: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
|
||||
@PluginsModule.NotNSClient notNsClient: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
|
||||
@PluginsModule.APS aps: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>,
|
||||
@PluginsModule.Unfinished unfinished: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>)
|
||||
@PluginsModule.Unfinished unfinished: Lazy<Map<@JvmSuppressWildcards Int, @JvmSuppressWildcards PluginBase>>
|
||||
)
|
||||
: List<@JvmSuppressWildcards PluginBase> {
|
||||
val plugins = allConfigs.toMutableMap()
|
||||
if (config.PUMPDRIVERS) plugins += pumpDrivers.get()
|
||||
|
@ -120,6 +130,7 @@ open class AppModule {
|
|||
@Provides
|
||||
@Singleton
|
||||
internal fun provideConstraints(activePlugin: ActivePlugin): Constraints = ConstraintsImpl(activePlugin)
|
||||
|
||||
@Module
|
||||
interface AppBindings {
|
||||
|
||||
|
@ -146,6 +157,9 @@ open class AppModule {
|
|||
@Binds fun bindLocalAlertUtilsInterface(localAlertUtils: LocalAlertUtilsImpl): LocalAlertUtils
|
||||
@Binds fun bindActivityNamesInterface(activityNames: ActivityNamesImpl): ActivityNames
|
||||
@Binds fun bindTrendCalculatorInterface(trendCalculator: TrendCalculatorImpl): TrendCalculator
|
||||
@Binds fun bindTddCalculatorInterface(tddCalculator: TddCalculatorImpl): TddCalculator
|
||||
@Binds fun bindTirCalculatorInterface(tirCalculator: TirCalculatorImpl): TirCalculator
|
||||
@Binds fun bindDexcomTirCalculatorInterface(dexcomTirCalculator: DexcomTirCalculatorImpl): DexcomTirCalculator
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,7 +23,7 @@ import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
|
|||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
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.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
|
|
|
@ -9,7 +9,7 @@ import androidx.work.WorkerParameters
|
|||
import androidx.work.workDataOf
|
||||
import dagger.android.HasAndroidInjector
|
||||
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.entities.GlucoseValue
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
|
|
|
@ -1,11 +1,10 @@
|
|||
package info.nightscout.androidaps.activities
|
||||
package info.nightscout.androidaps.plugins.source.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import info.nightscout.androidaps.activities.DialogAppCompatActivity
|
||||
import info.nightscout.androidaps.plugins.source.DexcomPlugin
|
||||
import javax.inject.Inject
|
||||
|
||||
class RequestDexcomPermissionActivity : DialogAppCompatActivity() {
|
||||
@Inject lateinit var dexcomPlugin: DexcomPlugin
|
||||
|
||||
private val requestCode = "AndroidAPS <3".map { it.code }.sum()
|
||||
|
|
@ -253,7 +253,6 @@
|
|||
<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_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 that’s 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_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="food_short">Food</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="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>
|
||||
|
@ -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="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="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="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="description_source_randombg">Generate random BG data (Demo mode only)</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="ns_receive_cgm">Receive/backfill CGM data</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="error_in_ic_values">Error in IC 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="count_selected">%1$d selected</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 "in range"">Below</string>
|
||||
<string name="in_range">In range</string>
|
||||
<string name="above" comment="above "in range"">Above</string>
|
||||
<string name="show_loop_records">Show loop records</string>
|
||||
<string name="show_hide_records">Hide loop records</string>
|
||||
<string name="loop_status">Loop status</string>
|
||||
|
|
|
@ -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)
|
||||
}
|
||||
|
||||
*/
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -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
|
||||
}
|
|
@ -225,6 +225,9 @@
|
|||
<string name="a11y_high">high</string>
|
||||
<string name="a11y_inrange">in range</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-->
|
||||
<string name="limitingbasalratio">Limiting max basal rate to %1$.2f U/h because of %2$s</string>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.utils.stats
|
||||
package info.nightscout.implementation.stats
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
|
@ -7,6 +7,8 @@ import android.widget.TableLayout
|
|||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
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.MidnightTime
|
||||
import info.nightscout.androidaps.utils.T
|
||||
|
@ -14,26 +16,27 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class DexcomTirCalculator @Inject constructor(
|
||||
class DexcomTirCalculatorImpl @Inject constructor(
|
||||
private val rh: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val dateUtil: DateUtil,
|
||||
private val repository: AppRepository
|
||||
) {
|
||||
) : DexcomTirCalculator {
|
||||
|
||||
val days = 14L
|
||||
|
||||
fun calculate(): DexcomTIR {
|
||||
override fun calculate(): DexcomTIR {
|
||||
val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
|
||||
val endTime = MidnightTime.calc(dateUtil.now())
|
||||
|
||||
val bgReadings = repository.compatGetBgReadingsDataFromTime(startTime, endTime, true).blockingGet()
|
||||
val result = DexcomTIR()
|
||||
val result = DexcomTirImpl()
|
||||
for (bg in bgReadings) result.add(bg.timestamp, bg.value)
|
||||
return result
|
||||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun stats(context: Context): TableLayout =
|
||||
override fun stats(context: Context): TableLayout =
|
||||
TableLayout(context).also { layout ->
|
||||
val tir = calculate()
|
||||
layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.utils.stats
|
||||
package info.nightscout.implementation.stats
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
|
@ -7,16 +7,17 @@ import android.view.Gravity
|
|||
import android.widget.TableRow
|
||||
import android.widget.TextView
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.androidaps.interfaces.stats.DexcomTIR
|
||||
import info.nightscout.implementation.R
|
||||
import java.util.*
|
||||
import kotlin.math.pow
|
||||
import kotlin.math.roundToInt
|
||||
import kotlin.math.sqrt
|
||||
|
||||
class DexcomTIR {
|
||||
class DexcomTirImpl : DexcomTIR {
|
||||
|
||||
private var veryLow = 0
|
||||
private var low = 0
|
||||
|
@ -26,7 +27,7 @@ class DexcomTIR {
|
|||
private var error = 0
|
||||
private var count = 0
|
||||
|
||||
var sum = 0.0
|
||||
private var sum = 0.0
|
||||
val values = mutableListOf<Double>()
|
||||
|
||||
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 mean() = sum / count
|
||||
|
||||
fun calculateSD(): Double {
|
||||
override fun calculateSD(): Double {
|
||||
if (count == 0) return 0.0
|
||||
var standardDeviation = 0.0
|
||||
for (num in values) standardDeviation += (num - mean()).pow(2.0)
|
||||
return sqrt(standardDeviation / count)
|
||||
}
|
||||
|
||||
fun toHbA1cView(context: Context, rh: ResourceHelper): TextView =
|
||||
override fun toHbA1cView(context: Context, rh: ResourceHelper): TextView =
|
||||
TextView(context).apply {
|
||||
text =
|
||||
if (count == 0) ""
|
||||
|
@ -86,7 +87,7 @@ class DexcomTIR {
|
|||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun toSDView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView =
|
||||
override fun toSDView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView =
|
||||
TextView(context).apply {
|
||||
val sd = calculateSD()
|
||||
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
|
||||
}
|
||||
|
||||
fun toRangeHeaderView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView =
|
||||
override fun toRangeHeaderView(context: Context, rh: ResourceHelper, profileFunction: ProfileFunction): TextView =
|
||||
TextView(context).apply {
|
||||
text = StringBuilder()
|
||||
.append(rh.gs(R.string.detailed_14_days))
|
||||
|
@ -129,7 +130,7 @@ class DexcomTIR {
|
|||
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 ->
|
||||
val lp = TableRow.LayoutParams(TableRow.LayoutParams.WRAP_CONTENT, TableRow.LayoutParams.WRAP_CONTENT)
|
||||
header.layoutParams = TableRow.LayoutParams(TableRow.LayoutParams.MATCH_PARENT, TableRow.LayoutParams.WRAP_CONTENT)
|
||||
|
@ -142,7 +143,7 @@ class DexcomTIR {
|
|||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun toTableRow(context: Context, rh: ResourceHelper): TableRow =
|
||||
override fun toTableRow(context: Context, rh: ResourceHelper): TableRow =
|
||||
TableRow(context).also { row ->
|
||||
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)
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.utils.stats
|
||||
package info.nightscout.implementation.stats
|
||||
|
||||
import android.content.Context
|
||||
import android.graphics.Typeface
|
||||
|
@ -8,27 +8,29 @@ import android.view.ViewGroup
|
|||
import android.widget.TableLayout
|
||||
import android.widget.TableRow
|
||||
import android.widget.TextView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.ValueWrapper
|
||||
import info.nightscout.androidaps.database.embedments.InterfaceIDs
|
||||
import info.nightscout.androidaps.database.entities.Bolus
|
||||
import info.nightscout.androidaps.database.entities.TotalDailyDose
|
||||
import info.nightscout.androidaps.extensions.convertedToAbsolute
|
||||
import info.nightscout.androidaps.extensions.toTableRow
|
||||
import info.nightscout.androidaps.extensions.toTableRowHeader
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
import info.nightscout.androidaps.interfaces.IobCobCalculator
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.androidaps.interfaces.stats.TddCalculator
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.MidnightTime
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.implementation.R
|
||||
import info.nightscout.shared.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
class TddCalculator @Inject constructor(
|
||||
@Singleton
|
||||
class TddCalculatorImpl @Inject constructor(
|
||||
private val aapsLogger: AAPSLogger,
|
||||
private val rh: ResourceHelper,
|
||||
private val activePlugin: ActivePlugin,
|
||||
|
@ -36,9 +38,9 @@ class TddCalculator @Inject constructor(
|
|||
private val dateUtil: DateUtil,
|
||||
private val iobCobCalculator: IobCobCalculator,
|
||||
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())
|
||||
val endTime = MidnightTime.calc(dateUtil.now())
|
||||
val stepSize = T.hours(24).msecs()
|
||||
|
@ -69,19 +71,19 @@ class TddCalculator @Inject constructor(
|
|||
return result
|
||||
}
|
||||
|
||||
fun calculateToday(): TotalDailyDose {
|
||||
override fun calculateToday(): TotalDailyDose {
|
||||
val startTime = MidnightTime.calc(dateUtil.now())
|
||||
val endTime = dateUtil.now()
|
||||
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 endTime = dateUtil.now() + T.hours(hour = endHours).msecs()
|
||||
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 endTimeAligned = endTime - endTime % (5 * 60 * 1000)
|
||||
val tdd = TotalDailyDose(timestamp = startTimeAligned)
|
||||
|
@ -112,7 +114,7 @@ class TddCalculator @Inject constructor(
|
|||
return tdd
|
||||
}
|
||||
|
||||
fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose? {
|
||||
override fun averageTDD(tdds: LongSparseArray<TotalDailyDose>): TotalDailyDose? {
|
||||
val totalTdd = TotalDailyDose(timestamp = dateUtil.now())
|
||||
if (tdds.size() == 0) return null
|
||||
for (i in 0 until tdds.size()) {
|
||||
|
@ -129,7 +131,7 @@ class TddCalculator @Inject constructor(
|
|||
return totalTdd
|
||||
}
|
||||
|
||||
fun stats(context: Context): TableLayout {
|
||||
override fun stats(context: Context): TableLayout {
|
||||
val tdds = calculate(7)
|
||||
val averageTdd = averageTDD(tdds)
|
||||
val todayTdd = calculateToday()
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.utils.stats
|
||||
package info.nightscout.implementation.stats
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
|
@ -9,26 +9,28 @@ import android.view.ViewGroup
|
|||
import android.widget.TableLayout
|
||||
import android.widget.TextView
|
||||
import info.nightscout.androidaps.Constants
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.interfaces.Profile
|
||||
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.MidnightTime
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.interfaces.ResourceHelper
|
||||
import info.nightscout.implementation.R
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
@Singleton
|
||||
class TirCalculator @Inject constructor(
|
||||
class TirCalculatorImpl @Inject constructor(
|
||||
private val rh: ResourceHelper,
|
||||
private val profileFunction: ProfileFunction,
|
||||
private val dateUtil: DateUtil,
|
||||
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 > highMgdl) throw RuntimeException("Low > High")
|
||||
val startTime = MidnightTime.calc(dateUtil.now() - T.days(days).msecs())
|
||||
|
@ -40,7 +42,7 @@ class TirCalculator @Inject constructor(
|
|||
val midnight = MidnightTime.calc(bg.timestamp)
|
||||
var tir = result[midnight]
|
||||
if (tir == null) {
|
||||
tir = TIR(midnight, lowMgdl, highMgdl)
|
||||
tir = TirImpl(midnight, lowMgdl, highMgdl)
|
||||
result.append(midnight, tir)
|
||||
}
|
||||
if (bg.value < 39) tir.error()
|
||||
|
@ -53,9 +55,9 @@ class TirCalculator @Inject constructor(
|
|||
|
||||
private fun averageTIR(tirs: LongSparseArray<TIR>): TIR {
|
||||
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 {
|
||||
TIR(7, 70.0, 180.0)
|
||||
TirImpl(7, 70.0, 180.0)
|
||||
}
|
||||
for (i in 0 until tirs.size()) {
|
||||
val tir = tirs.valueAt(i)
|
||||
|
@ -69,7 +71,7 @@ class TirCalculator @Inject constructor(
|
|||
}
|
||||
|
||||
@SuppressLint("SetTextI18n")
|
||||
fun stats(context: Context): TableLayout =
|
||||
override fun stats(context: Context): TableLayout =
|
||||
TableLayout(context).also { layout ->
|
||||
val lowTirMgdl = Constants.STATS_RANGE_LOW_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
|
||||
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))
|
||||
layout.addView(
|
||||
TextView(context).apply {
|
|
@ -1,26 +1,38 @@
|
|||
package info.nightscout.androidaps.utils.stats
|
||||
package info.nightscout.implementation.stats
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.Context
|
||||
import android.view.Gravity
|
||||
import android.widget.TableRow
|
||||
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.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
|
||||
internal var inRange = 0
|
||||
internal var above = 0
|
||||
internal var error = 0
|
||||
internal var count = 0
|
||||
override var below = 0
|
||||
override var inRange = 0
|
||||
override var above = 0
|
||||
override var error = 0
|
||||
override var count = 0
|
||||
|
||||
fun error() = run { error++ }
|
||||
fun below() = run { below++; count++ }
|
||||
fun inRange() = run { inRange++; count++ }
|
||||
fun above() = run { above++; count++ }
|
||||
override fun error() {
|
||||
error++
|
||||
}
|
||||
|
||||
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 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 ->
|
||||
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)
|
||||
|
@ -52,7 +64,7 @@ class TIR(val date: Long, val lowThreshold: Double, val highThreshold: Double) {
|
|||
}
|
||||
|
||||
@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 ->
|
||||
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)
|
|
@ -23,4 +23,18 @@
|
|||
<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>
|
||||
|
||||
<!-- 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 "in range"">Below</string>
|
||||
<string name="in_range">In range</string>
|
||||
<string name="above" comment="above "in range"">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>
|
||||
|
|
|
@ -17,7 +17,6 @@
|
|||
<string name="not_inserted">Not inserted</string>
|
||||
<string name="tdd_bolus">TDD Bolus</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="multiwave_bolus">Multiwave bolus</string>
|
||||
<string name="eb_formatter">%1$.2f / %2$.2f U for %3$d min</string>
|
||||
|
|
|
@ -35,6 +35,14 @@
|
|||
android:name=".activities.ErrorHelperActivity"
|
||||
android:exported="false"
|
||||
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>
|
||||
|
||||
|
|
|
@ -1,20 +1,21 @@
|
|||
package info.nightscout.androidaps.activities
|
||||
package info.nightscout.ui.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.os.Bundle
|
||||
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.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.utils.ActivityMonitor
|
||||
import info.nightscout.androidaps.utils.FabricPrivacy
|
||||
import info.nightscout.androidaps.utils.alertDialogs.OKDialog
|
||||
import info.nightscout.androidaps.utils.rx.AapsSchedulers
|
||||
import info.nightscout.androidaps.utils.stats.DexcomTirCalculator
|
||||
import info.nightscout.androidaps.utils.stats.TddCalculator
|
||||
import info.nightscout.androidaps.utils.stats.TirCalculator
|
||||
import info.nightscout.ui.R
|
||||
import info.nightscout.ui.databinding.ActivityStatsBinding
|
||||
import info.nightscout.ui.utils.ActivityMonitor
|
||||
import io.reactivex.rxjava3.core.Single
|
||||
import io.reactivex.rxjava3.disposables.CompositeDisposable
|
||||
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.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) }
|
||||
.subscribeOn(aapsSchedulers.io)
|
||||
|
@ -74,7 +75,7 @@ class StatsActivity : NoSplashAppCompatActivity() {
|
|||
|
||||
binding.ok.setOnClickListener { finish() }
|
||||
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)
|
||||
activityMonitor.reset()
|
||||
recreate()
|
|
@ -1,32 +1,29 @@
|
|||
package info.nightscout.androidaps.activities
|
||||
package info.nightscout.ui.activities
|
||||
|
||||
import android.os.Bundle
|
||||
import android.widget.ArrayAdapter
|
||||
import com.google.firebase.auth.FirebaseAuth
|
||||
import com.google.firebase.database.FirebaseDatabase
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.databinding.ActivitySurveyBinding
|
||||
import info.nightscout.androidaps.activities.NoSplashAppCompatActivity
|
||||
import info.nightscout.androidaps.dialogs.ProfileViewerDialog
|
||||
import info.nightscout.androidaps.interfaces.ActivePlugin
|
||||
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.InstanceId
|
||||
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.logging.LTag
|
||||
import info.nightscout.ui.R
|
||||
import info.nightscout.ui.databinding.ActivitySurveyBinding
|
||||
import info.nightscout.ui.defaultProfile.DefaultProfile
|
||||
import javax.inject.Inject
|
||||
|
||||
class SurveyActivity : NoSplashAppCompatActivity() {
|
||||
|
||||
@Inject lateinit var activePlugin: ActivePlugin
|
||||
@Inject lateinit var tddCalculator: TddCalculator
|
||||
@Inject lateinit var tirCalculator: TirCalculator
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var activityMonitor: ActivityMonitor
|
||||
@Inject lateinit var defaultProfile: DefaultProfile
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
|
||||
|
@ -43,24 +40,20 @@ class SurveyActivity : NoSplashAppCompatActivity() {
|
|||
val profileList = profileStore?.getProfileList() ?: return
|
||||
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 {
|
||||
val age = SafeParse.stringToDouble(binding.age.text.toString())
|
||||
val weight = SafeParse.stringToDouble(binding.weight.text.toString())
|
||||
val tdd = SafeParse.stringToDouble(binding.tdd.text.toString())
|
||||
if (age < 1 || age > 120) {
|
||||
ToastUtils.warnToast(this, R.string.invalidage)
|
||||
ToastUtils.warnToast(this, R.string.invalid_age)
|
||||
return@setOnClickListener
|
||||
}
|
||||
if ((weight < 5 || weight > 150) && tdd == 0.0) {
|
||||
ToastUtils.warnToast(this, R.string.invalidweight)
|
||||
ToastUtils.warnToast(this, R.string.invalid_weight)
|
||||
return@setOnClickListener
|
||||
}
|
||||
if ((tdd < 5 || tdd > 150) && weight == 0.0) {
|
||||
ToastUtils.warnToast(this, R.string.invalidweight)
|
||||
ToastUtils.warnToast(this, R.string.invalid_weight)
|
||||
return@setOnClickListener
|
||||
}
|
||||
profileFunction.getProfile()?.let { runningProfile ->
|
||||
|
@ -84,11 +77,11 @@ class SurveyActivity : NoSplashAppCompatActivity() {
|
|||
r.age = SafeParse.stringToInt(binding.age.text.toString())
|
||||
r.weight = SafeParse.stringToInt(binding.weight.text.toString())
|
||||
if (r.age < 1 || r.age > 120) {
|
||||
ToastUtils.warnToast(this, R.string.invalidage)
|
||||
ToastUtils.warnToast(this, R.string.invalid_age)
|
||||
return@setOnClickListener
|
||||
}
|
||||
if (r.weight < 5 || r.weight > 150) {
|
||||
ToastUtils.warnToast(this, R.string.invalidweight)
|
||||
ToastUtils.warnToast(this, R.string.invalid_weight)
|
||||
return@setOnClickListener
|
||||
}
|
||||
|
|
@ -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.extensions.pureProfileFromJson
|
||||
|
@ -13,31 +13,32 @@ import javax.inject.Inject
|
|||
import javax.inject.Singleton
|
||||
import kotlin.math.abs
|
||||
|
||||
@Suppress("LocalVariableName")
|
||||
@Singleton
|
||||
class DefaultProfile @Inject constructor(val dateUtil: DateUtil) {
|
||||
|
||||
var oneToFive: TreeMap<Double, Array<Double>> = TreeMap()
|
||||
var sixToEleven: TreeMap<Double, Array<Double>> = TreeMap()
|
||||
var twelveToSeventeen: TreeMap<Double, Array<Double>> = TreeMap()
|
||||
var eighteenToTwentyFour: TreeMap<Double, Array<Double>> = TreeMap()
|
||||
private var oneToFive: TreeMap<Double, Array<Double>> = TreeMap()
|
||||
private var sixToEleven: TreeMap<Double, Array<Double>> = TreeMap()
|
||||
private var twelveToSeventeen: 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? {
|
||||
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
|
||||
closest(oneToFive, _tdd * 0.3)?.let { array -> profile.put("basal", arrayToJson(array)) }
|
||||
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)))
|
||||
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))
|
||||
} 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
|
||||
closest(sixToEleven, _tdd * 0.4)?.let { array -> profile.put("basal", arrayToJson(array)) }
|
||||
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)))
|
||||
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))
|
||||
} 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
|
||||
closest(twelveToSeventeen, _tdd * 0.5)?.let { array -> profile.put("basal", arrayToJson(array)) }
|
||||
val ic = Round.roundTo(500.0 / _tdd, 1.0)
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.utils.defaultProfile
|
||||
package info.nightscout.ui.defaultProfile
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.data.PureProfile
|
||||
|
@ -15,22 +15,22 @@ import javax.inject.Singleton
|
|||
@Singleton
|
||||
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)
|
||||
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 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 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 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? {
|
||||
val basalSum = tdd * basalSumPct
|
||||
val profile = JSONObject()
|
||||
if (age >= 1 && age < 6) {
|
||||
if (age in 1.0..5.0) {
|
||||
profile.put("basal", arrayToJson(oneToFive, basalSum))
|
||||
profile.put("carbratio", singleValueArray(0.0))
|
||||
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("carbratio", singleValueArray(0.0))
|
||||
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("carbratio", singleValueArray(0.0))
|
||||
profile.put("sens", singleValueArrayFromMmolToUnits(0.0, units))
|
||||
|
@ -56,12 +56,14 @@ class DefaultProfileDPV @Inject constructor(val injector: HasAndroidInjector, va
|
|||
return basals
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun singleValueArray(value: Double): JSONArray {
|
||||
val array = JSONArray()
|
||||
array.put(JSONObject().put("time", "00:00").put("value", value).put("timeAsSeconds", 0 * 3600))
|
||||
return array
|
||||
}
|
||||
|
||||
@Suppress("SameParameterValue")
|
||||
private fun singleValueArrayFromMmolToUnits(value: Double, units: GlucoseUnit): JSONArray {
|
||||
val array = JSONArray()
|
||||
array.put(JSONObject().put("time", "00:00").put("value", Profile.fromMmolToUnits(value, units)).put("timeAsSeconds", 0 * 3600))
|
|
@ -2,8 +2,10 @@ package info.nightscout.ui.di
|
|||
|
||||
import dagger.Module
|
||||
import dagger.android.ContributesAndroidInjector
|
||||
import info.nightscout.ui.activities.SurveyActivity
|
||||
import info.nightscout.ui.activities.BolusProgressHelperActivity
|
||||
import info.nightscout.ui.activities.ErrorHelperActivity
|
||||
import info.nightscout.ui.activities.StatsActivity
|
||||
import info.nightscout.ui.activities.TDDStatsActivity
|
||||
import info.nightscout.ui.dialogs.CalibrationDialog
|
||||
import info.nightscout.ui.dialogs.CarbsDialog
|
||||
|
@ -18,5 +20,7 @@ abstract class UiModule {
|
|||
@ContributesAndroidInjector abstract fun contributesTDDStatsActivity(): TDDStatsActivity
|
||||
@ContributesAndroidInjector abstract fun contributeBolusProgressHelperActivity(): BolusProgressHelperActivity
|
||||
@ContributesAndroidInjector abstract fun contributeErrorHelperActivity(): ErrorHelperActivity
|
||||
@ContributesAndroidInjector abstract fun contributesStatsActivity(): StatsActivity
|
||||
@ContributesAndroidInjector abstract fun contributesSurveyActivity(): SurveyActivity
|
||||
|
||||
}
|
|
@ -1,4 +1,4 @@
|
|||
package info.nightscout.androidaps.utils
|
||||
package info.nightscout.ui.utils
|
||||
|
||||
import android.app.Activity
|
||||
import android.app.Application
|
||||
|
@ -10,12 +10,14 @@ import android.view.ViewGroup
|
|||
import android.widget.TableLayout
|
||||
import android.widget.TableRow
|
||||
import android.widget.TextView
|
||||
import info.nightscout.androidaps.R
|
||||
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.logging.AAPSLogger
|
||||
import info.nightscout.shared.logging.LTag
|
||||
import info.nightscout.shared.sharedPreferences.SP
|
||||
import info.nightscout.ui.R
|
||||
import javax.inject.Inject
|
||||
import javax.inject.Singleton
|
||||
|
||||
|
@ -69,7 +71,7 @@ class ActivityMonitor @Inject constructor(
|
|||
layout.layoutParams = TableLayout.LayoutParams(0, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)
|
||||
layout.addView(
|
||||
TextView(context).apply {
|
||||
text = rh.gs(R.string.activitymonitor)
|
||||
text = rh.gs(R.string.activity_monitor)
|
||||
setTypeface(typeface, Typeface.BOLD)
|
||||
gravity = Gravity.CENTER_HORIZONTAL
|
||||
setTextAppearance(android.R.style.TextAppearance_Material_Medium)
|
|
@ -5,7 +5,7 @@
|
|||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:orientation="vertical"
|
||||
tools:context=".activities.StatsActivity">
|
||||
tools:context="info.nightscout.ui.activities.StatsActivity">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
|
@ -68,7 +68,7 @@
|
|||
android:layout_height="match_parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/weigth_label"
|
||||
android:id="@+id/weight_label"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
|
@ -124,7 +124,7 @@
|
|||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="10dp"
|
||||
android:layout_marginEnd="20dp"
|
||||
android:text="@string/mostcommonprofile"
|
||||
android:text="@string/most_common_profile"
|
||||
android:textAppearance="@style/TextAppearance.AppCompat.Medium" />
|
||||
|
||||
<Spinner
|
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 5.2 KiB After Width: | Height: | Size: 5.2 KiB |
Before Width: | Height: | Size: 7.2 KiB After Width: | Height: | Size: 7.2 KiB |
Before Width: | Height: | Size: 4.7 KiB After Width: | Height: | Size: 4.7 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 4.1 KiB After Width: | Height: | Size: 4.1 KiB |
Before Width: | Height: | Size: 3.1 KiB After Width: | Height: | Size: 3.1 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 7.4 KiB After Width: | Height: | Size: 7.4 KiB |
Before Width: | Height: | Size: 10 KiB After Width: | Height: | Size: 10 KiB |
Before Width: | Height: | Size: 7 KiB After Width: | Height: | Size: 7 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 12 KiB After Width: | Height: | Size: 12 KiB |
Before Width: | Height: | Size: 17 KiB After Width: | Height: | Size: 17 KiB |
Before Width: | Height: | Size: 13 KiB After Width: | Height: | Size: 13 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 18 KiB After Width: | Height: | Size: 18 KiB |
Before Width: | Height: | Size: 26 KiB After Width: | Height: | Size: 26 KiB |
Before Width: | Height: | Size: 20 KiB After Width: | Height: | Size: 20 KiB |
|
@ -19,4 +19,21 @@
|
|||
<string name="configure">Configure opacity</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>
|
||||
|
|
39
ui/src/test/java/info/nightscout/androidaps/TestBase.kt
Normal 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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -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) {}
|
||||
}
|
|
@ -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.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.TestBaseWithProfile
|
||||
import org.junit.Assert.assertEquals
|
||||
import org.junit.Test
|
||||
|