NumberPicker -> kt

This commit is contained in:
Milos Kozak 2021-11-23 19:53:45 +01:00
parent ae573de63d
commit 68793233e8
18 changed files with 330 additions and 376 deletions

View file

@ -1,5 +1,6 @@
package info.nightscout.androidaps.activities package info.nightscout.androidaps.activities
import android.annotation.SuppressLint
import android.content.res.ColorStateList import android.content.res.ColorStateList
import android.os.Bundle import android.os.Bundle
import android.text.Editable import android.text.Editable
@ -168,7 +169,8 @@ class ProfileHelperActivity : NoSplashAppCompatActivity() {
binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null) binding.basalpctfromtdd.setParams(32.0, 32.0, 37.0, 1.0, DecimalFormat("0"), false, null)
binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress); @SuppressLint("SetTextI18n")
binding.tdds.text = getString(R.string.tdd) + ": " + rh.gs(R.string.calculation_in_progress)
Thread { Thread {
val tdds = tddCalculator.stats() val tdds = tddCalculator.stats()
runOnUiThread { binding.tdds.text = tdds } runOnUiThread { binding.tdds.text = tdds }

View file

@ -76,7 +76,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val unitLabel = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl) val unitLabel = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val bg = binding.bg.value ?: return false val bg = binding.bg.value
actions.add(rh.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, bg) + " " + unitLabel) actions.add(rh.gs(R.string.treatments_wizard_bg_label) + ": " + Profile.toCurrentUnitsString(profileFunction, bg) + " " + unitLabel)
if (bg > 0) { if (bg > 0) {
activity?.let { activity -> activity?.let { activity ->

View file

@ -189,7 +189,7 @@ class CarbsDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false if (_binding == null) return false
val carbs = binding.carbs.value?.toInt() ?: return false val carbs = binding.carbs.value.toInt()
val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value() val carbsAfterConstraints = constraintChecker.applyCarbsConstraints(Constraint(carbs)).value()
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
val activityTTDuration = defaultValueHelper.determineActivityTTDuration() val activityTTDuration = defaultValueHelper.determineActivityTTDuration()

View file

@ -79,7 +79,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false if (_binding == null) return false
val insulin = SafeParse.stringToDouble(binding.insulin.text ?: return false) val insulin = SafeParse.stringToDouble(binding.insulin.text)
val durationInMinutes = binding.duration.value.toInt() val durationInMinutes = binding.duration.value.toInt()
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()

View file

@ -106,7 +106,7 @@ class FillDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false if (_binding == null) return false
val insulin = SafeParse.stringToDouble(binding.fillInsulinamount.text ?: return false) val insulin = SafeParse.stringToDouble(binding.fillInsulinamount.text)
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()

View file

@ -149,7 +149,7 @@ class InsulinDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false if (_binding == null) return false
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
val insulin = SafeParse.stringToDouble(binding.amount.text ?: return false) val insulin = SafeParse.stringToDouble(binding.amount.text)
val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value() val insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
val units = profileFunction.getUnits() val units = profileFunction.getUnits()

View file

@ -162,7 +162,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
?: return false ?: return false
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
val duration = binding.duration.value?.toInt() ?: return false val duration = binding.duration.value.toInt()
if (duration > 0L) if (duration > 0L)
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, duration)) actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, duration))
val profileName = binding.profile.selectedItem.toString() val profileName = binding.profile.selectedItem.toString()

View file

@ -47,8 +47,8 @@ class TempBasalDialog : DialogFragmentWithDate() {
override fun onSaveInstanceState(savedInstanceState: Bundle) { override fun onSaveInstanceState(savedInstanceState: Bundle) {
super.onSaveInstanceState(savedInstanceState) super.onSaveInstanceState(savedInstanceState)
savedInstanceState.putDouble("duration", binding.duration.value) savedInstanceState.putDouble("duration", binding.duration.value)
savedInstanceState.putDouble("basalpercentinput", binding.basalpercentinput.value) savedInstanceState.putDouble("basalPercentInput", binding.basalPercentInput.value)
savedInstanceState.putDouble("basalabsoluteinput", binding.basalabsoluteinput.value) savedInstanceState.putDouble("basalAbsoluteInput", binding.basalAbsoluteInput.value)
} }
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?, override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
@ -67,10 +67,10 @@ class TempBasalDialog : DialogFragmentWithDate() {
val maxTempPercent = pumpDescription.maxTempPercent.toDouble() val maxTempPercent = pumpDescription.maxTempPercent.toDouble()
val tempPercentStep = pumpDescription.tempPercentStep.toDouble() val tempPercentStep = pumpDescription.tempPercentStep.toDouble()
binding.basalpercentinput.setParams(savedInstanceState?.getDouble("basalpercentinput") binding.basalPercentInput.setParams(savedInstanceState?.getDouble("basalPercentInput")
?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, binding.okcancel.ok) ?: 100.0, 0.0, maxTempPercent, tempPercentStep, DecimalFormat("0"), true, binding.okcancel.ok)
binding.basalabsoluteinput.setParams(savedInstanceState?.getDouble("basalabsoluteinput") binding.basalAbsoluteInput.setParams(savedInstanceState?.getDouble("basalAbsoluteInput")
?: profile.getBasal(), 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, binding.okcancel.ok) ?: profile.getBasal(), 0.0, pumpDescription.maxTempAbsolute, pumpDescription.tempAbsoluteStep, DecimalFormat("0.00"), true, binding.okcancel.ok)
val tempDurationStep = pumpDescription.tempDurationStep.toDouble() val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
@ -97,17 +97,17 @@ class TempBasalDialog : DialogFragmentWithDate() {
if (_binding == null) return false if (_binding == null) return false
var percent = 0 var percent = 0
var absolute = 0.0 var absolute = 0.0
val durationInMinutes = binding.duration.value?.toInt() ?: return false val durationInMinutes = binding.duration.value.toInt()
val profile = profileFunction.getProfile() ?: return false val profile = profileFunction.getProfile() ?: return false
val actions: LinkedList<String> = LinkedList() val actions: LinkedList<String> = LinkedList()
if (isPercentPump) { if (isPercentPump) {
val basalPercentInput = SafeParse.stringToInt(binding.basalpercentinput.text) val basalPercentInput = SafeParse.stringToInt(binding.basalPercentInput.text)
percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value() percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
actions.add(rh.gs(R.string.tempbasal_label) + ": $percent%") actions.add(rh.gs(R.string.tempbasal_label) + ": $percent%")
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes)) actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
if (percent != basalPercentInput) actions.add(rh.gs(R.string.constraintapllied)) if (percent != basalPercentInput) actions.add(rh.gs(R.string.constraintapllied))
} else { } else {
val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalabsoluteinput.text) val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalAbsoluteInput.text)
absolute = constraintChecker.applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value() absolute = constraintChecker.applyBasalConstraints(Constraint(basalAbsoluteInput), profile).value()
actions.add(rh.gs(R.string.tempbasal_label) + ": " + rh.gs(R.string.pump_basebasalrate, absolute)) actions.add(rh.gs(R.string.tempbasal_label) + ": " + rh.gs(R.string.pump_basebasalrate, absolute))
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes)) actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))

View file

@ -115,7 +115,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
override fun submit(): Boolean { override fun submit(): Boolean {
if (_binding == null) return false if (_binding == null) return false
val pumpDescription = activePlugin.activePump.pumpDescription val pumpDescription = activePlugin.activePump.pumpDescription
val insulin = SafeParse.stringToDouble(binding.insulin.text ?: return false) val insulin = SafeParse.stringToDouble(binding.insulin.text)
val carbs = SafeParse.stringToInt(binding.carbs.text) val carbs = SafeParse.stringToInt(binding.carbs.text)
val recordOnlyChecked = binding.recordOnly.isChecked val recordOnlyChecked = binding.recordOnly.isChecked
val actions: LinkedList<String?> = LinkedList() val actions: LinkedList<String?> = LinkedList()
@ -139,7 +139,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
OKDialog.showConfirmation(activity, rh.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), { OKDialog.showConfirmation(activity, rh.gs(R.string.overview_treatment_label), HtmlHelper.fromHtml(Joiner.on("<br/>").join(actions)), {
val action = when { val action = when {
insulinAfterConstraints.equals(0.0) -> Action.CARBS insulinAfterConstraints.equals(0.0) -> Action.CARBS
carbsAfterConstraints.equals(0) -> Action.BOLUS carbsAfterConstraints == 0 -> Action.BOLUS
else -> Action.TREATMENT else -> Action.TREATMENT
} }
val detailedBolusInfo = DetailedBolusInfo() val detailedBolusInfo = DetailedBolusInfo()

View file

@ -258,10 +258,7 @@ class WizardDialog : DaggerDialogFragment() {
val units = profileFunction.getUnits() val units = profileFunction.getUnits()
binding.bgunits.text = units.asText binding.bgunits.text = units.asText
if (units == GlucoseUnit.MGDL) binding.bgInput.step = if (units == GlucoseUnit.MGDL) 1.0 else 0.1
binding.bgInput.setStep(1.0)
else
binding.bgInput.setStep(0.1)
// Set BG if not old // Set BG if not old
binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0 binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0

View file

@ -65,7 +65,7 @@ class LocalProfileFragment : DaggerFragment() {
override fun afterTextChanged(s: Editable) {} override fun afterTextChanged(s: Editable) {}
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {} override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) { override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {
localProfilePlugin.currentProfile()?.dia = SafeParse.stringToDouble(binding.dia.text.toString()) localProfilePlugin.currentProfile()?.dia = SafeParse.stringToDouble(binding.dia.text)
localProfilePlugin.currentProfile()?.name = binding.name.text.toString() localProfilePlugin.currentProfile()?.name = binding.name.text.toString()
doEdit() doEdit()
} }

View file

@ -5,10 +5,7 @@ import android.util.AttributeSet
import android.view.LayoutInflater import android.view.LayoutInflater
import info.nightscout.androidaps.R import info.nightscout.androidaps.R
class NumberPickerVertical : NumberPicker { class NumberPickerVertical(context: Context, attrs: AttributeSet? = null) : NumberPicker(context, attrs) {
constructor(context: Context?) : super(context)
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
override fun inflate(context: Context) { override fun inflate(context: Context) {
LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true) LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true)

View file

@ -64,7 +64,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/basalpercentinput" android:id="@+id/basal_percent_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" /> android:layout_height="40dp" />
@ -98,7 +98,7 @@
android:textStyle="bold" /> android:textStyle="bold" />
<info.nightscout.androidaps.utils.ui.NumberPicker <info.nightscout.androidaps.utils.ui.NumberPicker
android:id="@+id/basalabsoluteinput" android:id="@+id/basal_absolute_input"
android:layout_width="130dp" android:layout_width="130dp"
android:layout_height="40dp" /> android:layout_height="40dp" />

View file

@ -34,6 +34,7 @@ public class ToastUtils {
graphicalToast(ctx, string, R.drawable.ic_toast_info, false); graphicalToast(ctx, string, R.drawable.ic_toast_info, false);
} }
@SuppressWarnings("unused")
public static void okToast(final Context ctx, final String string) { public static void okToast(final Context ctx, final String string) {
graphicalToast(ctx, string, R.drawable.ic_toast_check, false); graphicalToast(ctx, string, R.drawable.ic_toast_check, false);
} }

View file

@ -13,16 +13,16 @@ class MinutesNumberPicker constructor(context: Context, attrs: AttributeSet? = n
} }
override fun updateEditText() { override fun updateEditText() {
if (value == 0.0 && !allowZero) editText.setText("") if (currentValue == 0.0 && !allowZero) editText?.setText("")
else { else {
if (focused) editText.setText(DecimalFormat("0").format(value)) if (focused) editText?.setText(DecimalFormat("0").format(currentValue))
else { else {
val hours = (value / 60).toInt() val hours = (currentValue / 60).toInt()
val minutes = (value - hours * 60).toInt() val minutes = (currentValue - hours * 60).toInt()
val formatted = val formatted =
if (hours != 0) String.format(context.getString(R.string.format_hour_minute), hours, minutes) if (hours != 0) String.format(context.getString(R.string.format_hour_minute), hours, minutes)
else DecimalFormat("0").format(value) else DecimalFormat("0").format(currentValue)
editText.setText(formatted) editText?.setText(formatted)
} }
} }
} }

View file

@ -1,343 +0,0 @@
package info.nightscout.androidaps.utils.ui;
import android.app.Service;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
import android.text.Editable;
import android.text.TextWatcher;
import android.util.AttributeSet;
import android.view.KeyEvent;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.View;
import android.view.inputmethod.InputMethodManager;
import android.widget.Button;
import android.widget.EditText;
import android.widget.LinearLayout;
import java.text.NumberFormat;
import java.util.concurrent.Executors;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.TimeUnit;
import info.nightscout.androidaps.core.R;
import info.nightscout.androidaps.utils.SafeParse;
import info.nightscout.androidaps.utils.ToastUtils;
public class NumberPicker extends LinearLayout implements View.OnKeyListener,
View.OnTouchListener, View.OnClickListener {
public interface OnValueChangedListener {
void onValueChanged(double value);
}
EditText editText;
Button minusButton;
Button plusButton;
double value = 0;
double minValue = 0d;
double maxValue = 1d;
double step = 1d;
NumberFormat formatter;
boolean allowZero = false;
TextWatcher textWatcher = null;
Button okButton = null;
protected Boolean focused = false;
private Handler mHandler;
private ScheduledExecutorService mUpdater;
private OnValueChangedListener mOnValueChangedListener;
private class UpdateCounterTask implements Runnable {
private final boolean mInc;
private int repeated = 0;
private int multiplier = 1;
private final int doubleLimit = 5;
UpdateCounterTask(boolean inc) {
mInc = inc;
}
public void run() {
Message msg = new Message();
if (repeated % doubleLimit == 0) multiplier *= 2;
repeated++;
msg.arg1 = multiplier;
msg.arg2 = repeated;
if (mInc) {
msg.what = MSG_INC;
} else {
msg.what = MSG_DEC;
}
mHandler.sendMessage(msg);
}
}
private static final int MSG_INC = 0;
private static final int MSG_DEC = 1;
public NumberPicker(Context context) {
super(context, null);
this.initialize(context);
}
public NumberPicker(Context context, AttributeSet attrs) {
super(context, attrs);
this.initialize(context);
}
protected void inflate(Context context) {
LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true);
}
protected void initialize(Context context) {
// set layout view
inflate(context);
// init ui components
minusButton = findViewById(R.id.decrement);
minusButton.setId(View.generateViewId());
plusButton = findViewById(R.id.increment);
plusButton.setId(View.generateViewId());
editText = findViewById(R.id.display);
editText.setId(View.generateViewId());
mHandler = new Handler(msg -> {
switch (msg.what) {
case MSG_INC:
inc(msg.arg1);
return true;
case MSG_DEC:
dec(msg.arg1);
return true;
}
return false;
});
minusButton.setOnTouchListener(this);
minusButton.setOnKeyListener(this);
minusButton.setOnClickListener(this);
plusButton.setOnTouchListener(this);
plusButton.setOnKeyListener(this);
plusButton.setOnClickListener(this);
setTextWatcher(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
if (focused) value = SafeParse.stringToDouble(editText.getText().toString());
callValueChangedListener();
if (okButton != null) {
if (value > maxValue || value < minValue)
okButton.setVisibility(INVISIBLE);
else
okButton.setVisibility(VISIBLE);
}
}
});
editText.setOnFocusChangeListener((v, hasFocus) -> {
focused = hasFocus;
if (!focused) getValue(); // check min/max
updateEditText();
});
}
@Override
public void setTag(Object tag) {
editText.setTag(tag);
}
public void setOnValueChangedListener(OnValueChangedListener onValueChangedListener) {
mOnValueChangedListener = onValueChangedListener;
}
public void setTextWatcher(TextWatcher textWatcher) {
this.textWatcher = textWatcher;
editText.addTextChangedListener(textWatcher);
editText.setOnFocusChangeListener((v, hasFocus) -> {
if (!hasFocus) {
value = SafeParse.stringToDouble(editText.getText().toString());
if (value > maxValue) {
value = maxValue;
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
updateEditText();
if (okButton != null)
okButton.setVisibility(VISIBLE);
}
if (value < minValue) {
value = minValue;
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
updateEditText();
if (okButton != null)
okButton.setVisibility(VISIBLE);
}
}
});
}
public void setParams(Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formatter, boolean allowZero, Button okButton, TextWatcher textWatcher) {
if (this.textWatcher != null) {
editText.removeTextChangedListener(this.textWatcher);
}
setParams(initValue, minValue, maxValue, step, formatter, allowZero, okButton);
this.textWatcher = textWatcher;
if (textWatcher != null)
editText.addTextChangedListener(textWatcher);
}
public void setParams(Double initValue, Double minValue, Double maxValue, Double step, NumberFormat formatter, boolean allowZero, Button okButton) {
this.value = initValue;
this.minValue = minValue;
this.maxValue = maxValue;
this.step = step;
this.formatter = formatter;
this.allowZero = allowZero;
callValueChangedListener();
this.okButton = okButton;
editText.setKeyListener(DigitsKeyListenerWithComma.getInstance(minValue < 0, step != Math.rint(step)));
if (textWatcher != null)
editText.removeTextChangedListener(textWatcher);
updateEditText();
if (textWatcher != null)
editText.addTextChangedListener(textWatcher);
}
public void setValue(Double value) {
if (textWatcher != null)
editText.removeTextChangedListener(textWatcher);
this.value = value;
callValueChangedListener();
updateEditText();
if (textWatcher != null)
editText.addTextChangedListener(textWatcher);
}
public Double getValue() {
if (value > maxValue) {
value = maxValue;
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
}
if (value < minValue) {
value = minValue;
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
}
return value;
}
public String getText() {
return editText.getText().toString();
}
public void setStep(Double step) {
this.step = step;
}
private void inc(int multiplier) {
value += step * multiplier;
if (value > maxValue) {
value = maxValue;
callValueChangedListener();
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
stopUpdating();
}
updateEditText();
}
private void dec(int multiplier) {
value -= step * multiplier;
if (value < minValue) {
value = minValue;
callValueChangedListener();
ToastUtils.showToastInUiThread(getContext(), getContext().getString(R.string.youareonallowedlimit));
stopUpdating();
}
updateEditText();
}
protected void updateEditText() {
if (value == 0d && !allowZero)
editText.setText("");
else
editText.setText(formatter.format(value));
}
private void callValueChangedListener() {
if (mOnValueChangedListener != null)
mOnValueChangedListener.onValueChanged(value);
}
private void startUpdating(boolean inc) {
if (mUpdater != null) {
//log.debug("Another executor is still active");
return;
}
mUpdater = Executors.newSingleThreadScheduledExecutor();
mUpdater.scheduleAtFixedRate(new UpdateCounterTask(inc), 200, 200,
TimeUnit.MILLISECONDS);
}
private void stopUpdating() {
if (mUpdater != null) {
mUpdater.shutdownNow();
mUpdater = null;
}
}
@Override
public void onClick(View v) {
if (mUpdater == null) {
InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Service.INPUT_METHOD_SERVICE);
imm.hideSoftInputFromWindow(editText.getWindowToken(), 0);
editText.clearFocus();
if (v == plusButton) {
inc(1);
} else {
dec(1);
}
}
}
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
boolean isKeyOfInterest = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER;
boolean isReleased = event.getAction() == KeyEvent.ACTION_UP;
boolean isPressed = event.getAction() == KeyEvent.ACTION_DOWN
&& event.getAction() != KeyEvent.ACTION_MULTIPLE;
if (isKeyOfInterest && isReleased) {
stopUpdating();
} else if (isKeyOfInterest && isPressed) {
startUpdating(v == plusButton);
}
return false;
}
@Override
public boolean onTouch(View v, MotionEvent event) {
boolean isReleased = event.getAction() == MotionEvent.ACTION_UP || event.getAction() == MotionEvent.ACTION_CANCEL;
boolean isPressed = event.getAction() == MotionEvent.ACTION_DOWN;
if (isReleased) {
stopUpdating();
} else if (isPressed) {
startUpdating(v == plusButton);
}
return false;
}
}

View file

@ -0,0 +1,299 @@
package info.nightscout.androidaps.utils.ui
import android.annotation.SuppressLint
import android.app.Service
import android.content.Context
import android.os.Handler
import android.os.Looper
import android.os.Message
import android.text.Editable
import android.text.TextWatcher
import android.util.AttributeSet
import android.view.KeyEvent
import android.view.LayoutInflater
import android.view.MotionEvent
import android.view.View
import android.view.View.OnFocusChangeListener
import android.view.View.OnTouchListener
import android.view.inputmethod.InputMethodManager
import android.widget.Button
import android.widget.EditText
import android.widget.LinearLayout
import info.nightscout.androidaps.core.R
import info.nightscout.androidaps.utils.SafeParse
import info.nightscout.androidaps.utils.ToastUtils
import java.text.NumberFormat
import java.util.concurrent.Executors
import java.util.concurrent.ScheduledExecutorService
import java.util.concurrent.TimeUnit
import kotlin.math.round
@SuppressLint("ClickableViewAccessibility")
open class NumberPicker(context: Context, attrs: AttributeSet? = null) : LinearLayout(context, attrs), View.OnKeyListener, OnTouchListener, View.OnClickListener {
fun interface OnValueChangedListener {
fun onValueChanged(value: Double)
}
var editText: EditText? = null
private var minusButton: Button? = null
private var plusButton: Button? = null
var currentValue = 0.0
var minValue = 0.0
var maxValue = 1.0
var step = 1.0
var formatter: NumberFormat? = null
var allowZero = false
private var watcher: TextWatcher? = null
var okButton: Button? = null
protected var focused = false
private var mUpdater: ScheduledExecutorService? = null
private var mOnValueChangedListener: OnValueChangedListener? = null
private var mHandler: Handler = Handler(Looper.getMainLooper(), Handler.Callback { msg: Message ->
when (msg.what) {
MSG_INC -> {
inc(msg.arg1)
return@Callback true
}
MSG_DEC -> {
dec(msg.arg1)
return@Callback true
}
}
false
})
private inner class UpdateCounterTask(private val mInc: Boolean) : Runnable {
private var repeated = 0
private var multiplier = 1
private val doubleLimit = 5
override fun run() {
val msg = Message()
if (repeated % doubleLimit == 0) multiplier *= 2
repeated++
msg.arg1 = multiplier
msg.arg2 = repeated
if (mInc) {
msg.what = MSG_INC
} else {
msg.what = MSG_DEC
}
mHandler.sendMessage(msg)
}
}
protected open fun inflate(context: Context) {
LayoutInflater.from(context).inflate(R.layout.number_picker_layout, this, true)
}
protected fun initialize(context: Context) {
// set layout view
inflate(context)
// init ui components
minusButton = findViewById(R.id.decrement)
minusButton?.id = generateViewId()
plusButton = findViewById(R.id.increment)
plusButton?.id = generateViewId()
editText = findViewById(R.id.display)
editText?.id = generateViewId()
minusButton?.setOnTouchListener(this)
minusButton?.setOnKeyListener(this)
minusButton?.setOnClickListener(this)
plusButton?.setOnTouchListener(this)
plusButton?.setOnKeyListener(this)
plusButton?.setOnClickListener(this)
setTextWatcher(object : TextWatcher {
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
override fun afterTextChanged(s: Editable) {
if (focused) currentValue = SafeParse.stringToDouble(editText?.text.toString())
callValueChangedListener()
if (okButton != null) {
if (currentValue > maxValue || currentValue < minValue) okButton!!.visibility = INVISIBLE else okButton!!.visibility = VISIBLE
}
}
})
editText?.setOnFocusChangeListener { _: View?, hasFocus: Boolean ->
focused = hasFocus
if (!focused) value // check min/max
updateEditText()
}
}
override fun setTag(tag: Any) {
editText?.tag = tag
}
fun setOnValueChangedListener(onValueChangedListener: OnValueChangedListener?) {
mOnValueChangedListener = onValueChangedListener
}
fun setTextWatcher(textWatcher: TextWatcher) {
watcher = textWatcher
editText?.addTextChangedListener(textWatcher)
editText?.onFocusChangeListener = OnFocusChangeListener { _: View?, hasFocus: Boolean ->
if (!hasFocus) {
currentValue = SafeParse.stringToDouble(editText?.text.toString())
if (currentValue > maxValue) {
currentValue = maxValue
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
updateEditText()
if (okButton != null) okButton?.visibility = VISIBLE
}
if (currentValue < minValue) {
currentValue = minValue
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
updateEditText()
if (okButton != null) okButton?.visibility = VISIBLE
}
}
}
}
fun setParams(initValue: Double, minValue: Double, maxValue: Double, step: Double, formatter: NumberFormat?, allowZero: Boolean, okButton: Button?, textWatcher: TextWatcher?) {
if (watcher != null) {
editText?.removeTextChangedListener(watcher)
}
setParams(initValue, minValue, maxValue, step, formatter, allowZero, okButton)
watcher = textWatcher
if (textWatcher != null) editText?.addTextChangedListener(textWatcher)
}
fun setParams(initValue: Double, minValue: Double, maxValue: Double, step: Double, formatter: NumberFormat?, allowZero: Boolean, okButton: Button?) {
currentValue = initValue
this.minValue = minValue
this.maxValue = maxValue
this.step = step
this.formatter = formatter
this.allowZero = allowZero
callValueChangedListener()
this.okButton = okButton
editText?.keyListener = DigitsKeyListenerWithComma.getInstance(minValue < 0, step != round(step))
if (watcher != null) editText?.removeTextChangedListener(watcher)
updateEditText()
if (watcher != null) editText?.addTextChangedListener(watcher)
}
var value: Double
get() {
if (currentValue > maxValue) {
currentValue = maxValue
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
}
if (currentValue < minValue) {
currentValue = minValue
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
}
return currentValue
}
set(value) {
if (watcher != null) editText?.removeTextChangedListener(watcher)
currentValue = value
callValueChangedListener()
updateEditText()
if (watcher != null) editText?.addTextChangedListener(watcher)
}
val text: String
get() = editText?.text.toString()
private fun inc(multiplier: Int) {
currentValue += step * multiplier
if (currentValue > maxValue) {
currentValue = maxValue
callValueChangedListener()
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
stopUpdating()
}
updateEditText()
}
private fun dec(multiplier: Int) {
currentValue -= step * multiplier
if (currentValue < minValue) {
currentValue = minValue
callValueChangedListener()
ToastUtils.showToastInUiThread(context, context.getString(R.string.youareonallowedlimit))
stopUpdating()
}
updateEditText()
}
protected open fun updateEditText() {
if (currentValue == 0.0 && !allowZero) editText?.setText("") else editText?.setText(formatter?.format(currentValue))
}
private fun callValueChangedListener() {
if (mOnValueChangedListener != null) mOnValueChangedListener?.onValueChanged(currentValue)
}
private fun startUpdating(inc: Boolean) {
if (mUpdater != null) {
//log.debug("Another executor is still active");
return
}
mUpdater = Executors.newSingleThreadScheduledExecutor()
mUpdater?.scheduleAtFixedRate(
UpdateCounterTask(inc), 200, 200,
TimeUnit.MILLISECONDS
)
}
private fun stopUpdating() {
if (mUpdater != null) {
mUpdater?.shutdownNow()
mUpdater = null
}
}
override fun onClick(v: View) {
if (mUpdater == null) {
val imm = context.getSystemService(Service.INPUT_METHOD_SERVICE) as InputMethodManager
imm.hideSoftInputFromWindow(editText?.windowToken, 0)
editText?.clearFocus()
if (v === plusButton) {
inc(1)
} else {
dec(1)
}
}
}
override fun onKey(v: View, keyCode: Int, event: KeyEvent): Boolean {
val isKeyOfInterest = keyCode == KeyEvent.KEYCODE_DPAD_CENTER || keyCode == KeyEvent.KEYCODE_ENTER
val isReleased = event.action == KeyEvent.ACTION_UP
val isPressed = (event.action == KeyEvent.ACTION_DOWN)
if (isKeyOfInterest && isReleased) {
stopUpdating()
} else if (isKeyOfInterest && isPressed) {
startUpdating(v === plusButton)
}
return false
}
override fun onTouch(v: View, event: MotionEvent): Boolean {
val isReleased = event.action == MotionEvent.ACTION_UP || event.action == MotionEvent.ACTION_CANCEL
val isPressed = event.action == MotionEvent.ACTION_DOWN
if (isReleased) {
stopUpdating()
} else if (isPressed) {
startUpdating(v === plusButton)
}
return false
}
companion object {
private const val MSG_INC = 0
private const val MSG_DEC = 1
}
init {
initialize(context)
}
}

View file

@ -1,6 +1,7 @@
package info.nightscout.androidaps.danaRKorean.comm package info.nightscout.androidaps.danaRKorean.comm
import dagger.android.HasAndroidInjector import dagger.android.HasAndroidInjector
import info.nightscout.androidaps.dana.DanaPump
import info.nightscout.androidaps.danar.R import info.nightscout.androidaps.danar.R
import info.nightscout.androidaps.danar.comm.MessageBase import info.nightscout.androidaps.danar.comm.MessageBase
import info.nightscout.androidaps.events.EventRebuildTabs import info.nightscout.androidaps.events.EventRebuildTabs