From 58da7fc85450bb2331c11ef122872db3c4c9bc19 Mon Sep 17 00:00:00 2001 From: Milos Kozak Date: Tue, 16 Jul 2019 21:57:45 +0200 Subject: [PATCH] Preconditions, code cleanup --- .../general/automation/AutomationEvent.java | 9 + .../automation/AutomationFragment.java | 362 +----------------- .../general/automation/AutomationPlugin.java | 6 +- .../general/automation/EventListAdapter.java | 113 ++++++ .../general/automation/actions/Action.java | 3 + .../actions/ActionProfileSwitchPercent.java | 11 +- .../actions/ActionStartTempTarget.java | 6 + .../automation/dialogs/ActionListAdapter.java | 73 ++++ .../dialogs/ChooseActionDialog.java | 29 +- .../automation/dialogs/EditActionDialog.java | 6 +- .../automation/dialogs/EditEventDialog.java | 87 +++-- .../automation/dialogs/EditTriggerDialog.java | 18 +- .../dialogs/TriggerListAdapter.java | 186 +++++++++ .../automation/elements/InputPercent.java | 6 +- .../events/EventAutomationAddAction.java | 16 + .../events/EventAutomationUpdateTrigger.java | 16 + .../automation/triggers/TriggerConnector.java | 6 +- .../triggers/TriggerProfilePercent.java | 4 +- .../triggers/TriggerTempTarget.java | 2 +- .../res/layout/automation_dialog_event.xml | 23 +- app/src/main/res/values/strings.xml | 2 + 21 files changed, 546 insertions(+), 438 deletions(-) create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ActionListAdapter.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/TriggerListAdapter.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationAddAction.java create mode 100644 app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.java diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java index 088f230d63..b92dadc89b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationEvent.java @@ -33,6 +33,15 @@ public class AutomationEvent { 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); } 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 21a4f58fff..c43e7e0f44 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 @@ -1,44 +1,26 @@ package info.nightscout.androidaps.plugins.general.automation; import android.app.Activity; -import android.content.Context; import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.AdapterView; -import android.widget.ArrayAdapter; -import android.widget.Button; -import android.widget.ImageView; -import android.widget.LinearLayout; -import android.widget.RelativeLayout; -import android.widget.Spinner; import android.widget.TextView; -import androidx.annotation.DrawableRes; import androidx.annotation.NonNull; -import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; import com.squareup.otto.Subscribe; -import java.util.HashSet; -import java.util.List; - import butterknife.BindView; import butterknife.ButterKnife; 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.actions.Action; -import info.nightscout.androidaps.plugins.general.automation.dialogs.ChooseTriggerDialog; -import info.nightscout.androidaps.plugins.general.automation.dialogs.EditActionDialog; 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 info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; -import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; public class AutomationFragment extends SubscriberFragment { @@ -49,8 +31,6 @@ public class AutomationFragment extends SubscriberFragment { private EventListAdapter mEventListAdapter; - FragmentManager mFragmentManager; - @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { @@ -58,17 +38,11 @@ public class AutomationFragment extends SubscriberFragment { View view = inflater.inflate(R.layout.automation_fragment, container, false); unbinder = ButterKnife.bind(this, view); - mFragmentManager = getFragmentManager(); - final AutomationPlugin plugin = AutomationPlugin.getPlugin(); mEventListAdapter = new EventListAdapter(plugin.getAutomationEvents(), getFragmentManager()); mEventListView.setLayoutManager(new LinearLayoutManager(getContext())); mEventListView.setAdapter(mEventListAdapter); - EditEventDialog.setOnClickListener(event -> mEventListAdapter.notifyDataSetChanged()); - - updateGUI(); - return view; } @@ -77,6 +51,15 @@ public class AutomationFragment extends SubscriberFragment { updateGUI(); } + @Subscribe + public void onEvent(EventAutomationDataChanged unused) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(() -> { + mEventListAdapter.notifyDataSetChanged(); + }); + } + @Override public void updateGUI() { Activity activity = getActivity(); @@ -93,331 +76,10 @@ public class AutomationFragment extends SubscriberFragment { } @OnClick(R.id.fabAddEvent) - @SuppressWarnings("unused") - void onClickAddEvent(View v) { + void onClickAddEvent(View unused) { EditEventDialog dialog = EditEventDialog.newInstance(new AutomationEvent(), true); - if (getFragmentManager() != null) { + if (getFragmentManager() != null) dialog.show(getFragmentManager(), "EditEventDialog"); - } - } - - 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); - } - - /** - * RecyclerViewAdapter to display event lists. - */ - public static class EventListAdapter extends RecyclerView.Adapter { - private final List mEventList; - private final FragmentManager mFragmentManager; - - EventListAdapter(List 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 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 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.newInstance(event, false); - 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); - } - } - } - - /** - * RecyclerViewAdapter to display action lists. - */ - public static class ActionListAdapter extends RecyclerView.Adapter { - private final List mActionList; - private final FragmentManager mFragmentManager; - - public ActionListAdapter(FragmentManager manager, List events) { - this.mActionList = events; - this.mFragmentManager = manager; - } - - @NonNull - @Override - public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { - View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.automation_action_item, parent, false); - return new ViewHolder(v); - } - - @Override - public void onBindViewHolder(@NonNull ViewHolder holder, int position) { - final Action action = mActionList.get(position); - holder.actionTitle.setText(action.shortDescription()); - holder.layoutText.setOnClickListener(v -> { - if (action.hasDialog()) { - EditActionDialog dialog = EditActionDialog.newInstance(action); - dialog.show(mFragmentManager, "EditActionDialog"); - } - }); - holder.iconTrash.setOnClickListener(v -> { - mActionList.remove(action); - notifyDataSetChanged(); - }); - } - - @Override - public int getItemCount() { - return mActionList.size(); - } - - static class ViewHolder extends RecyclerView.ViewHolder { - TextView actionTitle; - TextView actionDescription; - LinearLayout layoutText; - ImageView iconTrash; - - ViewHolder(View view) { - super(view); - layoutText = view.findViewById(R.id.layoutText); - actionTitle = view.findViewById(R.id.viewActionTitle); - actionDescription = view.findViewById(R.id.viewActionDescription); - iconTrash = view.findViewById(R.id.iconTrash); - } - } - } - - /** - * Custom Adapter to display triggers dynamically with nested linear layouts. - */ - 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; - } - - FragmentManager getFM() { - return mFragmentManager; - } - - 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 = ChooseTriggerDialog.newInstance(); - dialog.setOnClickListener(newTriggerObject -> { - mRootConnector.add(newTriggerObject); - rebuild(fragmentManager); - }); - dialog.show(fragmentManager, "ChooseTriggerDialog"); - }); - 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()); - 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 = ChooseTriggerDialog.newInstance(); - 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); - } } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java index dfaaad0177..964326f54a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/AutomationPlugin.java @@ -26,10 +26,6 @@ import info.nightscout.androidaps.interfaces.PluginDescription; import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.plugins.general.automation.actions.Action; -import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopDisable; -import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopEnable; -import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopResume; -import info.nightscout.androidaps.plugins.general.automation.actions.ActionLoopSuspend; import info.nightscout.androidaps.plugins.general.automation.actions.ActionNotification; import info.nightscout.androidaps.plugins.general.automation.actions.ActionProfileSwitchPercent; import info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget; @@ -194,7 +190,7 @@ public class AutomationPlugin extends PluginBase { if (L.isEnabled(L.AUTOMATION)) log.debug("processActions"); for (AutomationEvent event : getAutomationEvents()) { - if (event.getTrigger().shouldRun()) { + if (event.getTrigger().shouldRun() && event.getPreconditions().shouldRun()) { List actions = event.getActions(); for (Action action : actions) { action.doAction(new Callback() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java new file mode 100644 index 0000000000..4bcd4bddfa --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/EventListAdapter.java @@ -0,0 +1,113 @@ +package info.nightscout.androidaps.plugins.general.automation; + +import android.content.Context; +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 { + private final List mEventList; + private final FragmentManager mFragmentManager; + + EventListAdapter(List 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 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 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.newInstance(event, false); + 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); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java index 82b620e26e..796f023f1d 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/Action.java @@ -9,6 +9,7 @@ import org.json.JSONObject; import javax.annotation.Nullable; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; import info.nightscout.androidaps.queue.Callback; /* @@ -44,6 +45,8 @@ import info.nightscout.androidaps.queue.Callback; public abstract class Action { + public Trigger precondition = null; + public abstract int friendlyName(); public abstract String shortDescription(); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java index d7376301a9..20b6abb081 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionProfileSwitchPercent.java @@ -11,10 +11,12 @@ 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; @@ -22,6 +24,10 @@ 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; @@ -29,7 +35,10 @@ public class ActionProfileSwitchPercent extends Action { @Override public String shortDescription() { - return MainApp.gs(R.string.startprofile, (int) pct.getValue(), (int) duration.getValue()); + 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 diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java index 24ae015360..66f262485b 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/actions/ActionStartTempTarget.java @@ -14,10 +14,12 @@ 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; @@ -29,6 +31,10 @@ public class ActionStartTempTarget extends Action { 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; diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ActionListAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ActionListAdapter.java new file mode 100644 index 0000000000..27f7742c00 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ActionListAdapter.java @@ -0,0 +1,73 @@ +package info.nightscout.androidaps.plugins.general.automation.dialogs; + +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.annotation.NonNull; +import androidx.fragment.app.FragmentManager; +import androidx.recyclerview.widget.RecyclerView; + +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.events.EventAutomationUpdateGui; + +public class ActionListAdapter extends RecyclerView.Adapter { + private final List mActionList; + private final FragmentManager mFragmentManager; + + public ActionListAdapter(FragmentManager manager, List events) { + this.mActionList = events; + this.mFragmentManager = manager; + } + + @NonNull + @Override + public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) { + View v = LayoutInflater.from(parent.getContext()).inflate(R.layout.automation_action_item, parent, false); + return new ViewHolder(v); + } + + @Override + public void onBindViewHolder(@NonNull ViewHolder holder, int position) { + final Action action = mActionList.get(position); + holder.actionTitle.setText(action.shortDescription()); + holder.layoutText.setOnClickListener(v -> { + if (action.hasDialog()) { + EditActionDialog dialog = EditActionDialog.newInstance(action); + dialog.show(mFragmentManager, "EditActionDialog"); + } + }); + holder.iconTrash.setOnClickListener(v -> { + mActionList.remove(action); + notifyDataSetChanged(); + MainApp.bus().post(new EventAutomationUpdateGui()); + }); + } + + @Override + public int getItemCount() { + return mActionList.size(); + } + + static class ViewHolder extends RecyclerView.ViewHolder { + TextView actionTitle; + TextView actionDescription; + LinearLayout layoutText; + ImageView iconTrash; + + ViewHolder(View view) { + super(view); + layoutText = view.findViewById(R.id.layoutText); + actionTitle = view.findViewById(R.id.viewActionTitle); + actionDescription = view.findViewById(R.id.viewActionDescription); + iconTrash = view.findViewById(R.id.iconTrash); + } + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseActionDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseActionDialog.java index ef83b1b661..ae1e19d561 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseActionDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/ChooseActionDialog.java @@ -14,9 +14,12 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; +import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; 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; public class ChooseActionDialog extends DialogFragment { @@ -24,22 +27,11 @@ public class ChooseActionDialog extends DialogFragment { void onClick(Action newActionObject); } - private static OnClickListener mClickListener = null; - private Unbinder mUnbinder; @BindView(R.id.radioGroup) RadioGroup mRadioGroup; - public static ChooseActionDialog newInstance() { - Bundle args = new Bundle(); - - ChooseActionDialog fragment = new ChooseActionDialog(); - fragment.setArguments(args); - - return fragment; - } - public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.automation_dialog_choose_action, container, false); @@ -95,10 +87,6 @@ public class ChooseActionDialog extends DialogFragment { } - public static void setOnClickListener(OnClickListener clickListener) { - mClickListener = clickListener; - } - @Override public void onDestroyView() { mUnbinder.unbind(); @@ -106,17 +94,14 @@ public class ChooseActionDialog extends DialogFragment { } @OnClick(R.id.ok) - @SuppressWarnings("unused") - public void onButtonOk(View view) { - if (mClickListener != null) - mClickListener.onClick(instantiateAction()); - + public void onButtonOk(View unused) { dismiss(); + MainApp.bus().post(new EventAutomationAddAction(instantiateAction())); + MainApp.bus().post(new EventAutomationUpdateGui()); } @OnClick(R.id.cancel) - @SuppressWarnings("unused") - public void onButtonCancel(View view) { + public void onButtonCancel(View unused) { dismiss(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditActionDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditActionDialog.java index f6952f817c..24bca41c62 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditActionDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditActionDialog.java @@ -80,16 +80,14 @@ public class EditActionDialog extends DialogFragment { } @OnClick(R.id.ok) - @SuppressWarnings("unused") - public void onButtonOk(View view) { + public void onButtonOk(View unused) { resultAction.apply(mAction); dismiss(); MainApp.bus().post(new EventAutomationUpdateGui()); } @OnClick(R.id.cancel) - @SuppressWarnings("unused") - public void onButtonCancel(View view) { + public void onButtonCancel(View unused) { dismiss(); } 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 c4734c8a2e..4c07001479 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 @@ -5,12 +5,12 @@ import android.os.Bundle; import android.view.LayoutInflater; import android.view.View; import android.view.ViewGroup; -import android.widget.Button; import android.widget.TextView; import android.widget.Toast; import androidx.annotation.NonNull; import androidx.fragment.app.DialogFragment; +import androidx.fragment.app.FragmentManager; import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.RecyclerView; @@ -24,10 +24,11 @@ import butterknife.Unbinder; import info.nightscout.androidaps.MainApp; 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.events.EventAutomationAddAction; 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.events.EventAutomationUpdateTrigger; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector; public class EditEventDialog extends DialogFragment { @@ -35,30 +36,31 @@ public class EditEventDialog extends DialogFragment { void onClick(AutomationEvent event); } - private static OnClickListener mClickListener = null; private static AutomationEvent staticEvent; - public static void setOnClickListener(OnClickListener clickListener) { - mClickListener = clickListener; - } - @BindView(R.id.inputEventTitle) TextInputEditText mEditEventTitle; @BindView(R.id.editTrigger) TextView mEditTrigger; - @BindView(R.id.editAction) - TextView mEditAction; + @BindView(R.id.addAction) + TextView mAddAction; @BindView(R.id.triggerDescription) TextView mTriggerDescription; + @BindView(R.id.forcedtriggerdescription) + TextView mForcedTriggerDescription; + + @BindView(R.id.forcedtriggerdescriptionlabel) + TextView mForcedTriggerDescriptionLabel; + @BindView(R.id.actionListView) RecyclerView mActionListView; private Unbinder mUnbinder; - private AutomationFragment.ActionListAdapter mActionListAdapter; + private ActionListAdapter mActionListAdapter; private AutomationEvent mEvent; private boolean mAddNew; @@ -99,11 +101,6 @@ public class EditEventDialog extends DialogFragment { // display root trigger mTriggerDescription.setText(mEvent.getTrigger().friendlyDescription()); - // setup trigger click event listener - EditTriggerDialog.setOnClickListener(trigger -> { - mEvent.setTrigger(trigger); - mTriggerDescription.setText(mEvent.getTrigger().friendlyDescription()); - }); mEditTrigger.setOnClickListener(v -> { EditTriggerDialog dialog = EditTriggerDialog.newInstance(mEvent.getTrigger()); if (getFragmentManager() != null) @@ -111,21 +108,18 @@ public class EditEventDialog extends DialogFragment { }); // setup action list view - mActionListAdapter = new AutomationFragment.ActionListAdapter(getFragmentManager(), mEvent.getActions()); + mActionListAdapter = new ActionListAdapter(getFragmentManager(), mEvent.getActions()); mActionListView.setLayoutManager(new LinearLayoutManager(getContext())); mActionListView.setAdapter(mActionListAdapter); - // setup action click event listener - ChooseActionDialog.setOnClickListener(newActionObject -> { - mEvent.addAction(newActionObject); - mActionListAdapter.notifyDataSetChanged(); - }); - mEditAction.setOnClickListener(v -> { - ChooseActionDialog dialog = ChooseActionDialog.newInstance(); - if (getFragmentManager() != null) - dialog.show(getFragmentManager(), "ChooseActionDialog"); + mAddAction.setOnClickListener(v -> { + FragmentManager fragmentManager = getFragmentManager(); + if (fragmentManager != null) + new ChooseActionDialog().show(fragmentManager, "ChooseActionDialog"); }); + showPreconditions(); + MainApp.bus().register(this); return view; @@ -142,12 +136,34 @@ public class EditEventDialog extends DialogFragment { public void onEventAutomationUpdateGui(EventAutomationUpdateGui ignored) { Activity activity = getActivity(); if (activity != null) - activity.runOnUiThread(() -> mActionListAdapter.notifyDataSetChanged()); + activity.runOnUiThread(() -> { + mActionListAdapter.notifyDataSetChanged(); + showPreconditions(); + }); + } + + @Subscribe + public void onEventAutomationAddAction(EventAutomationAddAction event) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(() -> { + mEvent.addAction(event.getAction()); + mActionListAdapter.notifyDataSetChanged(); + }); + } + + @Subscribe + public void onEventAutomationUpdateTrigger(EventAutomationUpdateTrigger event) { + Activity activity = getActivity(); + if (activity != null) + activity.runOnUiThread(() -> { + mEvent.setTrigger(event.getTrigger()); + mTriggerDescription.setText(mEvent.getTrigger().friendlyDescription()); + }); } @OnClick(R.id.ok) - @SuppressWarnings("unused") - public void onButtonOk(View view) { + public void onButtonOk(View unused) { // check for title String title = mEditEventTitle.getText().toString(); if (title.isEmpty()) { @@ -178,14 +194,12 @@ public class EditEventDialog extends DialogFragment { plugin.getAutomationEvents().add(mEvent); } - if (mClickListener != null) mClickListener.onClick(mEvent); dismiss(); MainApp.bus().post(new EventAutomationDataChanged()); } @OnClick(R.id.cancel) - @SuppressWarnings("unused") - public void onButtonCancel(View view) { + public void onButtonCancel(View unused) { dismiss(); } @@ -195,4 +209,15 @@ public class EditEventDialog extends DialogFragment { bundle.putBoolean("addNew", mAddNew); } + private void showPreconditions() { + TriggerConnector forcedTriggers = mEvent.getPreconditions(); + if (forcedTriggers.size() > 0) { + mForcedTriggerDescription.setVisibility(View.VISIBLE); + mForcedTriggerDescriptionLabel.setVisibility(View.VISIBLE); + mForcedTriggerDescription.setText(forcedTriggers.friendlyDescription()); + } else { + mForcedTriggerDescription.setVisibility(View.GONE); + mForcedTriggerDescriptionLabel.setVisibility(View.GONE); + } + } } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.java index 6cfe072567..033d8a7c78 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/EditTriggerDialog.java @@ -13,7 +13,9 @@ import butterknife.BindView; import butterknife.ButterKnife; import butterknife.OnClick; import butterknife.Unbinder; +import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.R; +import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger; import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; public class EditTriggerDialog extends DialogFragment { @@ -22,8 +24,6 @@ public class EditTriggerDialog extends DialogFragment { void onClick(Trigger newTriggerObject); } - private static OnClickListener mClickListener = null; - @BindView(R.id.layoutTrigger) LinearLayout mLayoutTrigger; @@ -58,10 +58,6 @@ public class EditTriggerDialog extends DialogFragment { return view; } - public static void setOnClickListener(OnClickListener clickListener) { - mClickListener = clickListener; - } - @Override public void onDestroyView() { mUnbinder.unbind(); @@ -69,17 +65,13 @@ public class EditTriggerDialog extends DialogFragment { } @OnClick(R.id.ok) - @SuppressWarnings("unused") - public void onButtonOk(View view) { - if (mClickListener != null) - mClickListener.onClick(mTrigger); - + public void onButtonOk(View unused) { dismiss(); + MainApp.bus().post(new EventAutomationUpdateTrigger(mTrigger)); } @OnClick(R.id.cancel) - @SuppressWarnings("unused") - public void onButtonCancel(View view) { + public void onButtonCancel(View unused) { dismiss(); } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/TriggerListAdapter.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/TriggerListAdapter.java new file mode 100644 index 0000000000..77c72a640d --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/dialogs/TriggerListAdapter.java @@ -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; + } + + 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 = ChooseTriggerDialog.newInstance(); + dialog.setOnClickListener(newTriggerObject -> { + mRootConnector.add(newTriggerObject); + rebuild(fragmentManager); + }); + dialog.show(fragmentManager, "ChooseTriggerDialog"); + }); + 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()); + 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 = ChooseTriggerDialog.newInstance(); + 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); + } + + private 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); + } + +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.java index 5f7d7654f0..03b47810ad 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/elements/InputPercent.java @@ -13,8 +13,8 @@ public class InputPercent extends Element { final TextWatcher textWatcher = new TextWatcher() { @Override public void afterTextChanged(Editable s) { - value = Math.max(value, 0d); - value = Math.min(value, 500d); + value = Math.max(value, 70d); + value = Math.min(value, 130d); } @Override @@ -41,7 +41,7 @@ public class InputPercent extends Element { @Override public void addToLayout(LinearLayout root) { NumberPicker numberPicker = new NumberPicker(root.getContext(), null); - numberPicker.setParams(100d, 0d, 500d, 10d, new DecimalFormat("0"), true, textWatcher); + numberPicker.setParams(100d, 70d, 130d, 5d, new DecimalFormat("0"), true, textWatcher); numberPicker.setValue(value); numberPicker.setOnValueChangedListener(value -> this.value = value); root.addView(numberPicker); diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationAddAction.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationAddAction.java new file mode 100644 index 0000000000..c9c788fa32 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationAddAction.java @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.general.automation.events; + +import info.nightscout.androidaps.events.Event; +import info.nightscout.androidaps.plugins.general.automation.actions.Action; + +public class EventAutomationAddAction extends Event { + private Action action; + + public EventAutomationAddAction(Action action) { + this.action = action; + } + + public Action getAction() { + return action; + } +} diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.java new file mode 100644 index 0000000000..5e8c7c4749 --- /dev/null +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/events/EventAutomationUpdateTrigger.java @@ -0,0 +1,16 @@ +package info.nightscout.androidaps.plugins.general.automation.events; + +import info.nightscout.androidaps.events.Event; +import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; + +public class EventAutomationUpdateTrigger extends Event { + private Trigger trigger; + + public EventAutomationUpdateTrigger(Trigger trigger) { + this.trigger = trigger; + } + + public Trigger getTrigger() { + return trigger; + } +} 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 d4e23e45a3..ae4bd35ad5 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 @@ -22,7 +22,7 @@ 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.AutomationFragment; +import info.nightscout.androidaps.plugins.general.automation.dialogs.TriggerListAdapter; import info.nightscout.androidaps.utils.JsonHelper; public class TriggerConnector extends Trigger { @@ -217,7 +217,7 @@ public class TriggerConnector extends Trigger { return null; } - private AutomationFragment.TriggerListAdapter adapter; + private TriggerListAdapter adapter; public void rebuildView(FragmentManager fragmentManager) { if (adapter != null) @@ -236,7 +236,7 @@ public class TriggerConnector extends Trigger { triggerListLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT)); root.addView(triggerListLayout); - adapter = new AutomationFragment().new TriggerListAdapter(fragmentManager, root.getContext(), triggerListLayout, this); + adapter = new TriggerListAdapter(fragmentManager, root.getContext(), triggerListLayout, this); } public TriggerConnector simplify() { diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java index f9f3c4b36d..d86bc35cb8 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerProfilePercent.java @@ -126,7 +126,7 @@ public class TriggerProfilePercent extends Trigger { return new TriggerProfilePercent(this); } - TriggerProfilePercent setValue(double value) { + public TriggerProfilePercent setValue(double value) { pct.setValue(value); return this; } @@ -136,7 +136,7 @@ public class TriggerProfilePercent extends Trigger { return this; } - TriggerProfilePercent comparator(Comparator.Compare compare) { + public TriggerProfilePercent comparator(Comparator.Compare compare) { this.comparator = new Comparator().setValue(compare); return this; } diff --git a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java index 68655a8490..378652ed2a 100644 --- a/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java +++ b/app/src/main/java/info/nightscout/androidaps/plugins/general/automation/triggers/TriggerTempTarget.java @@ -116,7 +116,7 @@ public class TriggerTempTarget extends Trigger { return this; } - TriggerTempTarget comparator(ComparatorExists.Compare compare) { + public TriggerTempTarget comparator(ComparatorExists.Compare compare) { this.comparator = new ComparatorExists().setValue(compare); return this; } diff --git a/app/src/main/res/layout/automation_dialog_event.xml b/app/src/main/res/layout/automation_dialog_event.xml index 2792a6c5f6..48041986f1 100644 --- a/app/src/main/res/layout/automation_dialog_event.xml +++ b/app/src/main/res/layout/automation_dialog_event.xml @@ -32,7 +32,8 @@ + android:text="@string/condition" + android:textStyle="bold" /> + + + + + android:text="@string/action" + android:textStyle="bold" /> Profile percentage Percent [%]: Start profile %1$d%% for %2$d min + Start profile %1$d%% exists not exists Temp target %1$s @@ -1470,6 +1471,7 @@ Then: Triggers: REMOVE + Preconditions: %1$d day