Work on automation plugin.
- Add MainApp.dpToPx() helper function - Remove trigger layout resources - Generate trigger layout programmatically - Improve ux (when composing trigger logic) - Refactoring
This commit is contained in:
parent
c60aae8630
commit
f98d40f71b
12 changed files with 324 additions and 189 deletions
|
@ -397,4 +397,9 @@ public class MainApp extends Application {
|
||||||
sDatabaseHelper = null;
|
sDatabaseHelper = null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static int dpToPx(int dp) {
|
||||||
|
float scale = sResources.getDisplayMetrics().density;
|
||||||
|
return (int) (dp*scale + 0.5f);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
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.support.annotation.NonNull;
|
import android.support.annotation.NonNull;
|
||||||
import android.support.v4.app.FragmentManager;
|
import android.support.v4.app.FragmentManager;
|
||||||
|
@ -9,7 +10,10 @@ import android.support.v7.widget.RecyclerView;
|
||||||
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.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Spinner;
|
||||||
import android.widget.TextView;
|
import android.widget.TextView;
|
||||||
|
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
|
@ -18,10 +22,12 @@ 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.dialogs.EditEventDialog;
|
import info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog;
|
||||||
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
import info.nightscout.androidaps.plugins.general.automation.triggers.Trigger;
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||||
|
|
||||||
public class AutomationFragment extends SubscriberFragment {
|
public class AutomationFragment extends SubscriberFragment {
|
||||||
|
|
||||||
|
@ -110,35 +116,98 @@ public class AutomationFragment extends SubscriberFragment {
|
||||||
*/
|
*/
|
||||||
public static class TriggerListAdapter {
|
public static class TriggerListAdapter {
|
||||||
private final LinearLayout mRootLayout;
|
private final LinearLayout mRootLayout;
|
||||||
private final LayoutInflater mInflater;
|
private final Context mContext;
|
||||||
private final List<Trigger> mTriggerList;
|
private final List<Trigger> mTriggerList;
|
||||||
|
|
||||||
public TriggerListAdapter(LayoutInflater inflater, LinearLayout rootLayout, List<Trigger> triggers) {
|
public TriggerListAdapter(Context context, LinearLayout rootLayout, List<Trigger> triggers) {
|
||||||
mRootLayout = rootLayout;
|
mRootLayout = rootLayout;
|
||||||
mInflater = inflater;
|
mContext = context;
|
||||||
mTriggerList = triggers;
|
mTriggerList = triggers;
|
||||||
build();
|
build();
|
||||||
}
|
}
|
||||||
|
|
||||||
public TriggerListAdapter(LayoutInflater inflater, LinearLayout rootLayout, Trigger trigger) {
|
public TriggerListAdapter(Context context, LinearLayout rootLayout, Trigger trigger) {
|
||||||
mRootLayout = rootLayout;
|
mRootLayout = rootLayout;
|
||||||
mInflater = inflater;
|
mContext = context;
|
||||||
mTriggerList = new ArrayList<>();
|
mTriggerList = new ArrayList<>();
|
||||||
mTriggerList.add(trigger);
|
mTriggerList.add(trigger);
|
||||||
build();
|
build();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
public void destroy() {
|
public void destroy() {
|
||||||
mRootLayout.removeAllViews();
|
mRootLayout.removeAllViews();
|
||||||
for(Trigger trigger : mTriggerList) {
|
}
|
||||||
trigger.destroyViewHolder();
|
|
||||||
}
|
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 build() {
|
private void build() {
|
||||||
|
boolean isFirstItem = true;
|
||||||
for(Trigger trigger : mTriggerList) {
|
for(Trigger trigger : mTriggerList) {
|
||||||
Trigger.ViewHolder viewHolder = trigger.createViewHolder(mInflater);
|
if (!isFirstItem) {
|
||||||
mRootLayout.addView(viewHolder.getView());
|
final TriggerConnector connector = trigger.getConnector();
|
||||||
|
final int initialPosition = connector.getConnectorType().ordinal();
|
||||||
|
Spinner spinner = createSpinner();
|
||||||
|
spinner.setSelection(initialPosition);
|
||||||
|
spinner.setBackgroundColor(MainApp.gc(R.color.black_overlay));
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
params.setMargins(0, MainApp.dpToPx(8), 0, MainApp.dpToPx(8));
|
||||||
|
spinner.setLayoutParams(params);
|
||||||
|
spinner.setOnItemSelectedListener(new AdapterView.OnItemSelectedListener() {
|
||||||
|
@Override
|
||||||
|
public void onItemSelected(AdapterView<?> parent, View view, int position, long id) {
|
||||||
|
if (position != initialPosition) {
|
||||||
|
// conector type changed
|
||||||
|
final TriggerConnector.Type newConnectorType = TriggerConnector.Type.values()[position];
|
||||||
|
|
||||||
|
if (connector.size() > 2) {
|
||||||
|
// split connector
|
||||||
|
int pos = connector.pos(trigger) - 1;
|
||||||
|
|
||||||
|
TriggerConnector newConnector = new TriggerConnector(newConnectorType);
|
||||||
|
{
|
||||||
|
Trigger t = connector.get(pos);
|
||||||
|
newConnector.add(t);
|
||||||
|
connector.remove(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
TriggerConnector subConnector = new TriggerConnector(connector.getConnectorType());
|
||||||
|
int count = connector.size() - pos;
|
||||||
|
for (int i = 0; i < count; ++i) {
|
||||||
|
Trigger t = connector.get(pos);
|
||||||
|
subConnector.add(t);
|
||||||
|
connector.remove(t);
|
||||||
|
}
|
||||||
|
newConnector.add(subConnector);
|
||||||
|
connector.add(newConnector);
|
||||||
|
} else {
|
||||||
|
connector.changeConnectorType(newConnectorType);
|
||||||
|
}
|
||||||
|
|
||||||
|
connector.simplify().rebuildView();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onNothingSelected(AdapterView<?> parent) {
|
||||||
|
|
||||||
|
}
|
||||||
|
});
|
||||||
|
mRootLayout.addView(spinner);
|
||||||
|
} else {
|
||||||
|
isFirstItem = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
mRootLayout.addView(trigger.createView(mContext));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -17,6 +17,7 @@ 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.AutomationFragment;
|
||||||
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
import info.nightscout.androidaps.plugins.general.automation.AutomationPlugin;
|
||||||
|
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerBg;
|
||||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerConnector;
|
||||||
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime;
|
import info.nightscout.androidaps.plugins.general.automation.triggers.TriggerTime;
|
||||||
|
|
||||||
|
@ -50,21 +51,19 @@ public class EditEventDialog extends DialogFragment {
|
||||||
|
|
||||||
// dummy initialization
|
// dummy initialization
|
||||||
TriggerConnector to = new TriggerConnector(TriggerConnector.Type.OR);
|
TriggerConnector to = new TriggerConnector(TriggerConnector.Type.OR);
|
||||||
|
to.add(new TriggerBg());
|
||||||
to.add(new TriggerTime());
|
to.add(new TriggerTime());
|
||||||
to.add(new TriggerTime());
|
mEvent.setTrigger(to);
|
||||||
TriggerConnector ta = new TriggerConnector();
|
|
||||||
ta.add(to);
|
|
||||||
mEvent.setTrigger(ta);
|
|
||||||
|
|
||||||
// display triggers
|
// display triggers
|
||||||
mTriggerListAdapter = new AutomationFragment.TriggerListAdapter(getLayoutInflater(), mLayoutTrigger, mEvent.getTrigger());
|
mTriggerListAdapter = new AutomationFragment.TriggerListAdapter(getContext(), mLayoutTrigger, mEvent.getTrigger());
|
||||||
|
|
||||||
return view;
|
return view;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void onDestroyView() {
|
public void onDestroyView() {
|
||||||
mTriggerListAdapter.destroy();
|
//mTriggerListAdapter.destroy();
|
||||||
mUnbinder.unbind();
|
mUnbinder.unbind();
|
||||||
super.onDestroyView();
|
super.onDestroyView();
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,15 +1,19 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||||
|
|
||||||
import android.support.annotation.LayoutRes;
|
import android.content.Context;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
import butterknife.ButterKnife;
|
import java.util.ArrayList;
|
||||||
import butterknife.Unbinder;
|
import java.util.List;
|
||||||
|
|
||||||
|
import info.nightscout.androidaps.MainApp;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
|
|
||||||
public abstract class Trigger {
|
public abstract class Trigger {
|
||||||
|
@ -61,16 +65,22 @@ public abstract class Trigger {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
protected ViewHolder viewHolder = null;
|
public static List<String> labels() {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for(Comparator c : values()) {
|
||||||
|
list.add(MainApp.gs(c.getStringRes()));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
protected TriggerConnector connector = null;
|
protected TriggerConnector connector = null;
|
||||||
|
|
||||||
Trigger() {
|
Trigger() {
|
||||||
}
|
}
|
||||||
|
|
||||||
public Trigger getConnector() {
|
public TriggerConnector getConnector() {
|
||||||
return connector;
|
return connector;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -99,31 +109,18 @@ public abstract class Trigger {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
public abstract ViewHolder createViewHolder(LayoutInflater inflater);
|
public View createView(Context context) {
|
||||||
|
final int padding = MainApp.dpToPx(4);
|
||||||
|
|
||||||
public ViewHolder getViewHolder() {
|
LinearLayout root = new LinearLayout(context);
|
||||||
return viewHolder;
|
root.setPadding(padding, padding, padding, padding);
|
||||||
}
|
root.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
|
|
||||||
public void destroyViewHolder() {
|
TextView title = new TextView(context);
|
||||||
if (viewHolder != null) {
|
title.setText(friendlyName());
|
||||||
viewHolder.destroy();
|
root.addView(title);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public static abstract class ViewHolder {
|
return root;
|
||||||
final View view;
|
|
||||||
final Unbinder unbinder;
|
|
||||||
|
|
||||||
public ViewHolder(LayoutInflater inflater, @LayoutRes int layout) {
|
|
||||||
view = inflater.inflate(layout, null);
|
|
||||||
unbinder = ButterKnife.bind(this, view);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void destroy() {
|
|
||||||
unbinder.unbind();
|
|
||||||
}
|
|
||||||
|
|
||||||
public View getView() { return view; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,28 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||||
|
|
||||||
import android.view.LayoutInflater;
|
import android.content.Context;
|
||||||
|
import android.text.Editable;
|
||||||
|
import android.text.TextWatcher;
|
||||||
|
import android.view.Gravity;
|
||||||
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.ArrayAdapter;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
import android.widget.Spinner;
|
||||||
|
import android.widget.TextView;
|
||||||
|
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
import org.json.JSONObject;
|
import org.json.JSONObject;
|
||||||
|
|
||||||
|
import java.text.DecimalFormat;
|
||||||
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
import info.nightscout.androidaps.MainApp;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.data.GlucoseStatus;
|
import info.nightscout.androidaps.data.GlucoseStatus;
|
||||||
import info.nightscout.androidaps.data.Profile;
|
import info.nightscout.androidaps.data.Profile;
|
||||||
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
|
import info.nightscout.androidaps.plugins.ConfigBuilder.ProfileFunctions;
|
||||||
import info.nightscout.utils.JsonHelper;
|
import info.nightscout.utils.JsonHelper;
|
||||||
|
import info.nightscout.utils.NumberPicker;
|
||||||
|
|
||||||
public class TriggerBg extends Trigger {
|
public class TriggerBg extends Trigger {
|
||||||
|
|
||||||
|
@ -18,6 +30,21 @@ public class TriggerBg extends Trigger {
|
||||||
protected Comparator comparator = Comparator.IS_EQUAL;
|
protected Comparator comparator = Comparator.IS_EQUAL;
|
||||||
protected String units = ProfileFunctions.getInstance().getProfileUnits();
|
protected String units = ProfileFunctions.getInstance().getProfileUnits();
|
||||||
|
|
||||||
|
final private TextWatcher textWatcher = new TextWatcher() {
|
||||||
|
@Override
|
||||||
|
public void afterTextChanged(Editable s) {
|
||||||
|
// TODO: validate inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void onTextChanged(CharSequence s, int start, int before, int count) {
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean shouldRun() {
|
public synchronized boolean shouldRun() {
|
||||||
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
GlucoseStatus glucoseStatus = GlucoseStatus.getGlucoseStatusData();
|
||||||
|
@ -72,11 +99,6 @@ public class TriggerBg extends Trigger {
|
||||||
return MainApp.gs(R.string.glucosecompared, comparator.getStringRes(), threshold, units);
|
return MainApp.gs(R.string.glucosecompared, comparator.getStringRes(), threshold, units);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
|
||||||
public ViewHolder createViewHolder(LayoutInflater inflater) {
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
TriggerBg threshold(double threshold) {
|
TriggerBg threshold(double threshold) {
|
||||||
this.threshold = threshold;
|
this.threshold = threshold;
|
||||||
return this;
|
return this;
|
||||||
|
@ -91,4 +113,48 @@ public class TriggerBg extends Trigger {
|
||||||
this.units = units;
|
this.units = units;
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
LinearLayout root = (LinearLayout) super.createView(context);
|
||||||
|
|
||||||
|
// spinner for comparator
|
||||||
|
Spinner spinner = new Spinner(context);
|
||||||
|
ArrayAdapter<String> spinnerArrayAdapter = new ArrayAdapter<>(context, android.R.layout.simple_spinner_item, Comparator.labels());
|
||||||
|
spinnerArrayAdapter.setDropDownViewResource(android.R.layout.simple_spinner_dropdown_item);
|
||||||
|
spinner.setAdapter(spinnerArrayAdapter);
|
||||||
|
LinearLayout.LayoutParams spinnerParams = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT,
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT
|
||||||
|
);
|
||||||
|
spinnerParams.setMargins(0, MainApp.dpToPx(4), 0, MainApp.dpToPx(4));
|
||||||
|
spinner.setLayoutParams(spinnerParams);
|
||||||
|
root.addView(spinner);
|
||||||
|
|
||||||
|
// horizontal layout
|
||||||
|
LinearLayout layout = new LinearLayout(context);
|
||||||
|
layout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
layout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
root.addView(layout);
|
||||||
|
|
||||||
|
// input filed for threshold
|
||||||
|
NumberPicker numberPicker = new NumberPicker(context, null);
|
||||||
|
numberPicker.setParams(0d, 0d, (double) 500, 1d, new DecimalFormat("0"), false, textWatcher);
|
||||||
|
numberPicker.setValue(100.0);
|
||||||
|
layout.addView(numberPicker);
|
||||||
|
|
||||||
|
// text view for unit
|
||||||
|
TextView tvUnits = new TextView(context);
|
||||||
|
LinearLayout.LayoutParams params = new LinearLayout.LayoutParams(
|
||||||
|
LinearLayout.LayoutParams.WRAP_CONTENT,
|
||||||
|
LinearLayout.LayoutParams.MATCH_PARENT
|
||||||
|
);
|
||||||
|
params.setMargins(MainApp.dpToPx(6), 0, 0, 0);
|
||||||
|
tvUnits.setLayoutParams(params);
|
||||||
|
tvUnits.setText(units);
|
||||||
|
tvUnits.setGravity(Gravity.CENTER_VERTICAL);
|
||||||
|
layout.addView(tvUnits);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,10 +1,11 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.view.LayoutInflater;
|
|
||||||
import android.view.View;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.Button;
|
||||||
import android.widget.LinearLayout;
|
import android.widget.LinearLayout;
|
||||||
import android.widget.TextView;
|
|
||||||
|
|
||||||
import org.json.JSONArray;
|
import org.json.JSONArray;
|
||||||
import org.json.JSONException;
|
import org.json.JSONException;
|
||||||
|
@ -13,8 +14,7 @@ import org.json.JSONObject;
|
||||||
import java.util.ArrayList;
|
import java.util.ArrayList;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import butterknife.BindView;
|
import info.nightscout.androidaps.MainApp;
|
||||||
import butterknife.OnClick;
|
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.androidaps.plugins.general.automation.AutomationFragment;
|
import info.nightscout.androidaps.plugins.general.automation.AutomationFragment;
|
||||||
import info.nightscout.utils.JsonHelper;
|
import info.nightscout.utils.JsonHelper;
|
||||||
|
@ -22,7 +22,8 @@ import info.nightscout.utils.JsonHelper;
|
||||||
public class TriggerConnector extends Trigger {
|
public class TriggerConnector extends Trigger {
|
||||||
public enum Type {
|
public enum Type {
|
||||||
AND,
|
AND,
|
||||||
OR;
|
OR,
|
||||||
|
XOR;
|
||||||
|
|
||||||
public boolean apply(boolean a, boolean b) {
|
public boolean apply(boolean a, boolean b) {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
|
@ -30,6 +31,8 @@ public class TriggerConnector extends Trigger {
|
||||||
return a && b;
|
return a && b;
|
||||||
case OR:
|
case OR:
|
||||||
return a || b;
|
return a || b;
|
||||||
|
case XOR:
|
||||||
|
return a ^ b;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -38,12 +41,22 @@ public class TriggerConnector extends Trigger {
|
||||||
switch (this) {
|
switch (this) {
|
||||||
case OR:
|
case OR:
|
||||||
return R.string.or;
|
return R.string.or;
|
||||||
|
case XOR:
|
||||||
|
return R.string.xor;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
case AND:
|
case AND:
|
||||||
return R.string.and;
|
return R.string.and;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static List<String> labels() {
|
||||||
|
List<String> list = new ArrayList<>();
|
||||||
|
for(Type t : values()) {
|
||||||
|
list.add(MainApp.gs(t.getStringRes()));
|
||||||
|
}
|
||||||
|
return list;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
protected List<Trigger> list = new ArrayList<>();
|
protected List<Trigger> list = new ArrayList<>();
|
||||||
|
@ -78,6 +91,13 @@ public class TriggerConnector extends Trigger {
|
||||||
return list.get(i);
|
return list.get(i);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public int pos(Trigger trigger) {
|
||||||
|
for(int i = 0; i < list.size(); ++i) {
|
||||||
|
if (list.get(i) == trigger) return i;
|
||||||
|
}
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public synchronized boolean shouldRun() {
|
public synchronized boolean shouldRun() {
|
||||||
boolean result = false;
|
boolean result = false;
|
||||||
|
@ -139,67 +159,104 @@ public class TriggerConnector extends Trigger {
|
||||||
return result.toString();
|
return result.toString();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private AutomationFragment.TriggerListAdapter adapter;
|
||||||
public ViewHolder createViewHolder(LayoutInflater inflater) {
|
|
||||||
ViewHolder v = new ViewHolder(inflater);
|
public void rebuildView() {
|
||||||
viewHolder = v;
|
if (adapter != null)
|
||||||
return v;
|
adapter.rebuild();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
final int padding = MainApp.dpToPx(5);
|
||||||
|
|
||||||
class ViewHolder extends Trigger.ViewHolder {
|
LinearLayout root = new LinearLayout(context);
|
||||||
|
root.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
root.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.MATCH_PARENT));
|
||||||
|
root.setPadding(padding,padding,padding,padding);
|
||||||
|
root.setBackgroundResource(R.drawable.border_automation_unit);
|
||||||
|
|
||||||
@BindView(R.id.triggerListLayout)
|
LinearLayout triggerListLayout = new LinearLayout(context);
|
||||||
LinearLayout triggerListLayout;
|
triggerListLayout.setOrientation(LinearLayout.VERTICAL);
|
||||||
|
triggerListLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
root.addView(triggerListLayout);
|
||||||
|
|
||||||
@BindView(R.id.title)
|
adapter = new AutomationFragment.TriggerListAdapter(context, triggerListLayout, list);
|
||||||
TextView titleView;
|
|
||||||
|
|
||||||
AutomationFragment.TriggerListAdapter adapter;
|
LinearLayout buttonLayout = new LinearLayout(context);
|
||||||
|
buttonLayout.setOrientation(LinearLayout.HORIZONTAL);
|
||||||
|
buttonLayout.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
root.addView(buttonLayout);
|
||||||
|
|
||||||
public ViewHolder(LayoutInflater inflater) {
|
Button buttonRemove = new Button(context);
|
||||||
super(inflater, R.layout.automation_trigger_connector);
|
buttonRemove.setText("-");
|
||||||
titleView.setText(friendlyName());
|
buttonRemove.setOnClickListener(v -> {
|
||||||
adapter = new AutomationFragment.TriggerListAdapter(inflater, triggerListLayout, list);
|
|
||||||
}
|
|
||||||
|
|
||||||
@OnClick(R.id.buttonRemove)
|
|
||||||
public void onButtonClickRemove(View view) {
|
|
||||||
if (connector != null) {
|
if (connector != null) {
|
||||||
connector.remove(TriggerConnector.this);
|
connector.remove(TriggerConnector.this);
|
||||||
((TriggerConnector.ViewHolder)connector.getViewHolder()).adapter.rebuild();
|
connector.simplify();
|
||||||
|
connector.adapter.rebuild();
|
||||||
} else {
|
} else {
|
||||||
// no parent
|
// no parent
|
||||||
list.clear();
|
list.clear();
|
||||||
|
simplify();
|
||||||
adapter.rebuild();
|
adapter.rebuild();
|
||||||
}
|
}
|
||||||
|
});
|
||||||
|
buttonLayout.addView(buttonRemove);
|
||||||
|
|
||||||
|
Button buttonAdd = new Button(context);
|
||||||
|
buttonAdd.setText("+");
|
||||||
|
buttonAdd.setOnClickListener(v -> {
|
||||||
|
addTrigger(adapter, new TriggerTime(), getConnectorType());
|
||||||
|
});
|
||||||
|
buttonLayout.addView(buttonAdd);
|
||||||
|
|
||||||
|
return root;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void addTrigger(AutomationFragment.TriggerListAdapter adapter, Trigger trigger, Type connection) {
|
||||||
|
if (getConnectorType().equals(connection)) {
|
||||||
|
add(trigger);
|
||||||
|
} else {
|
||||||
|
TriggerConnector t = new TriggerConnector(connection);
|
||||||
|
t.add(trigger);
|
||||||
|
add(t);
|
||||||
|
}
|
||||||
|
adapter.rebuild();
|
||||||
|
}
|
||||||
|
|
||||||
|
public TriggerConnector simplify() {
|
||||||
|
// simplify children
|
||||||
|
for(int i = 0; i < size(); ++i) {
|
||||||
|
if (get(i) instanceof TriggerConnector) {
|
||||||
|
TriggerConnector t = (TriggerConnector) get(i);
|
||||||
|
t.simplify();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@OnClick(R.id.buttonAddAnd)
|
// drop connector with only 1 element
|
||||||
public void onButtonClickAnd(View view) {
|
if (size() == 1 && get(0) instanceof TriggerConnector) {
|
||||||
addTrigger(new TriggerTime(), Type.AND);
|
TriggerConnector c = (TriggerConnector) get(0);
|
||||||
}
|
remove(c);
|
||||||
|
changeConnectorType(c.getConnectorType());
|
||||||
@OnClick(R.id.buttonAddOr)
|
for (Trigger t : c.list) {
|
||||||
public void onButtonClickOr(View view) {
|
|
||||||
addTrigger(new TriggerTime(), Type.OR);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void addTrigger(Trigger trigger, Type connection) {
|
|
||||||
if (getConnectorType().equals(connection)) {
|
|
||||||
add(trigger);
|
|
||||||
} else {
|
|
||||||
TriggerConnector t = new TriggerConnector(connection);
|
|
||||||
t.add(trigger);
|
|
||||||
add(t);
|
add(t);
|
||||||
}
|
}
|
||||||
adapter.rebuild();
|
c.list.clear();
|
||||||
|
return simplify();
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
// merge connectors
|
||||||
public void destroy() {
|
if (connector != null && (connector.getConnectorType().equals(connectorType) || size() == 1)) {
|
||||||
adapter.destroy();
|
connector.remove(this);
|
||||||
super.destroy();
|
for (Trigger t : list) {
|
||||||
|
connector.add(t);
|
||||||
|
}
|
||||||
|
list.clear();
|
||||||
|
return connector.simplify();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
package info.nightscout.androidaps.plugins.general.automation.triggers;
|
||||||
|
|
||||||
|
import android.content.Context;
|
||||||
import android.support.annotation.StringRes;
|
import android.support.annotation.StringRes;
|
||||||
import android.view.LayoutInflater;
|
import android.view.View;
|
||||||
|
import android.view.ViewGroup;
|
||||||
|
import android.widget.LinearLayout;
|
||||||
|
|
||||||
import com.dpro.widgets.WeekdaysPicker;
|
import com.dpro.widgets.WeekdaysPicker;
|
||||||
|
|
||||||
|
@ -12,7 +15,6 @@ import java.util.ArrayList;
|
||||||
import java.util.Calendar;
|
import java.util.Calendar;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
|
|
||||||
import butterknife.BindView;
|
|
||||||
import info.nightscout.androidaps.MainApp;
|
import info.nightscout.androidaps.MainApp;
|
||||||
import info.nightscout.androidaps.R;
|
import info.nightscout.androidaps.R;
|
||||||
import info.nightscout.utils.DateUtil;
|
import info.nightscout.utils.DateUtil;
|
||||||
|
@ -97,7 +99,7 @@ public class TriggerTime extends Trigger {
|
||||||
|
|
||||||
public TriggerTime() {
|
public TriggerTime() {
|
||||||
for(DayOfWeek day : DayOfWeek.values()) {
|
for(DayOfWeek day : DayOfWeek.values()) {
|
||||||
set(day, true);
|
set(day, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -231,34 +233,27 @@ public class TriggerTime extends Trigger {
|
||||||
return this;
|
return this;
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
private List<Integer> getSelectedDays() {
|
||||||
public ViewHolder createViewHolder(LayoutInflater inflater) {
|
List<Integer> selectedDays = new ArrayList<>();
|
||||||
ViewHolder v = new ViewHolder(inflater);
|
for(int i = 0; i < weekdays.length; ++i) {
|
||||||
viewHolder = v;
|
DayOfWeek day = DayOfWeek.values()[i];
|
||||||
return v;
|
boolean selected = weekdays[i];
|
||||||
}
|
if (selected) selectedDays.add(day.toCalendarInt());
|
||||||
|
|
||||||
class ViewHolder extends Trigger.ViewHolder {
|
|
||||||
|
|
||||||
@BindView(R.id.weekdays)
|
|
||||||
WeekdaysPicker weekdaysPicker;
|
|
||||||
|
|
||||||
public ViewHolder(LayoutInflater inflater) {
|
|
||||||
super(inflater, R.layout.automation_trigger_time);
|
|
||||||
|
|
||||||
List<Integer> selectedDays = new ArrayList<>();
|
|
||||||
for(int i = 0; i < weekdays.length; ++i) {
|
|
||||||
DayOfWeek day = DayOfWeek.values()[i];
|
|
||||||
boolean selected = weekdays[i];
|
|
||||||
if (selected) selectedDays.add(day.toCalendarInt());
|
|
||||||
}
|
|
||||||
weekdaysPicker.setSelectedDays(selectedDays);
|
|
||||||
|
|
||||||
weekdaysPicker.setOnWeekdaysChangeListener((view, i, list) -> {
|
|
||||||
set(DayOfWeek.fromCalendarInt(i), list.contains(i));
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
return selectedDays;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public View createView(Context context) {
|
||||||
|
LinearLayout root = (LinearLayout) super.createView(context);
|
||||||
|
|
||||||
|
WeekdaysPicker weekdaysPicker = new WeekdaysPicker(context);
|
||||||
|
weekdaysPicker.setEditable(true);
|
||||||
|
weekdaysPicker.setSelectedDays(getSelectedDays());
|
||||||
|
weekdaysPicker.setOnWeekdaysChangeListener((view, i, list) -> set(DayOfWeek.fromCalendarInt(i), list.contains(i)));
|
||||||
|
weekdaysPicker.setLayoutParams(new LinearLayout.LayoutParams(ViewGroup.LayoutParams.MATCH_PARENT, ViewGroup.LayoutParams.WRAP_CONTENT));
|
||||||
|
|
||||||
|
root.addView(weekdaysPicker);
|
||||||
|
return root;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -2,6 +2,6 @@
|
||||||
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
<shape xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:shape="rectangle">
|
android:shape="rectangle">
|
||||||
<stroke
|
<stroke
|
||||||
android:width="5dip"
|
android:width="3dip"
|
||||||
android:color="@android:color/white" />
|
android:color="@android:color/white" />
|
||||||
</shape>
|
</shape>
|
|
@ -5,6 +5,10 @@
|
||||||
android:layout_height="match_parent"
|
android:layout_height="match_parent"
|
||||||
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
tools:context="info.nightscout.androidaps.plugins.general.automation.dialogs.EditEventDialog">
|
||||||
|
|
||||||
|
<ScrollView
|
||||||
|
android:layout_width="wrap_content"
|
||||||
|
android:layout_height="wrap_content">
|
||||||
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
||||||
android:layout_width="match_parent"
|
android:layout_width="match_parent"
|
||||||
android:layout_height="wrap_content"
|
android:layout_height="wrap_content"
|
||||||
|
@ -28,4 +32,6 @@
|
||||||
|
|
||||||
</LinearLayout>
|
</LinearLayout>
|
||||||
|
|
||||||
|
</ScrollView>
|
||||||
|
|
||||||
</FrameLayout>
|
</FrameLayout>
|
|
@ -1,46 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout
|
|
||||||
xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
android:orientation="vertical"
|
|
||||||
android:padding="8dp"
|
|
||||||
android:background="@drawable/border_automation_unit">
|
|
||||||
|
|
||||||
<TextView
|
|
||||||
android:id="@+id/title"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:id="@+id/triggerListLayout"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="vertical"/>
|
|
||||||
|
|
||||||
<LinearLayout
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
android:orientation="horizontal">
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/buttonAddAnd"
|
|
||||||
android:text="@string/and"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/buttonAddOr"
|
|
||||||
android:text="@string/or"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
<Button
|
|
||||||
android:id="@+id/buttonRemove"
|
|
||||||
android:text="-"
|
|
||||||
android:layout_width="wrap_content"
|
|
||||||
android:layout_height="wrap_content" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1,14 +0,0 @@
|
||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="match_parent"
|
|
||||||
xmlns:app="http://schemas.android.com/apk/res-auto"
|
|
||||||
android:orientation="vertical">
|
|
||||||
|
|
||||||
<com.dpro.widgets.WeekdaysPicker
|
|
||||||
android:id="@+id/weekdays"
|
|
||||||
android:layout_width="match_parent"
|
|
||||||
android:layout_height="wrap_content"
|
|
||||||
app:sunday_first_day="false" />
|
|
||||||
|
|
||||||
</LinearLayout>
|
|
|
@ -1224,6 +1224,7 @@
|
||||||
<string name="glucosecompared">Glucose %1$s %2$.2f %3$s</string>
|
<string name="glucosecompared">Glucose %1$s %2$.2f %3$s</string>
|
||||||
<string name="and">And</string>
|
<string name="and">And</string>
|
||||||
<string name="or">Or</string>
|
<string name="or">Or</string>
|
||||||
|
<string name="xor">Exclusive or</string>
|
||||||
<string name="atspecifiedtime">At %1$s</string>
|
<string name="atspecifiedtime">At %1$s</string>
|
||||||
<string name="use_network_location">Use network location</string>
|
<string name="use_network_location">Use network location</string>
|
||||||
<string name="use_gps_location">Use GPS location</string>
|
<string name="use_gps_location">Use GPS location</string>
|
||||||
|
|
Loading…
Reference in a new issue