clean time related triggers

This commit is contained in:
Milos Kozak 2020-01-05 19:23:20 +01:00
parent fa4d4c9fa9
commit ec84c3fa70
6 changed files with 192 additions and 154 deletions

View file

@ -90,6 +90,8 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectElement(inputString: InputString) fun injectElement(inputString: InputString)
fun injectElement(inputTempTarget: InputTempTarget) fun injectElement(inputTempTarget: InputTempTarget)
fun injectElement(inputTimeRange: InputTimeRange) fun injectElement(inputTimeRange: InputTimeRange)
fun injectElement(inputTime: InputTime)
fun injectElement(inputWeekDay: InputWeekDay)
fun injectElement(labelWithElement: LabelWithElement) fun injectElement(labelWithElement: LabelWithElement)
fun injectElement(staticLabel: StaticLabel) fun injectElement(staticLabel: StaticLabel)

View file

@ -112,7 +112,7 @@ open class AppModule {
@ContributesAndroidInjector fun inputButtonInjector(): InputButton @ContributesAndroidInjector fun inputButtonInjector(): InputButton
@ContributesAndroidInjector fun comparatorInjector(): Comparator @ContributesAndroidInjector fun comparatorInjector(): Comparator
@ContributesAndroidInjector fun comparatorExistsInjector(): ComparatorExists @ContributesAndroidInjector fun comparatorExistsInjector(): ComparatorExists
@ContributesAndroidInjector fun inputTimeInjector(): InputDateTime @ContributesAndroidInjector fun inputDateTimeInjector(): InputDateTime
@ContributesAndroidInjector fun inputDeltaInjector(): InputDelta @ContributesAndroidInjector fun inputDeltaInjector(): InputDelta
@ContributesAndroidInjector fun inputDoubleInjector(): InputDouble @ContributesAndroidInjector fun inputDoubleInjector(): InputDouble
@ContributesAndroidInjector fun inputDurationInjector(): InputDuration @ContributesAndroidInjector fun inputDurationInjector(): InputDuration
@ -123,6 +123,8 @@ open class AppModule {
@ContributesAndroidInjector fun inputStringInjector(): InputString @ContributesAndroidInjector fun inputStringInjector(): InputString
@ContributesAndroidInjector fun inputTempTargetInjector(): InputTempTarget @ContributesAndroidInjector fun inputTempTargetInjector(): InputTempTarget
@ContributesAndroidInjector fun inputTimeRangeInjector(): InputTimeRange @ContributesAndroidInjector fun inputTimeRangeInjector(): InputTimeRange
@ContributesAndroidInjector fun inputTimeInjector(): InputTime
@ContributesAndroidInjector fun inputWeekDayInjector(): InputWeekDay
@ContributesAndroidInjector fun labelWithElementInjector(): LabelWithElement @ContributesAndroidInjector fun labelWithElementInjector(): LabelWithElement
@ContributesAndroidInjector fun staticLabelInjector(): StaticLabel @ContributesAndroidInjector fun staticLabelInjector(): StaticLabel

View file

@ -21,10 +21,10 @@ class InputTempTarget(mainApp: MainApp) : Element(mainApp) {
} }
override fun addToLayout(root: LinearLayout) { override fun addToLayout(root: LinearLayout) {
var minValue = 0.0 var minValue: Double
var maxValue = 0.0 var maxValue: Double
var step = 0.0 var step: Double
var decimalFormat: DecimalFormat? = null var decimalFormat: DecimalFormat?
if (units == Constants.MMOL) { // mmol if (units == Constants.MMOL) { // mmol
minValue = Constants.MIN_TT_MMOL minValue = Constants.MIN_TT_MMOL
maxValue = Constants.MAX_TT_MMOL maxValue = Constants.MAX_TT_MMOL

View file

@ -0,0 +1,57 @@
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 InputTime(mainApp: MainApp) : Element(mainApp) {
var value: Int = getMinSinceMidnight(DateUtil.now())
override fun addToLayout(root: LinearLayout) {
val label = TextView(root.context)
val startButton = TextView(root.context)
startButton.text = DateUtil.timeString(toMills(value))
val startTimeSetListener = TimePickerDialog.OnTimeSetListener { _, hour, minute ->
value = 60 * hour + minute
startButton.text = DateUtil.timeString(toMills(value))
}
startButton.setOnClickListener {
root.context?.let {
val cal = Calendar.getInstance()
cal.timeInMillis = toMills(value)
TimePickerDialog(it, startTimeSetListener,
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)
startButton.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)
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

@ -0,0 +1,86 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.StringRes
import com.dpro.widgets.WeekdaysPicker
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import java.util.*
class InputWeekDay(mainApp: MainApp) : Element(mainApp) {
enum class DayOfWeek {
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY;
fun toCalendarInt(): Int {
return calendarInts[ordinal]
}
@get:StringRes val shortName: Int
get() = shortNames[ordinal]
companion object {
private val calendarInts = intArrayOf(
Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY,
Calendar.SATURDAY,
Calendar.SUNDAY
)
private val shortNames = intArrayOf(
R.string.weekday_monday_short,
R.string.weekday_tuesday_short,
R.string.weekday_wednesday_short,
R.string.weekday_thursday_short,
R.string.weekday_friday_short,
R.string.weekday_saturday_short,
R.string.weekday_sunday_short
)
fun fromCalendarInt(day: Int): DayOfWeek {
for (i in calendarInts.indices) {
if (calendarInts[i] == day) return values()[i]
}
throw IllegalStateException("Invalid day")
}
}
}
val weekdays = BooleanArray(DayOfWeek.values().size)
init {
for (day in DayOfWeek.values()) set(day, false)
}
operator fun set(day: DayOfWeek, value: Boolean): InputWeekDay {
weekdays[day.ordinal] = value
return this
}
fun isSet(day: DayOfWeek): Boolean = weekdays[day.ordinal]
fun getSelectedDays(): List<Int> {
val selectedDays: MutableList<Int> = ArrayList()
for (i in weekdays.indices) {
val day = DayOfWeek.values()[i]
val selected = weekdays[i]
if (selected) selectedDays.add(day.toCalendarInt())
}
return selectedDays
}
override fun addToLayout(root: LinearLayout) {
val weekdaysPicker = WeekdaysPicker(root.context)
weekdaysPicker.setEditable(true)
weekdaysPicker.selectedDays = getSelectedDays()
weekdaysPicker.setOnWeekdaysChangeListener { _: View?, i: Int, list: List<Int?> -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)) }
weekdaysPicker.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
weekdaysPicker.sundayFirstDay = Calendar.getInstance().firstDayOfWeek == Calendar.SUNDAY
weekdaysPicker.redrawDays()
root.addView(weekdaysPicker)
}
}

View file

@ -1,99 +1,38 @@
package info.nightscout.androidaps.plugins.general.automation.triggers package info.nightscout.androidaps.plugins.general.automation.triggers
import android.app.TimePickerDialog
import android.graphics.Typeface
import android.text.format.DateFormat
import android.view.View
import android.view.ViewGroup
import android.widget.LinearLayout import android.widget.LinearLayout
import android.widget.TextView
import androidx.annotation.StringRes
import com.dpro.widgets.WeekdaysPicker
import com.google.common.base.Optional import com.google.common.base.Optional
import info.nightscout.androidaps.MainApp import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
import info.nightscout.androidaps.data.Profile
import info.nightscout.androidaps.logging.LTag import info.nightscout.androidaps.logging.LTag
import info.nightscout.androidaps.plugins.general.automation.elements.InputTime
import info.nightscout.androidaps.plugins.general.automation.elements.InputWeekDay
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.DateUtil
import info.nightscout.androidaps.utils.JsonHelper import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.MidnightTime
import info.nightscout.androidaps.utils.T import info.nightscout.androidaps.utils.T
import org.json.JSONObject import org.json.JSONObject
import java.util.* import java.util.*
class TriggerRecurringTime(mainApp: MainApp) : Trigger(mainApp) { class TriggerRecurringTime(mainApp: MainApp) : Trigger(mainApp) {
enum class DayOfWeek { private val days = InputWeekDay(mainApp)
MONDAY, TUESDAY, WEDNESDAY, THURSDAY, FRIDAY, SATURDAY, SUNDAY; private val time = InputTime(mainApp)
fun toCalendarInt(): Int {
return calendarInts[ordinal]
}
@get:StringRes val shortName: Int
get() = shortNames[ordinal]
companion object {
private val calendarInts = intArrayOf(
Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY,
Calendar.SATURDAY,
Calendar.SUNDAY
)
private val shortNames = intArrayOf(
R.string.weekday_monday_short,
R.string.weekday_tuesday_short,
R.string.weekday_wednesday_short,
R.string.weekday_thursday_short,
R.string.weekday_friday_short,
R.string.weekday_saturday_short,
R.string.weekday_sunday_short
)
fun fromCalendarInt(day: Int): DayOfWeek {
for (i in calendarInts.indices) {
if (calendarInts[i] == day) return values()[i]
}
throw IllegalStateException("Invalid day")
}
}
}
private val weekdays = BooleanArray(DayOfWeek.values().size)
private var hour = 0
private var minute = 0
private var validTo: Long = 0
constructor(mainApp: MainApp, triggerRecurringTime: TriggerRecurringTime) : this(mainApp) { constructor(mainApp: MainApp, triggerRecurringTime: TriggerRecurringTime) : this(mainApp) {
this.hour = triggerRecurringTime.hour this.time.value = triggerRecurringTime.time.value
this.minute = triggerRecurringTime.minute if (days.weekdays.size >= 0)
this.validTo = triggerRecurringTime.validTo System.arraycopy(triggerRecurringTime.days.weekdays, 0, days.weekdays, 0, triggerRecurringTime.days.weekdays.size)
if (weekdays.size >= 0)
System.arraycopy(triggerRecurringTime.weekdays, 0, weekdays, 0, triggerRecurringTime.weekdays.size)
} }
init {
for (day in DayOfWeek.values()) set(day, false)
}
operator fun set(day: DayOfWeek, value: Boolean): TriggerRecurringTime {
weekdays[day.ordinal] = value
return this
}
private fun isSet(day: DayOfWeek): Boolean = weekdays[day.ordinal]
override fun shouldRun(): Boolean { override fun shouldRun(): Boolean {
if (validTo != 0L && DateUtil.now() > validTo) return false val currentMinSinceMidnight = getMinSinceMidnight(DateUtil.now())
val c = Calendar.getInstance() val scheduledDayOfWeek = Calendar.getInstance()[Calendar.DAY_OF_WEEK]
val scheduledDayOfWeek = c[Calendar.DAY_OF_WEEK] val scheduled = getMinSinceMidnight(time.value.toLong())
val scheduledCal: Calendar = DateUtil.gregorianCalendar() if (days.isSet(Objects.requireNonNull(InputWeekDay.DayOfWeek.fromCalendarInt(scheduledDayOfWeek)))) {
scheduledCal[Calendar.HOUR_OF_DAY] = hour if (currentMinSinceMidnight >= scheduled && currentMinSinceMidnight - scheduled < 5) {
scheduledCal[Calendar.MINUTE] = minute
scheduledCal[Calendar.SECOND] = 0
val scheduled = scheduledCal.timeInMillis
if (isSet(Objects.requireNonNull(DayOfWeek.fromCalendarInt(scheduledDayOfWeek)))) {
if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription()) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true return true
} }
@ -104,11 +43,9 @@ class TriggerRecurringTime(mainApp: MainApp) : Trigger(mainApp) {
override fun toJSON(): String { override fun toJSON(): String {
val data = JSONObject() val data = JSONObject()
.put("hour", hour) .put("time", time.value)
.put("minute", minute) for (i in days.weekdays.indices) {
.put("validTo", validTo) data.put(InputWeekDay.DayOfWeek.values()[i].name, days.weekdays[i])
for (i in weekdays.indices) {
data.put(DayOfWeek.values()[i].name, weekdays[i])
} }
return JSONObject() return JSONObject()
.put("type", TriggerRecurringTime::class.java.name) .put("type", TriggerRecurringTime::class.java.name)
@ -118,11 +55,16 @@ class TriggerRecurringTime(mainApp: MainApp) : Trigger(mainApp) {
override fun fromJSON(data: String): Trigger { override fun fromJSON(data: String): Trigger {
val o = JSONObject(data) val o = JSONObject(data)
for (i in weekdays.indices) for (i in days.weekdays.indices)
weekdays[i] = JsonHelper.safeGetBoolean(o, DayOfWeek.values()[i].name) days.weekdays[i] = JsonHelper.safeGetBoolean(o, InputWeekDay.DayOfWeek.values()[i].name)
hour = JsonHelper.safeGetInt(o, "hour") if (o.has("hour")) {
minute = JsonHelper.safeGetInt(o, "minute") // do conversion from 2.5.1 format
validTo = JsonHelper.safeGetLong(o, "validTo") val hour = JsonHelper.safeGetInt(o, "hour")
val minute = JsonHelper.safeGetInt(o, "minute")
time.value = 60 * hour + minute
} else {
time.value = JsonHelper.safeGetInt(o, "time")
}
return this return this
} }
@ -133,17 +75,12 @@ class TriggerRecurringTime(mainApp: MainApp) : Trigger(mainApp) {
sb.append(resourceHelper.gs(R.string.every)) sb.append(resourceHelper.gs(R.string.every))
sb.append(" ") sb.append(" ")
var counter = 0 var counter = 0
for (i in getSelectedDays()) { for (i in days.getSelectedDays()) {
if (counter++ > 0) sb.append(",") if (counter++ > 0) sb.append(",")
sb.append(resourceHelper.gs(Objects.requireNonNull(DayOfWeek.fromCalendarInt(i)).shortName)) sb.append(resourceHelper.gs(Objects.requireNonNull(InputWeekDay.DayOfWeek.fromCalendarInt(i)).shortName))
} }
sb.append(" ") sb.append(" ")
val scheduledCal: Calendar = DateUtil.gregorianCalendar() sb.append(DateUtil.timeString(toMills(time.value)))
scheduledCal[Calendar.HOUR_OF_DAY] = hour
scheduledCal[Calendar.MINUTE] = minute
scheduledCal[Calendar.SECOND] = 0
val scheduled = scheduledCal.timeInMillis
sb.append(DateUtil.timeString(scheduled))
return if (counter == 0) resourceHelper.gs(R.string.never) else sb.toString() return if (counter == 0) resourceHelper.gs(R.string.never) else sb.toString()
} }
@ -151,61 +88,15 @@ class TriggerRecurringTime(mainApp: MainApp) : Trigger(mainApp) {
override fun duplicate(): Trigger = TriggerRecurringTime(mainApp, this) override fun duplicate(): Trigger = TriggerRecurringTime(mainApp, this)
private fun getSelectedDays(): List<Int> { private fun toMills(minutesSinceMidnight: Int): Long = MidnightTime.calc() + T.mins(minutesSinceMidnight.toLong()).msecs()
val selectedDays: MutableList<Int> = ArrayList()
for (i in weekdays.indices) { private fun getMinSinceMidnight(time: Long): Int = Profile.secondsFromMidnight(time) / 60
val day = DayOfWeek.values()[i]
val selected = weekdays[i]
if (selected) selectedDays.add(day.toCalendarInt())
}
return selectedDays
}
override fun generateDialog(root: LinearLayout) { override fun generateDialog(root: LinearLayout) {
val label = TextView(root.context) LayoutBuilder()
// TODO: Replace external tool WeekdaysPicker with a self-made GUI element .add(StaticLabel(mainApp, R.string.recurringTime))
val weekdaysPicker = WeekdaysPicker(root.context) .add(days)
weekdaysPicker.setEditable(true) .add(time)
weekdaysPicker.selectedDays = getSelectedDays() .build(root)
weekdaysPicker.setOnWeekdaysChangeListener { _: View?, i: Int, list: List<Int?> -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)) }
weekdaysPicker.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
weekdaysPicker.sundayFirstDay = Calendar.getInstance().firstDayOfWeek == Calendar.SUNDAY
weekdaysPicker.redrawDays()
root.addView(weekdaysPicker)
val timeButton = TextView(root.context)
val runAt = GregorianCalendar()
runAt[Calendar.HOUR_OF_DAY] = hour
runAt[Calendar.MINUTE] = minute
timeButton.text = DateUtil.timeString(runAt.timeInMillis)
val timeSetListener = TimePickerDialog.OnTimeSetListener { _, h, m ->
val cal = Calendar.getInstance()
hour = h
minute = m
cal.set(Calendar.HOUR_OF_DAY, hour)
cal.set(Calendar.MINUTE, minute)
cal.set(Calendar.SECOND, 0)
timeButton.text = DateUtil.timeString(cal.timeInMillis)
}
timeButton.setOnClickListener {
root.context?.let {
TimePickerDialog(it, timeSetListener, hour, 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)
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(timeButton)
root.addView(l)
} }
} }