Allow fractional values to be entered

pull/157/merge
Alinson S. Xavier 9 years ago
parent 177525817c
commit 83ce92d8ac

@ -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());
}

@ -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());
});
}

@ -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);
}
}

@ -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();
}

@ -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();

@ -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,

@ -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)

@ -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;
/**

@ -280,6 +280,7 @@ public abstract class ScoreList implements Iterable<Score>
if(habit.isNumerical())
{
value /= 1000;
value /= habit.getTargetValue();
value = Math.min(1, value);
}

@ -30,4 +30,23 @@
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
<TextView
android:id="@+id/tvSeparator"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="."/>
<NumberPicker
android:id="@+id/picker2"
android:layout_gravity="center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:descendantFocusability="blocksDescendants"
/>
<TextView
android:id="@+id/tvUnit"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
</LinearLayout>
Loading…
Cancel
Save