diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java index 47bda0c08..73ea43a13 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/edit/NumericalHabitDialogHelper.java @@ -19,6 +19,7 @@ package org.isoron.uhabits.activities.habits.edit; +import android.icu.text.*; import android.support.v4.app.*; import android.view.*; import android.widget.*; @@ -33,6 +34,8 @@ public class NumericalHabitDialogHelper { private DialogFragment frag; + private DecimalFormat valueFormatter = new DecimalFormat("#.##"); + @BindView(R.id.tvName) TextView tvName; @@ -81,7 +84,7 @@ public class NumericalHabitDialogHelper tvUnit.setText(habit.getUnit()); tvTargetType.setSelection(habit.getTargetType()); - tvTargetValue.setText(String.format("%.0f", habit.getTargetValue())); + tvTargetValue.setText(valueFormatter.format(habit.getTargetValue())); populateColor(habit.getColor()); } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java index 3c78c3ad1..efd734938 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsController.java @@ -165,10 +165,13 @@ public class ListHabitsController @Override public void onEdit(@NonNull Habit habit, long timestamp) { - int oldValue = habit.getCheckmarks().getValues(timestamp, timestamp)[0]; - screen.showNumberPicker(oldValue, newValue -> { + CheckmarkList checkmarks = habit.getCheckmarks(); + double oldValue = checkmarks.getValues(timestamp, timestamp)[0]; + + screen.showNumberPicker(oldValue / 1000, habit.getUnit(), newValue -> { + newValue = Math.round(newValue * 1000); commandRunner.execute( - new CreateRepetitionCommand(habit, timestamp, newValue), + new CreateRepetitionCommand(habit, timestamp, (int) newValue), habit.getId()); }); } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java index c0fcae8fa..98e981caa 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.java @@ -24,6 +24,7 @@ import android.content.*; import android.net.*; import android.support.annotation.*; import android.support.v7.app.AlertDialog; +import android.text.*; import android.view.*; import android.widget.*; @@ -39,6 +40,7 @@ import org.isoron.uhabits.models.*; import org.isoron.uhabits.utils.*; import java.io.*; +import java.lang.reflect.*; import javax.inject.*; @@ -46,7 +48,6 @@ import static android.content.DialogInterface.*; import static android.os.Build.VERSION.*; import static android.os.Build.VERSION_CODES.*; import static android.view.inputmethod.EditorInfo.*; -import static org.isoron.uhabits.utils.InterfaceUtils.*; @ActivityScope public class ListHabitsScreen extends BaseScreen @@ -287,27 +288,44 @@ public class ListHabitsScreen extends BaseScreen activity.startActivity(intent); } - public void showNumberPicker(int initialValue, + public void showNumberPicker(double value, + @NonNull String unit, @NonNull NumberPickerCallback callback) { LayoutInflater inflater = activity.getLayoutInflater(); View view = inflater.inflate(R.layout.number_picker_dialog, null); - final NumberPicker picker = - (NumberPicker) view.findViewById(R.id.picker); + final NumberPicker picker; + final NumberPicker picker2; + final TextView tvUnit; + + picker = (NumberPicker) view.findViewById(R.id.picker); + picker2 = (NumberPicker) view.findViewById(R.id.picker2); + tvUnit = (TextView) view.findViewById(R.id.tvUnit); + + int intValue = (int) Math.round(value * 100); picker.setMinValue(0); - picker.setMaxValue(Integer.MAX_VALUE); - picker.setValue(initialValue); + picker.setMaxValue(Integer.MAX_VALUE / 100); + picker.setValue(intValue / 100); picker.setWrapSelectorWheel(false); + picker2.setMinValue(0); + picker2.setMaxValue(19); + picker2.setFormatter(v -> String.format("%02d", 5 * v)); + picker2.setValue((intValue % 100) / 5); + refreshInitialValue(picker2); + + tvUnit.setText(unit); + AlertDialog dialog = new AlertDialog.Builder(activity) .setView(view) .setTitle(R.string.change_value) .setPositiveButton(android.R.string.ok, (d, which) -> { picker.clearFocus(); - callback.onNumberPicked(picker.getValue()); + double v = picker.getValue() + 0.05 * picker2.getValue(); + callback.onNumberPicked(v); }) .create(); @@ -319,13 +337,22 @@ public class ListHabitsScreen extends BaseScreen }); dialog.show(); + } - Window window = dialog.getWindow(); - if (window != null) + private void refreshInitialValue(NumberPicker picker2) + { + // Workaround for a bug on Android: + // https://code.google.com/p/android/issues/detail?id=35482 + try + { + Field f = NumberPicker.class.getDeclaredField("mInputText"); + f.setAccessible(true); + EditText inputText = (EditText) f.get(picker2); + inputText.setFilters(new InputFilter[0]); + } + catch (Exception e) { - int width = (int) dpToPixels(activity, 200); - int height = (int) dpToPixels(activity, 275); - window.setLayout(width, height); + throw new RuntimeException(e); } } @@ -395,6 +422,6 @@ public class ListHabitsScreen extends BaseScreen public interface NumberPickerCallback { - void onNumberPicked(int newValue); + void onNumberPicked(double newValue); } } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java index 8b86f3f78..e9ddcc96f 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.java @@ -157,8 +157,12 @@ public class HabitCardView extends FrameLayout public void setValues(int values[]) { + double dvalues[] = new double[values.length]; + for(int i = 0; i < values.length; i++) + dvalues[i] = (double) values[i] / 1000; + checkmarkPanel.setValues(values); - numberPanel.setValues(values); + numberPanel.setValues(dvalues); numberPanel.setThreshold(10); postInvalidate(); } diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java index 816e36b95..476cede53 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.java @@ -22,6 +22,7 @@ package org.isoron.uhabits.activities.habits.list.views; import android.content.*; import android.content.res.*; import android.graphics.*; +import android.icu.text.*; import android.support.annotation.*; import android.text.*; import android.util.*; @@ -44,7 +45,7 @@ public class NumberButtonView extends View private int color; - private int value; + private double value; private double threshold; @@ -93,17 +94,16 @@ public class NumberButtonView extends View * @param v * @return */ - private static String formatValue(int v) + private static String formatValue(double v) { - double fv = (double) v; - if (v >= 1e9) return String.format("%.1fG", fv / 1e9); - if (v >= 1e8) return String.format("%.0fM", fv / 1e6); - if (v >= 1e7) return String.format("%.1fM", fv / 1e6); - if (v >= 1e6) return String.format("%.1fM", fv / 1e6); - if (v >= 1e5) return String.format("%.0fk", fv / 1e3); - if (v >= 1e4) return String.format("%.1fk", fv / 1e3); - if (v >= 1e3) return String.format("%.1fk", fv / 1e3); - return String.format("%d", v); + if (v >= 1e9) return String.format("%.1fG", v / 1e9); + if (v >= 1e8) return String.format("%.0fM", v / 1e6); + if (v >= 1e7) return String.format("%.1fM", v / 1e6); + if (v >= 1e6) return String.format("%.1fM", v / 1e6); + if (v >= 1e5) return String.format("%.0fk", v / 1e3); + if (v >= 1e4) return String.format("%.1fk", v / 1e3); + if (v >= 1e3) return String.format("%.1fk", v / 1e3); + return new DecimalFormat("#.##").format(v); } public void setColor(int color) @@ -130,7 +130,7 @@ public class NumberButtonView extends View postInvalidate(); } - public void setValue(int value) + public void setValue(double value) { this.value = value; postInvalidate(); diff --git a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java index 5723b9e1e..82edfdc97 100644 --- a/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java +++ b/app/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.java @@ -47,7 +47,7 @@ public class NumberPanelView extends LinearLayout @Nullable private Preferences prefs; - private int values[]; + private double values[]; private double threshold; @@ -95,20 +95,16 @@ public class NumberPanelView extends LinearLayout public void initEditMode() { - int values[] = new int[nButtons]; - + double values[] = new double[nButtons]; for(int i = 0; i < nButtons; i++) - values[i] = new Random().nextInt((int)(threshold * 3)); - + values[i] = new Random().nextDouble() * (threshold * 3); setValues(values); } public NumberButtonView indexToButton(int i) { int position = i; - if (getCheckmarkOrder() == RIGHT_TO_LEFT) position = nButtons - i - 1; - return (NumberButtonView) getChildAt(position); } @@ -159,7 +155,7 @@ public class NumberPanelView extends LinearLayout setupButtons(); } - public void setValues(int[] values) + public void setValues(double[] values) { this.values = values; setupButtons(); @@ -218,7 +214,7 @@ public class NumberPanelView extends LinearLayout } setWillNotDraw(false); - values = new int[0]; + values = new double[0]; } private void setupButtonControllers(long timestamp, diff --git a/app/src/main/java/org/isoron/uhabits/models/Checkmark.java b/app/src/main/java/org/isoron/uhabits/models/Checkmark.java index 3ae1c4b1e..c434a4a87 100644 --- a/app/src/main/java/org/isoron/uhabits/models/Checkmark.java +++ b/app/src/main/java/org/isoron/uhabits/models/Checkmark.java @@ -51,6 +51,15 @@ public final class Checkmark private final long timestamp; + /** + * The value of the checkmark. + * + * For boolean habits, this equals either UNCHECKED, CHECKED_EXPLICITLY, + * or CHECKED_IMPLICITLY. + * + * For numerical habits, this number is stored in thousandths. That + * is, if the user enters value 1.50 on the app, it is stored as 1500. + */ private final int value; public Checkmark(long timestamp, int value) diff --git a/app/src/main/java/org/isoron/uhabits/models/Repetition.java b/app/src/main/java/org/isoron/uhabits/models/Repetition.java index 3104fda9c..274fe3517 100644 --- a/app/src/main/java/org/isoron/uhabits/models/Repetition.java +++ b/app/src/main/java/org/isoron/uhabits/models/Repetition.java @@ -30,6 +30,15 @@ public final class Repetition private final long timestamp; + /** + * The value of the repetition. + * + * For boolean habits, this equals either Checkmark.UNCHECKED, + * Checkmark.CHECKED_EXPLICITLY, or Checkmark.CHECKED_IMPLICITLY. + * + * For numerical habits, this number is stored in thousandths. That + * is, if the user enters value 1.50 on the app, it is stored as 1500. + */ private final int value; /** diff --git a/app/src/main/java/org/isoron/uhabits/models/ScoreList.java b/app/src/main/java/org/isoron/uhabits/models/ScoreList.java index 60a399a61..7eda54256 100644 --- a/app/src/main/java/org/isoron/uhabits/models/ScoreList.java +++ b/app/src/main/java/org/isoron/uhabits/models/ScoreList.java @@ -280,6 +280,7 @@ public abstract class ScoreList implements Iterable if(habit.isNumerical()) { + value /= 1000; value /= habit.getTargetValue(); value = Math.min(1, value); } diff --git a/app/src/main/res/layout/number_picker_dialog.xml b/app/src/main/res/layout/number_picker_dialog.xml index 396f9c819..42f268591 100644 --- a/app/src/main/res/layout/number_picker_dialog.xml +++ b/app/src/main/res/layout/number_picker_dialog.xml @@ -30,4 +30,23 @@ android:layout_width="wrap_content" android:layout_height="wrap_content"/> + + + + + + \ No newline at end of file