commit
c3be06d4e2
|
@ -215,6 +215,7 @@ allprojects {
|
|||
flatDir {
|
||||
dirs 'libs'
|
||||
}
|
||||
maven { url 'https://jitpack.io' }
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -274,6 +275,8 @@ dependencies {
|
|||
implementation "com.jakewharton:butterknife:${butterknifeVersion}"
|
||||
annotationProcessor "com.jakewharton:butterknife-compiler:${butterknifeVersion}"
|
||||
|
||||
implementation 'com.github.DavidProdinger:weekdays-selector:1.0.4'
|
||||
|
||||
testImplementation "junit:junit:4.12"
|
||||
testImplementation "org.json:json:20140107"
|
||||
testImplementation "org.mockito:mockito-core:2.8.47"
|
||||
|
|
|
@ -19,6 +19,7 @@
|
|||
<uses-permission android:name="com.google.android.permission.PROVIDE_BACKGROUND" />
|
||||
<uses-permission android:name="android.permission.FOREGROUND_SERVICE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />
|
||||
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
|
||||
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
|
||||
<uses-permission android:name="com.dexcom.cgm.EXTERNAL_PERMISSION" />
|
||||
|
@ -161,6 +162,9 @@
|
|||
<service
|
||||
android:name=".services.DataService"
|
||||
android:exported="false" />
|
||||
<service
|
||||
android:name=".services.LocationService"
|
||||
android:exported="false" />
|
||||
<service
|
||||
android:name=".plugins.pump.danaR.services.DanaRExecutionService"
|
||||
android:enabled="true"
|
||||
|
|
|
@ -45,6 +45,7 @@ import info.nightscout.androidaps.plugins.constraints.objectives.ObjectivesPlugi
|
|||
import info.nightscout.androidaps.plugins.constraints.safety.SafetyPlugin;
|
||||
import info.nightscout.androidaps.plugins.constraints.storage.StorageConstraintPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.actions.ActionsFragment;
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.careportal.CareportalPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.food.FoodPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.maintenance.LoggerUtils;
|
||||
|
@ -220,6 +221,8 @@ public class MainApp extends Application {
|
|||
if (engineeringMode)
|
||||
pluginsList.add(TidepoolPlugin.INSTANCE);
|
||||
pluginsList.add(MaintenancePlugin.initPlugin(this));
|
||||
if (engineeringMode)
|
||||
pluginsList.add(AutomationPlugin.INSTANCE);
|
||||
|
||||
pluginsList.add(ConfigBuilderPlugin.getPlugin());
|
||||
|
||||
|
@ -466,4 +469,9 @@ public class MainApp extends Application {
|
|||
}
|
||||
|
||||
}
|
||||
|
||||
public static int dpToPx(int dp) {
|
||||
float scale = sResources.getDisplayMetrics().density;
|
||||
return (int) (dp * scale + 0.5f);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -49,6 +49,7 @@ import info.nightscout.androidaps.plugins.source.SourceDexcomPlugin;
|
|||
import info.nightscout.androidaps.utils.LocaleHelper;
|
||||
import info.nightscout.androidaps.utils.OKDialog;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
||||
|
||||
public class PreferencesActivity extends PreferenceActivity implements SharedPreferences.OnSharedPreferenceChangeListener {
|
||||
MyPreferenceFragment myPreferenceFragment;
|
||||
|
@ -190,6 +191,7 @@ public class PreferencesActivity extends PreferenceActivity implements SharedPre
|
|||
addPreferencesFromResourceIfEnabled(NSClientPlugin.getPlugin(), PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(TidepoolPlugin.INSTANCE, PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(SmsCommunicatorPlugin.getPlugin(), PluginType.GENERAL);
|
||||
addPreferencesFromResourceIfEnabled(AutomationPlugin.INSTANCE, PluginType.GENERAL);
|
||||
|
||||
addPreferencesFromResource(R.xml.pref_others);
|
||||
addPreferencesFromResource(R.xml.pref_datachoices);
|
||||
|
|
|
@ -45,6 +45,11 @@ public class PumpEnactResult {
|
|||
return this;
|
||||
}
|
||||
|
||||
public PumpEnactResult comment(int comment) {
|
||||
this.comment = MainApp.gs(comment);
|
||||
return this;
|
||||
}
|
||||
|
||||
public PumpEnactResult duration(int duration) {
|
||||
this.duration = duration;
|
||||
return this;
|
||||
|
|
|
@ -9,6 +9,9 @@ import org.slf4j.LoggerFactory;
|
|||
import java.util.Objects;
|
||||
|
||||
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.interfaces.Interval;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
|
@ -191,4 +194,11 @@ public class TempTarget implements Interval {
|
|||
'}';
|
||||
}
|
||||
|
||||
public String friendlyDescription(String units) {
|
||||
return Profile.toTargetRangeString(low, high, Constants.MGDL, units) +
|
||||
units +
|
||||
"@" + MainApp.gs(R.string.mins, durationInMinutes) +
|
||||
(reason != null && !reason.equals("") ? "(" + reason + ")" : "");
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -0,0 +1,11 @@
|
|||
package info.nightscout.androidaps.events;
|
||||
|
||||
import android.location.Location;
|
||||
|
||||
public class EventLocationChange extends Event {
|
||||
public Location location;
|
||||
|
||||
public EventLocationChange(Location location) {
|
||||
this.location = location;
|
||||
}
|
||||
}
|
|
@ -77,6 +77,7 @@ public class L {
|
|||
|
||||
public static final String CORE = "CORE";
|
||||
public static final String AUTOSENS = "AUTOSENS";
|
||||
public static final String AUTOMATION = "AUTOMATION";
|
||||
public static final String EVENTS = "EVENTS";
|
||||
public static final String GLUCOSE = "GLUCOSE";
|
||||
public static final String BGSOURCE = "BGSOURCE";
|
||||
|
@ -97,11 +98,13 @@ public class L {
|
|||
public static final String PROFILE = "PROFILE";
|
||||
public static final String CONFIGBUILDER = "CONFIGBUILDER";
|
||||
public static final String UI = "UI";
|
||||
public static final String LOCATION = "LOCATION";
|
||||
public static final String SMS = "SMS";
|
||||
|
||||
private static void initialize() {
|
||||
logElements = new ArrayList<>();
|
||||
logElements.add(new LogElement(APS, true));
|
||||
logElements.add(new LogElement(AUTOMATION, true));
|
||||
logElements.add(new LogElement(AUTOSENS, false));
|
||||
logElements.add(new LogElement(BGSOURCE, true));
|
||||
logElements.add(new LogElement(GLUCOSE, false));
|
||||
|
@ -113,6 +116,7 @@ public class L {
|
|||
logElements.add(new LogElement(DATASERVICE, true));
|
||||
logElements.add(new LogElement(DATATREATMENTS, true));
|
||||
logElements.add(new LogElement(EVENTS, false, true));
|
||||
logElements.add(new LogElement(LOCATION, true));
|
||||
logElements.add(new LogElement(NOTIFICATION, true));
|
||||
logElements.add(new LogElement(NSCLIENT, true));
|
||||
logElements.add(new LogElement(TIDEPOOL, true));
|
||||
|
|
|
@ -0,0 +1,90 @@
|
|||
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.plugins.general.automation.actions.Action;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||
|
||||
public class AutomationEvent {
|
||||
|
||||
private Trigger trigger = new TriggerConnector();
|
||||
private List<Action> actions = new ArrayList<>();
|
||||
private String title;
|
||||
|
||||
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 TriggerConnector getPreconditions() {
|
||||
TriggerConnector trigger = new TriggerConnector(TriggerConnector.Type.AND);
|
||||
for (Action action : actions) {
|
||||
if (action.precondition != null)
|
||||
trigger.add(action.precondition);
|
||||
}
|
||||
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);
|
||||
// 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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
public AutomationEvent fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
// title
|
||||
title = d.optString("title", "");
|
||||
// trigger
|
||||
trigger = Trigger.instantiate(d.getString("trigger"));
|
||||
// actions
|
||||
JSONArray array = d.getJSONArray("actions");
|
||||
actions.clear();
|
||||
for (int i = 0; i < array.length(); i++) {
|
||||
actions.add(Action.instantiate(new JSONObject(array.getString(i))));
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.Fragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import kotlinx.android.synthetic.main.automation_fragment.*
|
||||
|
||||
class AutomationFragment : Fragment() {
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
private var eventListAdapter: EventListAdapter? = null
|
||||
|
||||
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
|
||||
add(disposable)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View? {
|
||||
return inflater.inflate(R.layout.automation_fragment, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
eventListAdapter = EventListAdapter(AutomationPlugin.automationEvents, fragmentManager)
|
||||
automation_eventListView.layoutManager = LinearLayoutManager(context)
|
||||
automation_eventListView.adapter = eventListAdapter
|
||||
|
||||
automation_fabAddEvent.setOnClickListener {
|
||||
val dialog = EditEventDialog()
|
||||
val args = Bundle()
|
||||
args.putString("event", AutomationEvent().toJSON())
|
||||
args.putInt("position", -1) // New event
|
||||
dialog.arguments = args
|
||||
fragmentManager?.let { dialog.show(it, "EditEventDialog") }
|
||||
}
|
||||
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutomationUpdateGui::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
eventListAdapter?.notifyDataSetChanged()
|
||||
val sb = StringBuilder()
|
||||
for (l in AutomationPlugin.executionLog) {
|
||||
sb.append(l)
|
||||
sb.append("\n")
|
||||
}
|
||||
automation_logView.text = sb.toString()
|
||||
}, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutomationDataChanged::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
eventListAdapter?.notifyDataSetChanged()
|
||||
}, {})
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
super.onStop()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,213 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation
|
||||
|
||||
import android.content.Intent
|
||||
import android.os.Handler
|
||||
import info.nightscout.androidaps.MainApp
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.events.EventChargingState
|
||||
import info.nightscout.androidaps.events.EventLocationChange
|
||||
import info.nightscout.androidaps.events.EventNetworkChange
|
||||
import info.nightscout.androidaps.events.EventPreferenceChange
|
||||
import info.nightscout.androidaps.interfaces.PluginBase
|
||||
import info.nightscout.androidaps.interfaces.PluginDescription
|
||||
import info.nightscout.androidaps.interfaces.PluginType
|
||||
import info.nightscout.androidaps.logging.L
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.*
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationDataChanged
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.*
|
||||
import info.nightscout.androidaps.plugins.iob.iobCobCalculator.events.EventAutosensCalculationFinished
|
||||
import info.nightscout.androidaps.queue.Callback
|
||||
import info.nightscout.androidaps.services.LocationService
|
||||
import info.nightscout.androidaps.utils.DateUtil
|
||||
import info.nightscout.androidaps.utils.SP
|
||||
import info.nightscout.androidaps.utils.T
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import io.reactivex.disposables.Disposable
|
||||
import io.reactivex.schedulers.Schedulers
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import org.slf4j.LoggerFactory
|
||||
import java.util.*
|
||||
|
||||
object AutomationPlugin : PluginBase(PluginDescription()
|
||||
.mainType(PluginType.GENERAL)
|
||||
.fragmentClass(AutomationFragment::class.qualifiedName)
|
||||
.pluginName(R.string.automation)
|
||||
.shortName(R.string.automation_short)
|
||||
.preferencesId(R.xml.pref_automation)
|
||||
.description(R.string.automation_description)) {
|
||||
|
||||
private val log = LoggerFactory.getLogger(L.AUTOMATION)
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
private const val key_AUTOMATION_EVENTS = "AUTOMATION_EVENTS"
|
||||
|
||||
val automationEvents = ArrayList<AutomationEvent>()
|
||||
var executionLog: MutableList<String> = ArrayList()
|
||||
|
||||
private val loopHandler = Handler()
|
||||
private lateinit var refreshLoop: Runnable
|
||||
|
||||
init {
|
||||
refreshLoop = Runnable {
|
||||
processActions()
|
||||
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
||||
}
|
||||
}
|
||||
|
||||
operator fun CompositeDisposable.plusAssign(disposable: Disposable) {
|
||||
add(disposable)
|
||||
}
|
||||
|
||||
override fun onStart() {
|
||||
val context = MainApp.instance().applicationContext
|
||||
context.startService(Intent(context, LocationService::class.java))
|
||||
|
||||
super.onStart()
|
||||
loadFromSP()
|
||||
loopHandler.postDelayed(refreshLoop, T.mins(1).msecs())
|
||||
|
||||
disposable += RxBus
|
||||
.toObservable(EventPreferenceChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ e ->
|
||||
if (e.isChanged(R.string.key_location)) {
|
||||
val ctx = MainApp.instance().applicationContext
|
||||
ctx.stopService(Intent(ctx, LocationService::class.java))
|
||||
ctx.startService(Intent(ctx, LocationService::class.java))
|
||||
}
|
||||
}, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutomationDataChanged::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ storeToSP() }, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventLocationChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ e ->
|
||||
e?.let {
|
||||
log.debug("Grabbed location: $it.location.latitude $it.location.longitude Provider: $it.location.provider")
|
||||
processActions()
|
||||
}
|
||||
}, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventChargingState::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ processActions() }, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventNetworkChange::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ processActions() }, {})
|
||||
disposable += RxBus
|
||||
.toObservable(EventAutosensCalculationFinished::class.java)
|
||||
.observeOn(Schedulers.io())
|
||||
.subscribe({ processActions() }, {})
|
||||
}
|
||||
|
||||
override fun onStop() {
|
||||
disposable.clear()
|
||||
loopHandler.removeCallbacks(refreshLoop)
|
||||
val context = MainApp.instance().applicationContext
|
||||
context.stopService(Intent(context, LocationService::class.java))
|
||||
}
|
||||
|
||||
private fun storeToSP() {
|
||||
val array = JSONArray()
|
||||
try {
|
||||
for (event in automationEvents) {
|
||||
array.put(JSONObject(event.toJSON()))
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
|
||||
SP.putString(key_AUTOMATION_EVENTS, array.toString())
|
||||
}
|
||||
|
||||
private fun loadFromSP() {
|
||||
automationEvents.clear()
|
||||
val data = SP.getString(key_AUTOMATION_EVENTS, "")
|
||||
if (data != "") {
|
||||
try {
|
||||
val array = JSONArray(data)
|
||||
for (i in 0 until array.length()) {
|
||||
val o = array.getJSONObject(i)
|
||||
val event = AutomationEvent().fromJSON(o.toString())
|
||||
automationEvents.add(event)
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Synchronized
|
||||
private fun processActions() {
|
||||
if (!isEnabled(PluginType.GENERAL))
|
||||
return
|
||||
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("processActions")
|
||||
for (event in automationEvents) {
|
||||
if (event.trigger.shouldRun() && event.preconditions.shouldRun()) {
|
||||
val actions = event.actions
|
||||
for (action in actions) {
|
||||
action.doAction(object : Callback() {
|
||||
override fun run() {
|
||||
val sb = StringBuilder()
|
||||
sb.append(DateUtil.timeString(DateUtil.now()))
|
||||
sb.append(" ")
|
||||
sb.append(if (result.success) "☺" else "X")
|
||||
sb.append(" ")
|
||||
sb.append(event.title)
|
||||
sb.append(": ")
|
||||
sb.append(action.shortDescription())
|
||||
sb.append(": ")
|
||||
sb.append(result.comment)
|
||||
executionLog.add(sb.toString())
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Executed: $sb")
|
||||
RxBus.send(EventAutomationUpdateGui())
|
||||
}
|
||||
})
|
||||
}
|
||||
event.trigger.executed(DateUtil.now())
|
||||
}
|
||||
}
|
||||
storeToSP() // save last run time
|
||||
}
|
||||
|
||||
fun getActionDummyObjects(): List<Action> {
|
||||
return listOf(
|
||||
//ActionLoopDisable(),
|
||||
//ActionLoopEnable(),
|
||||
//ActionLoopResume(),
|
||||
//ActionLoopSuspend(),
|
||||
ActionStartTempTarget(),
|
||||
ActionStopTempTarget(),
|
||||
ActionNotification(),
|
||||
ActionProfileSwitchPercent()
|
||||
)
|
||||
}
|
||||
|
||||
fun getTriggerDummyObjects(): List<Trigger> {
|
||||
return listOf(
|
||||
TriggerTime(),
|
||||
TriggerRecurringTime(),
|
||||
TriggerBg(),
|
||||
TriggerDelta(),
|
||||
TriggerIob(),
|
||||
TriggerCOB(),
|
||||
TriggerProfilePercent(),
|
||||
TriggerTempTarget(),
|
||||
TriggerWifiSsid(),
|
||||
TriggerLocation(),
|
||||
TriggerAutosensValue(),
|
||||
TriggerBolusAgo()
|
||||
)
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,120 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation;
|
||||
|
||||
import android.content.Context;
|
||||
import android.os.Bundle;
|
||||
import android.view.LayoutInflater;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.ImageView;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.RelativeLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.annotation.DrawableRes;
|
||||
import androidx.annotation.NonNull;
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
import androidx.recyclerview.widget.RecyclerView;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action;
|
||||
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog;
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||
|
||||
class EventListAdapter extends RecyclerView.Adapter<EventListAdapter.ViewHolder> {
|
||||
private final List<AutomationEvent> mEventList;
|
||||
private final FragmentManager mFragmentManager;
|
||||
|
||||
EventListAdapter(List<AutomationEvent> events, FragmentManager fragmentManager) {
|
||||
this.mEventList = events;
|
||||
this.mFragmentManager = fragmentManager;
|
||||
}
|
||||
|
||||
@NonNull
|
||||
@Override
|
||||
public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
|
||||
View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.automation_event_item, parent, false);
|
||||
return new ViewHolder(v, parent.getContext());
|
||||
}
|
||||
|
||||
private void addImage(@DrawableRes int res, Context context, LinearLayout layout) {
|
||||
ImageView iv = new ImageView(context);
|
||||
iv.setImageResource(res);
|
||||
iv.setLayoutParams(new LinearLayout.LayoutParams(MainApp.dpToPx(24), MainApp.dpToPx(24)));
|
||||
layout.addView(iv);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
|
||||
final AutomationEvent event = mEventList.get(position);
|
||||
holder.eventTitle.setText(event.getTitle());
|
||||
holder.iconLayout.removeAllViews();
|
||||
|
||||
// trigger icons
|
||||
HashSet<Integer> triggerIcons = new HashSet<>();
|
||||
TriggerConnector.fillIconSet((TriggerConnector) event.getTrigger(), triggerIcons);
|
||||
for (int res : triggerIcons) {
|
||||
addImage(res, holder.context, holder.iconLayout);
|
||||
}
|
||||
|
||||
// arrow icon
|
||||
ImageView iv = new ImageView(holder.context);
|
||||
iv.setImageResource(R.drawable.ic_arrow_forward_white_24dp);
|
||||
iv.setLayoutParams(new LinearLayout.LayoutParams(MainApp.dpToPx(24), MainApp.dpToPx(24)));
|
||||
iv.setPadding(MainApp.dpToPx(4), 0, MainApp.dpToPx(4), 0);
|
||||
holder.iconLayout.addView(iv);
|
||||
|
||||
// action icons
|
||||
HashSet<Integer> actionIcons = new HashSet<>();
|
||||
for (Action action : event.getActions()) {
|
||||
if (action.icon().isPresent())
|
||||
actionIcons.add(action.icon().get());
|
||||
}
|
||||
for (int res : actionIcons) {
|
||||
addImage(res, holder.context, holder.iconLayout);
|
||||
}
|
||||
|
||||
// remove event
|
||||
holder.iconTrash.setOnClickListener(v -> {
|
||||
mEventList.remove(event);
|
||||
notifyDataSetChanged();
|
||||
});
|
||||
|
||||
// edit event
|
||||
holder.rootLayout.setOnClickListener(v -> {
|
||||
//EditEventDialog dialog = EditEventDialog.Companion.newInstance(event, false);
|
||||
EditEventDialog dialog = new EditEventDialog();
|
||||
Bundle args = new Bundle();
|
||||
args.putString("event", event.toJSON());
|
||||
args.putInt("position", position);
|
||||
dialog.setArguments(args);
|
||||
if (mFragmentManager != null)
|
||||
dialog.show(mFragmentManager, "EditEventDialog");
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getItemCount() {
|
||||
return mEventList.size();
|
||||
}
|
||||
|
||||
static class ViewHolder extends RecyclerView.ViewHolder {
|
||||
final RelativeLayout rootLayout;
|
||||
final LinearLayout iconLayout;
|
||||
final TextView eventTitle;
|
||||
final Context context;
|
||||
final ImageView iconTrash;
|
||||
|
||||
ViewHolder(View view, Context context) {
|
||||
super(view);
|
||||
this.context = context;
|
||||
eventTitle = view.findViewById(R.id.viewEventTitle);
|
||||
rootLayout = view.findViewById(R.id.rootLayout);
|
||||
iconLayout = view.findViewById(R.id.iconLayout);
|
||||
iconTrash = view.findViewById(R.id.iconTrash);
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,104 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
/*
|
||||
Action ideas:
|
||||
|
||||
* cancel temp target
|
||||
* change preference setting
|
||||
* enable/disable plugin
|
||||
* create notification
|
||||
* create ugly alarm
|
||||
* create profile switch
|
||||
* set/cancel tbr
|
||||
* set/cancel extended bolus
|
||||
* run bolus wizard
|
||||
|
||||
Trigger ideas:
|
||||
|
||||
* location (close to)
|
||||
* connected to specific wifi
|
||||
* internet available/not available
|
||||
* nsclient connected/disconnected
|
||||
* iob
|
||||
* cob
|
||||
* autosens value
|
||||
* delta, short delta, long delta
|
||||
* last bolus ago
|
||||
* is tbr running
|
||||
* bolus wizard result
|
||||
* loop is enabled, disabled, suspended, running
|
||||
|
||||
*/
|
||||
|
||||
|
||||
public abstract class Action {
|
||||
|
||||
public Trigger precondition = null;
|
||||
|
||||
public abstract int friendlyName();
|
||||
|
||||
public abstract String shortDescription();
|
||||
|
||||
public abstract void doAction(Callback callback);
|
||||
|
||||
public void generateDialog(LinearLayout root) {
|
||||
}
|
||||
|
||||
public boolean hasDialog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", this.getClass().getName());
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
public abstract Optional<Integer> icon();
|
||||
|
||||
public Action fromJSON(String data) {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Action instantiate(JSONObject object) {
|
||||
try {
|
||||
String type = object.getString("type");
|
||||
JSONObject data = object.optJSONObject("data");
|
||||
Class clazz = Class.forName(type);
|
||||
return ((Action) clazz.newInstance()).fromJSON(data != null ? data.toString() : "");
|
||||
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException | JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void apply(Action a) {
|
||||
try {
|
||||
JSONObject object = new JSONObject(a.toJSON());
|
||||
String type = object.getString("type");
|
||||
JSONObject data = object.getJSONObject("data");
|
||||
if (type.equals(getClass().getName())) {
|
||||
fromJSON(data.toString());
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,49 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
public class ActionLoopDisable extends Action {
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.disableloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.disableloop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
|
||||
LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, false);
|
||||
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopDisable");
|
||||
ConfigBuilderPlugin.getPlugin().getCommandQueue().cancelTempBasal(true, new Callback() {
|
||||
@Override
|
||||
public void run() {
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopDisable"));
|
||||
if (callback != null)
|
||||
callback.result(result).run();
|
||||
}
|
||||
});
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadydisabled)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_stop_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.interfaces.PluginType;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
public class ActionLoopEnable extends Action {
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.enableloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.enableloop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (!LoopPlugin.getPlugin().isEnabled(PluginType.LOOP)) {
|
||||
LoopPlugin.getPlugin().setPluginEnabled(PluginType.LOOP, true);
|
||||
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopEnable");
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopEnable"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadyenabled)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_play_circle_outline_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,45 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ConfigBuilderPlugin;
|
||||
import info.nightscout.androidaps.plugins.general.nsclient.NSUpload;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
|
||||
public class ActionLoopResume extends Action {
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.resumeloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.resumeloop);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (LoopPlugin.getPlugin().isSuspended()) {
|
||||
LoopPlugin.getPlugin().suspendTo(0);
|
||||
ConfigBuilderPlugin.getPlugin().storeSettings("ActionLoopResume");
|
||||
NSUpload.uploadOpenAPSOffline(0);
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopResume"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.notsuspended)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_replay_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.plugins.aps.loop.LoopPlugin;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
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.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionLoopSuspend extends Action {
|
||||
public InputDuration minutes = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.suspendloop;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.suspendloopforXmin, minutes.getMinutes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
if (!LoopPlugin.getPlugin().isSuspended()) {
|
||||
LoopPlugin.getPlugin().suspendLoop(minutes.getMinutes());
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionLoopSuspend"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
} else {
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.alreadysuspended)).run();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_pause_circle_outline_24dp);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("minutes", minutes.getMinutes());
|
||||
o.put("type", this.getClass().getName());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject o = new JSONObject(data);
|
||||
minutes.setMinutes(JsonHelper.safeGetInt(o, "minutes"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", minutes))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,91 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.events.EventRefreshOverview;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
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.nsclient.NSUpload;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionNotification extends Action {
|
||||
public InputString text = new InputString();
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.notification;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.notification_message, text.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
Notification notification = new Notification(Notification.USERMESSAGE, text.getValue(), Notification.URGENT);
|
||||
RxBus.INSTANCE.send(new EventNewNotification(notification));
|
||||
NSUpload.uploadError(text.getValue());
|
||||
RxBus.INSTANCE.send(new EventRefreshOverview("ActionNotification"));
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_notifications);
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("text", text.getValue());
|
||||
o.put("type", this.getClass().getName());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject o = new JSONObject(data);
|
||||
text.setValue(JsonHelper.safeGetString(o, "text"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.message_short), "", text))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,95 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions;
|
||||
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.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.triggers.TriggerProfilePercent;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionProfileSwitchPercent extends Action {
|
||||
InputPercent pct = new InputPercent();
|
||||
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
|
||||
public ActionProfileSwitchPercent() {
|
||||
precondition = new TriggerProfilePercent().comparator(Comparator.Compare.IS_EQUAL).setValue(100);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.profilepercentage;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
if (duration.getMinutes() == 0)
|
||||
return MainApp.gs(R.string.startprofileforever, (int) pct.getValue());
|
||||
else
|
||||
return MainApp.gs(R.string.startprofile, (int) pct.getValue(), duration.getMinutes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
ProfileFunctions.doProfileSwitch((int) duration.getValue(), (int) pct.getValue(), 0);
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.percent_u), "", pct))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", ActionProfileSwitchPercent.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("percentage", pct.getValue());
|
||||
data.put("durationInMinutes", duration.getMinutes());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
pct.setValue(JsonHelper.safeGetInt(d, "percentage"));
|
||||
duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_actions_profileswitch);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,119 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
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.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.Source;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.ComparatorExists;
|
||||
import info.nightscout.androidaps.plugins.general.automation.elements.InputBg;
|
||||
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.triggers.TriggerTempTarget;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionStartTempTarget extends Action {
|
||||
String reason = "";
|
||||
InputBg value = new InputBg();
|
||||
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
|
||||
private TempTarget tempTarget;
|
||||
|
||||
public ActionStartTempTarget() {
|
||||
precondition = new TriggerTempTarget().comparator(ComparatorExists.Compare.NOT_EXISTS);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.starttemptarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
tempTarget = new TempTarget()
|
||||
.date(DateUtil.now())
|
||||
.duration(duration.getMinutes())
|
||||
.reason(reason)
|
||||
.source(Source.USER)
|
||||
.low(Profile.toMgdl(value.getValue(), value.getUnits()))
|
||||
.high(Profile.toMgdl(value.getValue(), value.getUnits()));
|
||||
return MainApp.gs(R.string.starttemptarget) + ": " + (tempTarget == null ? "null" : tempTarget.friendlyDescription(value.getUnits()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
tempTarget = new TempTarget()
|
||||
.date(DateUtil.now())
|
||||
.duration(duration.getMinutes())
|
||||
.reason(reason)
|
||||
.source(Source.USER)
|
||||
.low(Profile.toMgdl(value.getValue(), value.getUnits()))
|
||||
.high(Profile.toMgdl(value.getValue(), value.getUnits()));
|
||||
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateDialog(LinearLayout root) {
|
||||
int unitResId = value.getUnits().equals(Constants.MGDL) ? R.string.mgdl : R.string.mmol;
|
||||
|
||||
new LayoutBuilder()
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_temporarytarget), MainApp.gs(unitResId), value))
|
||||
.add(new LabelWithElement(MainApp.gs(R.string.careportal_newnstreatment_duration_min_label), "", duration))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", ActionStartTempTarget.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("reason", reason);
|
||||
data.put("value", value.getValue());
|
||||
data.put("units", value.getUnits());
|
||||
data.put("durationInMinutes", duration.getMinutes());
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
reason = JsonHelper.safeGetString(d, "reason");
|
||||
value.setUnits(JsonHelper.safeGetString(d, "units"));
|
||||
value.setValue(JsonHelper.safeGetDouble(d, "value"));
|
||||
duration.setMinutes(JsonHelper.safeGetInt(d, "durationInMinutes"));
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.icon_cp_cgm_target);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.actions;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.data.PumpEnactResult;
|
||||
import info.nightscout.androidaps.db.Source;
|
||||
import info.nightscout.androidaps.db.TempTarget;
|
||||
import info.nightscout.androidaps.plugins.treatments.TreatmentsPlugin;
|
||||
import info.nightscout.androidaps.queue.Callback;
|
||||
import info.nightscout.androidaps.utils.DateUtil;
|
||||
import info.nightscout.androidaps.utils.JsonHelper;
|
||||
|
||||
public class ActionStopTempTarget extends Action {
|
||||
String reason = "";
|
||||
private TempTarget tempTarget;
|
||||
|
||||
public ActionStopTempTarget() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.stoptemptarget;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String shortDescription() {
|
||||
return MainApp.gs(R.string.stoptemptarget);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void doAction(Callback callback) {
|
||||
tempTarget = new TempTarget().date(DateUtil.now()).duration(0).reason(reason).source(Source.USER).low(0).high(0);
|
||||
TreatmentsPlugin.getPlugin().addToHistoryTempTarget(tempTarget);
|
||||
if (callback != null)
|
||||
callback.result(new PumpEnactResult().success(true).comment(R.string.ok)).run();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasDialog() {
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String toJSON() {
|
||||
JSONObject o = new JSONObject();
|
||||
try {
|
||||
o.put("type", ActionStopTempTarget.class.getName());
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("reason", reason);
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return o.toString();
|
||||
}
|
||||
|
||||
@Override
|
||||
public Action fromJSON(String data) {
|
||||
try {
|
||||
JSONObject d = new JSONObject(data);
|
||||
reason = JsonHelper.safeGetString(d, "reason");
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_stop_24dp);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,54 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.ImageView
|
||||
import android.widget.LinearLayout
|
||||
import android.widget.TextView
|
||||
import androidx.fragment.app.FragmentManager
|
||||
import androidx.recyclerview.widget.RecyclerView
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
|
||||
class ActionListAdapter(private val fragmentManager: FragmentManager, private val actionList: MutableList<Action>) : RecyclerView.Adapter<ActionListAdapter.ViewHolder>() {
|
||||
|
||||
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
|
||||
val v = LayoutInflater.from(parent.context).inflate(R.layout.automation_action_item, parent, false)
|
||||
return ViewHolder(v)
|
||||
}
|
||||
|
||||
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
|
||||
val action = actionList[position]
|
||||
holder.bind(action, fragmentManager, this, position, actionList)
|
||||
}
|
||||
|
||||
override fun getItemCount(): Int {
|
||||
return actionList.size
|
||||
}
|
||||
|
||||
class ViewHolder(val view: View) : RecyclerView.ViewHolder(view) {
|
||||
|
||||
fun bind(action: Action, fragmentManager: FragmentManager, recyclerView: RecyclerView.Adapter<ViewHolder>, position : Int, actionList: MutableList<Action>) {
|
||||
view.findViewById<LinearLayout>(R.id.automation_layoutText).setOnClickListener {
|
||||
if (action.hasDialog()) {
|
||||
val args = Bundle()
|
||||
args.putInt("actionPosition", position)
|
||||
args.putString("action", action.toJSON())
|
||||
val dialog = EditActionDialog()
|
||||
dialog.arguments = args
|
||||
dialog.show(fragmentManager, "EditActionDialog")
|
||||
}
|
||||
}
|
||||
view.findViewById<ImageView>(R.id.automation_iconTrash).setOnClickListener {
|
||||
actionList.remove(action)
|
||||
recyclerView.notifyDataSetChanged()
|
||||
RxBus.send(EventAutomationUpdateGui())
|
||||
}
|
||||
view.findViewById<TextView>(R.id.automation_viewActionTitle).text = action.shortDescription()
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,85 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RadioButton
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationAddAction
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui
|
||||
import kotlinx.android.synthetic.main.automation_dialog_choose_action.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class ChooseActionDialog : DialogFragment() {
|
||||
|
||||
var checkedIndex = -1
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// restore checked radio button
|
||||
savedInstanceState?.let { bundle ->
|
||||
checkedIndex = bundle.getInt("checkedIndex")
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_choose_action, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
for (a in AutomationPlugin.getActionDummyObjects()) {
|
||||
val radioButton = RadioButton(context)
|
||||
radioButton.setText(a.friendlyName())
|
||||
radioButton.tag = a.javaClass
|
||||
automation_radioGroup.addView(radioButton)
|
||||
}
|
||||
|
||||
if (checkedIndex != -1)
|
||||
(automation_radioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
instantiateAction()?.let {
|
||||
RxBus.send(EventAutomationAddAction(it))
|
||||
RxBus.send(EventAutomationUpdateGui())
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
bundle.putInt("checkedIndex", determineCheckedIndex())
|
||||
}
|
||||
|
||||
private fun instantiateAction(): Action? {
|
||||
return getActionClass()?.let {
|
||||
it.newInstance() as Action
|
||||
}
|
||||
}
|
||||
|
||||
private fun getActionClass(): Class<*>? {
|
||||
val radioButtonID = automation_radioGroup.checkedRadioButtonId
|
||||
val radioButton = automation_radioGroup.findViewById<RadioButton>(radioButtonID)
|
||||
return radioButton?.let {
|
||||
it.tag as Class<*>
|
||||
}
|
||||
}
|
||||
|
||||
private fun determineCheckedIndex(): Int {
|
||||
for (i in 0 until automation_radioGroup.childCount) {
|
||||
if ((automation_radioGroup.getChildAt(i) as RadioButton).isChecked)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,89 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.RadioButton
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
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 kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class ChooseTriggerDialog : DialogFragment() {
|
||||
|
||||
private var checkedIndex = -1
|
||||
|
||||
private var clickListener: OnClickListener? = null
|
||||
|
||||
interface OnClickListener {
|
||||
fun onClick(newTriggerObject: Trigger?)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// restore checked radio button
|
||||
savedInstanceState?.let { bundle ->
|
||||
checkedIndex = bundle.getInt("checkedIndex")
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_choose_trigger, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
for (t in AutomationPlugin.getTriggerDummyObjects()) {
|
||||
val radioButton = RadioButton(context)
|
||||
radioButton.setText(t.friendlyName())
|
||||
radioButton.tag = t.javaClass
|
||||
automation_chooseTriggerRadioGroup.addView(radioButton)
|
||||
}
|
||||
|
||||
if (checkedIndex != -1)
|
||||
(automation_chooseTriggerRadioGroup.getChildAt(checkedIndex) as RadioButton).isChecked = true
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
clickListener?.onClick(instantiateTrigger())
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
fun setOnClickListener(clickListener: OnClickListener) {
|
||||
this.clickListener = clickListener
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
bundle.putInt("checkedIndex", determineCheckedIndex())
|
||||
}
|
||||
|
||||
private fun instantiateTrigger(): Trigger? {
|
||||
return getTriggerClass()?.let {
|
||||
it.newInstance() as Trigger
|
||||
}
|
||||
}
|
||||
|
||||
private fun getTriggerClass(): Class<*>? {
|
||||
val radioButtonID = automation_chooseTriggerRadioGroup.checkedRadioButtonId
|
||||
val radioButton = automation_chooseTriggerRadioGroup.findViewById<RadioButton>(radioButtonID)
|
||||
return radioButton?.let {
|
||||
it.tag as Class<*>
|
||||
}
|
||||
}
|
||||
|
||||
private fun determineCheckedIndex(): Int {
|
||||
for (i in 0 until automation_chooseTriggerRadioGroup.childCount) {
|
||||
if ((automation_chooseTriggerRadioGroup.getChildAt(i) as RadioButton).isChecked)
|
||||
return i
|
||||
}
|
||||
return -1
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,62 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import android.widget.Button
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateAction
|
||||
import kotlinx.android.synthetic.main.automation_dialog_action.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
import org.json.JSONObject
|
||||
|
||||
class EditActionDialog : DialogFragment() {
|
||||
|
||||
private var action: Action? = null
|
||||
private var actionPosition: Int = -1
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// load data from bundle
|
||||
(savedInstanceState ?: arguments)?.let { bundle ->
|
||||
actionPosition = bundle.getInt("actionPosition", -1)
|
||||
bundle.getString("action")?.let { action = Action.instantiate(JSONObject(it)) }
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_action, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
action?.let {
|
||||
automation_actionTitle.setText(it.friendlyName())
|
||||
automation_editActionLayout.removeAllViews()
|
||||
it.generateDialog(automation_editActionLayout)
|
||||
}
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
action?.let {
|
||||
RxBus.send(EventAutomationUpdateAction(it, actionPosition))
|
||||
}
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
super.onSaveInstanceState(bundle)
|
||||
action?.let {
|
||||
bundle.putInt("actionPosition", actionPosition)
|
||||
bundle.putString("action", it.toJSON())
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import androidx.recyclerview.widget.LinearLayoutManager
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent
|
||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.*
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector
|
||||
import info.nightscout.androidaps.utils.ToastUtils
|
||||
import io.reactivex.android.schedulers.AndroidSchedulers
|
||||
import io.reactivex.disposables.CompositeDisposable
|
||||
import kotlinx.android.synthetic.main.automation_dialog_event.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class EditEventDialog : DialogFragment() {
|
||||
|
||||
private var actionListAdapter: ActionListAdapter? = null
|
||||
private var event: AutomationEvent = AutomationEvent()
|
||||
private var position: Int = -1
|
||||
|
||||
private var disposable: CompositeDisposable = CompositeDisposable()
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// load data from bundle
|
||||
(savedInstanceState ?: arguments)?.let { bundle ->
|
||||
position = bundle.getInt("position", -1)
|
||||
bundle.getString("event")?.let { event = AutomationEvent().fromJSON(it) }
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_event, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
automation_inputEventTitle.setText(event.title)
|
||||
automation_triggerDescription.text = event.trigger.friendlyDescription()
|
||||
|
||||
automation_editTrigger.setOnClickListener {
|
||||
val args = Bundle()
|
||||
args.putString("trigger", event.trigger.toJSON())
|
||||
val dialog = EditTriggerDialog()
|
||||
dialog.arguments = args
|
||||
fragmentManager?.let { dialog.show(it, "EditTriggerDialog") }
|
||||
}
|
||||
|
||||
// setup action list view
|
||||
fragmentManager?.let { actionListAdapter = ActionListAdapter(it, event.actions) }
|
||||
automation_actionListView.layoutManager = LinearLayoutManager(context)
|
||||
automation_actionListView.adapter = actionListAdapter
|
||||
|
||||
automation_addAction.setOnClickListener { fragmentManager?.let { ChooseActionDialog().show(it, "ChooseActionDialog") } }
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
// check for title
|
||||
val title = automation_inputEventTitle.text.toString()
|
||||
if (title.isEmpty()) {
|
||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_task_name)
|
||||
return@setOnClickListener
|
||||
}
|
||||
event.title = title
|
||||
// check for at least one trigger
|
||||
val con = event.trigger as TriggerConnector
|
||||
if (con.size() == 0) {
|
||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_trigger)
|
||||
return@setOnClickListener
|
||||
}
|
||||
// check for at least one action
|
||||
if (event.actions.isEmpty()) {
|
||||
ToastUtils.showToastInUiThread(context, R.string.automation_missing_action)
|
||||
return@setOnClickListener
|
||||
}
|
||||
// store
|
||||
if (position == -1)
|
||||
AutomationPlugin.automationEvents.add(event)
|
||||
else
|
||||
AutomationPlugin.automationEvents[position] = event
|
||||
|
||||
dismiss()
|
||||
RxBus.send(EventAutomationDataChanged())
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
|
||||
showPreconditions()
|
||||
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationUpdateGui::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
actionListAdapter?.notifyDataSetChanged()
|
||||
showPreconditions()
|
||||
}, {})
|
||||
)
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationAddAction::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
event.addAction(it.action)
|
||||
actionListAdapter?.notifyDataSetChanged()
|
||||
}, {})
|
||||
)
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationUpdateTrigger::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
event.trigger = it.trigger
|
||||
automation_triggerDescription.text = event.trigger.friendlyDescription()
|
||||
}, {})
|
||||
)
|
||||
disposable.add(RxBus
|
||||
.toObservable(EventAutomationUpdateAction::class.java)
|
||||
.observeOn(AndroidSchedulers.mainThread())
|
||||
.subscribe({
|
||||
event.actions[it.position] = it.action
|
||||
actionListAdapter?.notifyDataSetChanged()
|
||||
}, {})
|
||||
)
|
||||
}
|
||||
|
||||
override fun onDestroyView() {
|
||||
super.onDestroyView()
|
||||
disposable.clear()
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
super.onSaveInstanceState(bundle)
|
||||
bundle.putString("event", event.toJSON())
|
||||
bundle.putInt("position", position)
|
||||
}
|
||||
|
||||
private fun showPreconditions() {
|
||||
val forcedTriggers = event.preconditions
|
||||
if (forcedTriggers.size() > 0) {
|
||||
automation_forcedTriggerDescription.visibility = View.VISIBLE
|
||||
automation_forcedTriggerDescriptionLabel.visibility = View.VISIBLE
|
||||
automation_forcedTriggerDescription.text = forcedTriggers.friendlyDescription()
|
||||
} else {
|
||||
automation_forcedTriggerDescription.visibility = View.GONE
|
||||
automation_forcedTriggerDescriptionLabel.visibility = View.GONE
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,50 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs
|
||||
|
||||
import android.os.Bundle
|
||||
import android.view.LayoutInflater
|
||||
import android.view.View
|
||||
import android.view.ViewGroup
|
||||
import androidx.fragment.app.DialogFragment
|
||||
import info.nightscout.androidaps.R
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus
|
||||
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
||||
import kotlinx.android.synthetic.main.automation_dialog_edit_trigger.*
|
||||
import kotlinx.android.synthetic.main.okcancel.*
|
||||
|
||||
class EditTriggerDialog : DialogFragment() {
|
||||
|
||||
private var trigger: Trigger? = null
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
savedInstanceState: Bundle?): View? {
|
||||
// load data from bundle
|
||||
(savedInstanceState ?: arguments)?.let { bundle ->
|
||||
bundle.getString("trigger")?.let { trigger = Trigger.instantiate(it) }
|
||||
}
|
||||
|
||||
dialog.setCanceledOnTouchOutside(false)
|
||||
return inflater.inflate(R.layout.automation_dialog_edit_trigger, container, false)
|
||||
}
|
||||
|
||||
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
|
||||
super.onViewCreated(view, savedInstanceState)
|
||||
|
||||
// display root trigger
|
||||
trigger?.let { it.generateDialog(automation_layoutTrigger, fragmentManager) }
|
||||
|
||||
// OK button
|
||||
ok.setOnClickListener {
|
||||
dismiss()
|
||||
RxBus.send(EventAutomationUpdateTrigger(trigger!!))
|
||||
}
|
||||
|
||||
// Cancel button
|
||||
cancel.setOnClickListener { dismiss() }
|
||||
}
|
||||
|
||||
override fun onSaveInstanceState(bundle: Bundle) {
|
||||
super.onSaveInstanceState(bundle)
|
||||
trigger?.let { bundle.putString("trigger", it.toJSON()) }
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.dialogs;
|
||||
|
||||
import android.content.Context;
|
||||
import android.view.View;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.AdapterView;
|
||||
import android.widget.ArrayAdapter;
|
||||
import android.widget.Button;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.Spinner;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
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;
|
||||
|
||||
public class TriggerListAdapter {
|
||||
private final LinearLayout mRootLayout;
|
||||
private final FragmentManager mFragmentManager;
|
||||
private final Context mContext;
|
||||
private final TriggerConnector mRootConnector;
|
||||
|
||||
public TriggerListAdapter(FragmentManager fragmentManager, Context context, LinearLayout rootLayout, TriggerConnector rootTrigger) {
|
||||
mRootLayout = rootLayout;
|
||||
mFragmentManager = fragmentManager;
|
||||
mContext = context;
|
||||
mRootConnector = rootTrigger;
|
||||
build(fragmentManager);
|
||||
}
|
||||
|
||||
public Context getContext() {
|
||||
return mContext;
|
||||
}
|
||||
|
||||
private FragmentManager getFM() {
|
||||
return mFragmentManager;
|
||||
}
|
||||
|
||||
private void destroy() {
|
||||
mRootLayout.removeAllViews();
|
||||
}
|
||||
|
||||
private void build(FragmentManager fragmentManager) {
|
||||
for (int i = 0; i < mRootConnector.size(); ++i) {
|
||||
final Trigger trigger = mRootConnector.get(i);
|
||||
|
||||
// spinner
|
||||
if (i > 0) {
|
||||
createSpinner(trigger);
|
||||
}
|
||||
|
||||
// trigger layout
|
||||
trigger.generateDialog(mRootLayout, fragmentManager);
|
||||
|
||||
// buttons
|
||||
createButtons(fragmentManager, trigger);
|
||||
}
|
||||
|
||||
if (mRootConnector.size() == 0) {
|
||||
Button buttonAdd = new Button(mContext);
|
||||
buttonAdd.setText(MainApp.gs(R.string.addnew));
|
||||
buttonAdd.setOnClickListener(v -> {
|
||||
ChooseTriggerDialog dialog = new ChooseTriggerDialog();
|
||||
dialog.setOnClickListener(newTriggerObject -> {
|
||||
mRootConnector.add(newTriggerObject);
|
||||
rebuild(fragmentManager);
|
||||
});
|
||||
dialog.show(fragmentManager, "ChooseTriggerDialog");
|
||||
});
|
||||
mRootLayout.addView(buttonAdd);
|
||||
}
|
||||
}
|
||||
|
||||
private Spinner createSpinner() {
|
||||
Spinner spinner = new Spinner(mContext);
|
||||
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, TriggerConnector.Type.labels());
|
||||
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||
spinner.setAdapter(spinnerArrayAdapter);
|
||||
return spinner;
|
||||
}
|
||||
|
||||
private void createSpinner(Trigger trigger) {
|
||||
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));
|
||||
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||
);
|
||||
params.setMargins(0, MainApp.dpToPx(8), 0, MainApp.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]);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onNothingSelected(AdapterView<?> parent) {
|
||||
}
|
||||
});
|
||||
mRootLayout.addView(spinner);
|
||||
}
|
||||
|
||||
private void createButtons(FragmentManager fragmentManager, Trigger trigger) {
|
||||
// do not create buttons for TriggerConnector
|
||||
if (trigger instanceof TriggerConnector) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Button Layout
|
||||
LinearLayout buttonLayout = new LinearLayout(mContext);
|
||||
buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||
buttonLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||
mRootLayout.addView(buttonLayout);
|
||||
|
||||
// Button [-]
|
||||
Button buttonRemove = new Button(mContext);
|
||||
buttonRemove.setText(MainApp.gs(R.string.delete_short));
|
||||
buttonRemove.setOnClickListener(v -> {
|
||||
final TriggerConnector connector = trigger.getConnector();
|
||||
connector.remove(trigger);
|
||||
connector.simplify().rebuildView(getFM());
|
||||
});
|
||||
buttonLayout.addView(buttonRemove);
|
||||
|
||||
// Button [+]
|
||||
Button buttonAdd = new Button(mContext);
|
||||
buttonAdd.setText(MainApp.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());
|
||||
});
|
||||
});
|
||||
buttonLayout.addView(buttonAdd);
|
||||
|
||||
// Button [*]
|
||||
Button buttonCopy = new Button(mContext);
|
||||
buttonCopy.setText(MainApp.gs(R.string.copy_short));
|
||||
buttonCopy.setOnClickListener(v -> {
|
||||
TriggerConnector connector = trigger.getConnector();
|
||||
connector.add(connector.pos(trigger) + 1, trigger.duplicate());
|
||||
connector.simplify().rebuildView(getFM());
|
||||
});
|
||||
buttonLayout.addView(buttonCopy);
|
||||
}
|
||||
|
||||
public void rebuild(FragmentManager fragmentManager) {
|
||||
destroy();
|
||||
build(fragmentManager);
|
||||
}
|
||||
|
||||
public static 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);
|
||||
|
||||
// move trigger from pos and pos+1 into new connector
|
||||
for (int i = 0; i < 2; ++i) {
|
||||
Trigger t = connector.get(pos);
|
||||
newConnector.add(t);
|
||||
connector.remove(t);
|
||||
}
|
||||
|
||||
connector.add(pos, newConnector);
|
||||
} else {
|
||||
connector.changeConnectorType(newConnectorType);
|
||||
}
|
||||
|
||||
connector.simplify().rebuildView(fragmentManager);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,123 @@
|
|||
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(), android.R.layout.simple_spinner_item, 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,90 @@
|
|||
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(), android.R.layout.simple_spinner_item, 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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.widget.LinearLayout;
|
||||
|
||||
public abstract class Element {
|
||||
public abstract void addToLayout(LinearLayout root);
|
||||
}
|
|
@ -0,0 +1,99 @@
|
|||
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 {
|
||||
|
||||
final TextWatcher textWatcher = new TextWatcher() {
|
||||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
if (units.equals(Constants.MMOL)) {
|
||||
value = Math.max(value, 4d);
|
||||
value = Math.min(value, 15d);
|
||||
} else {
|
||||
value = Math.max(value, 72d);
|
||||
value = Math.min(value, 270d);
|
||||
}
|
||||
}
|
||||
|
||||
@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 String units = Constants.MGDL;
|
||||
private double value;
|
||||
double minValue;
|
||||
private double maxValue;
|
||||
private double step;
|
||||
private DecimalFormat decimalFormat;
|
||||
|
||||
public InputBg() {
|
||||
super();
|
||||
setUnits(ProfileFunctions.getInstance().getProfileUnits());
|
||||
}
|
||||
|
||||
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, textWatcher);
|
||||
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 = 2;
|
||||
maxValue = 30;
|
||||
step = 0.1;
|
||||
decimalFormat = new DecimalFormat("0.0");
|
||||
} else {
|
||||
// mg/dL
|
||||
minValue = 40;
|
||||
maxValue = 540;
|
||||
step = 1;
|
||||
decimalFormat = new DecimalFormat("0");
|
||||
}
|
||||
|
||||
// make sure that value is in range
|
||||
textWatcher.afterTextChanged(null);
|
||||
|
||||
this.units = units;
|
||||
return this;
|
||||
}
|
||||
|
||||
public InputBg setValue(double value) {
|
||||
this.value = value;
|
||||
return this;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
return value;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,28 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,151 @@
|
|||
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;
|
||||
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) {
|
||||
}
|
||||
};
|
||||
|
||||
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(), android.R.layout.simple_spinner_item, 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, textWatcher);
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,77 @@
|
|||
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;
|
||||
double minValue;
|
||||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,61 @@
|
|||
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;
|
||||
}
|
||||
|
||||
@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;
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,57 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,58 @@
|
|||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,56 @@
|
|||
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;
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,59 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.elements;
|
||||
|
||||
import android.graphics.Typeface;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
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);
|
||||
|
||||
// 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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,26 @@
|
|||
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);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
|
||||
class EventAutomationAddAction(val action: Action) : Event()
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventAutomationDataChanged : Event()
|
|
@ -0,0 +1,7 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.automation.actions.Action
|
||||
|
||||
class EventAutomationUpdateAction(val action: Action, val position : Int) : Event() {
|
||||
}
|
|
@ -0,0 +1,5 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
|
||||
class EventAutomationUpdateGui : Event()
|
|
@ -0,0 +1,6 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.events
|
||||
|
||||
import info.nightscout.androidaps.events.Event
|
||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger
|
||||
|
||||
class EventAutomationUpdateTrigger(val trigger: Trigger) : Event()
|
|
@ -0,0 +1,94 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.content.ContextWrapper;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
import androidx.fragment.app.FragmentManager;
|
||||
|
||||
import com.google.common.base.Optional;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public abstract class Trigger {
|
||||
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public void generateDialog(LinearLayout root, FragmentManager fragmentManager) {
|
||||
TextView title = new TextView(root.getContext());
|
||||
title.setText(friendlyName());
|
||||
root.addView(title);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
Activity scanForActivity(Context cont) {
|
||||
if (cont == null)
|
||||
return null;
|
||||
else if (cont instanceof Activity)
|
||||
return (Activity) cont;
|
||||
else if (cont instanceof ContextWrapper)
|
||||
return scanForActivity(((ContextWrapper) cont).getBaseContext());
|
||||
|
||||
return null;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,169 @@
|
|||
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())
|
||||
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)
|
||||
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;
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,154 @@
|
|||
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.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 final double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
public 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.getMinutes(), InputDuration.TimeUnit.MINUTES);
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,153 @@
|
|||
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 = (int) (SP.getInt(R.string.key_treatmentssafety_maxcarbs, 48));
|
||||
private final double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
private InputDouble value = new InputDouble(0, (double) minValue, (double) maxValue, step, decimalFormat);
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,277 @@
|
|||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,208 @@
|
|||
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 double minValue = 0d;
|
||||
private double maxValue = 1d;
|
||||
private double step = 1;
|
||||
private DecimalFormat decimalFormat = new DecimalFormat("1");
|
||||
private String units;
|
||||
private DeltaType deltaType;
|
||||
|
||||
private InputDelta value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType);
|
||||
private Comparator comparator = new Comparator();
|
||||
|
||||
public TriggerDelta() {
|
||||
super();
|
||||
this.units = ProfileFunctions.getInstance().getProfileUnits();
|
||||
initializer();
|
||||
}
|
||||
|
||||
private TriggerDelta(TriggerDelta triggerDelta) {
|
||||
super();
|
||||
this.units = ProfileFunctions.getInstance().getProfileUnits();
|
||||
initializer();
|
||||
value = triggerDelta.value;
|
||||
lastRun = triggerDelta.lastRun;
|
||||
}
|
||||
|
||||
public double getValue() {
|
||||
deltaType = value.getDeltaType();
|
||||
return value.getValue();
|
||||
}
|
||||
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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;
|
||||
}
|
||||
|
||||
void initializer(){
|
||||
if (this.units.equals(Constants.MMOL)) {
|
||||
this.maxValue = 4d;
|
||||
this.minValue = -4d;
|
||||
this.step = 0.1d;
|
||||
this.decimalFormat = new DecimalFormat("0.1");
|
||||
this.deltaType = DeltaType.DELTA;
|
||||
} else {
|
||||
this.maxValue = 72d;
|
||||
this.minValue = -72d;
|
||||
this.step = 1d;
|
||||
this.deltaType = DeltaType.DELTA;
|
||||
}
|
||||
value = new InputDelta( (double) minValue,(double) minValue, (double) maxValue, step, decimalFormat, deltaType);
|
||||
}
|
||||
|
||||
|
||||
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) + ": ", "", value))
|
||||
.build(root);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,146 @@
|
|||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,167 @@
|
|||
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.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;
|
||||
|
||||
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"));
|
||||
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.getValue(), -90d, +90d, 0.00001d, new DecimalFormat("0.00000"));
|
||||
longitude = new InputDouble(triggerLocation.longitude.getValue(), -180d, +180d, 0.00001d, new DecimalFormat("0.00000"));
|
||||
distance = new InputDouble(200d, 0, 100000, 10d, new DecimalFormat("0"));
|
||||
lastRun = triggerLocation.lastRun;
|
||||
}
|
||||
|
||||
@Override
|
||||
public synchronized boolean shouldRun() {
|
||||
Location location = LocationService.getLastLocation();
|
||||
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);
|
||||
|
||||
if (calculatedDistance < distance.getValue()) {
|
||||
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", 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("lastRun", lastRun);
|
||||
o.put("data", data);
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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"));
|
||||
lastRun = JsonHelper.safeGetLong(d, "lastRun");
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.location;
|
||||
}
|
||||
|
||||
@Override
|
||||
public String friendlyDescription() {
|
||||
return MainApp.gs(R.string.locationis, name.getValue());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Optional<Integer> icon() {
|
||||
return Optional.of(R.drawable.ic_location_on);
|
||||
}
|
||||
|
||||
@Override
|
||||
public Trigger duplicate() {
|
||||
return new TriggerLocation(this);
|
||||
}
|
||||
|
||||
|
||||
TriggerLocation setLatitude(double value) {
|
||||
latitude.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerLocation setLongitude(double value) {
|
||||
longitude.setValue(value);
|
||||
return this;
|
||||
}
|
||||
|
||||
TriggerLocation setdistance(double value) {
|
||||
distance.setValue(value);
|
||||
return 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 InputButton(MainApp.gs(R.string.currentlocation), buttonAction), LocationService.getLastLocation() != null)
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,152 @@
|
|||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,317 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
import android.app.Activity;
|
||||
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.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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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));
|
||||
|
||||
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);
|
||||
Activity a = scanForActivity(root.getContext());
|
||||
if (a != null)
|
||||
tpd.show(a.getFragmentManager(), "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);
|
||||
}
|
||||
|
||||
}
|
|
@ -0,0 +1,131 @@
|
|||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int friendlyName() {
|
||||
return R.string.temptarget;
|
||||
}
|
||||
|
||||
@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.temptarget))
|
||||
.add(comparator)
|
||||
.build(root);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,186 @@
|
|||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.graphics.Typeface;
|
||||
import android.text.format.DateFormat;
|
||||
import android.view.ViewGroup;
|
||||
import android.widget.LinearLayout;
|
||||
import android.widget.TextView;
|
||||
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
Activity a = scanForActivity(root.getContext());
|
||||
if (a != null)
|
||||
dpd.show(a.getFragmentManager(), "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);
|
||||
Activity a = scanForActivity(root.getContext());
|
||||
if (a != null)
|
||||
tpd.show(a.getFragmentManager(), "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);
|
||||
}
|
||||
}
|
|
@ -0,0 +1,149 @@
|
|||
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.wifiConnected && comparator.getValue() == Comparator.Compare.IS_NOT_AVAILABLE) {
|
||||
if (L.isEnabled(L.AUTOMATION))
|
||||
log.debug("Ready for execution: " + friendlyDescription());
|
||||
return true;
|
||||
}
|
||||
|
||||
boolean doRun = eventNetworkChange.wifiConnected && comparator.getValue().check(eventNetworkChange.ssid, 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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
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);
|
||||
}
|
||||
}
|
|
@ -74,7 +74,8 @@ public class Notification {
|
|||
public static final int DST_IN_24H = 50;
|
||||
public static final int DISKFULL = 51;
|
||||
public static final int OLDVERSION = 52;
|
||||
public static final int OVER_24H_TIME_CHANGE_REQUESTED = 53;
|
||||
public static final int USERMESSAGE = 53;
|
||||
public static final int OVER_24H_TIME_CHANGE_REQUESTED = 54;
|
||||
|
||||
|
||||
public int id;
|
||||
|
|
|
@ -341,6 +341,22 @@ public class TreatmentsPlugin extends PluginBase implements TreatmentsInterface
|
|||
return last;
|
||||
}
|
||||
|
||||
public long getLastBolusTime(boolean isSMB) {
|
||||
long now = System.currentTimeMillis();
|
||||
long last = 0;
|
||||
synchronized (treatments) {
|
||||
for (Treatment t : treatments) {
|
||||
if (!t.isValid)
|
||||
continue;
|
||||
if (t.date > last && t.insulin > 0 && t.isValid && t.date <= now && isSMB == t.isSMB)
|
||||
last = t.date;
|
||||
}
|
||||
}
|
||||
if (L.isEnabled(L.DATATREATMENTS))
|
||||
log.debug("Last manual bolus time: " + new Date(last).toLocaleString());
|
||||
return last;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isInHistoryRealTempBasalInProgress() {
|
||||
return getRealTempBasalFromHistory(System.currentTimeMillis()) != null;
|
||||
|
|
|
@ -38,4 +38,8 @@ public class ChargingStateReceiver extends BroadcastReceiver {
|
|||
static public boolean isCharging() {
|
||||
return lastEvent != null && lastEvent.isCharging;
|
||||
}
|
||||
|
||||
static public EventChargingState getLastEvent() {
|
||||
return lastEvent;
|
||||
}
|
||||
}
|
|
@ -70,4 +70,8 @@ public class NetworkChangeReceiver extends BroadcastReceiver {
|
|||
public static boolean isWifiConnected() {
|
||||
return lastEvent != null && lastEvent.wifiConnected;
|
||||
}
|
||||
|
||||
public static EventNetworkChange getLastEvent() {
|
||||
return lastEvent;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,150 @@
|
|||
package info.nightscout.androidaps.services;
|
||||
|
||||
import android.app.Service;
|
||||
import android.content.Context;
|
||||
import android.content.Intent;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.location.Location;
|
||||
import android.location.LocationManager;
|
||||
import android.os.Bundle;
|
||||
import android.os.IBinder;
|
||||
|
||||
import androidx.core.app.ActivityCompat;
|
||||
|
||||
import org.slf4j.Logger;
|
||||
import org.slf4j.LoggerFactory;
|
||||
|
||||
import info.nightscout.androidaps.R;
|
||||
import info.nightscout.androidaps.events.EventLocationChange;
|
||||
import info.nightscout.androidaps.logging.L;
|
||||
import info.nightscout.androidaps.plugins.bus.RxBus;
|
||||
import info.nightscout.androidaps.utils.SP;
|
||||
import info.nightscout.androidaps.utils.T;
|
||||
|
||||
public class LocationService extends Service {
|
||||
private static Logger log = LoggerFactory.getLogger(L.LOCATION);
|
||||
|
||||
private LocationManager mLocationManager = null;
|
||||
private static final float LOCATION_DISTANCE = 10f;
|
||||
|
||||
private static final long LOCATION_INTERVAL_ACTIVE = T.mins(5).msecs();
|
||||
private static final long LOCATION_INTERVAL_PASSIVE = T.mins(1).msecs(); // this doesn't cost more power
|
||||
|
||||
private static Location mLastLocation;
|
||||
|
||||
private class LocationListener implements android.location.LocationListener {
|
||||
|
||||
LocationListener(String provider) {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("LocationListener " + provider);
|
||||
mLastLocation = new Location(provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onLocationChanged(Location location) {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onLocationChanged: " + location);
|
||||
mLastLocation.set(location);
|
||||
RxBus.INSTANCE.send(new EventLocationChange(location));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderDisabled(String provider) {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onProviderDisabled: " + provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onProviderEnabled(String provider) {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onProviderEnabled: " + provider);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatusChanged(String provider, int status, Bundle extras) {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onStatusChanged: " + provider);
|
||||
}
|
||||
}
|
||||
|
||||
LocationListener mLocationListener;
|
||||
|
||||
@Override
|
||||
public IBinder onBind(Intent arg0) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int onStartCommand(Intent intent, int flags, int startId) {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onStartCommand");
|
||||
super.onStartCommand(intent, flags, startId);
|
||||
return START_STICKY;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onCreate() {
|
||||
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onCreate");
|
||||
|
||||
initializeLocationManager();
|
||||
|
||||
try {
|
||||
if (SP.getString(R.string.key_location, "NONE").equals("NETWORK"))
|
||||
mLocationManager.requestLocationUpdates(
|
||||
LocationManager.NETWORK_PROVIDER,
|
||||
LOCATION_INTERVAL_ACTIVE,
|
||||
LOCATION_DISTANCE,
|
||||
mLocationListener = new LocationListener(LocationManager.NETWORK_PROVIDER)
|
||||
);
|
||||
if (SP.getString(R.string.key_location, "NONE").equals("GPS"))
|
||||
mLocationManager.requestLocationUpdates(
|
||||
LocationManager.GPS_PROVIDER,
|
||||
LOCATION_INTERVAL_ACTIVE,
|
||||
LOCATION_DISTANCE,
|
||||
mLocationListener = new LocationListener(LocationManager.GPS_PROVIDER)
|
||||
);
|
||||
if (SP.getString(R.string.key_location, "NONE").equals("PASSIVE"))
|
||||
mLocationManager.requestLocationUpdates(
|
||||
LocationManager.PASSIVE_PROVIDER,
|
||||
LOCATION_INTERVAL_PASSIVE,
|
||||
LOCATION_DISTANCE,
|
||||
mLocationListener = new LocationListener(LocationManager.PASSIVE_PROVIDER)
|
||||
);
|
||||
} catch (java.lang.SecurityException ex) {
|
||||
log.error("fail to request location update, ignore", ex);
|
||||
} catch (IllegalArgumentException ex) {
|
||||
log.error("network provider does not exist, " + ex.getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDestroy() {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("onDestroy");
|
||||
super.onDestroy();
|
||||
if (mLocationManager != null) {
|
||||
try {
|
||||
if (ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_FINE_LOCATION) != PackageManager.PERMISSION_GRANTED && ActivityCompat.checkSelfPermission(this, android.Manifest.permission.ACCESS_COARSE_LOCATION) != PackageManager.PERMISSION_GRANTED) {
|
||||
return;
|
||||
}
|
||||
mLocationManager.removeUpdates(mLocationListener);
|
||||
} catch (Exception ex) {
|
||||
log.error("fail to remove location listener, ignore", ex);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void initializeLocationManager() {
|
||||
if (L.isEnabled(L.LOCATION))
|
||||
log.debug("initializeLocationManager - Provider: " + SP.getString(R.string.key_location, "NONE"));
|
||||
if (mLocationManager == null) {
|
||||
mLocationManager = (LocationManager) getApplicationContext().getSystemService(Context.LOCATION_SERVICE);
|
||||
}
|
||||
}
|
||||
|
||||
public static Location getLastLocation() {
|
||||
return mLastLocation;
|
||||
}
|
||||
}
|
|
@ -120,11 +120,19 @@ public class DateUtil {
|
|||
}
|
||||
|
||||
public static String timeString(Date date) {
|
||||
return new DateTime(date).toString(DateTimeFormat.shortTime());
|
||||
String format = "hh:mma";
|
||||
if (android.text.format.DateFormat.is24HourFormat(MainApp.instance())) {
|
||||
format = "HH:mm";
|
||||
}
|
||||
return new DateTime(date).toString(DateTimeFormat.forPattern(format));
|
||||
}
|
||||
|
||||
public static String timeString(long mills) {
|
||||
return new DateTime(mills).toString(DateTimeFormat.shortTime());
|
||||
String format = "hh:mma";
|
||||
if (android.text.format.DateFormat.is24HourFormat(MainApp.instance())) {
|
||||
format = "HH:mm";
|
||||
}
|
||||
return new DateTime(mills).toString(DateTimeFormat.forPattern(format));
|
||||
}
|
||||
|
||||
public static String timeFullString(long mills) {
|
||||
|
@ -202,6 +210,10 @@ public class DateUtil {
|
|||
return diff < T.mins(2).msecs();
|
||||
}
|
||||
|
||||
public static GregorianCalendar gregorianCalendar() {
|
||||
return new GregorianCalendar();
|
||||
}
|
||||
|
||||
public static long getTimeZoneOffsetMs() {
|
||||
return new GregorianCalendar().getTimeZone().getRawOffset();
|
||||
}
|
||||
|
|
|
@ -33,6 +33,10 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
View.OnTouchListener, View.OnClickListener {
|
||||
private static Logger log = LoggerFactory.getLogger(NumberPicker.class);
|
||||
|
||||
public interface OnValueChangedListener {
|
||||
void onValueChanged(double value);
|
||||
}
|
||||
|
||||
EditText editText;
|
||||
Button minusButton;
|
||||
Button plusButton;
|
||||
|
@ -49,6 +53,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
|
||||
private Handler mHandler;
|
||||
private ScheduledExecutorService mUpdater;
|
||||
private OnValueChangedListener mOnValueChangedListener;
|
||||
|
||||
private class UpdateCounterTask implements Runnable {
|
||||
private boolean mInc;
|
||||
|
@ -133,17 +138,21 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
@Override
|
||||
public void afterTextChanged(Editable s) {
|
||||
value = SafeParse.stringToDouble(editText.getText().toString());
|
||||
callValueChangedListener();
|
||||
if (okButton != null) {
|
||||
if (value > maxValue || value < minValue)
|
||||
okButton.setVisibility(INVISIBLE);
|
||||
else
|
||||
okButton.setVisibility(VISIBLE);
|
||||
}
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void setOnValueChangedListener(OnValueChangedListener onValueChangedListener) {
|
||||
mOnValueChangedListener = onValueChangedListener;
|
||||
}
|
||||
|
||||
public void setTextWatcher(TextWatcher textWatcher) {
|
||||
this.textWatcher = textWatcher;
|
||||
editText.addTextChangedListener(textWatcher);
|
||||
|
@ -182,6 +191,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
this.step = step;
|
||||
this.formater = formater;
|
||||
this.allowZero = allowZero;
|
||||
callValueChangedListener();
|
||||
this.okButton = okButton;
|
||||
|
||||
editText.setKeyListener(DigitsKeyListener.getInstance(minValue < 0, step != Math.rint(step)));
|
||||
|
@ -197,6 +207,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
if (textWatcher != null)
|
||||
editText.removeTextChangedListener(textWatcher);
|
||||
this.value = value;
|
||||
callValueChangedListener();
|
||||
updateEditText();
|
||||
if (textWatcher != null)
|
||||
editText.addTextChangedListener(textWatcher);
|
||||
|
@ -218,6 +229,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
value += step * multiplier;
|
||||
if (value > maxValue) {
|
||||
value = maxValue;
|
||||
callValueChangedListener();
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.youareonallowedlimit));
|
||||
stopUpdating();
|
||||
}
|
||||
|
@ -228,6 +240,7 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
value -= step * multiplier;
|
||||
if (value < minValue) {
|
||||
value = minValue;
|
||||
callValueChangedListener();
|
||||
ToastUtils.showToastInUiThread(MainApp.instance().getApplicationContext(), MainApp.gs(R.string.youareonallowedlimit));
|
||||
stopUpdating();
|
||||
}
|
||||
|
@ -241,6 +254,11 @@ public class NumberPicker extends LinearLayout implements View.OnKeyListener,
|
|||
editText.setText(formater.format(value));
|
||||
}
|
||||
|
||||
private void callValueChangedListener() {
|
||||
if (mOnValueChangedListener != null)
|
||||
mOnValueChangedListener.onValueChanged(value);
|
||||
}
|
||||
|
||||
private void startUpdating(boolean inc) {
|
||||
if (mUpdater != null) {
|
||||
log.debug("Another executor is still active");
|
||||
|
|
|
@ -6,12 +6,19 @@ import android.os.Handler;
|
|||
import android.os.Looper;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.IdRes;
|
||||
|
||||
import info.nightscout.androidaps.MainApp;
|
||||
import info.nightscout.androidaps.plugins.general.overview.notifications.Notification;
|
||||
import info.nightscout.androidaps.plugins.general.overview.events.EventNewNotification;
|
||||
|
||||
|
||||
public class ToastUtils {
|
||||
public static void showToastInUiThread(final Context ctx,
|
||||
final int stringId) {
|
||||
showToastInUiThread(ctx, MainApp.gs(stringId));
|
||||
}
|
||||
|
||||
public static void showToastInUiThread(final Context ctx,
|
||||
final String string) {
|
||||
|
||||
|
|
43
app/src/main/java/info/nightscout/utils/MidnightTime.java
Normal file
43
app/src/main/java/info/nightscout/utils/MidnightTime.java
Normal file
|
@ -0,0 +1,43 @@
|
|||
package info.nightscout.utils;
|
||||
|
||||
import android.util.LongSparseArray;
|
||||
|
||||
import java.util.Calendar;
|
||||
|
||||
public class MidnightTime {
|
||||
private static LongSparseArray times = new LongSparseArray();
|
||||
|
||||
private static long hits = 0;
|
||||
private static long misses = 0;
|
||||
|
||||
public static long calc() {
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||
c.set(Calendar.MINUTE, 0);
|
||||
c.set(Calendar.SECOND, 0);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
return c.getTimeInMillis();
|
||||
}
|
||||
|
||||
public static long calc(long time) {
|
||||
Long m = (Long) times.get(time);
|
||||
if (m != null) {
|
||||
++hits;
|
||||
return m;
|
||||
}
|
||||
Calendar c = Calendar.getInstance();
|
||||
c.setTimeInMillis(time);
|
||||
c.set(Calendar.HOUR_OF_DAY, 0);
|
||||
c.set(Calendar.MINUTE, 0);
|
||||
c.set(Calendar.SECOND, 0);
|
||||
c.set(Calendar.MILLISECOND, 0);
|
||||
m = c.getTimeInMillis();
|
||||
times.append(time, m);
|
||||
++misses;
|
||||
return m;
|
||||
}
|
||||
|
||||
public static String log() {
|
||||
return "Hits: " + hits + " misses: " + misses + " stored: " + times.size();
|
||||
}
|
||||
}
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,8.41L16.59,13 18,11.59l-6,-6 -6,6L7.41,13 12,8.41zM6,18h12v-2H6v2z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable-anydpi/ic_keyboard_tab.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_keyboard_tab.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M11.59,7.41L15.17,11H1v2h14.17l-3.59,3.59L13,18l6,-6 -6,-6 -1.41,1.41zM20,6v12h2V6h-2z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable-anydpi/ic_location_on.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_location_on.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,2C8.13,2 5,5.13 5,9c0,5.25 7,13 7,13s7,-7.75 7,-13c0,-3.87 -3.13,-7 -7,-7zM12,11.5c-1.38,0 -2.5,-1.12 -2.5,-2.5s1.12,-2.5 2.5,-2.5 2.5,1.12 2.5,2.5 -1.12,2.5 -2.5,2.5z"/>
|
||||
</vector>
|
13
app/src/main/res/drawable-anydpi/ic_network_wifi.xml
Normal file
13
app/src/main/res/drawable-anydpi/ic_network_wifi.xml
Normal file
|
@ -0,0 +1,13 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12.01,21.49L23.64,7c-0.45,-0.34 -4.93,-4 -11.64,-4C5.28,3 0.81,6.66 0.36,7l11.63,14.49 0.01,0.01 0.01,-0.01z"
|
||||
android:fillAlpha=".3"/>
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M3.53,10.95l8.46,10.54 0.01,0.01 0.01,-0.01 8.46,-10.54C20.04,10.62 16.81,8 12,8c-4.81,0 -8.04,2.62 -8.47,2.95z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable-anydpi/ic_notifications.xml
Normal file
9
app/src/main/res/drawable-anydpi/ic_notifications.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,22c1.1,0 2,-0.9 2,-2h-4c0,1.1 0.89,2 2,2zM18,16v-5c0,-3.07 -1.64,-5.64 -4.5,-6.32L13.5,4c0,-0.83 -0.67,-1.5 -1.5,-1.5s-1.5,0.67 -1.5,1.5v0.68C7.63,5.36 6,7.92 6,11v5l-2,2v1h16v-1l-2,-2z"/>
|
||||
</vector>
|
BIN
app/src/main/res/drawable/as.png
Normal file
BIN
app/src/main/res/drawable/as.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.6 KiB |
7
app/src/main/res/drawable/border_automation_unit.xml
Normal file
7
app/src/main/res/drawable/border_automation_unit.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:shape="rectangle">
|
||||
<stroke
|
||||
android:width="3dip"
|
||||
android:color="@android:color/white" />
|
||||
</shape>
|
9
app/src/main/res/drawable/ic_access_alarm_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_access_alarm_24dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#72a8ff"
|
||||
android:pathData="M22,5.72l-4.6,-3.86 -1.29,1.53 4.6,3.86L22,5.72zM7.88,3.39L6.6,1.86 2,5.71l1.29,1.53 4.59,-3.85zM12.5,8L11,8v6l4.75,2.85 0.75,-1.23 -4,-2.37L12.5,8zM12,4c-4.97,0 -9,4.03 -9,9s4.02,9 9,9c4.97,0 9,-4.03 9,-9s-4.03,-9 -9,-9zM12,20c-3.87,0 -7,-3.13 -7,-7s3.13,-7 7,-7 7,3.13 7,7 -3.13,7 -7,7z"/>
|
||||
</vector>
|
9
app/src/main/res/drawable/ic_add_black_24dp.xml
Normal file
9
app/src/main/res/drawable/ic_add_black_24dp.xml
Normal file
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FF000000"
|
||||
android:pathData="M19,13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/>
|
||||
</vector>
|
|
@ -0,0 +1,9 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:width="24dp"
|
||||
android:height="24dp"
|
||||
android:viewportWidth="24.0"
|
||||
android:viewportHeight="24.0">
|
||||
<path
|
||||
android:fillColor="#FFFFFFFF"
|
||||
android:pathData="M12,4l-1.41,1.41L16.17,11H4v2h12.17l-5.58,5.59L12,20l8,-8z"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="@color/ribbonWarning"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M9,16h2L11,8L9,8v8zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8zM13,16h2L15,8h-2v8z"/>
|
||||
</vector>
|
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FF00FF00"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M10,16.5l6,-4.5 -6,-4.5v9zM12,2C6.48,2 2,6.48 2,12s4.48,10 10,10 10,-4.48 10,-10S17.52,2 12,2zM12,20c-4.41,0 -8,-3.59 -8,-8s3.59,-8 8,-8 8,3.59 8,8 -3.59,8 -8,8z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_replay_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_replay_24dp.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="#FF00FF00"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M12,5V1L7,6l5,5V7c3.31,0 6,2.69 6,6s-2.69,6 -6,6 -6,-2.69 -6,-6H4c0,4.42 3.58,8 8,8s8,-3.58 8,-8 -3.58,-8 -8,-8z"/>
|
||||
</vector>
|
5
app/src/main/res/drawable/ic_stop_24dp.xml
Normal file
5
app/src/main/res/drawable/ic_stop_24dp.xml
Normal file
|
@ -0,0 +1,5 @@
|
|||
<vector android:height="24dp" android:tint="@color/ribbonCritical"
|
||||
android:viewportHeight="24.0" android:viewportWidth="24.0"
|
||||
android:width="24dp" xmlns:android="http://schemas.android.com/apk/res/android">
|
||||
<path android:fillColor="#FFFFFF" android:pathData="M6,6h12v12H6z"/>
|
||||
</vector>
|
7
app/src/main/res/drawable/ic_trash_outline.xml
Normal file
7
app/src/main/res/drawable/ic_trash_outline.xml
Normal file
|
@ -0,0 +1,7 @@
|
|||
<vector xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:height="24dp"
|
||||
android:width="24dp"
|
||||
android:viewportWidth="24"
|
||||
android:viewportHeight="24">
|
||||
<path android:fillColor="@color/defaulttext" android:pathData="M9,3V4H4V6H5V19A2,2 0 0,0 7,21H17A2,2 0 0,0 19,19V6H20V4H15V3H9M7,6H17V19H7V6M9,8V17H11V8H9M13,8V17H15V8H13Z" />
|
||||
</vector>
|
BIN
app/src/main/res/drawable/icon_auto_delta.png
Normal file
BIN
app/src/main/res/drawable/icon_auto_delta.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 392 B |
44
app/src/main/res/layout/automation_action_item.xml
Normal file
44
app/src/main/res/layout/automation_action_item.xml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout
|
||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="match_parent"
|
||||
android:background="@color/ribbonDefault"
|
||||
android:paddingTop="8dp"
|
||||
android:paddingBottom="8dp"
|
||||
android:paddingLeft="4dp"
|
||||
android:paddingRight="4dp"
|
||||
android:layout_marginTop="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/automation_iconTrash"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:srcCompat="@drawable/ic_trash_outline"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:contentDescription="@string/overview_quickwizard_item_remove_button" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/automation_layoutText"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_toStartOf="@id/automation_iconTrash"
|
||||
android:layout_alignParentStart="true">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_viewActionTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
app:layout_constraintBottom_toBottomOf="parent"
|
||||
app:layout_constraintStart_toStartOf="parent"
|
||||
app:layout_constraintTop_toTopOf="parent" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
33
app/src/main/res/layout/automation_dialog_action.xml
Normal file
33
app/src/main/res/layout/automation_dialog_action.xml
Normal file
|
@ -0,0 +1,33 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:minWidth="300dp"
|
||||
android:padding="10dp">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="vertical">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_actionTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_gravity="center_horizontal"
|
||||
android:paddingBottom="10dp"
|
||||
android:textAppearance="?android:attr/textAppearanceLarge" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/automation_editActionLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp" />
|
||||
|
||||
<include layout="@layout/okcancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
30
app/src/main/res/layout/automation_dialog_choose_action.xml
Normal file
30
app/src/main/res/layout/automation_dialog_choose_action.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/please_choose_an_action_type" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/automation_radioGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginVertical="5dp" />
|
||||
|
||||
<include layout="@layout/okcancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
30
app/src/main/res/layout/automation_dialog_choose_trigger.xml
Normal file
30
app/src/main/res/layout/automation_dialog_choose_trigger.xml
Normal file
|
@ -0,0 +1,30 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/please_choose_a_trigger_type" />
|
||||
|
||||
<RadioGroup
|
||||
android:id="@+id/automation_chooseTriggerRadioGroup"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginVertical="5dp" />
|
||||
|
||||
<include layout="@layout/okcancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
93
app/src/main/res/layout/automation_dialog_edit_action.xml
Normal file
93
app/src/main/res/layout/automation_dialog_edit_action.xml
Normal file
|
@ -0,0 +1,93 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<android.support.design.widget.TextInputEditText
|
||||
android:id="@+id/automation_inputEventTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/eventname" />
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/if_label"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_editTrigger"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:text="@string/edit_short" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_triggerDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:layout_marginTop="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/then_label"/>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/editAction"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:text="@string/edit_short" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/actionDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<include layout="@layout/mdtp_done_button" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
32
app/src/main/res/layout/automation_dialog_edit_trigger.xml
Normal file
32
app/src/main/res/layout/automation_dialog_edit_trigger.xml
Normal file
|
@ -0,0 +1,32 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<TextView
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/triggers" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/automation_layoutTrigger"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<include layout="@layout/okcancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
113
app/src/main/res/layout/automation_dialog_event.xml
Normal file
113
app/src/main/res/layout/automation_dialog_event.xml
Normal file
|
@ -0,0 +1,113 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<ScrollView xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:focusableInTouchMode="true"
|
||||
android:orientation="vertical"
|
||||
android:padding="10dp">
|
||||
|
||||
<com.google.android.material.textfield.TextInputEditText
|
||||
android:id="@+id/automation_inputEventTitle"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:hint="@string/taskname" />
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/condition"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_editTrigger"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:background="@color/ribbonDefault"
|
||||
android:padding="8dp"
|
||||
android:text="@string/edit_short" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_triggerDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_forcedTriggerDescriptionLabel"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/preconditions"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_forcedTriggerDescription"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp"
|
||||
android:orientation="vertical" />
|
||||
|
||||
<View
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="2dip"
|
||||
android:layout_marginTop="5dp"
|
||||
android:layout_marginBottom="5dp"
|
||||
android:background="@color/listdelimiter" />
|
||||
|
||||
<RelativeLayout
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content">
|
||||
|
||||
<TextView
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:text="@string/action"
|
||||
android:textStyle="bold" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_addAction"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:background="@color/ribbonDefault"
|
||||
android:padding="8dp"
|
||||
android:text="@string/add_short" />
|
||||
|
||||
</RelativeLayout>
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/automation_actionListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_marginTop="10dp"
|
||||
android:layout_marginBottom="10dp" />
|
||||
|
||||
<include layout="@layout/okcancel" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</ScrollView>
|
46
app/src/main/res/layout/automation_event_item.xml
Normal file
46
app/src/main/res/layout/automation_event_item.xml
Normal file
|
@ -0,0 +1,46 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
||||
android:id="@+id/rootLayout"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginStart="8dp"
|
||||
android:layout_marginTop="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:background="@color/ribbonDefault"
|
||||
android:padding="8dp">
|
||||
|
||||
<ImageView
|
||||
android:id="@+id/iconTrash"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:contentDescription="@string/remove_label"
|
||||
android:orientation="horizontal"
|
||||
android:src="@drawable/ic_trash_outline" />
|
||||
|
||||
<LinearLayout
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_toStartOf="@id/iconTrash"
|
||||
android:orientation="vertical"
|
||||
app:layout_constraintTop_toTopOf="parent">
|
||||
|
||||
<TextView
|
||||
android:id="@+id/viewEventTitle"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content" />
|
||||
|
||||
<LinearLayout
|
||||
android:id="@+id/iconLayout"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:orientation="horizontal" />
|
||||
|
||||
</LinearLayout>
|
||||
|
||||
</RelativeLayout>
|
36
app/src/main/res/layout/automation_fragment.xml
Normal file
36
app/src/main/res/layout/automation_fragment.xml
Normal file
|
@ -0,0 +1,36 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:tools="http://schemas.android.com/tools"
|
||||
android:layout_width="fill_parent"
|
||||
android:layout_height="fill_parent"
|
||||
tools:context="info.nightscout.androidaps.plugins.general.automation.AutomationFragment">
|
||||
|
||||
<androidx.recyclerview.widget.RecyclerView
|
||||
android:id="@+id/automation_eventListView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="match_parent"
|
||||
android:layout_above="@+id/automation_logView"
|
||||
android:layout_alignParentStart="true"
|
||||
android:layout_alignParentTop="true"
|
||||
android:layout_marginBottom="-100dp" />
|
||||
|
||||
<TextView
|
||||
android:id="@+id/automation_logView"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="100dp"
|
||||
android:layout_alignParentBottom="true" />
|
||||
|
||||
<com.google.android.material.floatingactionbutton.FloatingActionButton
|
||||
android:id="@+id/automation_fabAddEvent"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_alignParentEnd="true"
|
||||
android:layout_alignParentBottom="true"
|
||||
android:layout_marginEnd="8dp"
|
||||
android:layout_marginBottom="8dp"
|
||||
android:clickable="true"
|
||||
android:focusable="true"
|
||||
android:src="@drawable/ic_add_black_24dp"
|
||||
tools:ignore="RelativeOverlap" />
|
||||
|
||||
</RelativeLayout>
|
44
app/src/main/res/layout/okcancel.xml
Normal file
44
app/src/main/res/layout/okcancel.xml
Normal file
|
@ -0,0 +1,44 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!-- Copyright (C) 2013 The Android Open Source Project
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
You may obtain a copy of the License at
|
||||
|
||||
http://www.apache.org/licenses/LICENSE-2.0
|
||||
|
||||
Unless required by applicable law or agreed to in writing, software
|
||||
distributed under the License is distributed on an "AS IS" BASIS,
|
||||
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
-->
|
||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
android:id="@+id/done_background"
|
||||
android:layout_width="match_parent"
|
||||
android:layout_height="56dp"
|
||||
android:orientation="horizontal"
|
||||
android:background="@android:color/transparent"
|
||||
android:gravity="end|right"
|
||||
android:layout_gravity="center_vertical"
|
||||
android:paddingBottom="8dp">
|
||||
|
||||
<Button
|
||||
android:id="@+id/cancel"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_marginRight="8dp"
|
||||
android:layout_marginEnd="8dp"
|
||||
style="@style/mdtp_ActionButton.Text"
|
||||
android:text="@string/mdtp_cancel" />
|
||||
|
||||
<Button
|
||||
android:id="@+id/ok"
|
||||
android:layout_width="wrap_content"
|
||||
android:layout_height="wrap_content"
|
||||
android:layout_marginRight="16dp"
|
||||
android:layout_marginEnd="16dp"
|
||||
style="@style/mdtp_ActionButton.Text"
|
||||
android:text="@string/mdtp_ok" />
|
||||
</LinearLayout>
|
||||
<!-- From: file:/Users/wdullaer/Documents/Programming%20Projects/MaterialDateTimePicker/library/src/main/res/layout/mdtp_done_button.xml -->
|
|
@ -120,6 +120,18 @@
|
|||
<item>@string/yes</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="location">
|
||||
<item>@string/use_passive_location</item>
|
||||
<item>@string/use_network_location</item>
|
||||
<item>@string/use_gps_location</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="locationValues" translatable="false">
|
||||
<item>PASSIVE</item>
|
||||
<item>NETWORK</item>
|
||||
<item>GPS</item>
|
||||
</string-array>
|
||||
|
||||
<string-array name="virtualPumpTypes">
|
||||
<item>Generic AAPS</item>
|
||||
<item>Accu-Chek Spirit</item>
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
<resources>
|
||||
<resources>
|
||||
<string name="treatmentssafety_title">Treatments safety</string>
|
||||
<string name="treatmentssafety_maxbolus_title">Max allowed bolus [U]</string>
|
||||
<string name="treatmentssafety_maxcarbs_title">Max allowed carbs [g]</string>
|
||||
|
@ -587,10 +587,12 @@
|
|||
<string name="loopsuspended">Loop suspended</string>
|
||||
<string name="loopsuspendedfor">Suspended (%1$d m)</string>
|
||||
<string name="loopsuperbolusfor">Superbolus (%1$d m)</string>
|
||||
<string name="suspendloop">Suspend loop</string>
|
||||
<string name="suspendloopfor1h">Suspend loop for 1h</string>
|
||||
<string name="suspendloopfor2h">Suspend loop for 2h</string>
|
||||
<string name="suspendloopfor3h">Suspend loop for 3h</string>
|
||||
<string name="suspendloopfor10h">Suspend loop for 10 h</string>
|
||||
<string name="suspendloopforXmin">Suspend loop for %1$d min</string>
|
||||
<string name="disconnectpumpfor15m">Disconnect pump for 15 min</string>
|
||||
<string name="disconnectpumpfor30m">Disconnect pump for 30 min</string>
|
||||
<string name="disconnectpumpfor1h">Disconnect pump for 1 h</string>
|
||||
|
@ -1308,6 +1310,47 @@
|
|||
<string name="min_recovery_duration">Min. recovery duration [s]</string>
|
||||
<string name="recovery_duration">Recovery duration</string>
|
||||
<string name="timeout_during_handshake">Timeout during handshake - reset bluetooth</string>
|
||||
<string name="weekday_sunday_short">Sun</string>
|
||||
<string name="weekday_saturday_short">Sat</string>
|
||||
<string name="weekday_friday_short">Fri</string>
|
||||
<string name="weekday_thursday_short">Thu</string>
|
||||
<string name="weekday_wednesday_short">Wed</string>
|
||||
<string name="weekday_tuesday_short">Tue</string>
|
||||
<string name="weekday_monday_short">Mon</string>
|
||||
<string name="automation_description">User defined automation tasks</string>
|
||||
<string name="automation_missing_task_name">Please enter a task name.</string>
|
||||
<string name="automation_missing_trigger">Please specify at least one trigger.</string>
|
||||
<string name="automation_missing_action">Please specify at least one action.</string>
|
||||
<string name="alreadyenabled">Already enabled</string>
|
||||
<string name="alreadydisabled">Already disabled</string>
|
||||
<string name="alreadysuspended">Already suspended</string>
|
||||
<string name="resumeloop">Resume loop</string>
|
||||
<string name="notsuspended">Not suspended</string>
|
||||
<string name="starttemptarget">Start temp target</string>
|
||||
<string name="stoptemptarget">Stop temp target</string>
|
||||
<string name="islesser">is lesser than</string>
|
||||
<string name="isequalorlesser">is equal or lesser than</string>
|
||||
<string name="isequal">is equal to</string>
|
||||
<string name="isequalorgreater">is equal or greater than</string>
|
||||
<string name="isgreater">is greater than</string>
|
||||
<string name="isnotavailable">is not available</string>
|
||||
<string name="unknown">unknown</string>
|
||||
<string name="glucoseisnotavailable">Glucose is not available</string>
|
||||
<string name="glucosecomparedmgdl">Glucose %1$s %2$.0f %3$s</string>
|
||||
<string name="glucosecomparedmmol">Glucose %1$s %2$.1f %3$s</string>
|
||||
<string name="percentagecompared">Profile pct %1$s %2$d</string>
|
||||
<string name="iobcompared">IOB %1$s %2$.1f</string>
|
||||
<string name="and">And</string>
|
||||
<string name="or">Or</string>
|
||||
<string name="xor">Exclusive or</string>
|
||||
<string name="atspecifiedtime">At %1$s</string>
|
||||
<string name="use_network_location">Use network location</string>
|
||||
<string name="use_gps_location">Use GPS location</string>
|
||||
<string name="use_passive_location">Use passive location</string>
|
||||
<string name="locationservice">Location service</string>
|
||||
<string name="key_location" translatable="false">location</string>
|
||||
<string name="automation_short">Auto</string>
|
||||
<string name="automation">Automation</string>
|
||||
|
||||
<string name="profile_total">== ∑ %1$s U</string>
|
||||
<string name="profile_ins_units_per_hout">U/h</string>
|
||||
|
@ -1368,6 +1411,18 @@
|
|||
<string name="sms_wrongcode">Wrong code. Command cancelled.</string>
|
||||
<string name="notconfigured">Not configured</string>
|
||||
<string name="profileswitchcreated">Profile switch created</string>
|
||||
<string name="recurringTime">Recurring time</string>
|
||||
<string name="every">Every</string>
|
||||
<string name="never">Never</string>
|
||||
<string name="mins">%1$dmins</string>
|
||||
<string name="condition">Condition:</string>
|
||||
<string name="action">Action:</string>
|
||||
<string name="iob_u">IOB [U]:</string>
|
||||
<string name="glucose_u">Glucose [%1$s]:</string>
|
||||
<string name="delete_short">DEL</string>
|
||||
<string name="add_short">ADD</string>
|
||||
<string name="copy_short">COPY</string>
|
||||
<string name="addnew">Add new</string>
|
||||
<string name="versionChecker">Version Checker</string>
|
||||
<string name="key_last_time_this_version_detected" translatable="false">last_time_this_version_detected</string>
|
||||
<string name="key_last_versionchecker_warning" translatable="false">last_versionchecker_waring</string>
|
||||
|
@ -1385,6 +1440,43 @@
|
|||
<string name="dexcom_short">DXCM</string>
|
||||
<string name="description_source_dexcom">Receive BG values from the patched Dexcom app.</string>
|
||||
|
||||
<string name="notification">Notification</string>
|
||||
<string name="notification_message">Notification: %1$s</string>
|
||||
<string name="message_short">Msg:</string>
|
||||
<string name="profilepercentage">Profile percentage</string>
|
||||
<string name="percent_u">Percent [%]:</string>
|
||||
<string name="startprofile">Start profile %1$d%% for %2$d min</string>
|
||||
<string name="startprofileforever">Start profile %1$d%%</string>
|
||||
<string name="exists">exists</string>
|
||||
<string name="notexists">not exists</string>
|
||||
<string name="temptargetcompared">Temp target %1$s</string>
|
||||
<string name="wifissidcompared">WiFi SSID %1$s %2$s</string>
|
||||
<string name="autosenscompared">Autosens %1$s %2$s %%</string>
|
||||
<string name="autosenslabel">Autosens %</string>
|
||||
<string name="deltacompared">%3$s %1$s %2$s</string>
|
||||
<string name="deltalabel">BG difference</string>
|
||||
<string name="currentlocation">Current Location</string>
|
||||
<string name="location">Location</string>
|
||||
<string name="latitude_short">Lat:</string>
|
||||
<string name="longitude_short">Lon:</string>
|
||||
<string name="distance_short">Dist [m]:</string>
|
||||
<string name="name_short">Name:</string>
|
||||
<string name="locationis">Location is %1$s</string>
|
||||
<string name="lastboluslabel">Last bolus ago</string>
|
||||
<string name="lastboluscompared">Last bolus time %1$s %2$s min ago</string>
|
||||
<string name="triggercoblabel">COB</string>
|
||||
<string name="cobcompared">COB %1$s %2$.0f</string>
|
||||
<string name="taskname">Task name</string>
|
||||
<string name="eventname">Event name</string>
|
||||
<string name="edit_short">EDIT</string>
|
||||
<string name="please_choose_an_action_type">Please choose an action type:</string>
|
||||
<string name="please_choose_a_trigger_type">Please choose a trigger type:</string>
|
||||
<string name="if_label">If:</string>
|
||||
<string name="then_label">Then:</string>
|
||||
<string name="triggers">Triggers:</string>
|
||||
<string name="remove_label">REMOVE</string>
|
||||
<string name="preconditions">Preconditions:</string>
|
||||
|
||||
<!-- Pump Abstract -->
|
||||
<string name="pump_operation_not_supported_by_pump_driver">Operation not supported by pump and/or driver.</string>
|
||||
<string name="pump_operation_not_yet_supported_by_pump">Operation not YET supported by pump.</string>
|
||||
|
@ -1569,4 +1661,4 @@
|
|||
<item quantity="one">%1$d minute</item>
|
||||
<item quantity="other">%1$d minutes</item>
|
||||
</plurals>
|
||||
</resources>
|
||||
</resources>
|
10
app/src/main/res/xml/pref_automation.xml
Normal file
10
app/src/main/res/xml/pref_automation.xml
Normal file
|
@ -0,0 +1,10 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
|
||||
xmlns:validate="http://schemas.android.com/apk/res-auto">
|
||||
<ListPreference
|
||||
android:title="@string/locationservice"
|
||||
android:defaultValue="PASSIVE"
|
||||
android:entries="@array/location"
|
||||
android:entryValues="@array/locationValues"
|
||||
android:key="@string/key_location" />
|
||||
</PreferenceScreen>
|
|
@ -55,6 +55,8 @@ public class AAPSMocker {
|
|||
public static Intent intentSent = null;
|
||||
|
||||
public static CommandQueue queue;
|
||||
public static ConfigBuilderPlugin configBuilderPlugin;
|
||||
public static ProfileFunctions profileFunctions;
|
||||
public static ConstraintChecker constraintChecker;
|
||||
|
||||
public static void mockStrings() {
|
||||
|
@ -147,6 +149,12 @@ public class AAPSMocker {
|
|||
when(MainApp.gs(R.string.pumpsuspended)).thenReturn("Pump suspended");
|
||||
when(MainApp.gs(R.string.cob)).thenReturn("COB");
|
||||
when(MainApp.gs(R.string.value_unavailable_short)).thenReturn("n/a");
|
||||
when(MainApp.gs(R.string.starttemptarget)).thenReturn("Start temp target");
|
||||
when(MainApp.gs(R.string.stoptemptarget)).thenReturn("Stop temp target");
|
||||
when(MainApp.gs(R.string.disableloop)).thenReturn("Disable loop");
|
||||
when(MainApp.gs(R.string.enableloop)).thenReturn("Enable loop");
|
||||
when(MainApp.gs(R.string.resumeloop)).thenReturn("Resume loop");
|
||||
when(MainApp.gs(R.string.suspendloop)).thenReturn("Suspend loop");
|
||||
when(MainApp.gs(R.string.pumpNotInitialized)).thenReturn("Pump not initialized!");
|
||||
}
|
||||
|
||||
|
@ -160,7 +168,7 @@ public class AAPSMocker {
|
|||
|
||||
public static void mockConfigBuilder() {
|
||||
PowerMockito.mockStatic(ConfigBuilderPlugin.class);
|
||||
ConfigBuilderPlugin configBuilderPlugin = mock(ConfigBuilderPlugin.class);
|
||||
configBuilderPlugin = mock(ConfigBuilderPlugin.class);
|
||||
when(ConfigBuilderPlugin.getPlugin()).thenReturn(configBuilderPlugin);
|
||||
}
|
||||
|
||||
|
@ -272,7 +280,7 @@ public class AAPSMocker {
|
|||
|
||||
public static void mockProfileFunctions() {
|
||||
PowerMockito.mockStatic(ProfileFunctions.class);
|
||||
ProfileFunctions profileFunctions = PowerMockito.mock(ProfileFunctions.class);
|
||||
profileFunctions = PowerMockito.mock(ProfileFunctions.class);
|
||||
PowerMockito.when(ProfileFunctions.getInstance()).thenReturn(profileFunctions);
|
||||
profile = getValidProfile();
|
||||
PowerMockito.when(ProfileFunctions.getInstance().getProfile()).thenReturn(profile);
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show more
Loading…
Reference in a new issue