diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java index 11df59eb9e..62956cbd87 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationFragment.java @@ -12,11 +12,11 @@ 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 android.widget.TextView; -import java.util.ArrayList; import java.util.List; import butterknife.BindView; @@ -25,6 +25,7 @@ import butterknife.OnClick; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.Common.SubscriberFragment; +import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog; import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog; import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; @@ -126,20 +127,12 @@ public class AutomationFragment extends SubscriberFragment { public static class TriggerListAdapter { private final LinearLayout mRootLayout; private final Context mContext; - private final List mTriggerList; + private final TriggerConnector mRootConnector; - public TriggerListAdapter(Context context, LinearLayout rootLayout, List triggers) { + public TriggerListAdapter(Context context, LinearLayout rootLayout, TriggerConnector rootTrigger) { mRootLayout = rootLayout; mContext = context; - mTriggerList = triggers; - build(); - } - - public TriggerListAdapter(Context context, LinearLayout rootLayout, Trigger trigger) { - mRootLayout = rootLayout; - mContext = context; - mTriggerList = new ArrayList<>(); - mTriggerList.add(trigger); + mRootConnector = rootTrigger; build(); } @@ -148,6 +141,38 @@ public class AutomationFragment extends SubscriberFragment { mRootLayout.removeAllViews(); } + private void build() { + for(int i = 0; i < mRootConnector.size(); ++i) { + final Trigger trigger = mRootConnector.get(i); + + // spinner + if (i > 0) { + createSpinner(trigger); + } + + // trigger layout + mRootLayout.addView(trigger.createView(mContext)); + + // buttons + createButtons(trigger); + } + + if (mRootConnector.size() == 0) { + Button buttonAdd = new Button(mContext); + buttonAdd.setText("Add New"); + buttonAdd.setOnClickListener(v -> { + ChooseTriggerDialog dialog = ChooseTriggerDialog.newInstance(); + FragmentManager manager = AutomationFragment.fragmentManager(); + dialog.show(manager, "ChooseTriggerDialog"); + dialog.setOnClickListener(newTriggerObject -> { + mRootConnector.add(newTriggerObject); + rebuild(); + }); + }); + mRootLayout.addView(buttonAdd); + } + } + private Spinner createSpinner() { Spinner spinner = new Spinner(mContext); ArrayAdapter spinnerArrayAdapter = new ArrayAdapter<>(mContext, android.R.layout.simple_spinner_item, TriggerConnector.Type.labels()); @@ -156,42 +181,79 @@ public class AutomationFragment extends SubscriberFragment { return spinner; } - private void build() { - boolean isFirstItem = true; - for(Trigger trigger : mTriggerList) { - if (!isFirstItem) { - 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) { - // conector type changed - changeConnector(trigger, connector, TriggerConnector.Type.values()[position]); - } - } - - @Override - public void onNothingSelected(AdapterView parent) { - - } - }); - mRootLayout.addView(spinner); - } else { - isFirstItem = false; + 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) { + // conector type changed + changeConnector(trigger, connector, TriggerConnector.Type.values()[position]); + } } - mRootLayout.addView(trigger.createView(mContext)); + @Override + public void onNothingSelected(AdapterView parent) { } + }); + mRootLayout.addView(spinner); + } + + private void createButtons(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("del"); + buttonRemove.setOnClickListener(v -> { + final TriggerConnector connector = trigger.getConnector(); + connector.remove(trigger); + connector.simplify().rebuildView(); + }); + buttonLayout.addView(buttonRemove); + + // Button [+] + Button buttonAdd = new Button(mContext); + buttonAdd.setText("add"); + buttonAdd.setOnClickListener(v -> { + ChooseTriggerDialog dialog = ChooseTriggerDialog.newInstance(); + FragmentManager manager = AutomationFragment.fragmentManager(); + dialog.show(manager, "ChooseTriggerDialog"); + dialog.setOnClickListener(newTriggerObject -> { + TriggerConnector connector = trigger.getConnector(); + connector.add(connector.pos(trigger)+1, newTriggerObject); + connector.simplify().rebuildView(); + }); + }); + buttonLayout.addView(buttonAdd); + + // Button [*] + Button buttonCopy = new Button(mContext); + buttonCopy.setText("copy"); + buttonCopy.setOnClickListener(v -> { + TriggerConnector connector = trigger.getConnector(); + connector.add(connector.pos(trigger)+1, trigger.duplicate()); + connector.simplify().rebuildView(); + }); + buttonLayout.addView(buttonCopy); } public static void changeConnector(final Trigger trigger, final TriggerConnector connector, final TriggerConnector.Type newConnectorType) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java index 1db1045413..a9c6d6ed0e 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditEventDialog.java @@ -17,9 +17,7 @@ import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.general.automation.AutomationEvent; import info.nightscout.androidaps.plugins.general.automation.AutomationFragment; import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; -import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; -import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime; public class EditEventDialog extends DialogFragment { @@ -49,14 +47,12 @@ public class EditEventDialog extends DialogFragment { View view = inflater.inflate(R.layout.automation_dialog_event, container, false); mUnbinder = ButterKnife.bind(this, view); - // dummy initialization - TriggerConnector to = new TriggerConnector(TriggerConnector.Type.OR); - to.add(new TriggerBg()); - to.add(new TriggerTime()); - mEvent.setTrigger(to); + // initialization + TriggerConnector rootTrigger = new TriggerConnector(TriggerConnector.Type.OR); + mEvent.setTrigger(rootTrigger); - // display triggers - mTriggerListAdapter = new AutomationFragment.TriggerListAdapter(getContext(), mLayoutTrigger, mEvent.getTrigger()); + // display root trigger + mLayoutTrigger.addView(rootTrigger.createView(getContext())); return view; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java index 2a055b24d6..32f758222c 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/Trigger.java @@ -97,6 +97,8 @@ public abstract class Trigger { void notifyAboutRun(long time) { } + public abstract Trigger duplicate(); + static Trigger instantiate(JSONObject object) { try { String type = object.getString("type"); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java index 3e2abd61a3..f82b1d9333 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerBg.java @@ -45,6 +45,17 @@ public class TriggerBg extends Trigger { } }; + public TriggerBg() { + super(); + } + + private TriggerBg(TriggerBg triggerBg) { + super(); + comparator = triggerBg.comparator; + units = triggerBg.units; + threshold = triggerBg.threshold; + } + @Override public synchronized boolean shouldRun() { GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData(); @@ -99,6 +110,11 @@ public class TriggerBg extends Trigger { return MainApp.gs(R.string.glucosecompared, comparator.getStringRes(), threshold, units); } + @Override + public Trigger duplicate() { + return new TriggerBg(this); + } + TriggerBg threshold(double threshold) { this.threshold = threshold; return this; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java index 83233b1f75..184f38c36b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerConnector.java @@ -2,10 +2,8 @@ package info.nightscout.androidaps.plugins.general.automation.triggers; import android.content.Context; import android.support.annotation.StringRes; -import android.support.v4.app.FragmentManager; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import android.widget.LinearLayout; import org.json.JSONArray; @@ -18,7 +16,6 @@ import java.util.List; import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; import info.nightscout.androidaps.plugins.general.automation.AutomationFragment; -import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog; import info.nightscout.utils.JsonHelper; public class TriggerConnector extends Trigger { @@ -172,6 +169,11 @@ public class TriggerConnector extends Trigger { return result.toString(); } + @Override + public Trigger duplicate() { + return null; + } + private AutomationFragment.TriggerListAdapter adapter; public void rebuildView() { @@ -194,53 +196,11 @@ public class TriggerConnector extends Trigger { triggerListLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); root.addView(triggerListLayout); - adapter = new AutomationFragment.TriggerListAdapter(context, triggerListLayout, list); - - LinearLayout buttonLayout = new LinearLayout(context); - buttonLayout.setOrientation(LinearLayout.HORIZONTAL); - buttonLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); - root.addView(buttonLayout); - - Button buttonRemove = new Button(context); - buttonRemove.setText("-"); - buttonRemove.setOnClickListener(v -> { - if (connector != null) { - connector.remove(TriggerConnector.this); - connector.simplify(); - connector.adapter.rebuild(); - } else { - // no parent - list.clear(); - simplify(); - adapter.rebuild(); - } - }); - buttonLayout.addView(buttonRemove); - - Button buttonAdd = new Button(context); - buttonAdd.setText("+"); - buttonAdd.setOnClickListener(v -> { - ChooseTriggerDialog dialog = ChooseTriggerDialog.newInstance(); - FragmentManager manager = AutomationFragment.fragmentManager(); - dialog.show(manager, "ChooseTriggerDialog"); - dialog.setOnClickListener(newTriggerObject -> addNewTrigger(adapter, newTriggerObject, getConnectorType())); - }); - buttonLayout.addView(buttonAdd); + adapter = new AutomationFragment.TriggerListAdapter(context, triggerListLayout, this); return root; } - private void addNewTrigger(AutomationFragment.TriggerListAdapter adapter, Trigger trigger, Type connection) { - if (getConnectorType().equals(connection)) { - add(trigger); - } else { - TriggerConnector t = new TriggerConnector(connection); - t.add(trigger); - add(t); - } - adapter.rebuild(); - } - public TriggerConnector simplify() { // simplify children for(int i = 0; i < size(); ++i) { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java index 7c10c67a14..1bb928fa6f 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTime.java @@ -85,22 +85,37 @@ public class TriggerTime extends Trigger { private final boolean[] weekdays = new boolean[DayOfWeek.values().length]; - long lastRun; + private long lastRun; // Single execution - long runAt; + private long runAt; // Recurring - boolean recurring; - int hour; - int minute; + private boolean recurring; + private int hour; + private int minute; - long validTo; + private long validTo; public TriggerTime() { + super(); setAll(false); } + private TriggerTime(TriggerTime triggerTime) { + super(); + lastRun = triggerTime.lastRun; + runAt = triggerTime.runAt; + recurring = triggerTime.recurring; + hour = triggerTime.hour; + minute = triggerTime.minute; + validTo = triggerTime.validTo; + + for(int i = 0; i < weekdays.length; ++i) { + weekdays[i] = triggerTime.weekdays[i]; + } + } + public void setAll(boolean value) { for(DayOfWeek day : DayOfWeek.values()) { set(day, value); @@ -207,6 +222,11 @@ public class TriggerTime extends Trigger { lastRun = time; } + @Override + public Trigger duplicate() { + return new TriggerTime(this); + } + TriggerTime lastRun(long lastRun) { this.lastRun = lastRun; return this; @@ -251,6 +271,7 @@ public class TriggerTime extends Trigger { public View createView(Context context) { LinearLayout root = (LinearLayout) super.createView(context); + // TODO: Replace external tool WeekdaysPicker with a self-made GUI element WeekdaysPicker weekdaysPicker = new WeekdaysPicker(context); weekdaysPicker.setEditable(true); weekdaysPicker.setSelectedDays(getSelectedDays());