Preconditions, code cleanup

This commit is contained in:
Milos Kozak 2019-07-16 21:57:45 +02:00
parent 67b06f51fe
commit 58da7fc854
21 changed files with 546 additions and 438 deletions

View file

@ -33,6 +33,15 @@ public class AutomationEvent {
return actions; 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) { public void addAction(Action action) {
actions.add(action); actions.add(action);
} }

View file

@ -1,44 +1,26 @@
package info.nightscout.androidaps.plugins.general.automation; package info.nightscout.androidaps.plugins.general.automation;
import android.app.Activity; import android.app.Activity;
import android.content.Context;
import android.os.Bundle; import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; 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 android.widget.TextView;
import androidx.annotation.DrawableRes;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
import com.squareup.otto.Subscribe; import com.squareup.otto.Subscribe;
import java.util.HashSet;
import java.util.List;
import butterknife.BindView; import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.common.SubscriberFragment; 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.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.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 { public class AutomationFragment extends SubscriberFragment {
@ -49,8 +31,6 @@ public class AutomationFragment extends SubscriberFragment {
private EventListAdapter mEventListAdapter; private EventListAdapter mEventListAdapter;
FragmentManager mFragmentManager;
@Override @Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
@ -58,17 +38,11 @@ public class AutomationFragment extends SubscriberFragment {
View view = inflater.inflate(R.layout.automation_fragment, container, false); View view = inflater.inflate(R.layout.automation_fragment, container, false);
unbinder = ButterKnife.bind(this, view); unbinder = ButterKnife.bind(this, view);
mFragmentManager = getFragmentManager();
final AutomationPlugin plugin = AutomationPlugin.getPlugin(); final AutomationPlugin plugin = AutomationPlugin.getPlugin();
mEventListAdapter = new EventListAdapter(plugin.getAutomationEvents(), getFragmentManager()); mEventListAdapter = new EventListAdapter(plugin.getAutomationEvents(), getFragmentManager());
mEventListView.setLayoutManager(new LinearLayoutManager(getContext())); mEventListView.setLayoutManager(new LinearLayoutManager(getContext()));
mEventListView.setAdapter(mEventListAdapter); mEventListView.setAdapter(mEventListAdapter);
EditEventDialog.setOnClickListener(event -> mEventListAdapter.notifyDataSetChanged());
updateGUI();
return view; return view;
} }
@ -77,6 +51,15 @@ public class AutomationFragment extends SubscriberFragment {
updateGUI(); updateGUI();
} }
@Subscribe
public void onEvent(EventAutomationDataChanged unused) {
Activity activity = getActivity();
if (activity != null)
activity.runOnUiThread(() -> {
mEventListAdapter.notifyDataSetChanged();
});
}
@Override @Override
public void updateGUI() { public void updateGUI() {
Activity activity = getActivity(); Activity activity = getActivity();
@ -93,331 +76,10 @@ public class AutomationFragment extends SubscriberFragment {
} }
@OnClick(R.id.fabAddEvent) @OnClick(R.id.fabAddEvent)
@SuppressWarnings("unused") void onClickAddEvent(View unused) {
void onClickAddEvent(View v) {
EditEventDialog dialog = EditEventDialog.newInstance(new AutomationEvent(), true); EditEventDialog dialog = EditEventDialog.newInstance(new AutomationEvent(), true);
if (getFragmentManager() != null) { if (getFragmentManager() != null)
dialog.show(getFragmentManager(), "EditEventDialog"); 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<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.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<ActionListAdapter.ViewHolder> {
private final List<Action> mActionList;
private final FragmentManager mFragmentManager;
public ActionListAdapter(FragmentManager manager, List<Action> 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<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 = 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);
}
} }
} }

View file

@ -26,10 +26,6 @@ import info.nightscout.androidaps.interfaces.PluginDescription;
import info.nightscout.androidaps.interfaces.PluginType; import info.nightscout.androidaps.interfaces.PluginType;
import info.nightscout.androidaps.logging.L; import info.nightscout.androidaps.logging.L;
import info.nightscout.androidaps.plugins.general.automation.actions.Action; 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.ActionNotification;
import info.nightscout.androidaps.plugins.general.automation.actions.ActionProfileSwitchPercent; import info.nightscout.androidaps.plugins.general.automation.actions.ActionProfileSwitchPercent;
import info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget; import info.nightscout.androidaps.plugins.general.automation.actions.ActionStartTempTarget;
@ -194,7 +190,7 @@ public class AutomationPlugin extends PluginBase {
if (L.isEnabled(L.AUTOMATION)) if (L.isEnabled(L.AUTOMATION))
log.debug("processActions"); log.debug("processActions");
for (AutomationEvent event : getAutomationEvents()) { for (AutomationEvent event : getAutomationEvents()) {
if (event.getTrigger().shouldRun()) { if (event.getTrigger().shouldRun() && event.getPreconditions().shouldRun()) {
List<Action> actions = event.getActions(); List<Action> actions = event.getActions();
for (Action action : actions) { for (Action action : actions) {
action.doAction(new Callback() { action.doAction(new Callback() {

View file

@ -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<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.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);
}
}
}

View file

@ -9,6 +9,7 @@ import org.json.JSONObject;
import javax.annotation.Nullable; import javax.annotation.Nullable;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
/* /*
@ -44,6 +45,8 @@ import info.nightscout.androidaps.queue.Callback;
public abstract class Action { public abstract class Action {
public Trigger precondition = null;
public abstract int friendlyName(); public abstract int friendlyName();
public abstract String shortDescription(); public abstract String shortDescription();

View file

@ -11,10 +11,12 @@ import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.plugins.configBuilder.ProfileFunctions; 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.InputDuration;
import info.nightscout.androidaps.plugins.general.automation.elements.InputPercent; 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.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder; 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.queue.Callback;
import info.nightscout.androidaps.utils.JsonHelper; import info.nightscout.androidaps.utils.JsonHelper;
@ -22,6 +24,10 @@ public class ActionProfileSwitchPercent extends Action {
InputPercent pct = new InputPercent(); InputPercent pct = new InputPercent();
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES); InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
public ActionProfileSwitchPercent() {
precondition = new TriggerProfilePercent().comparator(Comparator.Compare.IS_EQUAL).setValue(100);
}
@Override @Override
public int friendlyName() { public int friendlyName() {
return R.string.profilepercentage; return R.string.profilepercentage;
@ -29,7 +35,10 @@ public class ActionProfileSwitchPercent extends Action {
@Override @Override
public String shortDescription() { 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 @Override

View file

@ -14,10 +14,12 @@ import info.nightscout.androidaps.data.Profile;
import info.nightscout.androidaps.data.PumpEnactResult; import info.nightscout.androidaps.data.PumpEnactResult;
import info.nightscout.androidaps.db.Source; import info.nightscout.androidaps.db.Source;
import info.nightscout.androidaps.db.TempTarget; 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.InputBg;
import info.nightscout.androidaps.plugins.general.automation.elements.InputDuration; 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.LabelWithElement;
import info.nightscout.androidaps.plugins.general.automation.elements.LayoutBuilder; 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.plugins.treatments.TreatmentsPlugin;
import info.nightscout.androidaps.queue.Callback; import info.nightscout.androidaps.queue.Callback;
import info.nightscout.androidaps.utils.DateUtil; import info.nightscout.androidaps.utils.DateUtil;
@ -29,6 +31,10 @@ public class ActionStartTempTarget extends Action {
InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES); InputDuration duration = new InputDuration(0, InputDuration.TimeUnit.MINUTES);
private TempTarget tempTarget; private TempTarget tempTarget;
public ActionStartTempTarget() {
precondition = new TriggerTempTarget().comparator(ComparatorExists.Compare.NOT_EXISTS);
}
@Override @Override
public int friendlyName() { public int friendlyName() {
return R.string.starttemptarget; return R.string.starttemptarget;

View file

@ -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<ActionListAdapter.ViewHolder> {
private final List<Action> mActionList;
private final FragmentManager mFragmentManager;
public ActionListAdapter(FragmentManager manager, List<Action> 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);
}
}
}

View file

@ -14,9 +14,12 @@ import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.Unbinder; import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin; import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
import info.nightscout.androidaps.plugins.general.automation.actions.Action; 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 { public class ChooseActionDialog extends DialogFragment {
@ -24,22 +27,11 @@ public class ChooseActionDialog extends DialogFragment {
void onClick(Action newActionObject); void onClick(Action newActionObject);
} }
private static OnClickListener mClickListener = null;
private Unbinder mUnbinder; private Unbinder mUnbinder;
@BindView(R.id.radioGroup) @BindView(R.id.radioGroup)
RadioGroup mRadioGroup; 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, public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container,
Bundle savedInstanceState) { Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.automation_dialog_choose_action, container, false); 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 @Override
public void onDestroyView() { public void onDestroyView() {
mUnbinder.unbind(); mUnbinder.unbind();
@ -106,17 +94,14 @@ public class ChooseActionDialog extends DialogFragment {
} }
@OnClick(R.id.ok) @OnClick(R.id.ok)
@SuppressWarnings("unused") public void onButtonOk(View unused) {
public void onButtonOk(View view) {
if (mClickListener != null)
mClickListener.onClick(instantiateAction());
dismiss(); dismiss();
MainApp.bus().post(new EventAutomationAddAction(instantiateAction()));
MainApp.bus().post(new EventAutomationUpdateGui());
} }
@OnClick(R.id.cancel) @OnClick(R.id.cancel)
@SuppressWarnings("unused") public void onButtonCancel(View unused) {
public void onButtonCancel(View view) {
dismiss(); dismiss();
} }

View file

@ -80,16 +80,14 @@ public class EditActionDialog extends DialogFragment {
} }
@OnClick(R.id.ok) @OnClick(R.id.ok)
@SuppressWarnings("unused") public void onButtonOk(View unused) {
public void onButtonOk(View view) {
resultAction.apply(mAction); resultAction.apply(mAction);
dismiss(); dismiss();
MainApp.bus().post(new EventAutomationUpdateGui()); MainApp.bus().post(new EventAutomationUpdateGui());
} }
@OnClick(R.id.cancel) @OnClick(R.id.cancel)
@SuppressWarnings("unused") public void onButtonCancel(View unused) {
public void onButtonCancel(View view) {
dismiss(); dismiss();
} }

View file

@ -5,12 +5,12 @@ import android.os.Bundle;
import android.view.LayoutInflater; import android.view.LayoutInflater;
import android.view.View; import android.view.View;
import android.view.ViewGroup; import android.view.ViewGroup;
import android.widget.Button;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast; import android.widget.Toast;
import androidx.annotation.NonNull; import androidx.annotation.NonNull;
import androidx.fragment.app.DialogFragment; import androidx.fragment.app.DialogFragment;
import androidx.fragment.app.FragmentManager;
import androidx.recyclerview.widget.LinearLayoutManager; import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView; import androidx.recyclerview.widget.RecyclerView;
@ -24,10 +24,11 @@ import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.automation.AutomationEvent; 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.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.EventAutomationDataChanged;
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateGui; 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; import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
public class EditEventDialog extends DialogFragment { public class EditEventDialog extends DialogFragment {
@ -35,30 +36,31 @@ public class EditEventDialog extends DialogFragment {
void onClick(AutomationEvent event); void onClick(AutomationEvent event);
} }
private static OnClickListener mClickListener = null;
private static AutomationEvent staticEvent; private static AutomationEvent staticEvent;
public static void setOnClickListener(OnClickListener clickListener) {
mClickListener = clickListener;
}
@BindView(R.id.inputEventTitle) @BindView(R.id.inputEventTitle)
TextInputEditText mEditEventTitle; TextInputEditText mEditEventTitle;
@BindView(R.id.editTrigger) @BindView(R.id.editTrigger)
TextView mEditTrigger; TextView mEditTrigger;
@BindView(R.id.editAction) @BindView(R.id.addAction)
TextView mEditAction; TextView mAddAction;
@BindView(R.id.triggerDescription) @BindView(R.id.triggerDescription)
TextView mTriggerDescription; TextView mTriggerDescription;
@BindView(R.id.forcedtriggerdescription)
TextView mForcedTriggerDescription;
@BindView(R.id.forcedtriggerdescriptionlabel)
TextView mForcedTriggerDescriptionLabel;
@BindView(R.id.actionListView) @BindView(R.id.actionListView)
RecyclerView mActionListView; RecyclerView mActionListView;
private Unbinder mUnbinder; private Unbinder mUnbinder;
private AutomationFragment.ActionListAdapter mActionListAdapter; private ActionListAdapter mActionListAdapter;
private AutomationEvent mEvent; private AutomationEvent mEvent;
private boolean mAddNew; private boolean mAddNew;
@ -99,11 +101,6 @@ public class EditEventDialog extends DialogFragment {
// display root trigger // display root trigger
mTriggerDescription.setText(mEvent.getTrigger().friendlyDescription()); mTriggerDescription.setText(mEvent.getTrigger().friendlyDescription());
// setup trigger click event listener
EditTriggerDialog.setOnClickListener(trigger -> {
mEvent.setTrigger(trigger);
mTriggerDescription.setText(mEvent.getTrigger().friendlyDescription());
});
mEditTrigger.setOnClickListener(v -> { mEditTrigger.setOnClickListener(v -> {
EditTriggerDialog dialog = EditTriggerDialog.newInstance(mEvent.getTrigger()); EditTriggerDialog dialog = EditTriggerDialog.newInstance(mEvent.getTrigger());
if (getFragmentManager() != null) if (getFragmentManager() != null)
@ -111,21 +108,18 @@ public class EditEventDialog extends DialogFragment {
}); });
// setup action list view // setup action list view
mActionListAdapter = new AutomationFragment.ActionListAdapter(getFragmentManager(), mEvent.getActions()); mActionListAdapter = new ActionListAdapter(getFragmentManager(), mEvent.getActions());
mActionListView.setLayoutManager(new LinearLayoutManager(getContext())); mActionListView.setLayoutManager(new LinearLayoutManager(getContext()));
mActionListView.setAdapter(mActionListAdapter); mActionListView.setAdapter(mActionListAdapter);
// setup action click event listener mAddAction.setOnClickListener(v -> {
ChooseActionDialog.setOnClickListener(newActionObject -> { FragmentManager fragmentManager = getFragmentManager();
mEvent.addAction(newActionObject); if (fragmentManager != null)
mActionListAdapter.notifyDataSetChanged(); new ChooseActionDialog().show(fragmentManager, "ChooseActionDialog");
});
mEditAction.setOnClickListener(v -> {
ChooseActionDialog dialog = ChooseActionDialog.newInstance();
if (getFragmentManager() != null)
dialog.show(getFragmentManager(), "ChooseActionDialog");
}); });
showPreconditions();
MainApp.bus().register(this); MainApp.bus().register(this);
return view; return view;
@ -142,12 +136,34 @@ public class EditEventDialog extends DialogFragment {
public void onEventAutomationUpdateGui(EventAutomationUpdateGui ignored) { public void onEventAutomationUpdateGui(EventAutomationUpdateGui ignored) {
Activity activity = getActivity(); Activity activity = getActivity();
if (activity != null) 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) @OnClick(R.id.ok)
@SuppressWarnings("unused") public void onButtonOk(View unused) {
public void onButtonOk(View view) {
// check for title // check for title
String title = mEditEventTitle.getText().toString(); String title = mEditEventTitle.getText().toString();
if (title.isEmpty()) { if (title.isEmpty()) {
@ -178,14 +194,12 @@ public class EditEventDialog extends DialogFragment {
plugin.getAutomationEvents().add(mEvent); plugin.getAutomationEvents().add(mEvent);
} }
if (mClickListener != null) mClickListener.onClick(mEvent);
dismiss(); dismiss();
MainApp.bus().post(new EventAutomationDataChanged()); MainApp.bus().post(new EventAutomationDataChanged());
} }
@OnClick(R.id.cancel) @OnClick(R.id.cancel)
@SuppressWarnings("unused") public void onButtonCancel(View unused) {
public void onButtonCancel(View view) {
dismiss(); dismiss();
} }
@ -195,4 +209,15 @@ public class EditEventDialog extends DialogFragment {
bundle.putBoolean("addNew", mAddNew); 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);
}
}
} }

View file

@ -13,7 +13,9 @@ import butterknife.BindView;
import butterknife.ButterKnife; import butterknife.ButterKnife;
import butterknife.OnClick; import butterknife.OnClick;
import butterknife.Unbinder; import butterknife.Unbinder;
import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.plugins.general.automation.events.EventAutomationUpdateTrigger;
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger; import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
public class EditTriggerDialog extends DialogFragment { public class EditTriggerDialog extends DialogFragment {
@ -22,8 +24,6 @@ public class EditTriggerDialog extends DialogFragment {
void onClick(Trigger newTriggerObject); void onClick(Trigger newTriggerObject);
} }
private static OnClickListener mClickListener = null;
@BindView(R.id.layoutTrigger) @BindView(R.id.layoutTrigger)
LinearLayout mLayoutTrigger; LinearLayout mLayoutTrigger;
@ -58,10 +58,6 @@ public class EditTriggerDialog extends DialogFragment {
return view; return view;
} }
public static void setOnClickListener(OnClickListener clickListener) {
mClickListener = clickListener;
}
@Override @Override
public void onDestroyView() { public void onDestroyView() {
mUnbinder.unbind(); mUnbinder.unbind();
@ -69,17 +65,13 @@ public class EditTriggerDialog extends DialogFragment {
} }
@OnClick(R.id.ok) @OnClick(R.id.ok)
@SuppressWarnings("unused") public void onButtonOk(View unused) {
public void onButtonOk(View view) {
if (mClickListener != null)
mClickListener.onClick(mTrigger);
dismiss(); dismiss();
MainApp.bus().post(new EventAutomationUpdateTrigger(mTrigger));
} }
@OnClick(R.id.cancel) @OnClick(R.id.cancel)
@SuppressWarnings("unused") public void onButtonCancel(View unused) {
public void onButtonCancel(View view) {
dismiss(); dismiss();
} }

View file

@ -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<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 = 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);
}
}

View file

@ -13,8 +13,8 @@ public class InputPercent extends Element {
final TextWatcher textWatcher = new TextWatcher() { final TextWatcher textWatcher = new TextWatcher() {
@Override @Override
public void afterTextChanged(Editable s) { public void afterTextChanged(Editable s) {
value = Math.max(value, 0d); value = Math.max(value, 70d);
value = Math.min(value, 500d); value = Math.min(value, 130d);
} }
@Override @Override
@ -41,7 +41,7 @@ public class InputPercent extends Element {
@Override @Override
public void addToLayout(LinearLayout root) { public void addToLayout(LinearLayout root) {
NumberPicker numberPicker = new NumberPicker(root.getContext(), null); 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.setValue(value);
numberPicker.setOnValueChangedListener(value -> this.value = value); numberPicker.setOnValueChangedListener(value -> this.value = value);
root.addView(numberPicker); root.addView(numberPicker);

View file

@ -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;
}
}

View file

@ -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;
}
}

View file

@ -22,7 +22,7 @@ import java.util.List;
import info.nightscout.androidaps.MainApp; import info.nightscout.androidaps.MainApp;
import info.nightscout.androidaps.R; import info.nightscout.androidaps.R;
import info.nightscout.androidaps.logging.L; 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; import info.nightscout.androidaps.utils.JsonHelper;
public class TriggerConnector extends Trigger { public class TriggerConnector extends Trigger {
@ -217,7 +217,7 @@ public class TriggerConnector extends Trigger {
return null; return null;
} }
private AutomationFragment.TriggerListAdapter adapter; private TriggerListAdapter adapter;
public void rebuildView(FragmentManager fragmentManager) { public void rebuildView(FragmentManager fragmentManager) {
if (adapter != null) 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)); triggerListLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
root.addView(triggerListLayout); root.addView(triggerListLayout);
adapter = new AutomationFragment().new TriggerListAdapter(fragmentManager, root.getContext(), triggerListLayout, this); adapter = new TriggerListAdapter(fragmentManager, root.getContext(), triggerListLayout, this);
} }
public TriggerConnector simplify() { public TriggerConnector simplify() {

View file

@ -126,7 +126,7 @@ public class TriggerProfilePercent extends Trigger {
return new TriggerProfilePercent(this); return new TriggerProfilePercent(this);
} }
TriggerProfilePercent setValue(double value) { public TriggerProfilePercent setValue(double value) {
pct.setValue(value); pct.setValue(value);
return this; return this;
} }
@ -136,7 +136,7 @@ public class TriggerProfilePercent extends Trigger {
return this; return this;
} }
TriggerProfilePercent comparator(Comparator.Compare compare) { public TriggerProfilePercent comparator(Comparator.Compare compare) {
this.comparator = new Comparator().setValue(compare); this.comparator = new Comparator().setValue(compare);
return this; return this;
} }

View file

@ -116,7 +116,7 @@ public class TriggerTempTarget extends Trigger {
return this; return this;
} }
TriggerTempTarget comparator(ComparatorExists.Compare compare) { public TriggerTempTarget comparator(ComparatorExists.Compare compare) {
this.comparator = new ComparatorExists().setValue(compare); this.comparator = new ComparatorExists().setValue(compare);
return this; return this;
} }

View file

@ -32,7 +32,8 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/condition" /> android:text="@string/condition"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/editTrigger" android:id="@+id/editTrigger"
@ -54,6 +55,21 @@
android:layout_marginBottom="10dp" android:layout_marginBottom="10dp"
android:orientation="vertical" /> android:orientation="vertical" />
<TextView
android:id="@+id/forcedtriggerdescriptionlabel"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="@string/preconditions"
android:textStyle="bold" />
<TextView
android:id="@+id/forcedtriggerdescription"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:layout_marginBottom="10dp"
android:orientation="vertical" />
<View <View
android:layout_width="fill_parent" android:layout_width="fill_parent"
android:layout_height="2dip" android:layout_height="2dip"
@ -68,10 +84,11 @@
<TextView <TextView
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:text="@string/action" /> android:text="@string/action"
android:textStyle="bold" />
<TextView <TextView
android:id="@+id/editAction" android:id="@+id/addAction"
android:layout_width="wrap_content" android:layout_width="wrap_content"
android:layout_height="wrap_content" android:layout_height="wrap_content"
android:layout_alignParentTop="true" android:layout_alignParentTop="true"

View file

@ -1442,6 +1442,7 @@
<string name="profilepercentage">Profile percentage</string> <string name="profilepercentage">Profile percentage</string>
<string name="percent_u">Percent [%]:</string> <string name="percent_u">Percent [%]:</string>
<string name="startprofile">Start profile %1$d%% for %2$d min</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="exists">exists</string>
<string name="notexists">not exists</string> <string name="notexists">not exists</string>
<string name="temptargetcompared">Temp target %1$s</string> <string name="temptargetcompared">Temp target %1$s</string>
@ -1470,6 +1471,7 @@
<string name="then_label">Then:</string> <string name="then_label">Then:</string>
<string name="triggers">Triggers:</string> <string name="triggers">Triggers:</string>
<string name="remove_label">REMOVE</string> <string name="remove_label">REMOVE</string>
<string name="preconditions">Preconditions:</string>
<plurals name="objective_days"> <plurals name="objective_days">
<item quantity="one">%1$d day</item> <item quantity="one">%1$d day</item>