diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java index 0c8cc47b..8bb8e1e1 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/CommentMeasurementView.java @@ -20,6 +20,7 @@ import android.content.SharedPreferences; import android.os.Bundle; import android.support.v4.content.ContextCompat; import android.text.InputType; +import android.view.View; import android.widget.EditText; import com.health.openscale.R; @@ -75,20 +76,29 @@ public class CommentMeasurementView extends MeasurementView { } @Override - protected boolean validateAndSetInput(EditText view) { - setValue(view.getText().toString(), true); + protected boolean showSoftInputForInputDialog() { return true; } @Override - protected int getInputType() { - return InputType.TYPE_CLASS_TEXT + protected View getInputView() { + EditText input = new EditText(getContext()); + + input.setInputType(InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_AUTO_COMPLETE - | InputType.TYPE_TEXT_FLAG_MULTI_LINE; + | InputType.TYPE_TEXT_FLAG_MULTI_LINE); + input.setHint(R.string.info_enter_comment); + input.setText(getValueAsString()); + input.setSelectAllOnFocus(true); + + input.requestFocus(); + return input; } @Override - protected String getHintText() { - return getResources().getString(R.string.info_enter_comment); + protected boolean validateAndSetInput(View view) { + EditText editText = (EditText) view; + setValue(editText.getText().toString(), true); + return true; } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java index 977e9511..d78664cf 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/DateMeasurementView.java @@ -15,14 +15,12 @@ */ package com.health.openscale.gui.views; -import android.app.AlertDialog; -import android.app.DatePickerDialog; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v4.content.ContextCompat; +import android.view.View; import android.widget.DatePicker; -import android.widget.EditText; import com.health.openscale.R; import com.health.openscale.core.datatypes.ScaleMeasurement; @@ -94,37 +92,32 @@ public class DateMeasurementView extends MeasurementView { } @Override - protected boolean validateAndSetInput(EditText view) { + protected boolean showSoftInputForInputDialog() { return false; } @Override - protected int getInputType() { - return 0; - } + protected View getInputView() { + DatePicker datePicker = new DatePicker(getContext()); + datePicker.setPadding(0, 15, 0, 0); - @Override - protected String getHintText() { - return null; - } - - private DatePickerDialog.OnDateSetListener datePickerListener = new DatePickerDialog.OnDateSetListener() { - @Override - public void onDateSet(DatePicker view, int selectedYear, int selectedMonth, int selectedDay) { - Calendar cal = Calendar.getInstance(); - cal.setTime(date); - cal.set(selectedYear, selectedMonth, selectedDay); - setValue(cal.getTime(), true); - } - }; - - @Override - protected AlertDialog getInputDialog() { Calendar cal = Calendar.getInstance(); cal.setTime(date); + datePicker.updateDate(cal.get(Calendar.YEAR), cal.get(Calendar.MONTH), + cal.get(Calendar.DAY_OF_MONTH)); - return new DatePickerDialog( - getContext(), datePickerListener, cal.get(Calendar.YEAR), - cal.get(Calendar.MONTH), cal.get(Calendar.DAY_OF_MONTH)); + return datePicker; + } + + @Override + protected boolean validateAndSetInput(View view) { + DatePicker datePicker = (DatePicker) view; + + Calendar cal = Calendar.getInstance(); + cal.setTime(date); + cal.set(datePicker.getYear(), datePicker.getMonth(), datePicker.getDayOfMonth()); + setValue(cal.getTime(), true); + + return true; } } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java index 6e0f2724..ade46da1 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/FloatMeasurementView.java @@ -21,17 +21,18 @@ import android.graphics.Color; import android.graphics.drawable.Drawable; import android.os.Bundle; import android.os.Handler; -import android.text.InputType; import android.text.SpannableStringBuilder; import android.text.Spanned; import android.text.style.ForegroundColorSpan; import android.text.style.RelativeSizeSpan; +import android.view.LayoutInflater; import android.view.MotionEvent; import android.view.View; import android.widget.Button; import android.widget.EditText; import android.widget.LinearLayout; import android.widget.TableRow; +import android.widget.TextView; import com.health.openscale.R; import com.health.openscale.core.datatypes.ScaleMeasurement; @@ -48,6 +49,7 @@ public abstract class FloatMeasurementView extends MeasurementView { private static float NO_VALUE = -1.0f; private static float AUTO_VALUE = -2.0f; + private static float INC_DEC_DELTA = 0.1f; private Date dateTime; private float value = NO_VALUE; @@ -197,10 +199,10 @@ public abstract class FloatMeasurementView extends MeasurementView { } private void incValue() { - setValue(clampValue(value + 0.1f), previousValue, true); + setValue(clampValue(value + INC_DEC_DELTA), previousValue, true); } private void decValue() { - setValue(clampValue(value - 0.1f), previousValue, true); + setValue(clampValue(value - INC_DEC_DELTA), previousValue, true); } protected String formatValue(float value) { @@ -342,15 +344,20 @@ public abstract class FloatMeasurementView extends MeasurementView { } @Override - protected boolean validateAndSetInput(EditText view) { - final String text = view.getText().toString(); + protected boolean showSoftInputForInputDialog() { + return true; + } + private float validateAndGetInput(View view) { + EditText editText = view.findViewById(R.id.float_input); + String text = editText.getText().toString(); + + float newValue = -1; if (text.isEmpty()) { - view.setError(getResources().getString(R.string.error_value_required)); - return false; + editText.setError(getResources().getString(R.string.error_value_required)); + return newValue; } - float newValue; try { newValue = Float.valueOf(text.replace(',', '.')); } @@ -359,22 +366,70 @@ public abstract class FloatMeasurementView extends MeasurementView { } if (newValue < 0 || newValue > getMaxValue()) { - view.setError(getResources().getString(R.string.error_value_range)); - return false; + editText.setError(getResources().getString(R.string.error_value_range)); + newValue = -1; } - setValue(newValue, previousValue, true); - return true; + return newValue; } @Override - protected int getInputType() { - return InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_DECIMAL; + protected View getInputView() { + final LinearLayout view = (LinearLayout) LayoutInflater.from(getContext()) + .inflate(R.layout.float_input_view, null); + + final EditText input = view.findViewById(R.id.float_input); + input.setText(formatValue(value)); + input.requestFocus(); + + final TextView unit = view.findViewById(R.id.float_input_unit); + unit.setText(getUnit()); + + View.OnClickListener onClickListener = new View.OnClickListener() { + @Override + public void onClick(View button) { + float newValue = validateAndGetInput(view); + if (newValue < 0) { + return; + } + + if (button.getId() == R.id.btn_inc) { + newValue += INC_DEC_DELTA; + } + else { + newValue -= INC_DEC_DELTA; + } + + input.setText(formatValue(clampValue(newValue))); + input.selectAll(); + } + }; + + RepeatListener repeatListener = + new RepeatListener(400, 100, onClickListener); + + final Button inc = view.findViewById(R.id.btn_inc); + inc.setText("\u25b2 +" + formatValue(INC_DEC_DELTA)); + inc.setOnClickListener(onClickListener); + inc.setOnTouchListener(repeatListener); + + final Button dec = view.findViewById(R.id.btn_dec); + dec.setText("\u25bc -" + formatValue(INC_DEC_DELTA)); + dec.setOnClickListener(onClickListener); + dec.setOnTouchListener(repeatListener); + + return view; } @Override - protected String getHintText() { - return getResources().getString(R.string.info_enter_value_unit) + " " + getUnit(); + protected boolean validateAndSetInput(View view) { + float newValue = validateAndGetInput(view); + if (newValue >= 0) { + setValue(newValue, previousValue, true); + return true; + } + + return false; } private class RepeatListener implements OnTouchListener { diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java index 5860b4fe..7e238323 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/MeasurementView.java @@ -31,8 +31,8 @@ import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.view.inputmethod.InputMethodManager; -import android.widget.Button; import android.widget.EditText; +import android.widget.FrameLayout; import android.widget.ImageView; import android.widget.LinearLayout; import android.widget.Space; @@ -381,90 +381,96 @@ public abstract class MeasurementView extends TableLayout { return openScale.getSelectedScaleUser(); } - protected abstract boolean validateAndSetInput(EditText view); - protected abstract int getInputType(); - protected abstract String getHintText(); + protected abstract boolean showSoftInputForInputDialog(); + protected abstract View getInputView(); + protected abstract boolean validateAndSetInput(View view); - protected AlertDialog getInputDialog() { + private MeasurementView getNextView() { + ViewGroup parent = (ViewGroup) getParent(); + for (int i = parent.indexOfChild(this) + 1; i < parent.getChildCount(); ++i) { + MeasurementView next = (MeasurementView) parent.getChildAt(i); + if (next.isEditable()) { + return next; + } + } + return null; + } + + private void prepareInputDialog(final AlertDialog dialog) { + dialog.setTitle(getName()); + dialog.setIcon(getIcon()); + + final InputMethodManager imm = (InputMethodManager) getContext() + .getSystemService(Context.INPUT_METHOD_SERVICE); + if (showSoftInputForInputDialog()) { + imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); + } + else if (dialog.getCurrentFocus() != null) { + imm.hideSoftInputFromWindow(dialog.getCurrentFocus().getWindowToken(), 0); + } + + final View input = getInputView(); + + FrameLayout fl = dialog.findViewById(android.R.id.custom); + fl.removeAllViews(); + fl.addView(input, new LayoutParams(LinearLayout.LayoutParams.MATCH_PARENT, + LinearLayout.LayoutParams.WRAP_CONTENT)); + + View.OnClickListener clickListener = new View.OnClickListener() { + @Override + public void onClick(View view) { + if (view == dialog.getButton(DialogInterface.BUTTON_POSITIVE) + && !validateAndSetInput(input)) { + return; + } + imm.hideSoftInputFromWindow(view.getWindowToken(), 0); + dialog.dismiss(); + } + }; + + dialog.getButton(DialogInterface.BUTTON_POSITIVE).setOnClickListener(clickListener); + dialog.getButton(DialogInterface.BUTTON_NEGATIVE).setOnClickListener(clickListener); + + final MeasurementView next = getNextView(); + if (next != null) { + dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setOnClickListener(new OnClickListener() { + @Override + public void onClick(View v) { + if (validateAndSetInput(input)) { + next.prepareInputDialog(dialog); + } + } + }); + } + else { + dialog.getButton(DialogInterface.BUTTON_NEUTRAL).setVisibility(GONE); + } + } + + private void showInputDialog() { AlertDialog.Builder builder = new AlertDialog.Builder(getContext()); + builder.setTitle(getName()); builder.setIcon(getIcon()); - final EditText input = new EditText(getContext()); + // Dummy view to have the "custom" frame layout being created and show + // the soft input (if needed). + builder.setView(new EditText(getContext())); - input.setInputType(getInputType()); - input.setHint(getHintText()); - input.setText(getValueAsString()); - input.setSelectAllOnFocus(true); - builder.setView(input); + builder.setPositiveButton(R.string.label_ok, null); + builder.setNegativeButton(R.string.label_cancel, null); + builder.setNeutralButton(R.string.label_next, null); - ViewGroup parent = (ViewGroup) getParent(); - MeasurementView view = null; - for (int i = parent.indexOfChild(this) + 1; i < parent.getChildCount(); ++i) { - MeasurementView next = (MeasurementView) parent.getChildAt(i); - if (!next.isEditable() || next instanceof DateMeasurementView || next instanceof TimeMeasurementView) { - continue; - } - view = next; - break; - } - final MeasurementView next = view; - - builder.setPositiveButton(getResources().getString(R.string.label_ok), null); - builder.setNegativeButton(getResources().getString(R.string.label_cancel), null); - - if (next != null) { - builder.setNeutralButton(R.string.label_next, null); - } - - final AlertDialog floatDialog = builder.create(); - - floatDialog.setOnShowListener(new DialogInterface.OnShowListener() { + final AlertDialog dialog = builder.create(); + dialog.setOnShowListener(new DialogInterface.OnShowListener() { @Override - public void onShow(DialogInterface dialog) { - - Button positiveButton = floatDialog.getButton(AlertDialog.BUTTON_POSITIVE); - positiveButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - if (validateAndSetInput(input)) { - InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(input.getWindowToken(), 0); - floatDialog.dismiss(); - } - } - }); - - Button negativeButton = floatDialog.getButton(AlertDialog.BUTTON_NEGATIVE); - negativeButton.setOnClickListener(new View.OnClickListener() { - @Override - public void onClick(View view) { - InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.hideSoftInputFromWindow(input.getWindowToken(), 0); - floatDialog.dismiss(); - } - }); - - if (next != null) { - Button neutralButton = floatDialog.getButton(AlertDialog.BUTTON_NEUTRAL); - neutralButton.setOnClickListener(new OnClickListener() { - @Override - public void onClick(View v) { - if (validateAndSetInput(input)) { - floatDialog.dismiss(); - next.getInputDialog().show(); - } - } - }); - } + public void onShow(DialogInterface dialogInterface) { + prepareInputDialog(dialog); } }); - InputMethodManager imm = (InputMethodManager) getContext().getSystemService(Context.INPUT_METHOD_SERVICE); - imm.toggleSoftInput(InputMethodManager.SHOW_FORCED, InputMethodManager.HIDE_IMPLICIT_ONLY); - - return floatDialog; + dialog.show(); } private class onClickListenerEvaluation implements View.OnClickListener { @@ -476,7 +482,7 @@ public abstract class MeasurementView extends TableLayout { if (getMeasurementMode() == EDIT || getMeasurementMode() == ADD) { if (isEditable()) { - getInputDialog().show(); + showInputDialog(); } return; } diff --git a/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java b/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java index d9eebf76..508b260a 100644 --- a/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java +++ b/android_app/app/src/main/java/com/health/openscale/gui/views/TimeMeasurementView.java @@ -15,13 +15,11 @@ */ package com.health.openscale.gui.views; -import android.app.AlertDialog; -import android.app.TimePickerDialog; import android.content.Context; import android.content.SharedPreferences; import android.os.Bundle; import android.support.v4.content.ContextCompat; -import android.widget.EditText; +import android.view.View; import android.widget.TimePicker; import com.health.openscale.R; @@ -96,43 +94,38 @@ public class TimeMeasurementView extends MeasurementView { } @Override - protected boolean validateAndSetInput(EditText view) { + protected boolean showSoftInputForInputDialog() { return false; } @Override - protected int getInputType() { - return 0; - } + protected View getInputView() { + TimePicker timePicker = new TimePicker(getContext()); + timePicker.setPadding(0, 15, 0, 0); - @Override - protected String getHintText() { - return null; - } - - private TimePickerDialog.OnTimeSetListener timePickerListener = new TimePickerDialog.OnTimeSetListener() { - @Override - public void onTimeSet(TimePicker view, int hourOfDay, int minute) { - Calendar cal = Calendar.getInstance(); - cal.setTime(time); - - cal.set(Calendar.HOUR_OF_DAY, hourOfDay); - cal.set(Calendar.MINUTE, minute); - cal.set(Calendar.SECOND, 0); - cal.set(Calendar.MILLISECOND, 0); - - setValue(cal.getTime(), true); - } - }; - - @Override - protected AlertDialog getInputDialog() { Calendar cal = Calendar.getInstance(); cal.setTime(time); - return new TimePickerDialog( - getContext(), timePickerListener, - cal.get(Calendar.HOUR_OF_DAY), cal.get(Calendar.MINUTE), - android.text.format.DateFormat.is24HourFormat(getContext())); + timePicker.setCurrentHour(cal.get(Calendar.HOUR_OF_DAY)); + timePicker.setCurrentMinute(cal.get(Calendar.MINUTE)); + timePicker.setIs24HourView(android.text.format.DateFormat.is24HourFormat(getContext())); + + return timePicker; + } + + @Override + protected boolean validateAndSetInput(View view) { + TimePicker timePicker = (TimePicker) view; + + Calendar cal = Calendar.getInstance(); + cal.setTime(time); + cal.set(Calendar.HOUR_OF_DAY, timePicker.getCurrentHour()); + cal.set(Calendar.MINUTE, timePicker.getCurrentMinute()); + cal.set(Calendar.SECOND, 0); + cal.set(Calendar.MILLISECOND, 0); + + setValue(cal.getTime(), true); + + return true; } } diff --git a/android_app/app/src/main/res/layout/float_input_view.xml b/android_app/app/src/main/res/layout/float_input_view.xml new file mode 100644 index 00000000..1fc3cc16 --- /dev/null +++ b/android_app/app/src/main/res/layout/float_input_view.xml @@ -0,0 +1,48 @@ + + + +