Triggers injection

This commit is contained in:
Milos Kozak 2020-01-05 12:02:32 +01:00
parent bd1b1d8d76
commit 925de127a7
90 changed files with 2778 additions and 4284 deletions

View file

@ -4,11 +4,15 @@ 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
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
import info.nightscout.androidaps.plugins.general.automation.actions.*
import info.nightscout.androidaps.plugins.general.automation.elements.*
import info.nightscout.androidaps.plugins.general.automation.triggers.*
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.treatments.Treatment
import info.nightscout.androidaps.queue.commands.CommandSetProfile
@ -38,6 +42,26 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectObjective5(objective5: Objective5)
fun injectObjective6(objective6: Objective6)
fun injectAutomationEvent(automationEvent: AutomationEvent)
fun injectTrigger(trigger: Trigger)
fun injectTrigger(triggerAutosensValue: TriggerAutosensValue)
fun injectTrigger(triggerBg: TriggerBg)
fun injectTrigger(triggerBolusAgo: TriggerBolusAgo)
fun injectTrigger(triggerCOB: TriggerCOB)
fun injectTrigger(triggerConnector: TriggerConnector)
fun injectTrigger(triggerDelta: TriggerDelta)
fun injectTrigger(triggerDummy: TriggerDummy)
fun injectTrigger(triggerIob: TriggerIob)
fun injectTrigger(triggerLocation: TriggerLocation)
fun injectTrigger(triggerProfilePercent: TriggerProfilePercent)
fun injectTrigger(triggerPumpLastConnection: TriggerPumpLastConnection)
fun injectTrigger(triggerRecurringTime: TriggerRecurringTime)
fun injectTrigger(triggerTempTarget: TriggerTempTarget)
fun injectTrigger(triggerTime: TriggerTime)
fun injectTrigger(triggerTimeRange : TriggerTimeRange)
fun injectTrigger(triggerWifiSsid: TriggerWifiSsid)
fun injectAction(action: Action)
fun injectActionDummy(action: ActionDummy)
fun injectActionLoopDisable(action: ActionLoopDisable)
@ -51,6 +75,23 @@ interface AppComponent : AndroidInjector<MainApp> {
fun injectActionStartTempTarget(action: ActionStartTempTarget)
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(inputDelta: InputDelta)
fun injectElement(inputDouble: InputDouble)
fun injectElement(inputDuration: InputDuration)
fun injectElement(inputInsulin: InputInsulin)
fun injectElement(inputLocationMode: InputLocationMode)
fun injectElement(inputPercent: InputPercent)
fun injectElement(inputProfileName: InputProfileName)
fun injectElement(inputString: InputString)
fun injectElement(inputTempTarget: InputTempTarget)
fun injectElement(labelWithElement: LabelWithElement)
fun injectElement(staticLabel: StaticLabel)
fun injectTreatment(treatment: Treatment)
fun injectBgReading(bgReading: BgReading)

View file

@ -17,7 +17,10 @@ import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctionImplementation
import info.nightscout.androidaps.plugins.constraints.objectives.objectives.*
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
import info.nightscout.androidaps.plugins.general.automation.actions.*
import info.nightscout.androidaps.plugins.general.automation.elements.*
import info.nightscout.androidaps.plugins.general.automation.triggers.*
import info.nightscout.androidaps.plugins.general.overview.notifications.NotificationWithAction
import info.nightscout.androidaps.plugins.treatments.Treatment
import info.nightscout.androidaps.queue.commands.CommandSetProfile
@ -71,10 +74,30 @@ open class AppModule {
@ContributesAndroidInjector fun objective5Injector(): Objective5
@ContributesAndroidInjector fun objective6Injector(): Objective6
@ContributesAndroidInjector fun automationEventInjector(): AutomationEvent
@ContributesAndroidInjector fun triggerInjector(): Trigger
@ContributesAndroidInjector fun triggerAutosensValueInjector(): TriggerAutosensValue
@ContributesAndroidInjector fun triggerBgInjector(): TriggerBg
@ContributesAndroidInjector fun triggerBolusAgoInjector(): TriggerBolusAgo
@ContributesAndroidInjector fun triggerCOBInjector(): TriggerCOB
@ContributesAndroidInjector fun triggerConnectorInjector(): TriggerConnector
@ContributesAndroidInjector fun triggerDeltaInjector(): TriggerDelta
@ContributesAndroidInjector fun triggerDummyInjector(): TriggerDummy
@ContributesAndroidInjector fun triggerIobInjector(): TriggerIob
@ContributesAndroidInjector fun triggerLocationInjector(): TriggerLocation
@ContributesAndroidInjector fun triggerProfilePercentInjector(): TriggerProfilePercent
@ContributesAndroidInjector fun triggerPumpLastConnectonInjector(): TriggerPumpLastConnection
@ContributesAndroidInjector fun triggerRecurringTimeInjector(): TriggerRecurringTime
@ContributesAndroidInjector fun triggerTempTargetInjector(): TriggerTempTarget
@ContributesAndroidInjector fun triggerTime(): TriggerTime
@ContributesAndroidInjector fun triggerTimeRangeInjector(): TriggerTimeRange
@ContributesAndroidInjector fun triggerWifiSsidInjector(): TriggerWifiSsid
@ContributesAndroidInjector fun actionInjector(): Action
@ContributesAndroidInjector fun actionLoopDisableInjector(): ActionLoopDisable
@ContributesAndroidInjector fun actionLoopEnableInjector(): ActionLoopEnable
@ContributesAndroidInjector fun ActionLoopResumeInjector(): ActionLoopResume
@ContributesAndroidInjector fun actionLoopResumeInjector(): ActionLoopResume
@ContributesAndroidInjector fun actionLoopSuspendInjector(): ActionLoopSuspend
@ContributesAndroidInjector fun actionNotificationInjector(): ActionNotification
@ContributesAndroidInjector fun actionProfileSwitchInjector(): ActionProfileSwitch
@ -84,6 +107,23 @@ open class AppModule {
@ContributesAndroidInjector fun actionStopTempTargetInjector(): ActionStopTempTarget
@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 inputDeltaInjector(): InputDelta
@ContributesAndroidInjector fun inputDoubleInjector(): InputDouble
@ContributesAndroidInjector fun inputDurationInjector(): InputDuration
@ContributesAndroidInjector fun inputInsulinInjector(): InputInsulin
@ContributesAndroidInjector fun inputLocationModeInjector(): InputLocationMode
@ContributesAndroidInjector fun inputPercentInjector(): InputPercent
@ContributesAndroidInjector fun inputProfileNameInjector(): InputProfileName
@ContributesAndroidInjector fun inputStringInjector(): InputString
@ContributesAndroidInjector fun inputTempTargetInjector(): InputTempTarget
@ContributesAndroidInjector fun labelWithElementInjector(): LabelWithElement
@ContributesAndroidInjector fun staticLabelInjector(): StaticLabel
@ContributesAndroidInjector fun bgReadingInjector(): BgReading
@ContributesAndroidInjector fun treatmentInjector(): Treatment

View file

@ -1,103 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
import info.nightscout.androidaps.plugins.general.automation.actions.ActionDummy;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
public class AutomationEvent {
private static final Logger log = LoggerFactory.getLogger(AutomationEvent.class);
private Trigger trigger = new TriggerConnector();
private List<Action> actions = new ArrayList<>();
private String title;
private boolean enabled = true;
public void setTitle(String title) {
this.title = title;
}
public void setTrigger(Trigger trigger) {
this.trigger = trigger;
}
public Trigger getTrigger() {
return trigger;
}
public List<Action> getActions() {
return actions;
}
public boolean isEnabled() {
return enabled;
}
public void setEnabled(boolean newState) {
enabled = newState;
}
public TriggerConnector getPreconditions() {
TriggerConnector trigger = new TriggerConnector(TriggerConnector.Type.AND);
for (Action action : actions) {
if (action.getPrecondition() != null)
trigger.add(action.getPrecondition());
}
return trigger;
}
public void addAction(Action action) {
actions.add(action);
}
public String getTitle() {
return title;
}
public String toJSON() {
JSONObject o = new JSONObject();
try {
// title
o.put("title", title);
o.put("enabled", enabled);
// trigger
o.put("trigger", trigger.toJSON());
// actions
JSONArray array = new JSONArray();
for (Action a : actions) {
array.put(a.toJSON());
}
o.put("actions", array);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
public AutomationEvent fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
title = d.optString("title", "");
enabled = d.optBoolean("enabled", true);
trigger = Trigger.instantiate(d.getString("trigger"));
JSONArray array = d.getJSONArray("actions");
actions.clear();
for (int i = 0; i < array.length(); i++) {
actions.add(new ActionDummy(MainApp.instance()).instantiate(new JSONObject(array.getString(i))));
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return this;
}
}

View file

@ -0,0 +1,70 @@
package info.nightscout.androidaps.plugins.general.automation
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.general.automation.actions.Action
import info.nightscout.androidaps.plugins.general.automation.actions.ActionDummy
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.T
import org.json.JSONArray
import org.json.JSONObject
import java.util.*
import javax.inject.Inject
class AutomationEvent(private val mainApp: MainApp) {
@Inject lateinit var aapsLogger: AAPSLogger
var trigger: Trigger = TriggerConnector(mainApp)
val actions: MutableList<Action> = ArrayList()
var title: String? = null
var isEnabled = true
var lastRun: Long = 0
init {
mainApp.androidInjector().inject(this)
}
fun getPreconditions(): TriggerConnector {
val trigger = TriggerConnector(mainApp, TriggerConnector.Type.AND)
for (action in actions) {
action.precondition?.let { trigger.add(it) }
}
return trigger
}
fun addAction(action: Action) = actions.add(action)
fun toJSON(): String {
val array = JSONArray()
for (a in actions) array.put(a.toJSON())
return JSONObject()
.put("title", title)
.put("enabled", isEnabled)
.put("trigger", trigger.toJSON())
.put("actions", array)
.toString()
}
fun fromJSON(data: String?): AutomationEvent {
val d = JSONObject(data)
title = d.optString("title", "")
isEnabled = d.optBoolean("enabled", true)
trigger = TriggerDummy(mainApp).instantiate(JSONObject(d.getString("trigger")))
?: TriggerConnector(mainApp)
val array = d.getJSONArray("actions")
actions.clear()
for (i in 0 until array.length()) {
ActionDummy(mainApp).instantiate(JSONObject(array.getString(i)))?.let {
actions.add(it)
}
}
return this
}
fun shouldRun() : Boolean{
return lastRun <= DateUtil.now() - T.mins(5).msecs()
}
}

View file

@ -19,6 +19,7 @@ import androidx.recyclerview.widget.ItemTouchHelper
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import dagger.android.support.DaggerFragment
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
@ -45,6 +46,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var mainApp : MainApp
private var disposable: CompositeDisposable = CompositeDisposable()
private lateinit var eventListAdapter: EventListAdapter
@ -67,7 +69,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
automation_fabAddEvent.setOnClickListener {
val dialog = EditEventDialog()
val args = Bundle()
args.putString("event", AutomationEvent().toJSON())
args.putString("event", AutomationEvent(mainApp).toJSON())
args.putInt("position", -1) // New event
dialog.arguments = args
fragmentManager?.let { dialog.show(it, "EditEventDialog") }
@ -116,6 +118,19 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
itemTouchHelper?.startDrag(viewHolder)
}
fun fillIconSet(connector: TriggerConnector, set: HashSet<Int>) {
for (t in connector.list) {
if (t is TriggerConnector) {
fillIconSet(t, set)
} else {
val icon = t.icon()
if (icon.isPresent) {
set.add(icon.get()!!)
}
}
}
}
inner class EventListAdapter : RecyclerView.Adapter<EventListAdapter.ViewHolder>(), ItemTouchHelperAdapter {
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val v = LayoutInflater.from(parent.context).inflate(R.layout.automation_event_item, parent, false)
@ -137,7 +152,7 @@ class AutomationFragment : DaggerFragment(), OnStartDragListener {
holder.iconLayout.removeAllViews()
// trigger icons
val triggerIcons = HashSet<Int>()
TriggerConnector.fillIconSet(event.trigger as TriggerConnector, triggerIcons)
fillIconSet(event.trigger as TriggerConnector, triggerIcons)
for (res in triggerIcons) {
addImage(res, holder.context, holder.iconLayout)
}

View file

@ -149,7 +149,7 @@ class AutomationPlugin @Inject constructor(
val array = JSONArray(data)
for (i in 0 until array.length()) {
val o = array.getJSONObject(i)
val event = AutomationEvent().fromJSON(o.toString())
val event = AutomationEvent(mainApp).fromJSON(o.toString())
automationEvents.add(event)
}
} catch (e: JSONException) {
@ -169,7 +169,7 @@ class AutomationPlugin @Inject constructor(
aapsLogger.debug(LTag.AUTOMATION, "processActions")
for (event in automationEvents) {
if (event.isEnabled && event.trigger.shouldRun() && event.preconditions.shouldRun()) {
if (event.isEnabled && event.shouldRun() && event.trigger.shouldRun() && event.getPreconditions().shouldRun()) {
val actions = event.actions
for (action in actions) {
action.doAction(object : Callback() {
@ -190,7 +190,7 @@ class AutomationPlugin @Inject constructor(
}
})
}
event.trigger.executed(DateUtil.now())
event.lastRun = DateUtil.now()
}
}
storeToSP() // save last run time
@ -213,20 +213,20 @@ class AutomationPlugin @Inject constructor(
fun getTriggerDummyObjects(): List<Trigger> {
return listOf(
TriggerTime(),
TriggerRecurringTime(),
TriggerTimeRange(),
TriggerBg(),
TriggerDelta(),
TriggerIob(),
TriggerCOB(),
TriggerProfilePercent(),
TriggerTempTarget(),
TriggerWifiSsid(),
TriggerLocation(),
TriggerAutosensValue(),
TriggerBolusAgo(),
TriggerPumpLastConnection()
TriggerTime(mainApp),
TriggerRecurringTime(mainApp),
TriggerTimeRange(mainApp),
TriggerBg(mainApp),
TriggerDelta(mainApp),
TriggerIob(mainApp),
TriggerCOB(mainApp),
TriggerProfilePercent(mainApp),
TriggerTempTarget(mainApp),
TriggerWifiSsid(mainApp),
TriggerLocation(mainApp),
TriggerAutosensValue(mainApp),
TriggerBolusAgo(mainApp),
TriggerPumpLastConnection(mainApp)
)
}

View file

@ -17,6 +17,7 @@ import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
abstract class Action(val mainApp: MainApp) {
@Inject lateinit var aapsLogger: AAPSLogger
@ -61,7 +62,7 @@ abstract class Action(val mainApp: MainApp) {
val type = obj.getString("type")
val data = obj.optJSONObject("data")
val clazz = Class.forName(type).kotlin
return (clazz.constructors.first().call(mainApp) as Action).fromJSON(data?.toString()
return (clazz.primaryConstructor?.call(mainApp) as Action).fromJSON(data?.toString()
?: "")
//return (clazz.newInstance() as Action).fromJSON(data?.toString() ?: "")
} catch (e: ClassNotFoundException) {

View file

@ -14,15 +14,15 @@ import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class ActionLoopSuspend(mainApp: MainApp) : Action(mainApp) {
var minutes = InputDuration(0, InputDuration.TimeUnit.MINUTES)
var minutes = InputDuration(mainApp, 0, InputDuration.TimeUnit.MINUTES)
override fun friendlyName(): Int = R.string.suspendloop
override fun shortDescription(): String = resourceHelper.gs(R.string.suspendloopforXmin, minutes.minutes)
override fun shortDescription(): String = resourceHelper.gs(R.string.suspendloopforXmin, minutes.getMinutes())
@DrawableRes override fun icon(): Int = R.drawable.ic_pause_circle_outline_24dp
override fun doAction(callback: Callback) {
if (!loopPlugin.isSuspended) {
loopPlugin.suspendLoop(minutes.minutes)
loopPlugin.suspendLoop(minutes.getMinutes())
rxBus.send(EventRefreshOverview("ActionLoopSuspend"))
callback.result(PumpEnactResult().success(true).comment(R.string.ok))?.run()
} else {
@ -31,7 +31,7 @@ class ActionLoopSuspend(mainApp: MainApp) : Action(mainApp) {
}
override fun toJSON(): String {
val data = JSONObject().put("minutes", minutes.minutes)
val data = JSONObject().put("minutes", minutes.getMinutes())
return JSONObject()
.put("type", this.javaClass.name)
.put("data", data)
@ -40,7 +40,7 @@ class ActionLoopSuspend(mainApp: MainApp) : Action(mainApp) {
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
minutes.minutes = JsonHelper.safeGetInt(o, "minutes")
minutes.setMinutes(JsonHelper.safeGetInt(o, "minutes"))
return this
}
@ -48,7 +48,7 @@ class ActionLoopSuspend(mainApp: MainApp) : Action(mainApp) {
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(LabelWithElement(resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", minutes))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", minutes))
.build(root)
}
}

View file

@ -17,7 +17,7 @@ import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class ActionNotification(mainApp: MainApp) : Action(mainApp) {
var text = InputString()
var text = InputString(mainApp)
override fun friendlyName(): Int = R.string.notification
override fun shortDescription(): String = resourceHelper.gs(R.string.notification_message, text.value)
@ -41,7 +41,7 @@ class ActionNotification(mainApp: MainApp) : Action(mainApp) {
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
text.value = JsonHelper.safeGetString(o, "text")
text.value = JsonHelper.safeGetString(o, "text", "")
return this
}
@ -49,7 +49,7 @@ class ActionNotification(mainApp: MainApp) : Action(mainApp) {
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(LabelWithElement(resourceHelper.gs(R.string.message_short), "", text))
.add(LabelWithElement(mainApp,resourceHelper.gs(R.string.message_short), "", text))
.build(root)
}
}

View file

@ -15,7 +15,7 @@ import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class ActionProfileSwitch(mainApp: MainApp) : Action(mainApp) {
var inputProfileName: InputProfileName = InputProfileName("")
var inputProfileName: InputProfileName = InputProfileName(mainApp, "")
override fun friendlyName(): Int = R.string.profilename
override fun shortDescription(): String = resourceHelper.gs(R.string.changengetoprofilename, inputProfileName.value)
@ -51,7 +51,7 @@ class ActionProfileSwitch(mainApp: MainApp) : Action(mainApp) {
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(LabelWithElement(resourceHelper.gs(R.string.profilename), "", inputProfileName))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.profilename), "", inputProfileName))
.build(root)
}
@ -67,7 +67,7 @@ class ActionProfileSwitch(mainApp: MainApp) : Action(mainApp) {
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
inputProfileName.value = JsonHelper.safeGetString(o, "profileToSwitchTo")
inputProfileName.value = JsonHelper.safeGetString(o, "profileToSwitchTo", "")
return this
}
}

View file

@ -16,29 +16,29 @@ import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class ActionProfileSwitchPercent(mainApp: MainApp) : Action(mainApp) {
var pct = InputPercent()
var duration = InputDuration(0, InputDuration.TimeUnit.MINUTES)
var pct = InputPercent(mainApp)
var duration = InputDuration(mainApp, 0, InputDuration.TimeUnit.MINUTES)
override fun friendlyName(): Int = R.string.profilepercentage
override fun shortDescription(): String =
if (duration.minutes == 0) resourceHelper.gs(R.string.startprofileforever, pct.value.toInt())
else resourceHelper.gs(R.string.startprofile, pct.value.toInt(), duration.minutes)
if (duration.value == 0) resourceHelper.gs(R.string.startprofileforever, pct.value.toInt())
else resourceHelper.gs(R.string.startprofile, pct.value.toInt(), duration.value)
@DrawableRes override fun icon(): Int = R.drawable.icon_actions_profileswitch
init {
precondition = TriggerProfilePercent().comparator(Comparator.Compare.IS_EQUAL).setValue(100.0)
precondition = TriggerProfilePercent(mainApp, 100.0, Comparator.Compare.IS_EQUAL)
}
override fun doAction(callback: Callback) {
treatmentsPlugin.doProfileSwitch(duration.value.toInt(), pct.value.toInt(), 0)
treatmentsPlugin.doProfileSwitch(duration.value, pct.value.toInt(), 0)
callback.result(PumpEnactResult().success(true).comment(R.string.ok))?.run()
}
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(LabelWithElement(resourceHelper.gs(R.string.percent_u), "", pct))
.add(LabelWithElement(resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.percent_u), "", pct))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
.build(root)
}
@ -47,7 +47,7 @@ class ActionProfileSwitchPercent(mainApp: MainApp) : Action(mainApp) {
override fun toJSON(): String {
val data = JSONObject()
.put("percentage", pct.value)
.put("durationInMinutes", duration.minutes)
.put("durationInMinutes", duration.value)
return JSONObject()
.put("type", this.javaClass.name)
.put("data", data)
@ -57,7 +57,7 @@ class ActionProfileSwitchPercent(mainApp: MainApp) : Action(mainApp) {
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
pct.value = JsonHelper.safeGetDouble(o, "percentage")
duration.minutes = JsonHelper.safeGetInt(o, "durationInMinutes")
duration.value = JsonHelper.safeGetInt(o, "durationInMinutes")
return this
}
}

View file

@ -8,11 +8,11 @@ import info.nightscout.androidaps.plugins.general.automation.elements.InputStrin
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class ActionSendSMS(mainApp: MainApp) : Action(mainApp) {
var text = InputString()
var text = InputString(mainApp)
override fun friendlyName(): Int = R.string.sendsmsactiondescription
override fun shortDescription(): String = resourceHelper.gs(R.string.sendsmsactionlabel, text.value)
@ -33,7 +33,7 @@ class ActionSendSMS(mainApp: MainApp) : Action(mainApp) {
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
text.value = safeGetString(o, "text")
text.value = JsonHelper.safeGetString(o, "text", "")
return this
}
@ -41,7 +41,7 @@ class ActionSendSMS(mainApp: MainApp) : Action(mainApp) {
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(LabelWithElement(resourceHelper.gs(R.string.sendsmsactiontext), "", text))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.sendsmsactiontext), "", text))
.build(root)
}
}

View file

@ -17,17 +17,16 @@ import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuil
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTempTarget
import info.nightscout.androidaps.queue.Callback
import info.nightscout.androidaps.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble
import info.nightscout.androidaps.utils.JsonHelper.safeGetInt
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import org.json.JSONObject
class ActionStartTempTarget(mainApp: MainApp) : Action(mainApp) {
var value = InputTempTarget()
var duration = InputDuration(0, InputDuration.TimeUnit.MINUTES)
var value = InputTempTarget(mainApp)
var duration = InputDuration(mainApp, 0, InputDuration.TimeUnit.MINUTES)
init {
precondition = TriggerTempTarget().comparator(ComparatorExists.Compare.NOT_EXISTS)
precondition = TriggerTempTarget(mainApp, ComparatorExists.Compare.NOT_EXISTS)
}
override fun friendlyName(): Int = R.string.starttemptarget
@ -42,8 +41,8 @@ class ActionStartTempTarget(mainApp: MainApp) : Action(mainApp) {
override fun generateDialog(root: LinearLayout) {
val unitResId = if (value.units == Constants.MGDL) R.string.mgdl else R.string.mmol
LayoutBuilder()
.add(LabelWithElement(resourceHelper.gs(R.string.careportal_temporarytarget) + "\n[" + resourceHelper.gs(unitResId) + "]", "", value))
.add(LabelWithElement(resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.careportal_temporarytarget) + "\n[" + resourceHelper.gs(unitResId) + "]", "", value))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
.build(root)
}
@ -55,7 +54,7 @@ class ActionStartTempTarget(mainApp: MainApp) : Action(mainApp) {
val data = JSONObject()
.put("value", value.value)
.put("units", value.units)
.put("durationInMinutes", duration.minutes)
.put("durationInMinutes", duration.getMinutes())
return JSONObject()
.put("type", this.javaClass.name)
.put("data", data)
@ -64,16 +63,16 @@ class ActionStartTempTarget(mainApp: MainApp) : Action(mainApp) {
override fun fromJSON(data: String): Action {
val o = JSONObject(data)
value.units = safeGetString(o, "units")
value.units = JsonHelper.safeGetString(o, "units", Constants.MGDL)
value.value = safeGetDouble(o, "value")
duration.minutes = safeGetInt(o, "durationInMinutes")
duration.setMinutes(JsonHelper.safeGetInt(o, "durationInMinutes"))
return this
}
fun tt(): TempTarget =
TempTarget()
.date(DateUtil.now())
.duration(duration.minutes)
.duration(duration.getMinutes())
.reason("Automation")
.source(Source.USER)
.low(Profile.toMgdl(value.value, value.units))

View file

@ -15,6 +15,7 @@ import info.nightscout.androidaps.plugins.general.automation.events.EventAutomat
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
import kotlinx.android.synthetic.main.automation_dialog_choose_action.*
import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
class ChooseActionDialog : DialogFragmentWithDate() {
@Inject lateinit var automationPlugin: AutomationPlugin
@ -64,7 +65,7 @@ class ChooseActionDialog : DialogFragmentWithDate() {
private fun instantiateAction(): Action? {
return getActionClass()?.let {
val clazz = Class.forName(it).kotlin
clazz.constructors.first().call(mainApp) as Action
clazz.primaryConstructor?.call(mainApp) as Action
}
}

View file

@ -5,15 +5,18 @@ import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import android.widget.RadioButton
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import kotlinx.android.synthetic.main.automation_dialog_choose_trigger.*
import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
class ChooseTriggerDialog : DialogFragmentWithDate() {
@Inject lateinit var automationPlugin: AutomationPlugin
@Inject lateinit var mainApp : MainApp
private var checkedIndex = -1
private var clickListener: OnClickListener? = null
@ -39,7 +42,7 @@ class ChooseTriggerDialog : DialogFragmentWithDate() {
for (t in automationPlugin.getTriggerDummyObjects()) {
val radioButton = RadioButton(context)
radioButton.setText(t.friendlyName())
radioButton.tag = t.javaClass
radioButton.tag = t.javaClass.name
automation_chooseTriggerRadioGroup.addView(radioButton)
}
@ -65,15 +68,16 @@ class ChooseTriggerDialog : DialogFragmentWithDate() {
private fun instantiateTrigger(): Trigger? {
return getTriggerClass()?.let {
it.newInstance() as Trigger
val clazz = Class.forName(it).kotlin
clazz.primaryConstructor?.call(mainApp) as Trigger
}
}
private fun getTriggerClass(): Class<*>? {
private fun getTriggerClass(): String? {
val radioButtonID = automation_chooseTriggerRadioGroup.checkedRadioButtonId
val radioButton = automation_chooseTriggerRadioGroup.findViewById<RadioButton>(radioButtonID)
return radioButton?.let {
it.tag as Class<*>
it.tag as String
}
}

View file

@ -9,6 +9,7 @@ import android.widget.LinearLayout
import android.widget.TextView
import androidx.recyclerview.widget.LinearLayoutManager
import androidx.recyclerview.widget.RecyclerView
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
@ -31,21 +32,23 @@ import javax.inject.Inject
class EditEventDialog : DialogFragmentWithDate() {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp
@Inject lateinit var fabricPrivacy: FabricPrivacy
@Inject lateinit var automationPlugin: AutomationPlugin
private var actionListAdapter: ActionListAdapter? = null
private var event: AutomationEvent = AutomationEvent()
private lateinit var event: AutomationEvent
private var position: Int = -1
private var disposable: CompositeDisposable = CompositeDisposable()
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
savedInstanceState: Bundle?): View? {
event = AutomationEvent(mainApp)
// load data from bundle
(savedInstanceState ?: arguments)?.let { bundle ->
position = bundle.getInt("position", -1)
bundle.getString("event")?.let { event = AutomationEvent().fromJSON(it) }
bundle.getString("event")?.let { event = AutomationEvent(mainApp).fromJSON(it) }
}
onCreateViewGeneral()
@ -149,7 +152,7 @@ class EditEventDialog : DialogFragmentWithDate() {
}
private fun showPreconditions() {
val forcedTriggers = event.preconditions
val forcedTriggers = event.getPreconditions()
if (forcedTriggers.size() > 0) {
automation_forcedTriggerDescription.visibility = View.VISIBLE
automation_forcedTriggerDescriptionLabel.visibility = View.VISIBLE

View file

@ -4,16 +4,20 @@ import android.os.Bundle
import android.view.LayoutInflater
import android.view.View
import android.view.ViewGroup
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.dialogs.DialogFragmentWithDate
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerDummy
import kotlinx.android.synthetic.main.automation_dialog_edit_trigger.*
import org.json.JSONObject
import javax.inject.Inject
class EditTriggerDialog : DialogFragmentWithDate() {
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var mainApp: MainApp
private var trigger: Trigger? = null
@ -21,7 +25,7 @@ class EditTriggerDialog : DialogFragmentWithDate() {
savedInstanceState: Bundle?): View? {
// load data from bundle
(savedInstanceState ?: arguments)?.let { bundle ->
bundle.getString("trigger")?.let { trigger = Trigger.instantiate(it) }
bundle.getString("trigger")?.let { trigger = TriggerDummy(mainApp).instantiate(JSONObject(it)) }
}
onCreateViewGeneral()
@ -32,7 +36,7 @@ class EditTriggerDialog : DialogFragmentWithDate() {
super.onViewCreated(view, savedInstanceState)
// display root trigger
trigger?.generateDialog(automation_layoutTrigger, fragmentManager)
trigger?.generateDialog(automation_layoutTrigger)
}
override fun submit(): Boolean {

View file

@ -15,29 +15,28 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
import info.nightscout.androidaps.utils.resources.ResourceHelper;
public class TriggerListAdapter {
private final LinearLayout mRootLayout;
private final FragmentManager mFragmentManager;
private final Context mContext;
private final TriggerConnector mRootConnector;
private final MainApp mainApp;
private final ResourceHelper resourceHelper;
public TriggerListAdapter(FragmentManager fragmentManager, Context context, LinearLayout rootLayout, TriggerConnector rootTrigger) {
public TriggerListAdapter(MainApp mainApp, ResourceHelper resourceHelper, Context context, LinearLayout rootLayout, TriggerConnector rootTrigger) {
mRootLayout = rootLayout;
mFragmentManager = fragmentManager;
this.mainApp = mainApp;
this.resourceHelper = resourceHelper;
mContext = context;
mRootConnector = rootTrigger;
build(fragmentManager);
build(rootTrigger.scanForActivity(context).getSupportFragmentManager());
}
public Context getContext() {
return mContext;
}
private FragmentManager getFM() {
return mFragmentManager;
}
private void destroy() {
mRootLayout.removeAllViews();
}
@ -48,11 +47,11 @@ public class TriggerListAdapter {
// spinner
if (i > 0) {
createSpinner(trigger);
createSpinner(trigger, fragmentManager);
}
// trigger layout
trigger.generateDialog(mRootLayout, fragmentManager);
trigger.generateDialog(mRootLayout);
// buttons
createButtons(fragmentManager, trigger);
@ -60,7 +59,7 @@ public class TriggerListAdapter {
if (mRootConnector.size() == 0) {
Button buttonAdd = new Button(mContext);
buttonAdd.setText(MainApp.gs(R.string.addnew));
buttonAdd.setText(resourceHelper.gs(R.string.addnew));
buttonAdd.setOnClickListener(v -> {
ChooseTriggerDialog dialog = new ChooseTriggerDialog();
dialog.setOnClickListener(newTriggerObject -> {
@ -75,30 +74,30 @@ public class TriggerListAdapter {
private Spinner createSpinner() {
Spinner spinner = new Spinner(mContext);
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(mContext, R.layout.spinner_centered, TriggerConnector.Type.labels());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(mContext, R.layout.spinner_centered, TriggerConnector.Type.AND.labels(resourceHelper));
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
return spinner;
}
private void createSpinner(Trigger trigger) {
private void createSpinner(Trigger trigger, FragmentManager fragmentManager) {
final TriggerConnector connector = trigger.getConnector();
final int initialPosition = connector.getConnectorType().ordinal();
Spinner spinner = createSpinner();
spinner.setSelection(initialPosition);
spinner.setBackgroundColor(MainApp.gc(R.color.black_overlay));
spinner.setBackgroundColor(resourceHelper.gc(R.color.black_overlay));
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
params.setMargins(0, MainApp.dpToPx(8), 0, MainApp.dpToPx(8));
params.setMargins(0, resourceHelper.dpToPx(8), 0, resourceHelper.dpToPx(8));
spinner.setLayoutParams(params);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
if (position != initialPosition) {
// connector type changed
changeConnector(getFM(), trigger, connector, TriggerConnector.Type.values()[position]);
changeConnector(fragmentManager, trigger, connector, TriggerConnector.Type.values()[position]);
}
}
@ -123,35 +122,35 @@ public class TriggerListAdapter {
// Button [-]
Button buttonRemove = new Button(mContext);
buttonRemove.setText(MainApp.gs(R.string.delete_short));
buttonRemove.setText(resourceHelper.gs(R.string.delete_short));
buttonRemove.setOnClickListener(v -> {
final TriggerConnector connector = trigger.getConnector();
connector.remove(trigger);
connector.simplify().rebuildView(getFM());
connector.simplify().rebuildView(fragmentManager);
});
buttonLayout.addView(buttonRemove);
// Button [+]
Button buttonAdd = new Button(mContext);
buttonAdd.setText(MainApp.gs(R.string.add_short));
buttonAdd.setText(resourceHelper.gs(R.string.add_short));
buttonAdd.setOnClickListener(v -> {
ChooseTriggerDialog dialog = new ChooseTriggerDialog();
dialog.show(fragmentManager, "ChooseTriggerDialog");
dialog.setOnClickListener(newTriggerObject -> {
TriggerConnector connector = trigger.getConnector();
connector.add(connector.pos(trigger) + 1, newTriggerObject);
connector.simplify().rebuildView(getFM());
connector.simplify().rebuildView(fragmentManager);
});
});
buttonLayout.addView(buttonAdd);
// Button [*]
Button buttonCopy = new Button(mContext);
buttonCopy.setText(MainApp.gs(R.string.copy_short));
buttonCopy.setText(resourceHelper.gs(R.string.copy_short));
buttonCopy.setOnClickListener(v -> {
TriggerConnector connector = trigger.getConnector();
connector.add(connector.pos(trigger) + 1, trigger.duplicate());
connector.simplify().rebuildView(getFM());
connector.simplify().rebuildView(fragmentManager);
});
buttonLayout.addView(buttonCopy);
}
@ -161,12 +160,12 @@ public class TriggerListAdapter {
build(fragmentManager);
}
public static void changeConnector(final FragmentManager fragmentManager, final Trigger trigger, final TriggerConnector connector, final TriggerConnector.Type newConnectorType) {
public void changeConnector(final FragmentManager fragmentManager, final Trigger trigger, final TriggerConnector connector, final TriggerConnector.Type newConnectorType) {
if (connector.size() > 2) {
// split connector
int pos = connector.pos(trigger) - 1;
TriggerConnector newConnector = new TriggerConnector(newConnectorType);
TriggerConnector newConnector = new TriggerConnector(mainApp, newConnectorType);
// move trigger from pos and pos+1 into new connector
for (int i = 0; i < 2; ++i) {
@ -177,10 +176,8 @@ public class TriggerListAdapter {
connector.add(pos, newConnector);
} else {
connector.changeConnectorType(newConnectorType);
connector.setType(newConnectorType);
}
connector.simplify().rebuildView(fragmentManager);
}
}

View file

@ -1,123 +0,0 @@
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.StringRes;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
public class Comparator extends Element {
public enum Compare {
IS_LESSER,
IS_EQUAL_OR_LESSER,
IS_EQUAL,
IS_EQUAL_OR_GREATER,
IS_GREATER,
IS_NOT_AVAILABLE;
public @StringRes
int getStringRes() {
switch (this) {
case IS_LESSER:
return R.string.islesser;
case IS_EQUAL_OR_LESSER:
return R.string.isequalorlesser;
case IS_EQUAL:
return R.string.isequal;
case IS_EQUAL_OR_GREATER:
return R.string.isequalorgreater;
case IS_GREATER:
return R.string.isgreater;
case IS_NOT_AVAILABLE:
return R.string.isnotavailable;
default:
return R.string.unknown;
}
}
public <T extends Comparable> boolean check(T obj1, T obj2) {
if (obj1 == null || obj2 == null)
return this.equals(IS_NOT_AVAILABLE);
int comparison = obj1.compareTo(obj2);
switch (this) {
case IS_LESSER:
return comparison < 0;
case IS_EQUAL_OR_LESSER:
return comparison <= 0;
case IS_EQUAL:
return comparison == 0;
case IS_EQUAL_OR_GREATER:
return comparison >= 0;
case IS_GREATER:
return comparison > 0;
default:
return false;
}
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
for (Compare c : Compare.values()) {
list.add(MainApp.gs(c.getStringRes()));
}
return list;
}
}
private Compare compare = Compare.IS_EQUAL;
public Comparator() {
super();
}
public Comparator(Comparator another) {
super();
compare = another.getValue();
}
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), R.layout.spinner_centered, Compare.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
compare = Compare.values()[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(compare.ordinal());
root.addView(spinner);
}
public Compare getValue() {
return compare;
}
public Comparator setValue(Compare compare) {
this.compare = compare;
return this;
}
}

View file

@ -0,0 +1,88 @@
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.StringRes
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
class Comparator(mainApp: MainApp) : Element(mainApp) {
enum class Compare {
IS_LESSER,
IS_EQUAL_OR_LESSER,
IS_EQUAL,
IS_EQUAL_OR_GREATER,
IS_GREATER,
IS_NOT_AVAILABLE;
@get:StringRes val stringRes: Int
get() = when (this) {
IS_LESSER -> R.string.islesser
IS_EQUAL_OR_LESSER -> R.string.isequalorlesser
IS_EQUAL -> R.string.isequal
IS_EQUAL_OR_GREATER -> R.string.isequalorgreater
IS_GREATER -> R.string.isgreater
IS_NOT_AVAILABLE -> R.string.isnotavailable
}
fun <T : Comparable<T>> check(obj1: T, obj2: T): Boolean {
val comparison = obj1.compareTo(obj2)
return when (this) {
IS_LESSER -> comparison < 0
IS_EQUAL_OR_LESSER -> comparison <= 0
IS_EQUAL -> comparison == 0
IS_EQUAL_OR_GREATER -> comparison >= 0
IS_GREATER -> comparison > 0
else -> false
}
}
companion object {
fun labels(resourceHelper: ResourceHelper): List<String> {
val list: MutableList<String> = ArrayList()
for (c in values()) {
list.add(resourceHelper.gs(c.stringRes))
}
return list
}
}
}
constructor(mainApp: MainApp, value : Compare) : this(mainApp) {
this.value = value
}
var value = Compare.IS_EQUAL
override fun addToLayout(root: LinearLayout) {
val spinner = Spinner(root.context)
val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.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 = Compare.values()[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
spinner.setSelection(value.ordinal)
root.addView(spinner)
}
fun setValue(compare: Compare): Comparator {
value = compare
return this
}
}

View file

@ -1,90 +0,0 @@
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.StringRes;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
public class ComparatorExists extends Element {
public enum Compare {
EXISTS,
NOT_EXISTS;
public @StringRes
int getStringRes() {
switch (this) {
case EXISTS:
return R.string.exists;
case NOT_EXISTS:
return R.string.notexists;
default:
return R.string.unknown;
}
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
for (Compare c : Compare.values()) {
list.add(MainApp.gs(c.getStringRes()));
}
return list;
}
}
private Compare compare = Compare.EXISTS;
public ComparatorExists() {
super();
}
public ComparatorExists(ComparatorExists another) {
super();
compare = another.getValue();
}
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), R.layout.spinner_centered, Compare.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.MATCH_PARENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
compare = Compare.values()[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(compare.ordinal());
root.addView(spinner);
}
public Compare getValue() {
return compare;
}
public ComparatorExists setValue(Compare compare) {
this.compare = compare;
return this;
}
}

View file

@ -0,0 +1,57 @@
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.StringRes
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
class ComparatorExists(mainApp: MainApp) : Element(mainApp) {
enum class Compare {
EXISTS, NOT_EXISTS;
@get:StringRes val stringRes: Int
get() = when (this) {
EXISTS -> R.string.exists
NOT_EXISTS -> R.string.notexists
}
companion object {
fun labels(resourceHelper: ResourceHelper): List<String> {
val list: MutableList<String> = ArrayList()
for (c in values()) list.add(resourceHelper.gs(c.stringRes))
return list
}
}
}
constructor(mainApp: MainApp, value: Compare) : this(mainApp) {
this.value = value
}
var value = Compare.EXISTS
override fun addToLayout(root: LinearLayout) {
val spinner = Spinner(root.context)
val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, Compare.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 = Compare.values()[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
spinner.setSelection(value.ordinal)
root.addView(spinner)
}
}

View file

@ -1,7 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.widget.LinearLayout;
public abstract class Element {
public abstract void addToLayout(LinearLayout root);
}

View file

@ -0,0 +1,20 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.utils.resources.ResourceHelper
import javax.inject.Inject
abstract class Element(val mainApp: MainApp) {
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
abstract fun addToLayout(root: LinearLayout)
init {
mainApp.androidInjector().inject(this)
}
}

View file

@ -1,83 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.LinearLayout;
import java.text.DecimalFormat;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputBg extends Element {
static final int MMOL_MIN = 3;
static final int MMOL_MAX = 20;
static final int MGDL_MIN = 54;
static final int MGDL_MAX = 360;
private String units = Constants.MGDL;
private double value;
double minValue;
private double maxValue;
private double step;
private DecimalFormat decimalFormat;
public InputBg() {
super();
setUnits(ProfileFunctions.getSystemUnits());
if (getUnits().equals(Constants.MMOL))
value = MMOL_MIN;
else
value = MGDL_MIN;
}
public InputBg(InputBg another) {
super();
value = another.getValue();
setUnits(another.getUnits());
}
@Override
public void addToLayout(LinearLayout root) {
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null);
numberPicker.setOnValueChangedListener(value -> this.value = value);
root.addView(numberPicker);
}
public String getUnits() {
return units;
}
public InputBg setUnits(String units) {
// set default initial value
if (units.equals(Constants.MMOL)) {
// mmol
minValue = MMOL_MIN;
maxValue = MMOL_MAX;
step = 0.1;
decimalFormat = new DecimalFormat("0.0");
} else {
// mg/dL
minValue = MGDL_MIN;
maxValue = MGDL_MAX;
step = 1;
decimalFormat = new DecimalFormat("0");
}
this.units = units;
return this;
}
public InputBg setValue(double value) {
this.value = value;
return this;
}
public double getValue() {
return value;
}
}

View file

@ -0,0 +1,58 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import java.text.DecimalFormat
class InputBg(mainApp: MainApp) : Element(mainApp) {
var units = Constants.MGDL
var value = 0.0
private var minValue = 0.0
private var maxValue = 0.0
private var step = 0.0
private var decimalFormat: DecimalFormat? = null
constructor(mainApp: MainApp, value : Double, units: String) : this(mainApp) {
setUnits(units)
this.value = value
}
init {
setUnits(profileFunction.getUnits())
}
override fun addToLayout(root: LinearLayout) {
val numberPicker = NumberPicker(root.context, null)
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, false, root.findViewById(R.id.ok))
numberPicker.setOnValueChangedListener { value: Double -> this.value = value }
root.addView(numberPicker)
}
fun setUnits(units: String): InputBg {
if (units == Constants.MMOL) {
minValue = MMOL_MIN
maxValue = MMOL_MAX
step = 0.1
decimalFormat = DecimalFormat("0.0")
} else {
minValue = MGDL_MIN
maxValue = MGDL_MAX
step = 1.0
decimalFormat = DecimalFormat("0")
}
this.units = units
return this
}
companion object {
const val MMOL_MIN = 3.0
const val MMOL_MAX = 20.0
const val MGDL_MIN = 54.0
const val MGDL_MAX = 360.0
}
}

View file

@ -1,28 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.widget.Button;
import android.widget.LinearLayout;
public class InputButton extends Element {
String text;
Runnable runnable;
public InputButton(String text, Runnable runnable) {
this.text = text;
this.runnable = runnable;
}
@Override
public void addToLayout(LinearLayout root) {
Button button = new Button(root.getContext());
button.setText(text);
button.setOnClickListener(view -> {
if (runnable != null)
runnable.run();
});
root.addView(button);
}
}

View file

@ -0,0 +1,22 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.Button
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
class InputButton(mainApp: MainApp) : Element(mainApp) {
var text: String? = null
var runnable: Runnable? = null
constructor(mainApp: MainApp, text: String, runnable: Runnable) : this(mainApp) {
this.text = text
this.runnable = runnable
}
override fun addToLayout(root: LinearLayout) {
val button = Button(root.context)
button.text = text
button.setOnClickListener { runnable?.run() }
root.addView(button)
}
}

View file

@ -1,138 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import androidx.annotation.StringRes;
import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputDelta extends Element {
private Comparator.Compare compare = Comparator.Compare.IS_EQUAL;
public enum DeltaType {
DELTA,
SHORT_AVERAGE,
LONG_AVERAGE;
public @StringRes
int getStringRes() {
switch (this) {
case DELTA:
return R.string.delta;
case SHORT_AVERAGE:
return R.string.short_avgdelta;
case LONG_AVERAGE:
return R.string.long_avgdelta;
default:
return R.string.unknown;
}
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
for (DeltaType d : DeltaType.values()) {
list.add(MainApp.gs(d.getStringRes()));
}
return list;
}
}
private double value;
double minValue;
double maxValue;
private double step;
private DecimalFormat decimalFormat;
private DeltaType deltaType;
NumberPicker numberPicker;
public InputDelta() {
super();
}
public InputDelta(double value, double minValue, double maxValue, double step, DecimalFormat decimalFormat, DeltaType deltaType) {
super();
this.value = value;
this.minValue = minValue;
this.maxValue = maxValue;
this.step = step;
this.decimalFormat = decimalFormat;
this.deltaType = deltaType;
}
public InputDelta(InputDelta another) {
super();
value = another.getValue();
minValue = another.minValue;
maxValue = another.maxValue;
step = another.step;
decimalFormat = another.decimalFormat;
deltaType = another.deltaType;
}
@Override
public void addToLayout(LinearLayout root) {
Spinner spinner = new Spinner(root.getContext());
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(root.getContext(), R.layout.spinner_centered, DeltaType.labels());
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(spinnerArrayAdapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
deltaType = DeltaType.values()[position];
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(this.deltaType.ordinal());
// root.addView(spinner);
numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null);
numberPicker.setOnValueChangedListener(value -> this.value = value);
LinearLayout l = new LinearLayout(root.getContext());
l.setOrientation(LinearLayout.VERTICAL);
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
l.addView(spinner);
l.addView(numberPicker);
root.addView(l);
}
public InputDelta setValue(double value, DeltaType type) {
this.value = value;
this.deltaType = type;
if (numberPicker != null)
numberPicker.setValue(value);
return this;
}
public double getValue() {
return value;
}
public DeltaType getDeltaType() {
return deltaType;
}
}

View file

@ -0,0 +1,93 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.LinearLayout
import android.widget.Spinner
import androidx.annotation.StringRes
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.text.DecimalFormat
import java.util.*
class InputDelta(mainApp: MainApp) : Element(mainApp) {
enum class DeltaType {
DELTA, SHORT_AVERAGE, LONG_AVERAGE;
@get:StringRes val stringRes: Int
get() = when (this) {
DELTA -> R.string.delta
SHORT_AVERAGE -> R.string.short_avgdelta
LONG_AVERAGE -> R.string.long_avgdelta
}
companion object {
fun labels(resourceHelper: ResourceHelper): List<String> {
val list: MutableList<String> = ArrayList()
for (d in values()) {
list.add(resourceHelper.gs(d.stringRes))
}
return list
}
}
}
var value = 0.0
private var minValue = 0.0
private var maxValue = 0.0
private var step = 0.0
private var decimalFormat: DecimalFormat? = null
var deltaType: DeltaType = DeltaType.DELTA
constructor(mainApp: MainApp, value: Double, minValue: Double, maxValue: Double, step: Double, decimalFormat: DecimalFormat, deltaType: DeltaType) : this(mainApp) {
this.value = value
this.minValue = minValue
this.maxValue = maxValue
this.step = step
this.decimalFormat = decimalFormat
this.deltaType = deltaType
}
constructor(mainApp: MainApp, inputDelta: InputDelta) : this(mainApp) {
value = inputDelta.value
minValue = inputDelta.minValue
maxValue = inputDelta.maxValue
step = inputDelta.step
decimalFormat = inputDelta.decimalFormat
deltaType = inputDelta.deltaType
}
override fun addToLayout(root: LinearLayout) {
val spinner = Spinner(root.context)
val spinnerArrayAdapter = ArrayAdapter(root.context, R.layout.spinner_centered, DeltaType.labels(resourceHelper))
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = spinnerArrayAdapter
val spinnerParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
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) {
deltaType = DeltaType.values()[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
spinner.setSelection(deltaType.ordinal)
val numberPicker = NumberPicker(root.context, null)
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, null)
numberPicker.setOnValueChangedListener { value: Double -> this.value = value }
val l = LinearLayout(root.context)
l.orientation = LinearLayout.VERTICAL
l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
l.addView(spinner)
l.addView(numberPicker)
root.addView(l)
}
}

View file

@ -1,77 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.LinearLayout;
import java.text.DecimalFormat;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputDouble extends Element {
final TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
private double value;
private double minValue;
private double maxValue;
private double step;
private DecimalFormat decimalFormat;
NumberPicker numberPicker;
public InputDouble() {
super();
}
public InputDouble(double value, double minValue, double maxValue, double step, DecimalFormat decimalFormat) {
super();
this.value = value;
this.minValue = minValue;
this.maxValue = maxValue;
this.step = step;
this.decimalFormat = decimalFormat;
}
public InputDouble(InputDouble another) {
super();
value = another.getValue();
minValue = another.minValue;
maxValue = another.maxValue;
step = another.step;
decimalFormat = another.decimalFormat;
}
@Override
public void addToLayout(LinearLayout root) {
numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher);
numberPicker.setOnValueChangedListener(value -> this.value = value);
root.addView(numberPicker);
}
public InputDouble setValue(double value) {
this.value = value;
if (numberPicker != null)
numberPicker.setValue(value);
return this;
}
public double getValue() {
return value;
}
}

View file

@ -0,0 +1,45 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import java.text.DecimalFormat
class InputDouble(mainApp: MainApp) : Element(mainApp) {
var value = 0.0
private var minValue = 0.0
private var maxValue = 0.0
private var step = 0.0
private var decimalFormat: DecimalFormat? = null
private var numberPicker: NumberPicker? = null
constructor(mainApp: MainApp, value: Double, minValue: Double, maxValue: Double, step: Double, decimalFormat: DecimalFormat) : this(mainApp) {
this.value = value
this.minValue = minValue
this.maxValue = maxValue
this.step = step
this.decimalFormat = decimalFormat
}
constructor(mainApp: MainApp, inputDouble: InputDouble) : this(mainApp) {
this.value = inputDouble.value
this.minValue = inputDouble.minValue
this.maxValue = inputDouble.maxValue
this.step = inputDouble.step
this.decimalFormat = inputDouble.decimalFormat
}
override fun addToLayout(root: LinearLayout) {
numberPicker = NumberPicker(root.context, null)
numberPicker?.setParams(value, minValue, maxValue, step, decimalFormat, true, root.findViewById(R.id.ok))
numberPicker?.setOnValueChangedListener { value: Double -> this.value = value }
root.addView(numberPicker)
}
fun setValue(value: Double): InputDouble {
this.value = value
numberPicker?.value = value
return this
}
}

View file

@ -1,66 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.widget.LinearLayout;
import java.text.DecimalFormat;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputDuration extends Element {
public enum TimeUnit {
MINUTES,
HOURS
}
private TimeUnit unit;
private int value;
public InputDuration(int value, TimeUnit unit) {
this.unit = unit;
this.value = value;
}
public InputDuration(InputDuration another) {
unit = another.unit;
value = another.value;
}
@Override
public void addToLayout(LinearLayout root) {
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
if (unit.equals(TimeUnit.MINUTES)) {
// Minutes
numberPicker.setParams(0d, 0d, 24 * 60d, 10d, new DecimalFormat("0"), false, null);
} else {
// Hours
numberPicker.setParams(0d, 0d, 24d, 1d, new DecimalFormat("0"), false, null);
}
numberPicker.setValue((double) value);
numberPicker.setOnValueChangedListener(value -> this.value = (int) value);
root.addView(numberPicker);
}
TimeUnit getUnit() {
return unit;
}
public double getValue() {
return value;
}
public void setMinutes(int value) {
if (unit.equals(TimeUnit.MINUTES)) {
this.value = value;
} else {
this.value = value / 60;
}
}
public int getMinutes() {
if (unit.equals(TimeUnit.MINUTES)) {
return value;
} else {
return value * 60;
}
}
}

View file

@ -0,0 +1,49 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import java.text.DecimalFormat
class InputDuration(mainApp: MainApp) : Element(mainApp) {
enum class TimeUnit {
MINUTES, HOURS
}
constructor(mainApp: MainApp, value: Int, unit: TimeUnit) : this(mainApp) {
this.unit = unit
this.value = value
}
var unit: TimeUnit = TimeUnit.MINUTES
var value: Int = 0
override fun addToLayout(root: LinearLayout) {
val numberPicker = NumberPicker(root.context, null)
if (unit == TimeUnit.MINUTES)
numberPicker.setParams(0.0, 0.0, 24 * 60.0, 10.0, DecimalFormat("0"), false, root.findViewById(R.id.ok))
else
numberPicker.setParams(0.0, 0.0, 24.0, 1.0, DecimalFormat("0"), false, root.findViewById(R.id.ok))
numberPicker.value = value.toDouble()
numberPicker.setOnValueChangedListener { value: Double -> this.value = value.toInt() }
root.addView(numberPicker)
}
fun duplicate(): InputDuration {
val i = InputDuration(mainApp)
i.unit = unit
i.value = value
return i
}
fun getMinutes(): Int = if (unit == TimeUnit.MINUTES) value else value * 60
fun setMinutes(value: Int): InputDuration {
if (unit == TimeUnit.MINUTES)
this.value = value
else
this.value = value / 60
return this
}
}

View file

@ -1,57 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.LinearLayout;
import java.text.DecimalFormat;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputInsulin extends Element {
final TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
value = Math.max(value, -20d);
value = Math.min(value, 20d);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
private double value;
public InputInsulin() {
super();
}
public InputInsulin(InputInsulin another) {
super();
value = another.getValue();
}
@Override
public void addToLayout(LinearLayout root) {
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(0d, -20d, 20d, 0.1, new DecimalFormat("0.0"), true, null, textWatcher);
numberPicker.setValue(value);
numberPicker.setOnValueChangedListener(value -> this.value = value);
root.addView(numberPicker);
}
public double getValue() {
return value;
}
public InputInsulin setValue(double value) {
this.value = value;
return this;
}
}

View file

@ -0,0 +1,23 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import java.text.DecimalFormat
class InputInsulin(mainApp: MainApp) : Element(mainApp) {
var value = 0.0
constructor(mainApp: MainApp, another: InputInsulin) : this(mainApp) {
value = another.value
}
override fun addToLayout(root: LinearLayout) {
val numberPicker = NumberPicker(root.context, null)
numberPicker.setParams(0.0, -20.0, 20.0, 0.1, DecimalFormat("0.0"), true, root.findViewById(R.id.ok))
numberPicker.value = value
numberPicker.setOnValueChangedListener { value: Double -> this.value = value }
root.addView(numberPicker)
}
}

View file

@ -1,107 +0,0 @@
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.StringRes;
import java.util.ArrayList;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
public class InputLocationMode extends Element {
public enum Mode {
INSIDE,
OUTSIDE,
GOING_IN,
GOING_OUT;
public @StringRes
int getStringRes() {
switch (this) {
case INSIDE:
return R.string.location_inside;
case OUTSIDE:
return R.string.location_outside;
case GOING_IN:
return R.string.location_going_in;
case GOING_OUT:
return R.string.location_going_out;
default:
return R.string.unknown;
}
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
for (Mode c : Mode.values()) {
list.add(MainApp.gs(c.getStringRes()));
}
return list;
}
public Mode fromString(String wanted){
for (Mode c : Mode.values()) {
if(c.toString() == wanted)
return c;
}
return null;
}
}
private Mode mode;
public InputLocationMode() {
super();
mode = Mode.INSIDE;
}
public InputLocationMode(InputLocationMode another) {
super();
this.mode = another.mode;
}
@Override
public void addToLayout(LinearLayout root) {
ArrayAdapter<String> adapter = new ArrayAdapter<>(root.getContext(),
R.layout.spinner_centered, Mode.labels());
Spinner spinner = new Spinner(root.getContext());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setValue(Mode.values()[position]);
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(this.getValue().ordinal());
root.addView(spinner);
}
public Mode getValue() {
return mode;
}
public InputLocationMode setValue(Mode mode) {
this.mode = mode;
return this;
}
}

View file

@ -0,0 +1,71 @@
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.StringRes
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.resources.ResourceHelper
import java.util.*
class InputLocationMode(mainApp: MainApp) : Element(mainApp) {
enum class Mode {
INSIDE, OUTSIDE, GOING_IN, GOING_OUT;
@get:StringRes val stringRes: Int
get() = when (this) {
INSIDE -> R.string.location_inside
OUTSIDE -> R.string.location_outside
GOING_IN -> R.string.location_going_in
GOING_OUT -> R.string.location_going_out
}
fun fromString(wanted: String): Mode {
for (c in values()) {
if (c.toString() === wanted) return c
}
throw IllegalStateException("Invalid parameter")
}
companion object {
fun labels(resourceHelper: ResourceHelper): List<String> {
val list: MutableList<String> = ArrayList()
for (c in values()) {
list.add(resourceHelper.gs(c.stringRes))
}
return list
}
}
}
var value: Mode = Mode.INSIDE
constructor(mainApp: MainApp, value: InputLocationMode.Mode) : this(mainApp) {
this.value = value
}
override fun addToLayout(root: LinearLayout) {
val adapter = ArrayAdapter(root.context, R.layout.spinner_centered, Mode.labels(resourceHelper))
val spinner = Spinner(root.context)
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item)
spinner.adapter = adapter
val spinnerParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
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 = Mode.values()[position]
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
spinner.setSelection(value.ordinal)
root.addView(spinner)
}
}

View file

@ -1,58 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.LinearLayout;
import java.text.DecimalFormat;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputPercent extends Element {
final TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
value = Math.max(value, 70d);
value = Math.min(value, 130d);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
private double value;
public InputPercent() {
super();
value = 100d;
}
public InputPercent(InputPercent another) {
super();
value = another.getValue();
}
@Override
public void addToLayout(LinearLayout root) {
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(100d, 70d, 130d, 5d, new DecimalFormat("0"), true, null, textWatcher);
numberPicker.setValue(value);
numberPicker.setOnValueChangedListener(value -> this.value = value);
root.addView(numberPicker);
}
public double getValue() {
return value;
}
public InputPercent setValue(double value) {
this.value = value;
return this;
}
}

View file

@ -0,0 +1,28 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import java.text.DecimalFormat
class InputPercent(mainApp: MainApp) : Element(mainApp) {
var value: Double = 100.0
constructor(mainApp: MainApp, value: Double) : this(mainApp) {
this.value = value
}
override fun addToLayout(root: LinearLayout) {
val numberPicker = NumberPicker(root.context, null)
numberPicker.setParams(100.0, MIN, MAX, 5.0, DecimalFormat("0"), true, root.findViewById(R.id.ok))
numberPicker.value = value
numberPicker.setOnValueChangedListener { value: Double -> this.value = value }
root.addView(numberPicker)
}
companion object {
const val MIN = 70.0
const val MAX = 130.0
}
}

View file

@ -1,99 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.view.View;
import android.view.ViewGroup;
import android.widget.AdapterView;
import android.widget.ArrayAdapter;
import android.widget.LinearLayout;
import android.widget.Spinner;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.ProfileStore;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
public class InputProfileName extends Element {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
ProfileStore profileStore;
String profileName;
public InputProfileName(String name) {
super();
this.profileName = name;
}
public InputProfileName(InputProfileName another) {
super();
profileName = another.getValue();
}
@Override
public void addToLayout(LinearLayout root) {
ArrayList<CharSequence> profileList = new ArrayList<>();
profileStore = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile();
if (profileStore == null) {
log.error("ProfileStore is empty");
} else {
profileList = profileStore.getProfileList();
}
ArrayAdapter<CharSequence> adapter = new ArrayAdapter<>(root.getContext(),
R.layout.spinner_centered, profileList);
Spinner spinner = new Spinner(root.getContext());
adapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
spinner.setAdapter(adapter);
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
LinearLayout.LayoutParams.WRAP_CONTENT
);
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
spinner.setLayoutParams(spinnerParams);
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
@Override
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
setValue(listNames().get(position).toString());
}
@Override
public void onNothingSelected(AdapterView<?> parent) {
}
});
spinner.setSelection(0);
LinearLayout l = new LinearLayout(root.getContext());
l.setOrientation(LinearLayout.VERTICAL);
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
l.addView(spinner);
root.addView(l);
}
public InputProfileName setValue(String name) {
this.profileName = name;
return this;
}
public String getValue() {
return profileName;
}
public ArrayList<CharSequence> listNames(){
ArrayList<CharSequence> profileList = new ArrayList<>();
// profile
profileStore = ConfigBuilderPlugin.getPlugin().getActiveProfileInterface().getProfile();
if (profileStore == null) {
log.error("ProfileStore is empty");
} else {
profileList = profileStore.getProfileList();
}
return profileList;
}
}

View file

@ -0,0 +1,47 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.view.View
import android.view.ViewGroup
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.LinearLayout
import android.widget.Spinner
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
class InputProfileName(mainApp: MainApp) : Element(mainApp) {
var value: String = ""
constructor(mainApp: MainApp, name: String) : this(mainApp) {
value = name
}
override fun addToLayout(root: LinearLayout) {
val profileStore = ConfigBuilderPlugin.getPlugin().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)
val spinner = Spinner(root.context)
spinner.adapter = adapter
val spinnerParams = LinearLayout.LayoutParams(
LinearLayout.LayoutParams.WRAP_CONTENT,
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 = profileList[position].toString()
}
override fun onNothingSelected(parent: AdapterView<*>?) {}
}
spinner.setSelection(0)
val l = LinearLayout(root.context)
l.orientation = LinearLayout.VERTICAL
l.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT)
l.addView(spinner)
root.addView(l)
}
}

View file

@ -1,56 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.view.ViewGroup;
import android.widget.EditText;
import android.widget.LinearLayout;
public class InputString extends Element {
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
value = s.toString();
}
};
private String value = "";
public InputString() {
super();
}
public InputString(InputString another) {
super();
value = another.getValue();
}
@Override
public void addToLayout(LinearLayout root) {
EditText editText = new EditText(root.getContext());
editText.setText(value);
editText.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
editText.addTextChangedListener(textWatcher);
root.addView(editText);
}
public InputString setValue(String value) {
this.value = value;
return this;
}
public String getValue() {
return value;
}
}

View file

@ -0,0 +1,31 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.text.Editable
import android.text.TextWatcher
import android.view.ViewGroup
import android.widget.EditText
import android.widget.LinearLayout
import info.nightscout.androidaps.MainApp
class InputString(mainApp: MainApp) : Element(mainApp) {
var textWatcher: TextWatcher = object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
value = s.toString()
}
}
var value = ""
constructor(mainApp: MainApp, value: String) : this(mainApp) {
this.value = value
}
override fun addToLayout(root: LinearLayout) {
val editText = EditText(root.context)
editText.setText(value)
editText.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
editText.addTextChangedListener(textWatcher)
root.addView(editText)
}
}

View file

@ -1,95 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.text.Editable;
import android.text.TextWatcher;
import android.widget.LinearLayout;
import java.text.DecimalFormat;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.utils.NumberPicker;
public class InputTempTarget extends Element {
private String units = Constants.MGDL;
private double value;
double minValue;
private double maxValue;
private double step;
private DecimalFormat decimalFormat;
private final TextWatcher textWatcher = new TextWatcher() {
@Override
public void afterTextChanged(Editable s) {
value = Math.max(minValue, value);
value = Math.min(maxValue, value);
}
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
};
public InputTempTarget() {
super();
setUnits(ProfileFunctions.getSystemUnits());
if (getUnits().equals(Constants.MMOL))
value = 6;
else
value = 110;
}
public InputTempTarget(InputTempTarget another) {
super();
value = another.getValue();
setUnits(another.getUnits());
}
@Override
public void addToLayout(LinearLayout root) {
NumberPicker numberPicker = new NumberPicker(root.getContext(), null);
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, null, textWatcher);
numberPicker.setOnValueChangedListener(value -> this.value = value);
root.addView(numberPicker);
}
public String getUnits() {
return units;
}
public InputTempTarget setUnits(String units) {
// set default initial value
if (units.equals(Constants.MMOL)) {
// mmol
minValue = Constants.MIN_TT_MMOL;
maxValue = Constants.MAX_TT_MMOL;
step = 0.1;
decimalFormat = new DecimalFormat("0.0");
} else {
// mg/dL
minValue = Constants.MIN_TT_MGDL;
maxValue = Constants.MAX_TT_MGDL;
step = 1;
decimalFormat = new DecimalFormat("0");
}
this.units = units;
return this;
}
public InputTempTarget setValue(double value) {
this.value = value;
return this;
}
public double getValue() {
return value;
}
}

View file

@ -0,0 +1,44 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import info.nightscout.androidaps.Constants
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
import info.nightscout.androidaps.utils.NumberPicker
import java.text.DecimalFormat
class InputTempTarget(mainApp: MainApp) : Element(mainApp) {
var units = Constants.MGDL
var value = 0.0
init {
value = if (units == Constants.MMOL) 6.0 else 110.0
}
constructor(mainApp: MainApp, inputTempTarget: InputTempTarget) : this(mainApp) {
value = inputTempTarget.value
units = inputTempTarget.units
}
override fun addToLayout(root: LinearLayout) {
var minValue = 0.0
var maxValue = 0.0
var step = 0.0
var decimalFormat: DecimalFormat? = null
if (units == Constants.MMOL) { // mmol
minValue = Constants.MIN_TT_MMOL
maxValue = Constants.MAX_TT_MMOL
step = 0.1
decimalFormat = DecimalFormat("0.0")
} else { // mg/dL
minValue = Constants.MIN_TT_MGDL
maxValue = Constants.MAX_TT_MGDL
step = 1.0
decimalFormat = DecimalFormat("0")
}
val numberPicker = NumberPicker(root.context, null)
numberPicker.setParams(value, minValue, maxValue, step, decimalFormat, true, root.findViewById(R.id.ok))
numberPicker.setOnValueChangedListener { value: Double -> this.value = value }
root.addView(numberPicker)
}
}

View file

@ -1,64 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.graphics.Typeface;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TableLayout;
import android.widget.TextView;
import info.nightscout.androidaps.MainApp;
public class LabelWithElement extends Element {
final Element element;
final String textPre;
final String textPost;
public LabelWithElement(String textPre, String textPost, Element element) {
this.element = element;
this.textPre = textPre;
this.textPost = textPost;
}
@Override
public void addToLayout(LinearLayout root) {
// container layout
LinearLayout layout = new LinearLayout(root.getContext());
layout.setOrientation(LinearLayout.HORIZONTAL);
layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
// text view pre element
int px = MainApp.dpToPx(10);
TextView textViewPre = new TextView(root.getContext());
textViewPre.setText(textPre);
textViewPre.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
//textViewPre.setWidth(MainApp.dpToPx(120));
textViewPre.setPadding(px, px, px, px);
textViewPre.setTypeface(textViewPre.getTypeface(), Typeface.BOLD);
layout.addView(textViewPre);
TextView spacer = new TextView(root.getContext());
spacer.setLayoutParams(new TableLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f));
layout.addView(spacer);
// add element to layout
element.addToLayout(layout);
// text view post element
if (textPost != null) {
px = MainApp.dpToPx(5);
TextView textViewPost = new TextView(root.getContext());
textViewPost.setText(textPost);
textViewPost.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT));
//textViewPost.setWidth(MainApp.dpToPx(45));
textViewPost.setPadding(px, px, px, px);
textViewPost.setTypeface(textViewPost.getTypeface(), Typeface.BOLD);
layout.addView(textViewPost);
}
// add layout to root layout
root.addView(layout);
}
}

View file

@ -0,0 +1,55 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.graphics.Typeface
import android.view.ViewGroup
import android.widget.LinearLayout
import android.widget.TableLayout
import android.widget.TextView
import info.nightscout.androidaps.MainApp
class LabelWithElement(mainApp: MainApp) : Element(mainApp) {
var element: Element? = null
var textPre: String = ""
var textPost: String = ""
constructor(mainApp: MainApp, textPre: String, textPost: String, element: Element) : this(mainApp) {
this.textPre = textPre
this.textPost = textPost
this.element = element
}
override fun addToLayout(root: LinearLayout) { // container layout
val layout = LinearLayout(root.context)
layout.orientation = LinearLayout.HORIZONTAL
layout.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
// text view pre element
var px = resourceHelper.dpToPx(10)
val textViewPre = TextView(root.context)
textViewPre.text = textPre
textViewPre.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
//textViewPre.setWidth(MainApp.dpToPx(120));
textViewPre.setPadding(px, px, px, px)
textViewPre.setTypeface(textViewPre.typeface, Typeface.BOLD)
layout.addView(textViewPre)
val spacer = TextView(root.context)
spacer.layoutParams = TableLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT, 1f)
layout.addView(spacer)
// add element to layout
element?.addToLayout(layout)
// text view post element
px = resourceHelper.dpToPx(5)
val textViewPost = TextView(root.context)
textViewPost.text = textPost
textViewPost.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT,
ViewGroup.LayoutParams.WRAP_CONTENT)
//textViewPost.setWidth(MainApp.dpToPx(45));
textViewPost.setPadding(px, px, px, px)
textViewPost.setTypeface(textViewPost.typeface, Typeface.BOLD)
layout.addView(textViewPost)
// add layout to root layout
root.addView(layout)
}
}

View file

@ -1,26 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.widget.LinearLayout;
import java.util.ArrayList;
public class LayoutBuilder {
ArrayList<Element> mElements = new ArrayList<>();
public LayoutBuilder add(Element element) {
mElements.add(element);
return this;
}
public LayoutBuilder add(Element element, boolean condition) {
if (condition) mElements.add(element);
return this;
}
public void build(LinearLayout layout) {
for (Element e : mElements) {
e.addToLayout(layout);
}
}
}

View file

@ -0,0 +1,23 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.widget.LinearLayout
import java.util.*
class LayoutBuilder {
var mElements = ArrayList<Element>()
fun add(element: Element): LayoutBuilder {
mElements.add(element)
return this
}
fun add(element: Element, condition: Boolean): LayoutBuilder {
if (condition) mElements.add(element)
return this
}
fun build(layout: LinearLayout) {
for (e in mElements) {
e.addToLayout(layout)
}
}
}

View file

@ -1,36 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.elements;
import android.graphics.Typeface;
import android.widget.LinearLayout;
import android.widget.TextView;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
public class StaticLabel extends Element {
String label;
public StaticLabel(String label) {
super();
this.label = label;
}
public StaticLabel(int resourceId) {
super();
this.label = MainApp.gs(resourceId);
}
@Override
public void addToLayout(LinearLayout root) {
// text view pre element
int px = MainApp.dpToPx(10);
TextView textView = new TextView(root.getContext());
textView.setText(label);
// textViewPre.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setPadding(px, px, px, px);
textView.setTypeface(textView.getTypeface(), Typeface.BOLD);
textView.setBackgroundColor(MainApp.gc(R.color.mdtp_line_dark));
// add element to layout
root.addView(textView);
}
}

View file

@ -0,0 +1,30 @@
package info.nightscout.androidaps.plugins.general.automation.elements
import android.graphics.Typeface
import android.widget.LinearLayout
import android.widget.TextView
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.R
class StaticLabel(mainApp: MainApp) : Element(mainApp) {
var label = ""
constructor(mainApp: MainApp, label: String) : this(mainApp) {
this.label = label
}
constructor(mainApp: MainApp, resourceId: Int) : this(mainApp) {
label = resourceHelper.gs(resourceId)
}
override fun addToLayout(root: LinearLayout) { // text view pre element
val px = resourceHelper.dpToPx(10)
val textView = TextView(root.context)
textView.text = label
// textViewPre.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
textView.setPadding(px, px, px, px)
textView.setTypeface(textView.typeface, Typeface.BOLD)
textView.setBackgroundColor(resourceHelper.gc(R.color.mdtp_line_dark))
root.addView(textView)
}
}

View file

@ -1,97 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.content.Context;
import android.content.ContextWrapper;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import javax.annotation.Nullable;
public abstract class Trigger {
private static final Logger log = LoggerFactory.getLogger(Trigger.class);
TriggerConnector connector = null;
long lastRun;
Trigger() {
}
public TriggerConnector getConnector() {
return connector;
}
public abstract boolean shouldRun();
public abstract String toJSON();
/*package*/
abstract Trigger fromJSON(String data);
public abstract int friendlyName();
public abstract String friendlyDescription();
public abstract Optional<Integer> icon();
public void executed(long time) {
lastRun = time;
}
public long getLastRun() {
return lastRun;
}
public abstract Trigger duplicate();
public static Trigger instantiate(String json) {
try {
return instantiate(new JSONObject(json));
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return null;
}
@Nullable
public static Trigger instantiate(JSONObject object) {
try {
String type = object.getString("type");
JSONObject data = object.getJSONObject("data");
Class clazz = Class.forName(type);
return ((Trigger) clazz.newInstance()).fromJSON(data.toString());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
log.error("Unhandled exception", e);
}
return null;
}
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
TextView title = new TextView(root.getContext());
title.setText(friendlyName());
root.addView(title);
}
@Nullable
AppCompatActivity scanForActivity(Context cont) {
if (cont == null)
return null;
else if (cont instanceof AppCompatActivity)
return (AppCompatActivity) cont;
else if (cont instanceof ContextWrapper)
return scanForActivity(((ContextWrapper) cont).getBaseContext());
return null;
}
}

View file

@ -0,0 +1,79 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.content.Context
import android.content.ContextWrapper
import android.widget.LinearLayout
import android.widget.TextView
import androidx.appcompat.app.AppCompatActivity
import com.google.common.base.Optional
import info.nightscout.androidaps.MainApp
import info.nightscout.androidaps.logging.AAPSLogger
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin
import info.nightscout.androidaps.services.LocationService
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import org.json.JSONException
import org.json.JSONObject
import javax.inject.Inject
import kotlin.reflect.full.primaryConstructor
abstract class Trigger(val mainApp: MainApp) {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var resourceHelper: ResourceHelper
@Inject lateinit var profileFunction: ProfileFunction
@Inject lateinit var sp : SP
@Inject lateinit var locationService: LocationService
@Inject lateinit var treatmentsPlugin: TreatmentsPlugin
@Inject lateinit var configBuilderPlugin: ConfigBuilderPlugin
@Inject lateinit var iobCobCalculatorPlugin: IobCobCalculatorPlugin
var connector: TriggerConnector? = null
init {
mainApp.androidInjector().inject(this)
}
abstract fun shouldRun(): Boolean
abstract fun toJSON(): String
abstract fun fromJSON(data: String): Trigger
abstract fun friendlyName(): Int
abstract fun friendlyDescription(): String
abstract fun icon(): Optional<Int?>
abstract fun duplicate(): Trigger
open fun generateDialog(root: LinearLayout) {
val title = TextView(root.context)
title.setText(friendlyName())
root.addView(title)
}
fun scanForActivity(cont: Context?): AppCompatActivity? {
if (cont == null) return null
else if (cont is AppCompatActivity) return cont
else if (cont is ContextWrapper) return scanForActivity(cont.baseContext)
return null
}
fun instantiate(obj: JSONObject): Trigger? {
try {
val type = obj.getString("type")
val data = obj.getJSONObject("data")
val clazz = Class.forName(type).kotlin
return (clazz.primaryConstructor?.call(mainApp) as Trigger).fromJSON(data?.toString()
?: "")
} catch (e: ClassNotFoundException) {
aapsLogger.error("Unhandled exception", e)
} catch (e: InstantiationException) {
aapsLogger.error("Unhandled exception", e)
} catch (e: IllegalAccessException) {
aapsLogger.error("Unhandled exception", e)
} catch (e: JSONException) {
aapsLogger.error("Unhandled exception", e)
}
return null
}
}

View file

@ -1,153 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.AutosensData;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
public class TriggerAutosensValue extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private final int minValue = (int) (SP.getDouble("openapsama_autosens_min", 0.7d) * 100);
private final int maxValue = (int) (SP.getDouble("openapsama_autosens_max", 1.2d) * 100);
private final double step = 1;
private DecimalFormat decimalFormat = new DecimalFormat("1");
private InputDouble value = new InputDouble(100, (double) minValue, (double) maxValue, step, decimalFormat);
private Comparator comparator = new Comparator();
public TriggerAutosensValue() {
super();
}
private TriggerAutosensValue(TriggerAutosensValue triggerAutosensValue) {
super();
value = new InputDouble(triggerAutosensValue.value);
lastRun = triggerAutosensValue.lastRun;
comparator = new Comparator(triggerAutosensValue.comparator);
}
public double getValue() {
return value.getValue();
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
AutosensData autosensData = IobCobCalculatorPlugin.getPlugin().getLastAutosensData("Automation trigger");
if (autosensData == null)
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
return true;
else
return false;
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
boolean doRun = comparator.getValue().check((autosensData.autosensResult.ratio), getValue() / 100d);
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerAutosensValue.class.getName());
JSONObject data = new JSONObject();
data.put("value", getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
value.setValue(JsonHelper.safeGetDouble(d, "value"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.autosenslabel;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.autosenscompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.as);
}
@Override
public Trigger duplicate() {
return new TriggerAutosensValue(this);
}
TriggerAutosensValue setValue(int requestedValue) {
this.value.setValue(requestedValue);
return this;
}
TriggerAutosensValue lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerAutosensValue comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.autosenslabel))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.autosenslabel) + ": ", "", value))
.build(root);
}
}

View file

@ -0,0 +1,82 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import org.json.JSONObject
import java.text.DecimalFormat
class TriggerAutosensValue(mainApp: MainApp) : Trigger(mainApp) {
private val minValue = (sp.getDouble(R.string.key_openapsama_autosens_min, 0.7) * 100).toInt()
private val maxValue = (sp.getDouble(R.string.key_openapsama_autosens_max, 1.2) * 100).toInt()
private val step = 1.0
private val decimalFormat = DecimalFormat("1")
private var autosens: InputDouble = InputDouble(mainApp, 100.0, minValue.toDouble(), maxValue.toDouble(), step, decimalFormat)
var comparator: Comparator = Comparator(mainApp)
private constructor(mainApp: MainApp, triggerAutosensValue: TriggerAutosensValue) : this(mainApp) {
autosens = InputDouble(mainApp, triggerAutosensValue.autosens)
comparator = Comparator(mainApp, triggerAutosensValue.comparator.value)
}
override fun shouldRun(): Boolean {
val autosensData = iobCobCalculatorPlugin.getLastAutosensData("Automation trigger")
?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
true
} else {
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
false
}
if (comparator.value.check(autosensData.autosensResult.ratio, autosens.value / 100.0)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("value", autosens.value)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
autosens.setValue(safeGetDouble(d, "value"))
comparator.setValue(Comparator.Compare.valueOf(safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.autosenslabel
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.autosenscompared, resourceHelper.gs(comparator.value.stringRes), autosens.value)
override fun icon(): Optional<Int?> = Optional.of(R.drawable.`as`)
override fun duplicate(): Trigger = TriggerAutosensValue(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.autosenslabel))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.autosenslabel) + ": ", "", autosens))
.build(root)
}
}

View file

@ -1,178 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputBg;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerBg extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private InputBg bg = new InputBg();
private Comparator comparator = new Comparator();
public TriggerBg() {
super();
}
private TriggerBg(TriggerBg triggerBg) {
super();
bg = new InputBg(triggerBg.bg);
comparator = new Comparator(triggerBg.comparator);
lastRun = triggerBg.lastRun;
}
public double getValue() {
return bg.getValue();
}
public Comparator getComparator() {
return comparator;
}
public String getUnits() {
return bg.getUnits();
}
public long getLastRun() {
return lastRun;
}
@Override
public synchronized boolean shouldRun() {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (lastRun > DateUtil.now() - T.mins(5).msecs()) {
if (L.isEnabled(L.AUTOMATION))
log.debug("NOT ready for execution: " + friendlyDescription());
return false;
}
if (glucoseStatus == null && comparator.getValue().equals(Comparator.Compare.IS_NOT_AVAILABLE)) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
if (glucoseStatus == null) {
if (L.isEnabled(L.AUTOMATION))
log.debug("NOT ready for execution: " + friendlyDescription());
return false;
}
boolean doRun = comparator.getValue().check(glucoseStatus.glucose, Profile.toMgdl(bg.getValue(), bg.getUnits()));
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
if (L.isEnabled(L.AUTOMATION))
log.debug("NOT ready for execution: " + friendlyDescription());
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerBg.class.getName());
JSONObject data = new JSONObject();
data.put("bg", bg.getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
data.put("units", bg.getUnits());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
bg.setUnits(JsonHelper.safeGetString(d, "units"));
bg.setValue(JsonHelper.safeGetDouble(d, "bg"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.glucose;
}
@Override
public String friendlyDescription() {
if (comparator.getValue().equals(Comparator.Compare.IS_NOT_AVAILABLE))
return MainApp.gs(R.string.glucoseisnotavailable);
else {
return MainApp.gs(bg.getUnits().equals(Constants.MGDL) ? R.string.glucosecomparedmgdl : R.string.glucosecomparedmmol, MainApp.gs(comparator.getValue().getStringRes()), bg.getValue(), bg.getUnits());
}
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.icon_cp_bgcheck);
}
@Override
public Trigger duplicate() {
return new TriggerBg(this);
}
TriggerBg setValue(double value) {
bg.setValue(value);
return this;
}
TriggerBg lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerBg comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
TriggerBg setUnits(String units) {
bg.setUnits(units);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.glucose))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.glucose_u, bg.getUnits()), "", bg))
.build(root);
}
}

View file

@ -0,0 +1,90 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
import com.google.common.base.Optional
import info.nightscout.androidaps.Constants
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputBg
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class TriggerBg(mainApp: MainApp) : Trigger(mainApp) {
private var bg = InputBg(mainApp)
var comparator = Comparator(mainApp)
constructor(mainApp: MainApp, value : Double, units : String, compare: Comparator.Compare) : this(mainApp){
bg = InputBg(mainApp, value, units)
comparator = Comparator(mainApp, compare)
}
constructor(mainApp: MainApp, triggerBg: TriggerBg) : this(mainApp){
bg = InputBg(mainApp, triggerBg.bg.value, triggerBg.bg.units)
comparator = Comparator(mainApp, triggerBg.comparator.value)
}
override fun shouldRun(): Boolean {
val glucoseStatus = GlucoseStatus.getGlucoseStatusData()
if (glucoseStatus == null && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
if (glucoseStatus == null) {
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
if (comparator.value.check(glucoseStatus.glucose, Profile.toMgdl(bg.value, bg.units))) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("bg", bg.value)
.put("comparator", comparator.value.toString())
.put("units", bg.units)
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
bg.setUnits(JsonHelper.safeGetString(d, "units")!!)
bg.value = JsonHelper.safeGetDouble(d, "bg")
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.glucose
override fun friendlyDescription(): String {
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE)
resourceHelper.gs(R.string.glucoseisnotavailable)
else
resourceHelper.gs(if (bg.units == Constants.MGDL) R.string.glucosecomparedmgdl else R.string.glucosecomparedmmol, resourceHelper.gs(comparator.value.stringRes), bg.value, bg.units)
}
override fun icon(): Optional<Int?> = Optional.of(R.drawable.icon_cp_bgcheck)
override fun duplicate(): Trigger = TriggerBg(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.glucose))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.glucose_u, bg.units), "", bg))
.build(root)
}
}

View file

@ -1,150 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerBolusAgo extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private InputDuration minutesAgo = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
private Comparator comparator = new Comparator();
public TriggerBolusAgo() {
super();
}
private TriggerBolusAgo(TriggerBolusAgo triggerBolusAgo) {
super();
minutesAgo = new InputDuration(triggerBolusAgo.minutesAgo);
lastRun = triggerBolusAgo.lastRun;
comparator = new Comparator(triggerBolusAgo.comparator);
}
public double getValue() {
return minutesAgo.getValue();
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
long lastBolusTime = TreatmentsPlugin.getPlugin().getLastBolusTime(false);
if (lastBolusTime == 0)
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
return true;
else
return false;
double minutesAgo = (double) (DateUtil.now() - lastBolusTime) / (60 * 1000);
if (L.isEnabled(L.AUTOMATION))
log.debug("LastBolus min ago: " + minutesAgo);
boolean doRun = comparator.getValue().check((minutesAgo), getValue());
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerBolusAgo.class.getName());
JSONObject data = new JSONObject();
data.put("minutesAgo", getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
minutesAgo.setMinutes(JsonHelper.safeGetInt(d, "minutesAgo"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.lastboluslabel;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.lastboluscompared, MainApp.gs(comparator.getValue().getStringRes()), (int) getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.icon_bolus);
}
@Override
public Trigger duplicate() {
return new TriggerBolusAgo(this);
}
TriggerBolusAgo setValue(int requestedValue) {
this.minutesAgo.setMinutes(requestedValue);
return this;
}
TriggerBolusAgo lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerBolusAgo comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.lastboluslabel))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.lastboluslabel) + ": ", "", minutesAgo))
.build(root);
}
}

View file

@ -0,0 +1,81 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
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
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import org.json.JSONObject
class TriggerBolusAgo(mainApp: MainApp) : Trigger(mainApp) {
private var minutesAgo: InputDuration = InputDuration(mainApp, 0, InputDuration.TimeUnit.MINUTES)
var comparator: Comparator = Comparator(mainApp)
private constructor(mainApp: MainApp, triggerBolusAgo: TriggerBolusAgo) : this(mainApp) {
minutesAgo = InputDuration(mainApp, triggerBolusAgo.minutesAgo.value, InputDuration.TimeUnit.MINUTES)
comparator = Comparator(mainApp, triggerBolusAgo.comparator.value)
}
override fun shouldRun(): Boolean {
val lastBolusTime = treatmentsPlugin.getLastBolusTime(false)
if (lastBolusTime == 0L)
return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
true
} else {
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
false
}
val last = (DateUtil.now() - lastBolusTime).toDouble() / (60 * 1000)
aapsLogger.debug(LTag.AUTOMATION, "LastBolus min ago: $minutesAgo")
val doRun = comparator.value.check(last.toInt(), minutesAgo.getMinutes())
if (doRun) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("minutesAgo", minutesAgo.value)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
minutesAgo.setMinutes(JsonHelper.safeGetInt(d, "minutesAgo"))
comparator.setValue(Comparator.Compare.valueOf(safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.lastboluslabel
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.lastboluscompared, resourceHelper.gs(comparator.value.stringRes), minutesAgo.getMinutes())
override fun icon(): Optional<Int?> = Optional.of(R.drawable.icon_bolus)
override fun duplicate(): Trigger = TriggerBolusAgo(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.lastboluslabel))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.lastboluslabel) + ": ", "", minutesAgo))
.build(root)
}
}

View file

@ -1,151 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.CobInfo;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.SP;
import info.nightscout.androidaps.utils.T;
public class TriggerCOB extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private final int minValue = 0;
private final int maxValue = SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48);
private InputDouble value = new InputDouble(0, (double) minValue, (double) maxValue, 1, new DecimalFormat("1"));
private Comparator comparator = new Comparator();
public TriggerCOB() {
super();
}
private TriggerCOB(TriggerCOB triggerCOB) {
super();
value = new InputDouble(triggerCOB.value);
lastRun = triggerCOB.lastRun;
comparator = new Comparator(triggerCOB.comparator);
}
public double getValue() {
return value.getValue();
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
CobInfo cobInfo = IobCobCalculatorPlugin.getPlugin().getCobInfo(false, "AutomationTriggerCOB");
if (cobInfo == null)
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
return true;
else
return false;
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
boolean doRun = comparator.getValue().check((cobInfo.displayCob), getValue());
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerCOB.class.getName());
JSONObject data = new JSONObject();
data.put("carbs", getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
value.setValue(JsonHelper.safeGetDouble(d, "carbs"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.triggercoblabel;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.cobcompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.icon_cp_bolus_carbs);
}
@Override
public Trigger duplicate() {
return new TriggerCOB(this);
}
TriggerCOB setValue(int requestedValue) {
this.value.setValue(requestedValue);
return this;
}
TriggerCOB lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerCOB comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.triggercoblabel))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.triggercoblabel) + ": ", "", value))
.build(root);
}
}

View file

@ -0,0 +1,81 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.JsonHelper.safeGetDouble
import org.json.JSONObject
import java.text.DecimalFormat
class TriggerCOB(mainApp: MainApp) : Trigger(mainApp) {
private val minValue = 0
private val maxValue = sp.getInt(R.string.key_treatmentssafety_maxcarbs, 48)
private var cob: InputDouble = InputDouble(mainApp, 0.0, minValue.toDouble(), maxValue.toDouble(), 1.0, DecimalFormat("1"))
var comparator: Comparator = Comparator(mainApp)
private constructor(mainApp: MainApp, triggerCOB: TriggerCOB) : this(mainApp) {
cob = InputDouble(mainApp, triggerCOB.cob)
comparator = Comparator(mainApp, triggerCOB.comparator.value)
}
override fun shouldRun(): Boolean {
val cobInfo = iobCobCalculatorPlugin.getCobInfo(false, "AutomationTriggerCOB")
if (cobInfo.displayCob == null) {
return if (comparator.value === Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
true
} else {
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
false
}
}
if (comparator.value.check(cobInfo.displayCob, cob.value)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
@Synchronized override fun toJSON(): String {
val data = JSONObject()
.put("carbs", cob.value)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
cob.setValue(safeGetDouble(d, "carbs"))
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.triggercoblabel
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.cobcompared, resourceHelper.gs(comparator.value.stringRes), cob.value)
override fun icon(): Optional<Int?> = Optional.of(R.drawable.icon_cp_bolus_carbs)
override fun duplicate(): Trigger = TriggerCOB(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.triggercoblabel))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.triggercoblabel) + ": ", "", cob))
.build(root)
}
}

View file

@ -1,277 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import androidx.annotation.StringRes;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.dialogs.TriggerListAdapter;
import info.nightscout.androidaps.utils.JsonHelper;
public class TriggerConnector extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
public enum Type {
AND,
OR,
XOR;
public boolean apply(boolean a, boolean b) {
switch (this) {
case AND:
return a && b;
case OR:
return a || b;
case XOR:
return a ^ b;
}
return false;
}
public @StringRes
int getStringRes() {
switch (this) {
case OR:
return R.string.or;
case XOR:
return R.string.xor;
default:
case AND:
return R.string.and;
}
}
public static List<String> labels() {
List<String> list = new ArrayList<>();
for (Type t : values()) {
list.add(MainApp.gs(t.getStringRes()));
}
return list;
}
}
public static void fillIconSet(TriggerConnector connector, HashSet<Integer> set) {
for (Trigger t : connector.list) {
if (t instanceof TriggerConnector) {
fillIconSet((TriggerConnector) t, set);
} else {
Optional<Integer> icon = t.icon();
if (icon.isPresent()) {
set.add(icon.get());
}
}
}
}
protected List<Trigger> list = new ArrayList<>();
private Type connectorType;
public TriggerConnector() {
connectorType = Type.AND;
}
public TriggerConnector(Type connectorType) {
this.connectorType = connectorType;
}
public void changeConnectorType(Type type) {
this.connectorType = type;
}
public Type getConnectorType() {
return connectorType;
}
public synchronized void add(Trigger t) {
list.add(t);
t.connector = this;
}
public synchronized void add(int pos, Trigger t) {
list.add(pos, t);
t.connector = this;
}
public synchronized boolean remove(Trigger t) {
return list.remove(t);
}
public int size() {
return list.size();
}
public Trigger get(int i) {
return list.get(i);
}
public int pos(Trigger trigger) {
for (int i = 0; i < list.size(); ++i) {
if (list.get(i) == trigger) return i;
}
return -1;
}
@Override
public synchronized boolean shouldRun() {
boolean result = true;
// check first trigger
if (list.size() > 0)
result = list.get(0).shouldRun();
// check all others
for (int i = 1; i < list.size(); ++i) {
result = connectorType.apply(result, list.get(i).shouldRun());
}
if (result)
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription().replace("\n", " "));
return result;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerConnector.class.getName());
JSONObject data = new JSONObject();
data.put("connectorType", connectorType.toString());
JSONArray array = new JSONArray();
for (Trigger t : list) {
array.put(t.toJSON());
}
data.put("triggerList", array);
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
connectorType = Type.valueOf(JsonHelper.safeGetString(d, "connectorType"));
JSONArray array = d.getJSONArray("triggerList");
list.clear();
for (int i = 0; i < array.length(); i++) {
Trigger newItem = instantiate(new JSONObject(array.getString(i)));
add(newItem);
}
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return connectorType.getStringRes();
}
@Override
public String friendlyDescription() {
int counter = 0;
StringBuilder result = new StringBuilder();
for (Trigger t : list) {
if (counter++ > 0) result.append("\n").append(MainApp.gs(friendlyName())).append("\n");
result.append(t.friendlyDescription());
}
return result.toString();
}
@Override
public Optional<Integer> icon() {
return Optional.absent();
}
@Override
public void executed(long time) {
for (int i = 0; i < list.size(); ++i) {
list.get(i).executed(time);
}
}
@Override
public Trigger duplicate() {
return null;
}
private TriggerListAdapter adapter;
public void rebuildView(FragmentManager fragmentManager) {
if (adapter != null)
adapter.rebuild(fragmentManager);
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
final int padding = MainApp.dpToPx(5);
root.setPadding(padding, padding, padding, padding);
root.setBackgroundResource(R.drawable.border_automation_unit);
LinearLayout triggerListLayout = new LinearLayout(root.getContext());
triggerListLayout.setOrientation(LinearLayout.VERTICAL);
triggerListLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(triggerListLayout);
adapter = new TriggerListAdapter(fragmentManager, root.getContext(), triggerListLayout, this);
}
public TriggerConnector simplify() {
// simplify children
for (int i = 0; i < size(); ++i) {
if (get(i) instanceof TriggerConnector) {
TriggerConnector t = (TriggerConnector) get(i);
t.simplify();
}
}
// drop connector with only 1 element
if (size() == 1 && get(0) instanceof TriggerConnector) {
TriggerConnector c = (TriggerConnector) get(0);
remove(c);
changeConnectorType(c.getConnectorType());
for (Trigger t : c.list) {
add(t);
}
c.list.clear();
return simplify();
}
// merge connectors
if (connector != null && (connector.getConnectorType().equals(connectorType) || size() == 1)) {
final int pos = connector.pos(this);
connector.remove(this);
// move triggers of child connector into parent connector
for (int i = size() - 1; i >= 0; --i) {
connector.add(pos, get(i));
}
list.clear();
return connector.simplify();
}
return this;
}
}

View file

@ -0,0 +1,181 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.view.ViewGroup
import android.widget.LinearLayout
import androidx.annotation.StringRes
import androidx.fragment.app.FragmentManager
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.dialogs.TriggerListAdapter
import info.nightscout.androidaps.utils.JsonHelper.safeGetString
import info.nightscout.androidaps.utils.resources.ResourceHelper
import org.json.JSONArray
import org.json.JSONObject
import java.util.*
class TriggerConnector(mainApp: MainApp) : Trigger(mainApp) {
var list: MutableList<Trigger> = ArrayList()
var connectorType: Type = Type.AND
enum class Type {
AND, OR, XOR;
fun apply(a: Boolean, b: Boolean): Boolean =
when (this) {
AND -> a && b
OR -> a || b
XOR -> a xor b
}
@get:StringRes val stringRes: Int
get() = when (this) {
OR -> R.string.or
XOR -> R.string.xor
AND -> R.string.and
}
fun labels(resourceHelper: ResourceHelper): List<String> {
val list: MutableList<String> = ArrayList()
for (t in values()) {
list.add(resourceHelper.gs(t.stringRes))
}
return list
}
}
constructor(mainApp: MainApp, connectorType: Type) : this(mainApp) {
this.connectorType = connectorType
}
fun setType(type: Type) {
connectorType = type
}
@Synchronized
fun add(t: Trigger) {
list.add(t)
t.connector = this
}
@Synchronized
fun add(pos: Int, t: Trigger) {
list.add(pos, t)
t.connector = this
}
@Synchronized
fun remove(t: Trigger): Boolean = list.remove(t)
fun size(): Int = list.size
operator fun get(i: Int): Trigger = list[i]
fun pos(trigger: Trigger): Int {
for (i in list.indices) {
if (list[i] === trigger) return i
}
return -1
}
@Synchronized override fun shouldRun(): Boolean {
var result = true
// check first trigger
if (list.size > 0) result = list[0].shouldRun()
// check all others
for (i in 1 until list.size) {
result = connectorType.apply(result, list[i].shouldRun())
}
if (result) aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription().replace("\n", " "))
return result
}
@Synchronized override fun toJSON(): String {
val array = JSONArray()
for (t in list) array.put(t.toJSON())
val data = JSONObject()
.put("connectorType", connectorType.toString())
.put("triggerList", array)
return JSONObject()
.put("type", TriggerConnector::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
connectorType = Type.valueOf(safeGetString(d, "connectorType")!!)
val array = d.getJSONArray("triggerList")
list.clear()
for (i in 0 until array.length()) {
instantiate(JSONObject(array.getString(i)))?.let {
add(it)
}
}
return this
}
override fun friendlyName(): Int = connectorType.stringRes
override fun friendlyDescription(): String {
val result = StringBuilder()
for ((counter, t) in list.withIndex()) {
if (counter > 0)
result.append("\n").append(resourceHelper.gs(friendlyName())).append("\n")
result.append(t.friendlyDescription())
}
return result.toString()
}
override fun icon(): Optional<Int?> = Optional.absent()
override fun duplicate(): Trigger = TriggerConnector(mainApp, connectorType)
private var adapter: TriggerListAdapter? = null
fun rebuildView(fragmentManager: FragmentManager) = adapter?.rebuild(fragmentManager)
override fun generateDialog(root: LinearLayout) {
val padding = resourceHelper.dpToPx(5)
root.setPadding(padding, padding, padding, padding)
root.setBackgroundResource(R.drawable.border_automation_unit)
val triggerListLayout = LinearLayout(root.context)
triggerListLayout.orientation = LinearLayout.VERTICAL
triggerListLayout.layoutParams = LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)
root.addView(triggerListLayout)
adapter = TriggerListAdapter(mainApp, resourceHelper, root.context, triggerListLayout, this)
}
fun simplify(): TriggerConnector { // simplify children
for (i in 0 until size()) {
if (get(i) is TriggerConnector) {
val t = get(i) as TriggerConnector
t.simplify()
}
}
// drop connector with only 1 element
if (size() == 1 && get(0) is TriggerConnector) {
val c = get(0) as TriggerConnector
remove(c)
connectorType = c.connectorType
for (t in c.list) add(t)
c.list.clear()
return simplify()
}
// merge connectors
connector?.let { connector ->
if (connector.connectorType == connectorType || size() == 1) {
val pos = connector.pos(this)
connector.remove(this)
// move triggers of child connector into parent connector
for (i in size() - 1 downTo 0) {
connector.add(pos, get(i))
}
list.clear()
return connector.simplify()
}
}
return this
}
}

View file

@ -1,202 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.Constants;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta.DeltaType;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerDelta extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private final int MMOL_MAX = 4;
private final int MGDL_MAX = 72;
private String units;
private DeltaType deltaType;
private InputDelta value;
private Comparator comparator;
public TriggerDelta() {
super();
this.units = ProfileFunctions.getSystemUnits();
initializer();
}
private TriggerDelta(TriggerDelta triggerDelta) {
super();
lastRun = triggerDelta.lastRun;
this.units = triggerDelta.units;
deltaType = triggerDelta.deltaType;
value = new InputDelta(triggerDelta.value);
comparator = new Comparator(triggerDelta.comparator);
}
public double getValue() {
deltaType = value.getDeltaType();
return value.getValue();
}
private void initializer() {
this.deltaType = DeltaType.DELTA;
comparator = new Comparator();
if (units.equals(Constants.MMOL))
value = new InputDelta(0, -MMOL_MAX, MMOL_MAX, 0.1d, new DecimalFormat("0.1"), DeltaType.DELTA);
else
value = new InputDelta(0, -MGDL_MAX, MGDL_MAX, 1d, new DecimalFormat("1"), DeltaType.DELTA);
}
public DeltaType getType() {
return deltaType;
}
public String getUnits() {
return this.units;
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
if (glucoseStatus == null)
if (comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
return true;
else
return false;
// Setting type of delta
double delta;
if (deltaType == DeltaType.SHORT_AVERAGE)
delta = glucoseStatus.short_avgdelta;
else if (deltaType == DeltaType.LONG_AVERAGE)
delta = glucoseStatus.long_avgdelta;
else
delta = glucoseStatus.delta;
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
boolean doRun = comparator.getValue().check(delta, Profile.toMgdl(value.getValue(), this.units));
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: delta is " + delta + " " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerDelta.class.getName());
JSONObject data = new JSONObject();
data.put("value", getValue());
data.put("units", units);
data.put("lastRun", lastRun);
data.put("deltaType", getType());
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
units = JsonHelper.safeGetString(d, "units");
deltaType = DeltaType.valueOf(JsonHelper.safeGetString(d, "deltaType", ""));
value.setValue(JsonHelper.safeGetDouble(d, "value"), deltaType);
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.deltalabel;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.deltacompared, MainApp.gs(comparator.getValue().getStringRes()), getValue(), MainApp.gs(deltaType.getStringRes()));
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.icon_auto_delta);
}
@Override
public Trigger duplicate() {
return new TriggerDelta(this);
}
TriggerDelta setValue(double requestedValue, DeltaType requestedType) {
this.value.setValue(requestedValue, requestedType);
this.deltaType = requestedType;
return this;
}
TriggerDelta setUnits(String units) {
this.units = units;
return this;
}
TriggerDelta lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerDelta comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.deltalabel))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.deltalabel_u, getUnits()) + ": ", "", value))
.build(root);
}
}

View file

@ -0,0 +1,106 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
import com.google.common.base.Optional
import info.nightscout.androidaps.Constants
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta
import info.nightscout.androidaps.plugins.general.automation.elements.InputDelta.DeltaType
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.GlucoseStatus
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
import java.text.DecimalFormat
class TriggerDelta(mainApp: MainApp) : Trigger(mainApp) {
var units: String = Constants.MGDL
private var delta: InputDelta = InputDelta(mainApp)
var comparator: Comparator = Comparator(mainApp)
companion object {
private const val MMOL_MAX = 4.0
private const val MGDL_MAX = 72.0
}
init {
units = profileFunction.getUnits()
delta = if (units == Constants.MMOL) InputDelta(mainApp, 0.0, (-MMOL_MAX), MMOL_MAX, 0.1, DecimalFormat("0.1"), DeltaType.DELTA)
else InputDelta(mainApp, 0.0, (-MGDL_MAX), MGDL_MAX, 1.0, DecimalFormat("1"), DeltaType.DELTA)
}
private constructor(mainApp: MainApp, triggerDelta: TriggerDelta) : this(mainApp) {
units = triggerDelta.units
delta = InputDelta(mainApp, triggerDelta.delta)
comparator = Comparator(mainApp, triggerDelta.comparator.value)
}
override fun shouldRun(): Boolean {
val glucoseStatus = GlucoseStatus.getGlucoseStatusData()
?: return if (comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
true
} else {
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
false
}
val calculatedDelta = when (delta.deltaType) {
DeltaType.SHORT_AVERAGE -> glucoseStatus.short_avgdelta
DeltaType.LONG_AVERAGE -> glucoseStatus.long_avgdelta
else -> glucoseStatus.delta
}
if (comparator.value.check(calculatedDelta, Profile.toMgdl(delta.value, units))) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: delta is " + calculatedDelta + " " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("value", delta.value)
.put("units", units)
.put("deltaType", delta.deltaType)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
units = JsonHelper.safeGetString(d, "units")!!
val type = DeltaType.valueOf(JsonHelper.safeGetString(d, "deltaType", ""))
val value = JsonHelper.safeGetDouble(d, "value")
delta =
if (units == Constants.MMOL) InputDelta(mainApp, value, (-MMOL_MAX), MMOL_MAX, 0.1, DecimalFormat("0.1"), type)
else InputDelta(mainApp, value, (-MGDL_MAX), MGDL_MAX, 1.0, DecimalFormat("1"), type)
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.deltalabel
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.deltacompared, resourceHelper.gs(comparator.value.stringRes), delta.value, resourceHelper.gs(delta.deltaType.stringRes))
override fun icon(): Optional<Int?> = Optional.of(R.drawable.icon_auto_delta)
override fun duplicate(): Trigger = TriggerDelta(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.deltalabel))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.deltalabel_u, units) + ": ", "", delta))
.build(root)
}
}

View file

@ -0,0 +1,36 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import com.google.common.base.Optional
import info.nightscout.androidaps.MainApp
// Used for instantiation of other triggers only
class TriggerDummy(mainApp: MainApp) : Trigger(mainApp) {
override fun shouldRun(): Boolean {
throw NotImplementedError("An operation is not implemented")
}
override fun toJSON(): String {
throw NotImplementedError("An operation is not implemented")
}
override fun fromJSON(data: String): Trigger {
throw NotImplementedError("An operation is not implemented")
}
override fun friendlyName(): Int {
throw NotImplementedError("An operation is not implemented")
}
override fun friendlyDescription(): String {
throw NotImplementedError("An operation is not implemented")
}
override fun icon(): Optional<Int?> {
throw NotImplementedError("An operation is not implemented")
}
override fun duplicate(): Trigger {
throw NotImplementedError("An operation is not implemented")
}
}

View file

@ -1,146 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.IobTotal;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputInsulin;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.IobCobCalculatorPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerIob extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private InputInsulin insulin = new InputInsulin();
private Comparator comparator = new Comparator();
public TriggerIob() {
super();
}
private TriggerIob(TriggerIob triggerIob) {
super();
insulin = new InputInsulin(triggerIob.insulin);
comparator = new Comparator(triggerIob.comparator);
lastRun = triggerIob.lastRun;
}
public double getValue() {
return insulin.getValue();
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null)
return false;
IobTotal iob = IobCobCalculatorPlugin.getPlugin().calculateFromTreatmentsAndTempsSynchronized(DateUtil.now(), profile);
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
boolean doRun = comparator.getValue().check(iob.iob, getValue());
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerIob.class.getName());
JSONObject data = new JSONObject();
data.put("insulin", getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
insulin.setValue(JsonHelper.safeGetDouble(d, "insulin"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.iob;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.iobcompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_keyboard_capslock);
}
@Override
public Trigger duplicate() {
return new TriggerIob(this);
}
TriggerIob setValue(double threshold) {
insulin.setValue(threshold);
return this;
}
TriggerIob lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerIob comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.iob))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.iob_u), "", insulin))
.build(root);
}
}

View file

@ -0,0 +1,72 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputInsulin
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
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
import org.json.JSONObject
class TriggerIob(mainApp: MainApp) : Trigger(mainApp) {
private var insulin = InputInsulin(mainApp)
var comparator: Comparator = Comparator(mainApp)
constructor(mainApp: MainApp, triggerIob: TriggerIob) : this(mainApp) {
insulin = InputInsulin(mainApp, triggerIob.insulin)
comparator = Comparator(mainApp, triggerIob.comparator.value)
}
val value: Double = 0.0
override fun shouldRun(): Boolean {
val profile = profileFunction.getProfile() ?: return false
val iob = iobCobCalculatorPlugin.calculateFromTreatmentsAndTempsSynchronized(DateUtil.now(), profile)
if (comparator.value.check(iob.iob, value)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
@Synchronized override fun toJSON(): String {
val data = JSONObject()
.put("insulin", value)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
insulin.value = JsonHelper.safeGetDouble(d, "insulin")
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.iob
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.iobcompared, resourceHelper.gs(comparator.value.stringRes), value)
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_keyboard_capslock)
override fun duplicate(): Trigger = TriggerIob(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.iob))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.iob_u), "", insulin))
.build(root)
}
}

View file

@ -1,190 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.location.Location;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.text.DecimalFormat;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.InputButton;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDouble;
import info.nightscout.androidaps.plugins.general.automation.elements.InputLocationMode;
import info.nightscout.androidaps.plugins.general.automation.elements.InputString;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.services.LocationService;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
import static info.nightscout.androidaps.plugins.general.automation.elements.InputLocationMode.Mode.*;
public class TriggerLocation extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
InputDouble latitude = new InputDouble(0d, -90d, +90d, 0.000001d, new DecimalFormat("0.000000"));
InputDouble longitude = new InputDouble(0d, -180d, +180d, 0.000001d, new DecimalFormat("0.000000"));
InputDouble distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0"));
InputLocationMode modeSelected = new InputLocationMode();
InputLocationMode.Mode lastMode = INSIDE;
InputString name = new InputString();
private Runnable buttonAction = () -> {
Location location = LocationService.getLastLocation();
if (location != null) {
latitude.setValue(location.getLatitude());
longitude.setValue(location.getLongitude());
log.debug(String.format("Grabbed location: %f %f", latitude.getValue(), longitude.getValue()));
}
};
public TriggerLocation() {
super();
}
private TriggerLocation(TriggerLocation triggerLocation) {
super();
latitude = new InputDouble(triggerLocation.latitude);
longitude = new InputDouble(triggerLocation.longitude);
distance = new InputDouble(triggerLocation.distance);
modeSelected = new InputLocationMode(triggerLocation.modeSelected);
if (modeSelected.getValue() == GOING_OUT)
lastMode = OUTSIDE;
lastRun = triggerLocation.lastRun;
name = triggerLocation.name;
}
@Override
public synchronized boolean shouldRun() {
Location location = this.getCurrentLocation();
if (location == null)
return false;
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
Location a = new Location("Trigger");
a.setLatitude(latitude.getValue());
a.setLongitude(longitude.getValue());
double calculatedDistance = location.distanceTo(a);
// log.debug("Moded(current/last/wanted): "+(currentMode(calculatedDistance))+"/"+lastMode+"/"+modeSelected.getValue());
// log.debug("Distance: "+calculatedDistance + "("+distance.getValue()+")");
if ((modeSelected.getValue() == INSIDE) && (calculatedDistance <= distance.getValue()) ||
((modeSelected.getValue() == OUTSIDE) && (calculatedDistance > distance.getValue())) ||
((modeSelected.getValue() == GOING_IN) && (calculatedDistance <= distance.getValue()) && (lastMode == OUTSIDE)) ||
((modeSelected.getValue() == GOING_OUT) && (calculatedDistance > distance.getValue()) && (lastMode == INSIDE))
) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
lastMode = currentMode(calculatedDistance);
return true;
}
lastMode = currentMode(calculatedDistance); // current mode will be last mode for the next check
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerLocation.class.getName());
JSONObject data = new JSONObject();
data.put("latitude", latitude.getValue());
data.put("longitude", longitude.getValue());
data.put("distance", distance.getValue());
data.put("name", name.getValue());
data.put("mode", modeSelected.getValue());
data.put("lastRun", lastRun);
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
latitude.setValue(JsonHelper.safeGetDouble(d, "latitude"));
longitude.setValue(JsonHelper.safeGetDouble(d, "longitude"));
distance.setValue(JsonHelper.safeGetDouble(d, "distance"));
name.setValue(JsonHelper.safeGetString(d, "name"));
modeSelected.setValue(InputLocationMode.Mode.valueOf(JsonHelper.safeGetString(d, "mode")));
if (modeSelected.getValue() == GOING_OUT)
lastMode = OUTSIDE;
lastRun = DateUtil.now(); // set lastRun to now to give the service 5 mins to get the location properly
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.location;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.locationis, MainApp.gs(modeSelected.getValue().getStringRes()), " " + name.getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_location_on);
}
@Override
public Trigger duplicate() {
return new TriggerLocation(this);
}
TriggerLocation lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.location))
.add(new LabelWithElement(MainApp.gs(R.string.name_short), "", name))
.add(new LabelWithElement(MainApp.gs(R.string.latitude_short), "", latitude))
.add(new LabelWithElement(MainApp.gs(R.string.longitude_short), "", longitude))
.add(new LabelWithElement(MainApp.gs(R.string.distance_short), "", distance))
.add(new LabelWithElement(MainApp.gs(R.string.location_mode), "", modeSelected))
.add(new InputButton(MainApp.gs(R.string.currentlocation), buttonAction), LocationService.getLastLocation() != null)
.build(root);
}
// Method to return the actual mode based on the current distance
InputLocationMode.Mode currentMode(double currentDistance){
if ( currentDistance <= this.distance.getValue() )
return INSIDE;
else
return OUTSIDE;
}
// for mocking only TODO remove
static Location getCurrentLocation(){
return LocationService.getLastLocation();
}
}

View file

@ -0,0 +1,109 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.location.Location
import android.widget.LinearLayout
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.*
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
import java.text.DecimalFormat
class TriggerLocation(mainApp: MainApp) : Trigger(mainApp) {
var latitude = InputDouble(mainApp, 0.0, -90.0, +90.0, 0.000001, DecimalFormat("0.000000"))
var longitude = InputDouble(mainApp, 0.0, -180.0, +180.0, 0.000001, DecimalFormat("0.000000"))
var distance = InputDouble(mainApp, 200.0, 0.0, 100000.0, 10.0, DecimalFormat("0"))
var modeSelected = InputLocationMode(mainApp)
var name: InputString = InputString(mainApp)
var lastMode = InputLocationMode.Mode.INSIDE
private val buttonAction = Runnable {
val location = locationService.lastLocation
if (location != null) {
latitude.value = location.latitude
longitude.value = location.longitude
aapsLogger.debug(LTag.AUTOMATION, String.format("Grabbed location: %f %f", latitude.value, longitude.value))
}
}
private constructor(mainApp: MainApp, triggerLocation: TriggerLocation) : this(mainApp) {
latitude = InputDouble(mainApp, triggerLocation.latitude)
longitude = InputDouble(mainApp, triggerLocation.longitude)
distance = InputDouble(mainApp, triggerLocation.distance)
modeSelected = InputLocationMode(mainApp, triggerLocation.modeSelected.value)
if (modeSelected.value == InputLocationMode.Mode.GOING_OUT)
lastMode = InputLocationMode.Mode.OUTSIDE
name = triggerLocation.name
}
@Synchronized override fun shouldRun(): Boolean {
val location: Location = locationService.lastLocation ?: return false
val a = Location("Trigger")
a.latitude = latitude.value
a.longitude = longitude.value
val calculatedDistance = location.distanceTo(a).toDouble()
if (modeSelected.value == InputLocationMode.Mode.INSIDE && calculatedDistance <= distance.value ||
modeSelected.value == InputLocationMode.Mode.OUTSIDE && calculatedDistance > distance.value ||
modeSelected.value == InputLocationMode.Mode.GOING_IN && calculatedDistance <= distance.value && lastMode == InputLocationMode.Mode.OUTSIDE ||
modeSelected.value == InputLocationMode.Mode.GOING_OUT && calculatedDistance > distance.value && lastMode == InputLocationMode.Mode.INSIDE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
lastMode = currentMode(calculatedDistance)
return true
}
lastMode = currentMode(calculatedDistance) // current mode will be last mode for the next check
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("latitude", latitude.value)
.put("longitude", longitude.value)
.put("distance", distance.value)
.put("name", name.value)
.put("mode", modeSelected.value)
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
latitude.value = JsonHelper.safeGetDouble(d, "latitude")
longitude.value = JsonHelper.safeGetDouble(d, "longitude")
distance.value = JsonHelper.safeGetDouble(d, "distance")
name.value = JsonHelper.safeGetString(d, "name")!!
modeSelected.value = InputLocationMode.Mode.valueOf(JsonHelper.safeGetString(d, "mode")!!)
if (modeSelected.value == InputLocationMode.Mode.GOING_OUT) lastMode = InputLocationMode.Mode.OUTSIDE
return this
}
override fun friendlyName(): Int = R.string.location
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.locationis, resourceHelper.gs(modeSelected.value.stringRes), " " + name.value)
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_location_on)
override fun duplicate(): Trigger = TriggerLocation(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.location))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.name_short), "", name))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.latitude_short), "", latitude))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.longitude_short), "", longitude))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.distance_short), "", distance))
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.location_mode), "", modeSelected))
.add(InputButton(mainApp, resourceHelper.gs(R.string.currentlocation), buttonAction), locationService.lastLocation != null)
.build(root)
}
// Method to return the actual mode based on the current distance
fun currentMode(currentDistance: Double): InputLocationMode.Mode {
return if (currentDistance <= distance.value) InputLocationMode.Mode.INSIDE else InputLocationMode.Mode.OUTSIDE
}
}

View file

@ -1,152 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputPercent;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
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;
import info.nightscout.androidaps.utils.T;
public class TriggerProfilePercent extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private InputPercent pct = new InputPercent();
private Comparator comparator = new Comparator();
public TriggerProfilePercent() {
super();
}
private TriggerProfilePercent(TriggerProfilePercent triggerProfilePercent) {
super();
pct = new InputPercent(triggerProfilePercent.pct);
comparator = new Comparator(triggerProfilePercent.comparator);
lastRun = triggerProfilePercent.lastRun;
}
public double getValue() {
return pct.getValue();
}
public Comparator getComparator() {
return comparator;
}
public long getLastRun() {
return lastRun;
}
@Override
public synchronized boolean shouldRun() {
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
Profile profile = ProfileFunctions.getInstance().getProfile();
if (profile == null && comparator.getValue().equals(Comparator.Compare.IS_NOT_AVAILABLE)) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
if (profile == null)
return false;
boolean doRun = comparator.getValue().check((double) profile.getPercentage(), pct.getValue());
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerProfilePercent.class.getName());
JSONObject data = new JSONObject();
data.put("percentage", pct.getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
pct.setValue(JsonHelper.safeGetDouble(d, "percentage"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.profilepercentage;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.percentagecompared, MainApp.gs(comparator.getValue().getStringRes()), (int) pct.getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.icon_actions_profileswitch);
}
@Override
public Trigger duplicate() {
return new TriggerProfilePercent(this);
}
public TriggerProfilePercent setValue(double value) {
pct.setValue(value);
return this;
}
TriggerProfilePercent lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
public TriggerProfilePercent comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.profilepercentage))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.percent_u), "", pct))
.build(root);
}
}

View file

@ -0,0 +1,81 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputPercent
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class TriggerProfilePercent(mainApp: MainApp) : Trigger(mainApp) {
private var pct = InputPercent(mainApp)
var comparator = Comparator(mainApp)
constructor(mainApp: MainApp, value: Double, compare: Comparator.Compare) : this(mainApp) {
pct = InputPercent(mainApp, value)
comparator = Comparator(mainApp, compare)
}
constructor(mainApp: MainApp, triggerProfilePercent: TriggerProfilePercent) : this(mainApp) {
pct = InputPercent(mainApp, triggerProfilePercent.pct.value)
comparator = Comparator(mainApp, triggerProfilePercent.comparator.value)
}
override fun shouldRun(): Boolean {
val profile = profileFunction.getProfile()
if (profile == null && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
if (profile == null) {
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
if (comparator.value.check(profile.percentage.toDouble(), pct.value)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
@Synchronized override fun toJSON(): String {
val data = JSONObject()
.put("percentage", pct.value)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
pct.value = JsonHelper.safeGetDouble(d, "percentage")
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.profilepercentage
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.percentagecompared, resourceHelper.gs(comparator.value.stringRes), pct.value.toInt())
override fun icon(): Optional<Int?> = Optional.of(R.drawable.icon_actions_profileswitch)
override fun duplicate(): Trigger = TriggerProfilePercent(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.profilepercentage))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.percent_u), "", pct))
.build(root)
}
}

View file

@ -1,146 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
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;
import info.nightscout.androidaps.utils.T;
public class TriggerPumpLastConnection extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private InputDuration minutesAgo = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
private Comparator comparator = new Comparator();
public TriggerPumpLastConnection() {
super();
}
private TriggerPumpLastConnection(TriggerPumpLastConnection triggerPumpLastConnection) {
super();
minutesAgo = new InputDuration(triggerPumpLastConnection.minutesAgo);
lastRun = triggerPumpLastConnection.lastRun;
comparator = new Comparator(triggerPumpLastConnection.comparator);
}
public double getValue() {
return minutesAgo.getValue();
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
long lastConnection = ConfigBuilderPlugin.getPlugin().getActivePump().lastDataTime();
if (lastConnection == 0 && comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE)
return true;
double minutesAgo = (double) (DateUtil.now() - lastConnection) / (60 * 1000);
if (L.isEnabled(L.AUTOMATION))
log.debug("Last connection min ago: " + minutesAgo);
boolean doRun = comparator.getValue().check((minutesAgo), getValue());
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerPumpLastConnection.class.getName());
JSONObject data = new JSONObject();
data.put("minutesAgo", getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
minutesAgo.setMinutes(JsonHelper.safeGetInt(d, "minutesAgo"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.automation_trigger_pump_last_connection_label;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.automation_trigger_pump_last_connection_compared, MainApp.gs(comparator.getValue().getStringRes()), (int) getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.remove);
}
@Override
public Trigger duplicate() {
return new TriggerPumpLastConnection(this);
}
TriggerPumpLastConnection setValue(int requestedValue) {
this.minutesAgo.setMinutes(requestedValue);
return this;
}
TriggerPumpLastConnection lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerPumpLastConnection comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.automation_trigger_pump_last_connection_label))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.automation_trigger_pump_last_connection_description) + ": ", "", minutesAgo))
.build(root);
}
}

View file

@ -0,0 +1,81 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
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.JsonHelper.safeGetString
import org.json.JSONObject
class TriggerPumpLastConnection(mainApp: MainApp) : Trigger(mainApp) {
private var minutesAgo = InputDuration(mainApp)
private var comparator = Comparator(mainApp)
constructor(mainApp: MainApp, value: Int, unit: InputDuration.TimeUnit, compare: Comparator.Compare) : this(mainApp) {
minutesAgo = InputDuration(mainApp, value, unit)
comparator = Comparator(mainApp, compare)
}
constructor(mainApp: MainApp, triggerPumpLastConnection: TriggerPumpLastConnection) : this(mainApp) {
minutesAgo = InputDuration(mainApp, triggerPumpLastConnection.minutesAgo.value, triggerPumpLastConnection.minutesAgo.unit)
comparator = Comparator(mainApp, triggerPumpLastConnection.comparator.value)
}
override fun shouldRun(): Boolean {
val lastConnection = configBuilderPlugin.activePump?.lastDataTime() ?: return false
if (lastConnection == 0L && comparator.value === Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
val connectionAgo = (DateUtil.now() - lastConnection) / (60 * 1000)
aapsLogger.debug(LTag.AUTOMATION, "Last connection min ago: $connectionAgo")
if (comparator.value.check(connectionAgo.toInt(), minutesAgo.value)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("minutesAgo", minutesAgo.value)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
minutesAgo.setMinutes(safeGetInt(d, "minutesAgo"))
comparator.setValue(Comparator.Compare.valueOf(safeGetString(d, "comparator")!!))
return this
}
override fun friendlyName(): Int = R.string.automation_trigger_pump_last_connection_label
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.automation_trigger_pump_last_connection_compared, resourceHelper.gs(comparator.value.stringRes), minutesAgo.value)
override fun icon(): Optional<Int?> = Optional.of(R.drawable.remove)
override fun duplicate(): Trigger = TriggerPumpLastConnection(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.automation_trigger_pump_last_connection_label))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.automation_trigger_pump_last_connection_description) + ": ", "", minutesAgo))
.build(root)
}
}

View file

@ -1,319 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.graphics.Typeface;
import android.text.format.DateFormat;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.annotation.Nullable;
import androidx.annotation.StringRes;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import com.dpro.widgets.WeekdaysPicker;
import com.google.common.base.Optional;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.GregorianCalendar;
import java.util.List;
import java.util.Objects;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerRecurringTime extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
public enum DayOfWeek {
MONDAY,
TUESDAY,
WEDNESDAY,
THURSDAY,
FRIDAY,
SATURDAY,
SUNDAY;
private static final int[] calendarInts = new int[]{
Calendar.MONDAY,
Calendar.TUESDAY,
Calendar.WEDNESDAY,
Calendar.THURSDAY,
Calendar.FRIDAY,
Calendar.SATURDAY,
Calendar.SUNDAY
};
private static final int[] shortNames = new int[]{
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
};
public int toCalendarInt() {
return calendarInts[ordinal()];
}
@Nullable
public static DayOfWeek fromCalendarInt(int day) {
for (int i = 0; i < calendarInts.length; ++i) {
if (calendarInts[i] == day)
return values()[i];
}
return null;
}
public @StringRes
int getShortName() {
return shortNames[ordinal()];
}
}
private final boolean[] weekdays = new boolean[DayOfWeek.values().length];
// Recurring
private int hour;
private int minute;
private long validTo;
public TriggerRecurringTime() {
super();
setAll(false);
}
private TriggerRecurringTime(TriggerRecurringTime triggerTime) {
super();
lastRun = triggerTime.lastRun;
hour = triggerTime.hour;
minute = triggerTime.minute;
validTo = triggerTime.validTo;
if (weekdays.length >= 0)
System.arraycopy(triggerTime.weekdays, 0, weekdays, 0, weekdays.length);
}
public void setAll(boolean value) {
for (DayOfWeek day : DayOfWeek.values()) {
set(day, value);
}
}
public TriggerRecurringTime set(DayOfWeek day, boolean value) {
weekdays[day.ordinal()] = value;
return this;
}
private boolean isSet(DayOfWeek day) {
return weekdays[day.ordinal()];
}
@Override
public boolean shouldRun() {
if (validTo != 0 && DateUtil.now() > validTo)
return false;
Calendar c = Calendar.getInstance();
int scheduledDayOfWeek = c.get(Calendar.DAY_OF_WEEK);
Calendar scheduledCal = DateUtil.gregorianCalendar();
scheduledCal.set(Calendar.HOUR_OF_DAY, hour);
scheduledCal.set(Calendar.MINUTE, minute);
scheduledCal.set(Calendar.SECOND, 0);
long scheduled = scheduledCal.getTimeInMillis();
if (isSet(Objects.requireNonNull(DayOfWeek.fromCalendarInt(scheduledDayOfWeek)))) {
if (DateUtil.now() >= scheduled && DateUtil.now() - scheduled < T.mins(5).msecs()) {
if (lastRun < scheduled) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
}
}
return false;
}
@Override
public String toJSON() {
JSONObject object = new JSONObject();
JSONObject data = new JSONObject();
try {
data.put("lastRun", lastRun);
for (int i = 0; i < weekdays.length; ++i) {
data.put(DayOfWeek.values()[i].name(), weekdays[i]);
}
data.put("hour", hour);
data.put("minute", minute);
data.put("validTo", validTo);
object.put("type", TriggerRecurringTime.class.getName());
object.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return object.toString();
}
@Override
Trigger fromJSON(String data) {
JSONObject o;
try {
o = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(o, "lastRun");
for (int i = 0; i < weekdays.length; ++i) {
weekdays[i] = JsonHelper.safeGetBoolean(o, DayOfWeek.values()[i].name());
}
hour = JsonHelper.safeGetInt(o, "hour");
minute = JsonHelper.safeGetInt(o, "minute");
validTo = JsonHelper.safeGetLong(o, "validTo");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.recurringTime;
}
@Override
public String friendlyDescription() {
int counter = 0;
StringBuilder sb = new StringBuilder();
sb.append(MainApp.gs(R.string.every));
sb.append(" ");
for (Integer i : getSelectedDays()) {
if (counter > 0)
sb.append(",");
sb.append(MainApp.gs(Objects.requireNonNull(DayOfWeek.fromCalendarInt(i)).getShortName()));
counter++;
}
sb.append(" ");
Calendar scheduledCal = DateUtil.gregorianCalendar();
scheduledCal.set(Calendar.HOUR_OF_DAY, hour);
scheduledCal.set(Calendar.MINUTE, minute);
scheduledCal.set(Calendar.SECOND, 0);
long scheduled = scheduledCal.getTimeInMillis();
sb.append(DateUtil.timeString(scheduled));
if (counter == 0)
return MainApp.gs(R.string.never);
return sb.toString();
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_access_alarm_24dp);
}
@Override
public Trigger duplicate() {
return new TriggerRecurringTime(this);
}
TriggerRecurringTime lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
@SuppressWarnings("SameParameterValue")
TriggerRecurringTime validTo(long validTo) {
this.validTo = validTo;
return this;
}
TriggerRecurringTime hour(int hour) {
this.hour = hour;
return this;
}
TriggerRecurringTime minute(int minute) {
this.minute = minute;
return this;
}
private List<Integer> getSelectedDays() {
List<Integer> selectedDays = new ArrayList<>();
for (int i = 0; i < weekdays.length; ++i) {
DayOfWeek day = DayOfWeek.values()[i];
boolean selected = weekdays[i];
if (selected) selectedDays.add(day.toCalendarInt());
}
return selectedDays;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
TextView label = new TextView(root.getContext());
// TODO: Replace external tool WeekdaysPicker with a self-made GUI element
WeekdaysPicker weekdaysPicker = new WeekdaysPicker(root.getContext());
weekdaysPicker.setEditable(true);
weekdaysPicker.setSelectedDays(getSelectedDays());
weekdaysPicker.setOnWeekdaysChangeListener((view, i, list) -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)));
weekdaysPicker.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
weekdaysPicker.setSundayFirstDay(Calendar.getInstance().getFirstDayOfWeek() == Calendar.SUNDAY);
weekdaysPicker.redrawDays();
root.addView(weekdaysPicker);
TextView timeButton = new TextView(root.getContext());
GregorianCalendar runAt = new GregorianCalendar();
//Date runAt = new Date();
runAt.set(Calendar.HOUR_OF_DAY, hour);
runAt.set(Calendar.MINUTE, minute);
timeButton.setText(DateUtil.timeString(runAt.getTimeInMillis()));
timeButton.setOnClickListener(view -> {
TimePickerDialog tpd = TimePickerDialog.newInstance(
(view12, hourOfDay, minute, second) -> {
hour(hourOfDay);
minute(minute);
runAt.set(Calendar.HOUR_OF_DAY, hour);
runAt.set(Calendar.MINUTE, minute);
timeButton.setText(DateUtil.timeString(runAt.getTimeInMillis()));
},
runAt.get(Calendar.HOUR_OF_DAY),
runAt.get(Calendar.MINUTE),
DateFormat.is24HourFormat(root.getContext())
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
AppCompatActivity a = scanForActivity(root.getContext());
if (a != null)
tpd.show(a.getSupportFragmentManager(), "TimePickerDialog");
});
int px = MainApp.dpToPx(10);
label.setText(MainApp.gs(R.string.atspecifiedtime, ""));
label.setTypeface(label.getTypeface(), Typeface.BOLD);
label.setPadding(px, px, px, px);
timeButton.setPadding(px, px, px, px);
LinearLayout l = new LinearLayout(root.getContext());
l.setOrientation(LinearLayout.HORIZONTAL);
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
l.addView(label);
l.addView(timeButton);
root.addView(l);
}
}

View file

@ -0,0 +1,211 @@
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.TextView
import androidx.annotation.StringRes
import com.dpro.widgets.WeekdaysPicker
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.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper
import info.nightscout.androidaps.utils.T
import org.json.JSONObject
import java.util.*
class TriggerRecurringTime(mainApp: MainApp) : Trigger(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")
}
}
}
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) {
this.hour = triggerRecurringTime.hour
this.minute = triggerRecurringTime.minute
this.validTo = triggerRecurringTime.validTo
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 {
if (validTo != 0L && DateUtil.now() > validTo) return false
val c = Calendar.getInstance()
val scheduledDayOfWeek = c[Calendar.DAY_OF_WEEK]
val scheduledCal: Calendar = DateUtil.gregorianCalendar()
scheduledCal[Calendar.HOUR_OF_DAY] = hour
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())
return true
}
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("hour", hour)
.put("minute", minute)
.put("validTo", validTo)
for (i in weekdays.indices) {
data.put(DayOfWeek.values()[i].name, weekdays[i])
}
return JSONObject()
.put("type", TriggerRecurringTime::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val o = JSONObject(data)
for (i in weekdays.indices)
weekdays[i] = JsonHelper.safeGetBoolean(o, DayOfWeek.values()[i].name)
hour = JsonHelper.safeGetInt(o, "hour")
minute = JsonHelper.safeGetInt(o, "minute")
validTo = JsonHelper.safeGetLong(o, "validTo")
return this
}
override fun friendlyName(): Int = R.string.recurringTime
override fun friendlyDescription(): String {
val sb = StringBuilder()
sb.append(resourceHelper.gs(R.string.every))
sb.append(" ")
var counter = 0
for (i in getSelectedDays()) {
if (counter++ > 0) sb.append(",")
sb.append(resourceHelper.gs(Objects.requireNonNull(DayOfWeek.fromCalendarInt(i)).shortName))
}
sb.append(" ")
val scheduledCal: Calendar = DateUtil.gregorianCalendar()
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()
}
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_access_alarm_24dp)
override fun duplicate(): Trigger = TriggerRecurringTime(mainApp, this)
private 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 generateDialog(root: LinearLayout) {
val label = TextView(root.context)
// TODO: Replace external tool WeekdaysPicker with a self-made GUI element
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)
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)
}
}

View file

@ -1,131 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.db.TempTarget;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerTempTarget extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private ComparatorExists comparator = new ComparatorExists();
public TriggerTempTarget() {
super();
}
private TriggerTempTarget(TriggerTempTarget triggerTempTarget) {
super();
comparator = new ComparatorExists(triggerTempTarget.comparator);
lastRun = triggerTempTarget.lastRun;
}
public ComparatorExists getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
TempTarget tt = TreatmentsPlugin.getPlugin().getTempTargetFromHistory();
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
if (tt == null && comparator.getValue() == ComparatorExists.Compare.NOT_EXISTS) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
if (tt != null && comparator.getValue() == ComparatorExists.Compare.EXISTS) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerTempTarget.class.getName());
JSONObject data = new JSONObject();
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(ComparatorExists.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.careportal_temporarytarget;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.temptargetcompared, MainApp.gs(comparator.getValue().getStringRes()));
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_keyboard_tab);
}
@Override
public Trigger duplicate() {
return new TriggerTempTarget(this);
}
TriggerTempTarget lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
public TriggerTempTarget comparator(ComparatorExists.Compare compare) {
this.comparator = new ComparatorExists().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.careportal_temporarytarget))
.add(comparator)
.build(root);
}
}

View file

@ -0,0 +1,69 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.ComparatorExists
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class TriggerTempTarget(mainApp: MainApp) : Trigger(mainApp) {
var comparator = ComparatorExists(mainApp)
constructor(mainApp: MainApp, compare: ComparatorExists.Compare) : this(mainApp) {
comparator = ComparatorExists(mainApp, compare)
}
constructor(mainApp: MainApp, triggerTempTarget: TriggerTempTarget) : this(mainApp) {
comparator = ComparatorExists(mainApp, triggerTempTarget.comparator.value)
}
override fun shouldRun(): Boolean {
val tt = treatmentsPlugin.tempTargetFromHistory
if (tt == null && comparator.value == ComparatorExists.Compare.NOT_EXISTS) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
if (tt != null && comparator.value == ComparatorExists.Compare.EXISTS) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", TriggerTempTarget::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
comparator.value = ComparatorExists.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!)
return this
}
override fun friendlyName(): Int = R.string.careportal_temporarytarget
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.temptargetcompared, resourceHelper.gs(comparator.value.stringRes))
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_keyboard_tab)
override fun duplicate(): Trigger = TriggerTempTarget(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.careportal_temporarytarget))
.add(comparator)
.build(root)
}
}

View file

@ -1,186 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.graphics.Typeface;
import android.text.format.DateFormat;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import com.wdullaer.materialdatetimepicker.date.DatePickerDialog;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.GregorianCalendar;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerTime extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private long runAt;
public TriggerTime() {
runAt = DateUtil.now();
}
private TriggerTime(TriggerTime triggerTime) {
super();
lastRun = triggerTime.lastRun;
runAt = triggerTime.runAt;
}
@Override
public boolean shouldRun() {
long now = DateUtil.now();
if (now >= runAt && now - runAt < T.mins(5).msecs())
if (lastRun < runAt) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public String toJSON() {
JSONObject object = new JSONObject();
JSONObject data = new JSONObject();
try {
data.put("runAt", runAt);
data.put("lastRun", lastRun);
object.put("type", TriggerTime.class.getName());
object.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return object.toString();
}
@Override
Trigger fromJSON(String data) {
JSONObject o;
try {
o = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(o, "lastRun");
runAt = JsonHelper.safeGetLong(o, "runAt");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.time;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(runAt));
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_access_alarm_24dp);
}
TriggerTime runAt(long runAt) {
this.runAt = runAt;
return this;
}
TriggerTime lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
@Override
public Trigger duplicate() {
return new TriggerTime(this);
}
long getRunAt() {
return runAt;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
TextView label = new TextView(root.getContext());
TextView dateButton = new TextView(root.getContext());
TextView timeButton = new TextView(root.getContext());
dateButton.setText(DateUtil.dateString(runAt));
timeButton.setText(DateUtil.timeString(runAt));
dateButton.setOnClickListener(view -> {
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(runAt);
DatePickerDialog dpd = DatePickerDialog.newInstance(
(view1, year, monthOfYear, dayOfMonth) -> {
calendar.set(Calendar.YEAR, year);
calendar.set(Calendar.MONTH, monthOfYear);
calendar.set(Calendar.DAY_OF_MONTH, dayOfMonth);
runAt = calendar.getTimeInMillis();
dateButton.setText(DateUtil.dateString(runAt));
},
calendar.get(Calendar.YEAR),
calendar.get(Calendar.MONTH),
calendar.get(Calendar.DAY_OF_MONTH)
);
dpd.setThemeDark(true);
dpd.dismissOnPause(true);
AppCompatActivity a = scanForActivity(root.getContext());
if (a != null)
dpd.show(a.getSupportFragmentManager(), "DatePickerDialog");
});
timeButton.setOnClickListener(view -> {
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(runAt);
TimePickerDialog tpd = TimePickerDialog.newInstance(
(view12, hourOfDay, minute, second) -> {
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
calendar.set(Calendar.MINUTE, minute);
runAt = calendar.getTimeInMillis();
timeButton.setText(DateUtil.timeString(runAt));
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
DateFormat.is24HourFormat(root.getContext())
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
AppCompatActivity a = scanForActivity(root.getContext());
if (a != null)
tpd.show(a.getSupportFragmentManager(), "TimePickerDialog");
});
int px = MainApp.dpToPx(10);
label.setText(MainApp.gs(R.string.atspecifiedtime, ""));
label.setTypeface(label.getTypeface(), Typeface.BOLD);
label.setPadding(px, px, px, px);
dateButton.setPadding(px, px, px, px);
timeButton.setPadding(px, px, px, px);
LinearLayout l = new LinearLayout(root.getContext());
l.setOrientation(LinearLayout.HORIZONTAL);
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
l.addView(label);
l.addView(dateButton);
l.addView(timeButton);
root.addView(l);
}
}

View file

@ -0,0 +1,132 @@
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.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper.safeGetLong
import info.nightscout.androidaps.utils.T
import org.json.JSONObject
import java.util.*
class TriggerTime(mainApp: MainApp) : Trigger(mainApp) {
var runAt = DateUtil.now()
constructor(mainApp: MainApp, runAt: Long) : this(mainApp) {
this.runAt = runAt
}
constructor(mainApp: MainApp, triggerTime : TriggerTime) : this(mainApp) {
this.runAt = triggerTime.runAt
}
override fun shouldRun(): Boolean {
val now = DateUtil.now()
if (now >= runAt && now - runAt < T.mins(5).msecs()) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("runAt", runAt)
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val o = JSONObject(data)
runAt = safeGetLong(o, "runAt")
return this
}
override fun friendlyName(): Int = R.string.time
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.atspecifiedtime, DateUtil.dateAndTimeString(runAt))
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_access_alarm_24dp)
override fun duplicate(): Trigger = TriggerTime(mainApp, runAt)
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)
}
}

View file

@ -1,235 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.graphics.Typeface;
import android.text.format.DateFormat;
import android.view.ViewGroup;
import android.widget.LinearLayout;
import android.widget.TextView;
import androidx.appcompat.app.AppCompatActivity;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import com.wdullaer.materialdatetimepicker.time.TimePickerDialog;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.util.Calendar;
import java.util.GregorianCalendar;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
// Trigger for time range ( from 10:00AM till 13:00PM )
public class TriggerTimeRange extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
// in minutes since midnight 60 means 1AM
private int start;
private int end;
long timeZoneOffset = DateUtil.getTimeZoneOffsetMs();
public TriggerTimeRange() {
start = getMinSinceMidnight(DateUtil.now());
end = getMinSinceMidnight(DateUtil.now());
}
private TriggerTimeRange(TriggerTimeRange triggerTimeRange) {
super();
lastRun = triggerTimeRange.lastRun;
start = triggerTimeRange.start;
end = triggerTimeRange.end;
}
@Override
public boolean shouldRun() {
int currentMinSinceMidnight = getMinSinceMidnight(DateUtil.now());
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
boolean doRun = false;
if (start < end && start < currentMinSinceMidnight && currentMinSinceMidnight < end)
doRun = true;
// handle cases like 10PM to 6AM
else if (start > end && (start < currentMinSinceMidnight || currentMinSinceMidnight < end))
doRun = true;
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public String toJSON() {
JSONObject object = new JSONObject();
JSONObject data = new JSONObject();
// check for too big values
if (start > 1440)
start = getMinSinceMidnight(start);
if (end > 1440)
end = getMinSinceMidnight(end);
try {
data.put("start", getMinSinceMidnight(start));
data.put("end", getMinSinceMidnight(end));
data.put("lastRun", lastRun);
object.put("type", TriggerTimeRange.class.getName());
object.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
log.debug(object.toString());
return object.toString();
}
@Override
TriggerTimeRange fromJSON(String data) {
JSONObject o;
try {
o = new JSONObject(data);
lastRun = JsonHelper.safeGetLong(o, "lastRun");
start = JsonHelper.safeGetInt(o, "start");
end = JsonHelper.safeGetInt(o, "end");
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.time_range;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.timerange_value, DateUtil.timeString(toMilis(start) - timeZoneOffset), DateUtil.timeString(toMilis(end) - timeZoneOffset));
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_access_alarm_24dp);
}
TriggerTimeRange period(int start, int end) {
this.start = getMinSinceMidnight(start * 60000);
this.end = getMinSinceMidnight(end * 60000);
return this;
}
TriggerTimeRange lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
@Override
public Trigger duplicate() {
return new TriggerTimeRange(this);
}
long toMilis(long minutesSinceMidnight) {
return minutesSinceMidnight * 60 * 1000;
}
public int getMinSinceMidnight(long time) {
// if passed argument is smaller than 1440 ( 24 h * 60 min ) that value is already converted
if (0 < time && time < 1441)
return (int) time;
Calendar calendar = DateUtil.gregorianCalendar();
calendar.setTimeInMillis(time);
return (calendar.get(Calendar.HOUR_OF_DAY) * 60) + calendar.get(Calendar.MINUTE);
}
int getStart() {
return start;
}
int getEnd() {
return end;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
TextView label = new TextView(root.getContext());
TextView startButton = new TextView(root.getContext());
TextView endButton = new TextView(root.getContext());
log.debug("Start is: " + start);
log.debug("End is: " + end);
startButton.setText(DateUtil.timeString(toMilis(start) - timeZoneOffset));
endButton.setText(MainApp.gs(R.string.and) + " " + DateUtil.timeString(toMilis(end) - timeZoneOffset));
startButton.setOnClickListener(view -> {
GregorianCalendar calendar = new GregorianCalendar();
//setTimeInMillis sets time in milliseconds after
// * January 1, 1970, 0:00:00 GMT., but our time contains timezone offsset
calendar.setTimeInMillis(toMilis(start) - timeZoneOffset);
TimePickerDialog tpd = TimePickerDialog.newInstance(
(view12, hourOfDay, minute, second) -> {
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
calendar.set(Calendar.MINUTE, minute);
start = getMinSinceMidnight(calendar.getTimeInMillis());
startButton.setText(DateUtil.timeString(toMilis(start) - timeZoneOffset));
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
DateFormat.is24HourFormat(root.getContext())
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
AppCompatActivity a = scanForActivity(root.getContext());
if (a != null)
tpd.show(a.getSupportFragmentManager(), "TimePickerDialog");
});
endButton.setOnClickListener(view -> {
GregorianCalendar calendar = new GregorianCalendar();
calendar.setTimeInMillis(toMilis(end) - timeZoneOffset);
TimePickerDialog tpd = TimePickerDialog.newInstance(
(view12, hourOfDay, minute, second) -> {
calendar.set(Calendar.HOUR_OF_DAY, hourOfDay);
calendar.set(Calendar.MINUTE, minute);
end = getMinSinceMidnight(calendar.getTimeInMillis());
endButton.setText(MainApp.gs(R.string.and) + " " + DateUtil.timeString(toMilis(end) - timeZoneOffset));
},
calendar.get(Calendar.HOUR_OF_DAY),
calendar.get(Calendar.MINUTE),
DateFormat.is24HourFormat(root.getContext())
);
tpd.setThemeDark(true);
tpd.dismissOnPause(true);
AppCompatActivity a = scanForActivity(root.getContext());
if (a != null)
tpd.show(a.getSupportFragmentManager(), "TimePickerDialog");
});
int px = MainApp.dpToPx(10);
label.setText(MainApp.gs(R.string.between));
label.setTypeface(label.getTypeface(), Typeface.BOLD);
startButton.setPadding(px, px, px, px);
endButton.setPadding(px, px, px, px);
LinearLayout l = new LinearLayout(root.getContext());
l.setOrientation(LinearLayout.HORIZONTAL);
l.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
l.addView(label);
l.addView(startButton);
l.addView(endButton);
root.addView(l);
}
}

View file

@ -0,0 +1,145 @@
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.utils.DateUtil
import info.nightscout.androidaps.utils.JsonHelper.safeGetInt
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())
constructor(mainApp: MainApp, start : Int, end :Int) : this(mainApp) {
this.start = start
this.end = end
}
constructor(mainApp: MainApp, triggerTimeRange: TriggerTimeRange) : this(mainApp) {
this.start = triggerTimeRange.start
this.end = triggerTimeRange.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 (doRun) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("start", getMinSinceMidnight(start.toLong()))
.put("end", getMinSinceMidnight(end.toLong()))
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): TriggerTimeRange {
val o = JSONObject(data)
start = safeGetInt(o, "start")
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)))
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_access_alarm_24dp)
override fun duplicate(): Trigger = TriggerTimeRange(mainApp, start, end)
private fun toMills(minutesSinceMidnight: Int): Long = T.secs(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)
}
}

View file

@ -1,149 +0,0 @@
package info.nightscout.androidaps.plugins.general.automation.triggers;
import android.widget.LinearLayout;
import androidx.fragment.app.FragmentManager;
import com.google.common.base.Optional;
import org.json.JSONException;
import org.json.JSONObject;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R;
import info.nightscout.androidaps.events.EventNetworkChange;
import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.elements.Comparator;
import info.nightscout.androidaps.plugins.general.automation.elements.InputString;
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder;
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel;
import info.nightscout.androidaps.receivers.NetworkChangeReceiver;
import info.nightscout.androidaps.utils.DateUtil;
import info.nightscout.androidaps.utils.JsonHelper;
import info.nightscout.androidaps.utils.T;
public class TriggerWifiSsid extends Trigger {
private static Logger log = LoggerFactory.getLogger(L.AUTOMATION);
private InputString ssid = new InputString();
private Comparator comparator = new Comparator();
public TriggerWifiSsid() {
super();
}
private TriggerWifiSsid(TriggerWifiSsid triggerWifiSsid) {
super();
ssid = new InputString(triggerWifiSsid.ssid);
comparator = new Comparator(triggerWifiSsid.comparator);
lastRun = triggerWifiSsid.lastRun;
}
public String getValue() {
return ssid.getValue();
}
public Comparator getComparator() {
return comparator;
}
@Override
public synchronized boolean shouldRun() {
EventNetworkChange eventNetworkChange = NetworkChangeReceiver.getLastEvent();
if (eventNetworkChange == null)
return false;
if (lastRun > DateUtil.now() - T.mins(5).msecs())
return false;
if (!eventNetworkChange.getWifiConnected() && comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
boolean doRun = eventNetworkChange.getWifiConnected() && comparator.getValue().check(eventNetworkChange.connectedSsid(), getValue());
if (doRun) {
if (L.isEnabled(L.AUTOMATION))
log.debug("Ready for execution: " + friendlyDescription());
return true;
}
return false;
}
@Override
public synchronized String toJSON() {
JSONObject o = new JSONObject();
try {
o.put("type", TriggerWifiSsid.class.getName());
JSONObject data = new JSONObject();
data.put("ssid", getValue());
data.put("lastRun", lastRun);
data.put("comparator", comparator.getValue().toString());
o.put("data", data);
} catch (JSONException e) {
log.error("Unhandled exception", e);
}
return o.toString();
}
@Override
Trigger fromJSON(String data) {
try {
JSONObject d = new JSONObject(data);
ssid.setValue(JsonHelper.safeGetString(d, "ssid"));
lastRun = JsonHelper.safeGetLong(d, "lastRun");
comparator.setValue(Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")));
} catch (Exception e) {
log.error("Unhandled exception", e);
}
return this;
}
@Override
public int friendlyName() {
return R.string.ns_wifi_ssids;
}
@Override
public String friendlyDescription() {
return MainApp.gs(R.string.wifissidcompared, MainApp.gs(comparator.getValue().getStringRes()), getValue());
}
@Override
public Optional<Integer> icon() {
return Optional.of(R.drawable.ic_network_wifi);
}
@Override
public Trigger duplicate() {
return new TriggerWifiSsid(this);
}
TriggerWifiSsid setValue(String value) {
ssid.setValue(value);
return this;
}
TriggerWifiSsid lastRun(long lastRun) {
this.lastRun = lastRun;
return this;
}
TriggerWifiSsid comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare);
return this;
}
@Override
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
new LayoutBuilder()
.add(new StaticLabel(R.string.ns_wifi_ssids))
.add(comparator)
.add(new LabelWithElement(MainApp.gs(R.string.ns_wifi_ssids) + ": ", "", ssid))
.build(root);
}
}

View file

@ -0,0 +1,78 @@
package info.nightscout.androidaps.plugins.general.automation.triggers
import android.widget.LinearLayout
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.Comparator
import info.nightscout.androidaps.plugins.general.automation.elements.InputString
import info.nightscout.androidaps.plugins.general.automation.elements.LabelWithElement
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder
import info.nightscout.androidaps.plugins.general.automation.elements.StaticLabel
import info.nightscout.androidaps.receivers.NetworkChangeReceiver
import info.nightscout.androidaps.utils.JsonHelper
import org.json.JSONObject
class TriggerWifiSsid(mainApp: MainApp) : Trigger(mainApp) {
private var ssid = InputString(mainApp)
var comparator = Comparator(mainApp)
constructor(mainApp: MainApp, ssid: String, compare: Comparator.Compare) : this(mainApp) {
this.ssid = InputString(mainApp, ssid)
comparator = Comparator(mainApp, compare)
}
constructor(mainApp: MainApp, triggerWifiSsid: TriggerWifiSsid) : this(mainApp) {
this.ssid = InputString(mainApp, triggerWifiSsid.ssid.value)
comparator = Comparator(mainApp, triggerWifiSsid.comparator.value)
}
override fun shouldRun(): Boolean {
val eventNetworkChange = NetworkChangeReceiver.getLastEvent() ?: return false
if (!eventNetworkChange.wifiConnected && comparator.value == Comparator.Compare.IS_NOT_AVAILABLE) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
if (eventNetworkChange.wifiConnected && comparator.value.check(eventNetworkChange.connectedSsid(), ssid.value)) {
aapsLogger.debug(LTag.AUTOMATION, "Ready for execution: " + friendlyDescription())
return true
}
aapsLogger.debug(LTag.AUTOMATION, "NOT ready for execution: " + friendlyDescription())
return false
}
override fun toJSON(): String {
val data = JSONObject()
.put("ssid", ssid)
.put("comparator", comparator.value.toString())
return JSONObject()
.put("type", this::class.java.name)
.put("data", data)
.toString()
}
override fun fromJSON(data: String): Trigger {
val d = JSONObject(data)
ssid.value = JsonHelper.safeGetString(d, "ssid")!!
comparator.value = Comparator.Compare.valueOf(JsonHelper.safeGetString(d, "comparator")!!)
return this
}
override fun friendlyName(): Int = R.string.ns_wifi_ssids
override fun friendlyDescription(): String =
resourceHelper.gs(R.string.wifissidcompared, resourceHelper.gs(comparator.value.stringRes), ssid.value)
override fun icon(): Optional<Int?> = Optional.of(R.drawable.ic_network_wifi)
override fun duplicate(): Trigger = TriggerWifiSsid(mainApp, this)
override fun generateDialog(root: LinearLayout) {
LayoutBuilder()
.add(StaticLabel(mainApp, R.string.ns_wifi_ssids))
.add(comparator)
.add(LabelWithElement(mainApp, resourceHelper.gs(R.string.ns_wifi_ssids) + ": ", "", ssid))
.build(root)
}
}

View file

@ -8,10 +8,12 @@ import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton
/**
* Created by adrian on 14/08/17.
*/
@Singleton
class InsulinOrefRapidActingPlugin @Inject constructor(
resourceHelper: ResourceHelper,
rxBus: RxBusWrapper,

View file

@ -8,10 +8,12 @@ import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import javax.inject.Inject
import javax.inject.Singleton
/**
* Created by adrian on 14/08/17.
*/
@Singleton
class InsulinOrefUltraRapidActingPlugin @Inject constructor(
private val sp: SP,
resourceHelper: ResourceHelper,

View file

@ -26,7 +26,7 @@ import io.reactivex.disposables.CompositeDisposable
import io.reactivex.schedulers.Schedulers
import javax.inject.Inject
class LocationService : DaggerService() {
class LocationService @Inject constructor(): DaggerService() {
@Inject lateinit var aapsLogger: AAPSLogger
@Inject lateinit var rxBus: RxBusWrapper
@Inject lateinit var sp: SP
@ -40,13 +40,10 @@ class LocationService : DaggerService() {
private val LOCATION_INTERVAL_ACTIVE = T.mins(5).msecs()
private val LOCATION_INTERVAL_PASSIVE = T.mins(1).msecs() // this doesn't cost more power
var lastLocation: Location? = null
companion object {
private const val LOCATION_DISTANCE = 10f
private var lastLocation: Location? = null
@JvmStatic
@Deprecated("replace by injection")
fun getLastLocation(): Location? = lastLocation
}
inner class LocationListener internal constructor(val provider: String) : android.location.LocationListener {

View file

@ -81,13 +81,6 @@ public class TriggerAutosensValueTest {
Assert.assertEquals(Comparator.Compare.IS_EQUAL_OR_LESSER, t.getComparator().getValue());
}
@Test
public void executeTest() {
TriggerAutosensValue t = new TriggerAutosensValue().setValue(213).comparator(Comparator.Compare.IS_EQUAL_OR_LESSER);
t.executed(1);
Assert.assertEquals(1l, t.getLastRun());
}
String ASJson = "{\"data\":{\"comparator\":\"IS_EQUAL\",\"lastRun\":0,\"value\":410},\"type\":\"info.nightscout.androidaps.plugins.general.automation.triggers.TriggerAutosensValue\"}";
@Test

View file

@ -2,6 +2,7 @@ package info.nightscout.androidaps.plugins.insulin
import info.nightscout.androidaps.R
import info.nightscout.androidaps.plugins.bus.RxBusWrapper
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunction
import info.nightscout.androidaps.utils.resources.ResourceHelper
import info.nightscout.androidaps.utils.sharedPreferences.SP
import junit.framework.Assert.assertEquals
@ -34,10 +35,11 @@ class InsulinOrefFreePeakPluginTest {
@Mock lateinit var sp: SP
@Mock lateinit var resourceHelper: ResourceHelper
@Mock lateinit var rxBus: RxBusWrapper
@Mock lateinit var profileFunction: ProfileFunction
@Before
fun setup() {
sut = InsulinOrefFreePeakPlugin(sp, resourceHelper, rxBus)
sut = InsulinOrefFreePeakPlugin(sp, resourceHelper, rxBus, profileFunction)
}
@Test