NumberPicker -> kt
This commit is contained in:
parent
ae573de63d
commit
68793233e8
18 changed files with 330 additions and 376 deletions
|
@ -1,5 +1,6 @@
|
|||
package info.nightscout.androidaps.activities
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.res.ColorStateList
|
||||
import android.os.Bundle
|
||||
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.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 {
|
||||
val tdds = tddCalculator.stats()
|
||||
runOnUiThread { binding.tdds.text = tdds }
|
||||
|
|
|
@ -76,7 +76,7 @@ class CalibrationDialog : DialogFragmentWithDate() {
|
|||
val units = profileFunction.getUnits()
|
||||
val unitLabel = if (units == GlucoseUnit.MMOL) rh.gs(R.string.mmol) else rh.gs(R.string.mgdl)
|
||||
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)
|
||||
if (bg > 0) {
|
||||
activity?.let { activity ->
|
||||
|
|
|
@ -189,7 +189,7 @@ class CarbsDialog : DialogFragmentWithDate() {
|
|||
|
||||
override fun submit(): Boolean {
|
||||
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 units = profileFunction.getUnits()
|
||||
val activityTTDuration = defaultValueHelper.determineActivityTTDuration()
|
||||
|
|
|
@ -79,7 +79,7 @@ class ExtendedBolusDialog : DialogFragmentWithDate() {
|
|||
|
||||
override fun submit(): Boolean {
|
||||
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 actions: LinkedList<String> = LinkedList()
|
||||
val insulinAfterConstraint = constraintChecker.applyExtendedBolusConstraints(Constraint(insulin)).value()
|
||||
|
|
|
@ -106,7 +106,7 @@ class FillDialog : DialogFragmentWithDate() {
|
|||
|
||||
override fun submit(): Boolean {
|
||||
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 insulinAfterConstraints = constraintChecker.applyBolusConstraints(Constraint(insulin)).value()
|
||||
|
|
|
@ -149,7 +149,7 @@ class InsulinDialog : DialogFragmentWithDate() {
|
|||
override fun submit(): Boolean {
|
||||
if (_binding == null) return false
|
||||
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 actions: LinkedList<String?> = LinkedList()
|
||||
val units = profileFunction.getUnits()
|
||||
|
|
|
@ -162,7 +162,7 @@ class ProfileSwitchDialog : DialogFragmentWithDate() {
|
|||
?: return false
|
||||
|
||||
val actions: LinkedList<String> = LinkedList()
|
||||
val duration = binding.duration.value?.toInt() ?: return false
|
||||
val duration = binding.duration.value.toInt()
|
||||
if (duration > 0L)
|
||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, duration))
|
||||
val profileName = binding.profile.selectedItem.toString()
|
||||
|
|
|
@ -47,8 +47,8 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
override fun onSaveInstanceState(savedInstanceState: Bundle) {
|
||||
super.onSaveInstanceState(savedInstanceState)
|
||||
savedInstanceState.putDouble("duration", binding.duration.value)
|
||||
savedInstanceState.putDouble("basalpercentinput", binding.basalpercentinput.value)
|
||||
savedInstanceState.putDouble("basalabsoluteinput", binding.basalabsoluteinput.value)
|
||||
savedInstanceState.putDouble("basalPercentInput", binding.basalPercentInput.value)
|
||||
savedInstanceState.putDouble("basalAbsoluteInput", binding.basalAbsoluteInput.value)
|
||||
}
|
||||
|
||||
override fun onCreateView(inflater: LayoutInflater, container: ViewGroup?,
|
||||
|
@ -67,10 +67,10 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
val maxTempPercent = pumpDescription.maxTempPercent.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)
|
||||
|
||||
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)
|
||||
|
||||
val tempDurationStep = pumpDescription.tempDurationStep.toDouble()
|
||||
|
@ -97,17 +97,17 @@ class TempBasalDialog : DialogFragmentWithDate() {
|
|||
if (_binding == null) return false
|
||||
var percent = 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 actions: LinkedList<String> = LinkedList()
|
||||
if (isPercentPump) {
|
||||
val basalPercentInput = SafeParse.stringToInt(binding.basalpercentinput.text)
|
||||
val basalPercentInput = SafeParse.stringToInt(binding.basalPercentInput.text)
|
||||
percent = constraintChecker.applyBasalPercentConstraints(Constraint(basalPercentInput), profile).value()
|
||||
actions.add(rh.gs(R.string.tempbasal_label) + ": $percent%")
|
||||
actions.add(rh.gs(R.string.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
||||
if (percent != basalPercentInput) actions.add(rh.gs(R.string.constraintapllied))
|
||||
} else {
|
||||
val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalabsoluteinput.text)
|
||||
val basalAbsoluteInput = SafeParse.stringToDouble(binding.basalAbsoluteInput.text)
|
||||
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.duration) + ": " + rh.gs(R.string.format_mins, durationInMinutes))
|
||||
|
|
|
@ -115,7 +115,7 @@ class TreatmentDialog : DialogFragmentWithDate() {
|
|||
override fun submit(): Boolean {
|
||||
if (_binding == null) return false
|
||||
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 recordOnlyChecked = binding.recordOnly.isChecked
|
||||
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)), {
|
||||
val action = when {
|
||||
insulinAfterConstraints.equals(0.0) -> Action.CARBS
|
||||
carbsAfterConstraints.equals(0) -> Action.BOLUS
|
||||
carbsAfterConstraints == 0 -> Action.BOLUS
|
||||
else -> Action.TREATMENT
|
||||
}
|
||||
val detailedBolusInfo = DetailedBolusInfo()
|
||||
|
|
|
@ -258,10 +258,7 @@ class WizardDialog : DaggerDialogFragment() {
|
|||
|
||||
val units = profileFunction.getUnits()
|
||||
binding.bgunits.text = units.asText
|
||||
if (units == GlucoseUnit.MGDL)
|
||||
binding.bgInput.setStep(1.0)
|
||||
else
|
||||
binding.bgInput.setStep(0.1)
|
||||
binding.bgInput.step = if (units == GlucoseUnit.MGDL) 1.0 else 0.1
|
||||
|
||||
// Set BG if not old
|
||||
binding.bgInput.value = iobCobCalculator.ads.actualBg()?.valueToUnits(units) ?: 0.0
|
||||
|
|
|
@ -65,7 +65,7 @@ class LocalProfileFragment : DaggerFragment() {
|
|||
override fun afterTextChanged(s: Editable) {}
|
||||
override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: 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()
|
||||
doEdit()
|
||||
}
|
||||
|
|
|
@ -5,10 +5,7 @@ import android.util.AttributeSet
|
|||
import android.view.LayoutInflater
|
||||
import info.nightscout.androidaps.R
|
||||
|
||||
class NumberPickerVertical : NumberPicker {
|
||||
|
||||
constructor(context: Context?) : super(context)
|
||||
constructor(context: Context?, attrs: AttributeSet?) : super(context, attrs)
|
||||
class NumberPickerVertical(context: Context, attrs: AttributeSet? = null) : NumberPicker(context, attrs) {
|
||||
|
||||
override fun inflate(context: Context) {
|
||||
LayoutInflater.from(context).inflate(R.layout.number_picker_layout_vertical, this, true)
|
||||
|
|
|
@ -64,7 +64,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/basalpercentinput"
|
||||
android:id="@+id/basal_percent_input"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
|
@ -98,7 +98,7 @@
|
|||
android:textStyle="bold" />
|
||||
|
||||
<info.nightscout.androidaps.utils.ui.NumberPicker
|
||||
android:id="@+id/basalabsoluteinput"
|
||||
android:id="@+id/basal_absolute_input"
|
||||
android:layout_width="130dp"
|
||||
android:layout_height="40dp" />
|
||||
|
||||
|
|
|
@ -34,6 +34,7 @@ public class ToastUtils {
|
|||
graphicalToast(ctx, string, R.drawable.ic_toast_info, false);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unused")
|
||||
public static void okToast(final Context ctx, final String string) {
|
||||
graphicalToast(ctx, string, R.drawable.ic_toast_check, false);
|
||||
}
|
||||
|
|
|
@ -13,16 +13,16 @@ class MinutesNumberPicker constructor(context: Context, attrs: AttributeSet? = n
|
|||
}
|
||||
|
||||
override fun updateEditText() {
|
||||
if (value == 0.0 && !allowZero) editText.setText("")
|
||||
if (currentValue == 0.0 && !allowZero) editText?.setText("")
|
||||
else {
|
||||
if (focused) editText.setText(DecimalFormat("0").format(value))
|
||||
if (focused) editText?.setText(DecimalFormat("0").format(currentValue))
|
||||
else {
|
||||
val hours = (value / 60).toInt()
|
||||
val minutes = (value - hours * 60).toInt()
|
||||
val hours = (currentValue / 60).toInt()
|
||||
val minutes = (currentValue - hours * 60).toInt()
|
||||
val formatted =
|
||||
if (hours != 0) String.format(context.getString(R.string.format_hour_minute), hours, minutes)
|
||||
else DecimalFormat("0").format(value)
|
||||
editText.setText(formatted)
|
||||
else DecimalFormat("0").format(currentValue)
|
||||
editText?.setText(formatted)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
|
@ -1,6 +1,7 @@
|
|||
package info.nightscout.androidaps.danaRKorean.comm
|
||||
|
||||
import dagger.android.HasAndroidInjector
|
||||
import info.nightscout.androidaps.dana.DanaPump
|
||||
import info.nightscout.androidaps.danar.R
|
||||
import info.nightscout.androidaps.danar.comm.MessageBase
|
||||
import info.nightscout.androidaps.events.EventRebuildTabs
|
||||
|
|
Loading…
Reference in a new issue