Merge branch 'AddActionCP' into dev
This commit is contained in:
commit
65a14c8eca
10 changed files with 320 additions and 1 deletions
|
@ -130,7 +130,6 @@
|
|||
<string name="overview">Overview</string>
|
||||
<string name="treatments">Treatments</string>
|
||||
<string name="virtualpump">Virtual Pump</string>
|
||||
<string name="careportal">Careportal</string>
|
||||
|
||||
|
||||
<string name="configbuilder_pump">Pump</string>
|
||||
|
|
|
@ -39,6 +39,7 @@ abstract class AutomationModule {
|
|||
@ContributesAndroidInjector abstract fun actionLoopSuspendInjector(): ActionLoopSuspend
|
||||
@ContributesAndroidInjector abstract fun actionNotificationInjector(): ActionNotification
|
||||
@ContributesAndroidInjector abstract fun actionAlarmInjector(): ActionAlarm
|
||||
@ContributesAndroidInjector abstract fun actionCarePortalEventInjector(): ActionCarePortalEvent
|
||||
@ContributesAndroidInjector abstract fun actionProfileSwitchInjector(): ActionProfileSwitch
|
||||
@ContributesAndroidInjector abstract fun actionProfileSwitchPercentInjector(): ActionProfileSwitchPercent
|
||||
@ContributesAndroidInjector abstract fun actionSendSMSInjector(): ActionSendSMS
|
||||
|
|
|
@ -293,6 +293,7 @@ class AutomationPlugin @Inject constructor(
|
|||
ActionStopTempTarget(injector),
|
||||
ActionNotification(injector),
|
||||
ActionAlarm(injector),
|
||||
ActionCarePortalEvent(injector),
|
||||
ActionProfileSwitchPercent(injector),
|
||||
ActionProfileSwitch(injector),
|
||||
ActionSendSMS(injector)
|
||||
|
|
|
@ -51,6 +51,8 @@ abstract class Action(val injector: HasAndroidInjector) {
|
|||
return when (type) {
|
||||
ActionAlarm::class.java.name, // backward compatibility
|
||||
ActionAlarm::class.java.simpleName -> ActionAlarm(injector).fromJSON(data.toString())
|
||||
ActionCarePortalEvent::class.java.name,
|
||||
ActionCarePortalEvent::class.java.simpleName -> ActionCarePortalEvent(injector).fromJSON(data.toString())
|
||||
ActionDummy::class.java.name,
|
||||
ActionDummy::class.java.simpleName -> ActionDummy(injector).fromJSON(data.toString())
|
||||
ActionLoopDisable::class.java.name,
|
||||
|
|
|
@ -0,0 +1,119 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||
|
||||
import android.widget.LinearLayout
|
||||
import androidx.annotation.DrawableRes
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.database.AppRepository
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.database.entities.UserEntry
|
||||
import info.nightscout.androidaps.database.entities.ValueWithUnit
|
||||
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||
import info.nightscout.androidaps.extensions.fromConstant
|
||||
import info.nightscout.androidaps.interfaces.ProfileFunction
|
||||
import info.nightscout.androidaps.logging.LTag
|
||||
import info.nightscout.androidaps.logging.UserEntryLogger
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.*
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatusProvider
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.JsonHelper
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
import info.nightscout.androidaps.utils.sharedPreferences.SP
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.rxkotlin.plusAssign
|
||||
import org.json.JSONObject
|
||||
import javax.inject.Inject
|
||||
|
||||
class ActionCarePortalEvent(injector: HasAndroidInjector) : Action(injector) {
|
||||
|
||||
@Inject lateinit var resourceHelper: ResourceHelper
|
||||
@Inject lateinit var repository: AppRepository
|
||||
@Inject lateinit var profileFunction: ProfileFunction
|
||||
@Inject lateinit var dateUtil: DateUtil
|
||||
@Inject lateinit var sp: SP
|
||||
@Inject lateinit var glucoseStatusProvider: GlucoseStatusProvider
|
||||
@Inject lateinit var uel: UserEntryLogger
|
||||
|
||||
|
||||
private val disposable = CompositeDisposable()
|
||||
|
||||
var note = InputString()
|
||||
var duration = InputDuration(0, InputDuration.TimeUnit.MINUTES)
|
||||
var cpEvent = InputCarePortalMenu(resourceHelper)
|
||||
private var valuesWithUnit = mutableListOf<ValueWithUnit?>()
|
||||
|
||||
private constructor(injector: HasAndroidInjector, actionCPEvent: ActionCarePortalEvent) : this(injector) {
|
||||
cpEvent = InputCarePortalMenu(resourceHelper, actionCPEvent.cpEvent.value)
|
||||
}
|
||||
|
||||
override fun friendlyName(): Int = R.string.careportal
|
||||
override fun shortDescription(): String = resourceHelper.gs(cpEvent.value.stringRes, note.value)
|
||||
|
||||
@DrawableRes override fun icon(): Int = cpEvent.value.drawableRes
|
||||
|
||||
override fun doAction(callback: Callback) {
|
||||
val enteredBy = sp.getString("careportal_enteredby", "AndroidAPS")
|
||||
val eventTime = dateUtil.now()
|
||||
val therapyEvent = TherapyEvent(
|
||||
timestamp = eventTime,
|
||||
type = cpEvent.value.therapyEventType,
|
||||
glucoseUnit = TherapyEvent.GlucoseUnit.fromConstant(profileFunction.getUnits())
|
||||
)
|
||||
valuesWithUnit.add(ValueWithUnit.TherapyEventType(therapyEvent.type))
|
||||
|
||||
therapyEvent.enteredBy = enteredBy
|
||||
if ( therapyEvent.type == TherapyEvent.Type.QUESTION || therapyEvent.type == TherapyEvent.Type.ANNOUNCEMENT) {
|
||||
val glucoseStatus = glucoseStatusProvider.glucoseStatusData
|
||||
if (glucoseStatus != null) {
|
||||
therapyEvent.glucose = glucoseStatus.glucose
|
||||
therapyEvent.glucoseType = TherapyEvent.MeterType.SENSOR
|
||||
valuesWithUnit.add(ValueWithUnit.fromGlucoseUnit(glucoseStatus.glucose, profileFunction.getUnits().asText))
|
||||
valuesWithUnit.add(ValueWithUnit.TherapyEventMeterType(TherapyEvent.MeterType.SENSOR))
|
||||
}
|
||||
} else {
|
||||
therapyEvent.duration = T.mins(duration.value.toLong()).msecs()
|
||||
valuesWithUnit.add(ValueWithUnit.Minute(duration.value).takeIf { !duration.value.equals(0) } )
|
||||
}
|
||||
therapyEvent.note = note.value
|
||||
valuesWithUnit.add(ValueWithUnit.SimpleString(note.value).takeIf { note.value.isNotBlank() } )
|
||||
disposable += repository.runTransactionForResult(InsertIfNewByTimestampTherapyEventTransaction(therapyEvent))
|
||||
.subscribe(
|
||||
{ result -> result.inserted.forEach { aapsLogger.debug(LTag.DATABASE, "Inserted therapy event $it") } },
|
||||
{ aapsLogger.error(LTag.DATABASE, "Error while saving therapy event", it) }
|
||||
)
|
||||
uel.log(UserEntry.Action.CAREPORTAL, UserEntry.Sources.Automation, title, valuesWithUnit)
|
||||
}
|
||||
|
||||
override fun toJSON(): String {
|
||||
val data = JSONObject()
|
||||
.put("cpEvent", cpEvent.value)
|
||||
.put("note", note.value)
|
||||
.put("durationInMinutes", duration.value)
|
||||
return JSONObject()
|
||||
.put("type", this.javaClass.name)
|
||||
.put("data", data)
|
||||
.toString()
|
||||
}
|
||||
|
||||
override fun fromJSON(data: String): Action {
|
||||
val o = JSONObject(data)
|
||||
cpEvent.value = InputCarePortalMenu.EventType.valueOf(JsonHelper.safeGetString(o, "cpEvent")!!)
|
||||
note.value = JsonHelper.safeGetString(o, "note", "")
|
||||
duration.value = JsonHelper.safeGetInt(o, "durationInMinutes")
|
||||
return this
|
||||
}
|
||||
|
||||
override fun hasDialog(): Boolean = true
|
||||
|
||||
override fun generateDialog(root: LinearLayout) {
|
||||
LayoutBuilder()
|
||||
.add(cpEvent)
|
||||
.add(LabelWithElement(resourceHelper, resourceHelper.gs(R.string.duration_min_label), "", duration))
|
||||
.add(LabelWithElement(resourceHelper, resourceHelper.gs(R.string.notes_label), "", note))
|
||||
.build(root)
|
||||
}
|
||||
|
||||
override fun isValid(): Boolean = true
|
||||
}
|
|
@ -0,0 +1,84 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||
|
||||
import android.view.View
|
||||
import android.widget.AdapterView
|
||||
import android.widget.ArrayAdapter
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.Spinner
|
||||
import androidx.annotation.DrawableRes
|
||||
import androidx.annotation.LayoutRes
|
||||
import androidx.annotation.StringRes
|
||||
import androidx.core.graphics.drawable.IconCompat
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.database.entities.TherapyEvent
|
||||
import info.nightscout.androidaps.database.entities.UserEntry
|
||||
import info.nightscout.androidaps.utils.resources.ResourceHelper
|
||||
|
||||
class InputCarePortalMenu(private val resourceHelper: ResourceHelper) : Element() {
|
||||
|
||||
enum class EventType (val therapyEventType: TherapyEvent.Type) {
|
||||
NOTE (TherapyEvent.Type.NOTE),
|
||||
EXERCISE (TherapyEvent.Type.EXERCISE),
|
||||
QUESTION (TherapyEvent.Type.QUESTION),
|
||||
ANNOUNCEMENT (TherapyEvent.Type.ANNOUNCEMENT);
|
||||
|
||||
@get:StringRes val stringRes: Int
|
||||
get() = when (this) {
|
||||
NOTE -> R.string.careportal_note_message
|
||||
EXERCISE -> R.string.careportal_exercise_message
|
||||
QUESTION -> R.string.careportal_question_message
|
||||
ANNOUNCEMENT -> R.string.careportal_announcement_message
|
||||
}
|
||||
|
||||
@get:DrawableRes val drawableRes: Int
|
||||
get() = when (this) {
|
||||
NOTE -> R.drawable.ic_cp_note
|
||||
EXERCISE -> R.drawable.ic_cp_exercise
|
||||
QUESTION -> R.drawable.ic_cp_question
|
||||
ANNOUNCEMENT -> R.drawable.ic_cp_announcement
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun labels(resourceHelper: ResourceHelper): List<String> {
|
||||
val list: MutableList<String> = ArrayList()
|
||||
for (e in values()) {
|
||||
list.add(resourceHelper.gs(e.stringRes))
|
||||
}
|
||||
return list
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
constructor(resourceHelper: ResourceHelper, value: EventType) : this(resourceHelper) {
|
||||
this.value = value
|
||||
}
|
||||
|
||||
var value = EventType.NOTE
|
||||
|
||||
override fun addToLayout(root: LinearLayout) {
|
||||
val spinner = Spinner(root.context)
|
||||
val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, EventType.labels(resourceHelper))
|
||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
|
||||
spinner.adapter = spinnerArrayAdapter
|
||||
val spinnerParams = LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
)
|
||||
spinnerParams.setMargins(0, resourceHelper.dpToPx(4), 0, resourceHelper.dpToPx(4))
|
||||
spinner.layoutParams = spinnerParams
|
||||
spinner.onItemSelectedListener = object : AdapterView.OnItemSelectedListener {
|
||||
override fun onItemSelected(parent: AdapterView<*>?, view: View?, position: Int, id: Long) {
|
||||
value = EventType.values()[position]
|
||||
}
|
||||
|
||||
override fun onNothingSelected(parent: AdapterView<*>?) {}
|
||||
}
|
||||
spinner.setSelection(value.ordinal)
|
||||
root.addView(spinner)
|
||||
}
|
||||
|
||||
fun setValue(eventType: EventType): InputCarePortalMenu {
|
||||
value = eventType
|
||||
return this
|
||||
}
|
||||
}
|
|
@ -0,0 +1,81 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions
|
||||
|
||||
import info.nightscout.androidaps.automation.R
|
||||
import info.nightscout.androidaps.database.transactions.InsertIfNewByTimestampTherapyEventTransaction
|
||||
import info.nightscout.androidaps.database.transactions.Transaction
|
||||
import info.nightscout.androidaps.interfaces.GlucoseUnit
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputCarePortalMenu
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import io.reactivex.Single
|
||||
import org.junit.Assert
|
||||
import org.junit.Before
|
||||
import org.junit.Test
|
||||
import org.mockito.ArgumentMatchers
|
||||
import org.mockito.Mockito.`when`
|
||||
|
||||
class ActionCarePortalEventTest : ActionsTestBase() {
|
||||
|
||||
private lateinit var sut: ActionCarePortalEvent
|
||||
|
||||
@Before
|
||||
fun setup() {
|
||||
`when`(sp.getString(ArgumentMatchers.anyString(), ArgumentMatchers.anyString())).thenReturn("AndroidAPS")
|
||||
`when`(
|
||||
resourceHelper.gs(
|
||||
ArgumentMatchers.eq(R.string.careportal_note_message),
|
||||
ArgumentMatchers.anyString()
|
||||
)
|
||||
).thenReturn("Note : %s")
|
||||
`when`(dateUtil.now()).thenReturn(0)
|
||||
`when`(profileFunction.getUnits()).thenReturn(GlucoseUnit.MGDL)
|
||||
`when`(repository.runTransactionForResult(anyObject<Transaction<InsertIfNewByTimestampTherapyEventTransaction.TransactionResult>>()))
|
||||
.thenReturn(Single.just(InsertIfNewByTimestampTherapyEventTransaction.TransactionResult().apply {
|
||||
}))
|
||||
sut = ActionCarePortalEvent(injector)
|
||||
sut.cpEvent = InputCarePortalMenu(resourceHelper)
|
||||
sut.cpEvent.value = InputCarePortalMenu.EventType.NOTE
|
||||
sut.note = InputString("Asd")
|
||||
sut.duration = InputDuration(5, InputDuration.TimeUnit.MINUTES)
|
||||
}
|
||||
|
||||
@Test fun friendlyNameTest() {
|
||||
Assert.assertEquals(R.string.careportal, sut.friendlyName())
|
||||
}
|
||||
|
||||
@Test fun shortDescriptionTest() {
|
||||
Assert.assertEquals("Note : %s", sut.shortDescription())
|
||||
}
|
||||
|
||||
@Test fun iconTest() {
|
||||
Assert.assertEquals(R.drawable.ic_cp_note, sut.icon())
|
||||
}
|
||||
|
||||
@Test fun doActionTest() {
|
||||
sut.doAction(object : Callback() {
|
||||
override fun run() {
|
||||
Assert.assertTrue(result.success)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Test fun hasDialogTest() {
|
||||
Assert.assertTrue(sut.hasDialog())
|
||||
}
|
||||
|
||||
@Test fun toJSONTest() {
|
||||
Assert.assertEquals(
|
||||
"{\"data\":{\"note\":\"Asd\",\"cpEvent\":\"NOTE\",\"durationInMinutes\":5},\"type\":\"info.nightscout.androidaps.plugins.general.automation.actions.ActionCarePortalEvent\"}",
|
||||
sut.toJSON()
|
||||
)
|
||||
}
|
||||
|
||||
@Test fun fromJSONTest() {
|
||||
sut.note = InputString("Asd")
|
||||
sut.fromJSON("{\"note\":\"Asd\",\"cpEvent\":\"NOTE\",\"durationInMinutes\":5}")
|
||||
Assert.assertEquals("Asd", sut.note.value)
|
||||
Assert.assertEquals(5, sut.duration.value)
|
||||
Assert.assertEquals(InputCarePortalMenu.EventType.NOTE, sut.cpEvent.value)
|
||||
}
|
||||
}
|
|
@ -131,6 +131,14 @@ open class ActionsTestBase : TestBaseWithProfile() {
|
|||
it.rxBus = rxBus
|
||||
it.uel = uel
|
||||
}
|
||||
if (it is ActionCarePortalEvent) {
|
||||
it.resourceHelper = resourceHelper
|
||||
it.repository = repository
|
||||
it.sp = sp
|
||||
it.dateUtil = dateUtil
|
||||
it.profileFunction = profileFunction
|
||||
it.uel = uel
|
||||
}
|
||||
if (it is PumpEnactResult) {
|
||||
it.resourceHelper = resourceHelper
|
||||
}
|
||||
|
|
|
@ -0,0 +1,19 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements
|
||||
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTestBase
|
||||
import org.junit.Assert
|
||||
import org.junit.Test
|
||||
|
||||
class InputCarePortalEventTest : TriggerTestBase() {
|
||||
|
||||
@Test
|
||||
fun labelsTest() {
|
||||
Assert.assertEquals(4, InputCarePortalMenu.EventType.labels(resourceHelper).size)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun setValueTest() {
|
||||
val cp = InputCarePortalMenu(resourceHelper, InputCarePortalMenu.EventType.EXERCISE)
|
||||
Assert.assertEquals(InputCarePortalMenu.EventType.EXERCISE, cp.value)
|
||||
}
|
||||
}
|
|
@ -250,12 +250,17 @@
|
|||
<string name="activitymonitorformat"><![CDATA[<b><span style=\"color:yellow\">%1$s:</span></b> <b>%2$s</b> in <b>%3$d</b> days<br>]]></string>
|
||||
|
||||
<!-- Translator-->
|
||||
<string name="careportal">Careportal</string>
|
||||
<string name="careportal_bgcheck">BG Check</string>
|
||||
<string name="careportal_mbg">Manual BG or Calibration</string>
|
||||
<string name="careportal_announcement">Announcement</string>
|
||||
<string name="careportal_note">Note</string>
|
||||
<string name="careportal_question">Question</string>
|
||||
<string name="careportal_exercise">Exercise</string>
|
||||
<string name="careportal_announcement_message">Announcement : %1$s</string>
|
||||
<string name="careportal_note_message">Note : %1$s</string>
|
||||
<string name="careportal_question_message">Question : %1$s</string>
|
||||
<string name="careportal_exercise_message">Exercise : %1$s</string>
|
||||
<string name="careportal_pumpsitechange">Pump Site Change</string>
|
||||
<string name="careportal_cgmsensorinsert">CGM Sensor Insert</string>
|
||||
<string name="careportal_cgmsensorstart">CGM Sensor Start</string>
|
||||
|
|
Loading…
Reference in a new issue