automation improvement

This commit is contained in:
Milos Kozak 2020-01-05 17:19:03 +01:00
parent 925de127a7
commit fa4d4c9fa9
7 changed files with 218 additions and 173 deletions

View file

@ -4,7 +4,6 @@ import dagger.BindsInstance
import dagger.Component
import dagger.android.AndroidInjectionModule
import dagger.android.AndroidInjector
import dagger.android.ContributesAndroidInjector
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.db.BgReading
import info.nightscout.androidaps.plugins.aps.openAPSMA.LoggerCallback
@ -76,10 +75,11 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectActionStopTempTarget(action: ActionStopTempTarget)
fun injectElement(element: Element)
fun injectElement(comparator: Comparator)
fun injectElement(comparatorExists: ComparatorExists)
fun injectElement(inputBg: InputBg)
fun injectElement(inputButton: InputButton)
fun injectElement(comparator: Comparator)
fun injectElement(comparatorExists: ComparatorExists)
fun injectElement(inputDateTime: InputDateTime)
fun injectElement(inputDelta: InputDelta)
fun injectElement(inputDouble: InputDouble)
fun injectElement(inputDuration: InputDuration)
@ -89,6 +89,7 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectElement(inputProfileName: InputProfileName)
fun injectElement(inputString: InputString)
fun injectElement(inputTempTarget: InputTempTarget)
fun injectElement(inputTimeRange: InputTimeRange)
fun injectElement(labelWithElement: LabelWithElement)
fun injectElement(staticLabel: StaticLabel)

View file

@ -108,10 +108,11 @@ open class AppModule {
@ContributesAndroidInjector fun actionDummyInjector(): ActionDummy
@ContributesAndroidInjector fun elementInjector(): Element
@ContributesAndroidInjector fun comparatorInjector(): Comparator
@ContributesAndroidInjector fun comparatorExistsInjector(): ComparatorExists
@ContributesAndroidInjector fun inputBgInjector(): InputBg
@ContributesAndroidInjector fun inputButtonInjector(): InputButton
@ContributesAndroidInjector fun comparatorInjector(): Comparator
@ContributesAndroidInjector fun comparatorExistsInjector(): ComparatorExists
@ContributesAndroidInjector fun inputTimeInjector(): InputDateTime
@ContributesAndroidInjector fun inputDeltaInjector(): InputDelta
@ContributesAndroidInjector fun inputDoubleInjector(): InputDouble
@ContributesAndroidInjector fun inputDurationInjector(): InputDuration
@ -121,6 +122,7 @@ open class AppModule {
@ContributesAndroidInjector fun inputProfileNameInjector(): InputProfileName
@ContributesAndroidInjector fun inputStringInjector(): InputString
@ContributesAndroidInjector fun inputTempTargetInjector(): InputTempTarget
@ContributesAndroidInjector fun inputTimeRangeInjector(): InputTimeRange
@ContributesAndroidInjector fun labelWithElementInjector(): LabelWithElement
@ContributesAndroidInjector fun staticLabelInjector(): StaticLabel

View file

@ -0,0 +1,89 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.graphics.Typeface
import android.text.format.DateFormat
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.DateUtil
import java.util.*
class InputDateTime(mainApp: MainApp) : Element(mainApp) {
var value : Long = DateUtil.now()
constructor(mainApp: MainApp, value : Long) : this(mainApp) {
this.value = value
}
override fun addToLayout(root: LinearLayout) {
val label = TextView(root.context)
val dateButton = TextView(root.context)
val timeButton = TextView(root.context)
dateButton.text = DateUtil.dateString(value)
timeButton.text = DateUtil.timeString(value)
// create an OnDateSetListener
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
val cal = Calendar.getInstance()
cal.timeInMillis = value
cal.set(Calendar.YEAR, year)
cal.set(Calendar.MONTH, monthOfYear)
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
value = cal.timeInMillis
dateButton.text = DateUtil.dateString(value)
}
dateButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = value
DatePickerDialog(it, dateSetListener,
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH)
).show()
}
}
// create an OnTimeSetListener
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val cal = Calendar.getInstance()
cal.timeInMillis = value
cal.set(Calendar.HOUR_OF_DAY, hour)
cal.set(Calendar.MINUTE, minute)
cal.set(Calendar.SECOND, 0) // randomize seconds to prevent creating record of the same time, if user choose time manually
value = cal.timeInMillis
timeButton.text = DateUtil.timeString(value)
}
timeButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = value
TimePickerDialog(it, timeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(mainApp)
).show()
}
}
val px = resourceHelper.dpToPx(10)
label.text = resourceHelper.gs(R.string.atspecifiedtime, "")
label.setTypeface(label.typeface, Typeface.BOLD)
label.setPadding(px, px, px, px)
dateButton.setPadding(px, px, px, px)
timeButton.setPadding(px, px, px, px)
val l = LinearLayout(root.context)
l.orientation = LinearLayout.HORIZONTAL
l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
l.addView(label)
l.addView(dateButton)
l.addView(timeButton)
root.addView(l)
}
}

View file

@ -18,7 +18,7 @@ class InputProfileName(mainApp: MainApp) : Element(mainApp) {
}
override fun addToLayout(root: LinearLayout) {
val profileStore = ConfigBuilderPlugin.getPlugin().activeProfileInterface.profile ?: return
val profileStore = configBuilderPlugin.activeProfileInterface.profile ?: return
val profileList = profileStore.getProfileList()
val adapter = ArrayAdapter(root.context, R.layout.spinner_centered, profileList)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)

View file

@ -0,0 +1,80 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.app.TimePickerDialog
import android.graphics.Typeface
import android.text.format.DateFormat
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T
import java.util.*
class InputTimeRange(mainApp: MainApp) : Element(mainApp) {
var start: Int = getMinSinceMidnight(DateUtil.now())
var end: Int = getMinSinceMidnight(DateUtil.now())
override fun addToLayout(root: LinearLayout) {
val label = TextView(root.context)
val startButton = TextView(root.context)
val endButton = TextView(root.context)
startButton.text = DateUtil.timeString(toMills(start))
@Suppress("SetTextI18n")
endButton.text = resourceHelper.gs(R.string.and) + " " + DateUtil.timeString(toMills(end))
val startTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
start = 60 * hour + minute
startButton.text = DateUtil.timeString(toMills(start))
}
startButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(start)
TimePickerDialog(it, startTimeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(mainApp)
).show()
}
}
val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
end = 60 * hour + minute
endButton.text = DateUtil.timeString(toMills(end))
}
endButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(end)
TimePickerDialog(it, endTimeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(mainApp)
).show()
}
}
val px = resourceHelper.dpToPx(10)
label.text = resourceHelper.gs(R.string.between)
label.setTypeface(label.typeface, Typeface.BOLD)
startButton.setPadding(px, px, px, px)
endButton.setPadding(px, px, px, px)
val l = LinearLayout(root.context)
l.orientation = LinearLayout.HORIZONTAL
l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
l.addView(label)
l.addView(startButton)
l.addView(endButton)
root.addView(l)
}
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
}

View file

@ -1,36 +1,32 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.app.DatePickerDialog
import android.app.TimePickerDialog
import android.graphics.Typeface
import android.text.format.DateFormat
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import com.google.common.base.Optional
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.automation.elements.InputDateTime
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T
import org.json.JSONObject
import java.util.*
class TriggerTime(mainApp: MainApp) : Trigger(mainApp) {
var runAt = DateUtil.now()
var time = InputDateTime(mainApp)
constructor(mainApp: MainApp, runAt: Long) : this(mainApp) {
this.runAt = runAt
this.time.value = runAt
}
constructor(mainApp: MainApp, triggerTime : TriggerTime) : this(mainApp) {
this.runAt = triggerTime.runAt
constructor(mainApp: MainApp, triggerTime: TriggerTime) : this(mainApp) {
this.time.value = triggerTime.time.value
}
override fun shouldRun(): Boolean {
val now = DateUtil.now()
if (now >= runAt && now - runAt < T.mins(5).msecs()) {
if (now >= time.value && now - time.value < T.mins(5).msecs()) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
@ -40,7 +36,7 @@ class TriggerTime(mainApp: MainApp) : Trigger(mainApp) {
override fun toJSON(): String {
val data = JSONObject()
.put("runAt", runAt)
.put("runAt", time.value)
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
@ -49,84 +45,23 @@ class TriggerTime(mainApp: MainApp) : Trigger(mainApp) {
override fun fromJSON(data: String): Trigger {
val o = JSONObject(data)
runAt = safeGetLong(o, "runAt")
time.value = JsonHelper.safeGetLong(o, "runAt")
return this
}
override fun friendlyName(): Int = R.string.time
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(runAt))
resourceHelper.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(time.value))
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_access_alarm_24dp)
override fun duplicate(): Trigger = TriggerTime(mainApp, runAt)
override fun duplicate(): Trigger = TriggerTime(mainApp, time.value)
override fun generateDialog(root: LinearLayout) {
val label = TextView(root.context)
val dateButton = TextView(root.context)
val timeButton = TextView(root.context)
dateButton.text = DateUtil.dateString(runAt)
timeButton.text = DateUtil.timeString(runAt)
// create an OnDateSetListener
val dateSetListener = DatePickerDialog.OnDateSetListener { _, year, monthOfYear, dayOfMonth ->
val cal = Calendar.getInstance()
cal.timeInMillis = runAt
cal.set(Calendar.YEAR, year)
cal.set(Calendar.MONTH, monthOfYear)
cal.set(Calendar.DAY_OF_MONTH, dayOfMonth)
runAt = cal.timeInMillis
dateButton.text = DateUtil.dateString(runAt)
}
dateButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = runAt
DatePickerDialog(it, dateSetListener,
cal.get(Calendar.YEAR),
cal.get(Calendar.MONTH),
cal.get(Calendar.DAY_OF_MONTH)
).show()
}
}
// create an OnTimeSetListener
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val cal = Calendar.getInstance()
cal.timeInMillis = runAt
cal.set(Calendar.HOUR_OF_DAY, hour)
cal.set(Calendar.MINUTE, minute)
cal.set(Calendar.SECOND, 0) // randomize seconds to prevent creating record of the same time, if user choose time manually
runAt = cal.timeInMillis
timeButton.text = DateUtil.timeString(runAt)
}
timeButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = runAt
TimePickerDialog(it, timeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(mainApp)
).show()
}
}
val px = resourceHelper.dpToPx(10)
label.text = resourceHelper.gs(R.string.atspecifiedtime, "")
label.setTypeface(label.typeface, Typeface.BOLD)
label.setPadding(px, px, px, px)
dateButton.setPadding(px, px, px, px)
timeButton.setPadding(px, px, px, px)
val l = LinearLayout(root.context)
l.orientation = LinearLayout.HORIZONTAL
l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
l.addView(label)
l.addView(dateButton)
l.addView(timeButton)
root.addView(l)
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.time))
.add(time)
.build(root)
}
}

View file

@ -1,44 +1,41 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.app.TimePickerDialog
import android.graphics.Typeface
import android.text.format.DateFormat
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TextView
import com.google.common.base.Optional
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.automation.elements.InputTimeRange
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper.safeGetInt
import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T
import org.json.JSONObject
import java.util.*
// Trigger for time range ( from 10:00AM till 13:00PM )
class TriggerTimeRange(mainApp: MainApp) : Trigger(mainApp) {
// in minutes since midnight 60 means 1AM
var start: Int = getMinSinceMidnight(DateUtil.now())
var end: Int = getMinSinceMidnight(DateUtil.now())
var range = InputTimeRange(mainApp)
constructor(mainApp: MainApp, start : Int, end :Int) : this(mainApp) {
this.start = start
this.end = end
constructor(mainApp: MainApp, start: Int, end: Int) : this(mainApp) {
range.start = start
range.end = end
}
constructor(mainApp: MainApp, triggerTimeRange: TriggerTimeRange) : this(mainApp) {
this.start = triggerTimeRange.start
this.end = triggerTimeRange.end
range.start = triggerTimeRange.range.start
range.end = triggerTimeRange.range.end
}
override fun shouldRun(): Boolean {
val currentMinSinceMidnight = getMinSinceMidnight(DateUtil.now())
var doRun = false
if (start < end && start < currentMinSinceMidnight && currentMinSinceMidnight < end) doRun = true
else if (start > end && (start < currentMinSinceMidnight || currentMinSinceMidnight < end)) doRun = true
if (range.start < range.end && range.start < currentMinSinceMidnight && currentMinSinceMidnight < range.end) doRun = true
else if (range.start > range.end && (range.start < currentMinSinceMidnight || currentMinSinceMidnight < range.end)) doRun = true
if (doRun) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
@ -49,8 +46,8 @@ class TriggerTimeRange(mainApp: MainApp) : Trigger(mainApp) {
override fun toJSON(): String {
val data = JSONObject()
.put("start", getMinSinceMidnight(start.toLong()))
.put("end", getMinSinceMidnight(end.toLong()))
.put("start", getMinSinceMidnight(range.start.toLong()))
.put("end", getMinSinceMidnight(range.end.toLong()))
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
@ -59,87 +56,28 @@ class TriggerTimeRange(mainApp: MainApp) : Trigger(mainApp) {
override fun fromJSON(data: String): TriggerTimeRange {
val o = JSONObject(data)
start = safeGetInt(o, "start")
end = safeGetInt(o, "end")
range.start = safeGetInt(o, "start")
range.end = safeGetInt(o, "end")
return this
}
override fun friendlyName(): Int = R.string.time_range
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.timerange_value, DateUtil.timeString(toMills(start)), DateUtil.timeString(toMills(end)))
resourceHelper.gs(R.string.timerange_value, DateUtil.timeString(toMills(range.start)), DateUtil.timeString(toMills(range.end)))
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_access_alarm_24dp)
override fun duplicate(): Trigger = TriggerTimeRange(mainApp, start, end)
override fun duplicate(): Trigger = TriggerTimeRange(mainApp, range.start, range.end)
private fun toMills(minutesSinceMidnight: Int): Long = T.secs(minutesSinceMidnight.toLong()).msecs()
private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
override fun generateDialog(root: LinearLayout) {
val label = TextView(root.context)
val startButton = TextView(root.context)
val endButton = TextView(root.context)
startButton.text = DateUtil.timeString(toMills(start))
@Suppress("SetTextI18n")
endButton.text = resourceHelper.gs(R.string.and) + " " + DateUtil.timeString(toMills(end))
val startTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(start)
cal.set(Calendar.HOUR_OF_DAY, hour)
cal.set(Calendar.MINUTE, minute)
cal.set(Calendar.SECOND, 0)
start = getMinSinceMidnight(cal.timeInMillis)
startButton.text = DateUtil.timeString(toMills(start))
}
startButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(start)
TimePickerDialog(it, startTimeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(mainApp)
).show()
}
}
val endTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(end)
cal.set(Calendar.HOUR_OF_DAY, hour)
cal.set(Calendar.MINUTE, minute)
cal.set(Calendar.SECOND, 0) // randomize seconds to prevent creating record of the same time, if user choose time manually
end = getMinSinceMidnight(cal.timeInMillis)
endButton.text = DateUtil.timeString(toMills(end))
}
endButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(end)
TimePickerDialog(it, endTimeSetListener,
cal.get(Calendar.HOUR_OF_DAY),
cal.get(Calendar.MINUTE),
DateFormat.is24HourFormat(mainApp)
).show()
}
}
val px = resourceHelper.dpToPx(10)
label.text = resourceHelper.gs(R.string.between)
label.setTypeface(label.typeface, Typeface.BOLD)
startButton.setPadding(px, px, px, px)
endButton.setPadding(px, px, px, px)
val l = LinearLayout(root.context)
l.orientation = LinearLayout.HORIZONTAL
l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
l.addView(label)
l.addView(startButton)
l.addView(endButton)
root.addView(l)
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.time_range))
.add(range)
.build(root)
}
}