pull/419/merge
Jake Powell 7 years ago committed by GitHub
commit 28f70578b6
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

@ -24,6 +24,7 @@ import android.os.*;
import android.support.annotation.*;
import android.support.v7.app.*;
import android.text.format.*;
import android.util.Log;
import android.view.*;
import com.android.datetimepicker.time.*;
@ -40,14 +41,13 @@ import org.isoron.uhabits.core.preferences.*;
import butterknife.*;
import static android.view.View.GONE;
import static android.view.View.VISIBLE;
import static org.isoron.uhabits.core.ui.ThemeSwitcher.THEME_LIGHT;
public class EditHabitDialog extends AppCompatDialogFragment
{
public static final String BUNDLE_HABIT_ID = "habitId";
public static final String BUNDLE_HABIT_TYPE = "habitType";
protected Habit originalHabit;
protected Preferences prefs;
@ -63,6 +63,9 @@ public class EditHabitDialog extends AppCompatDialogFragment
@BindView(R.id.namePanel)
NameDescriptionPanel namePanel;
@BindView(R.id.typePanel)
TypePanel typePanel;
@BindView(R.id.reminderPanel)
ReminderPanel reminderPanel;
@ -112,6 +115,7 @@ public class EditHabitDialog extends AppCompatDialogFragment
populateForm();
setupReminderController();
setupTypeController();
setupNameController();
return view;
@ -138,11 +142,6 @@ public class EditHabitDialog extends AppCompatDialogFragment
}
}
private int getTypeFromArguments()
{
return getArguments().getInt(BUNDLE_HABIT_TYPE);
}
private void initDependencies()
{
Context appContext = getContext().getApplicationContext();
@ -164,9 +163,9 @@ public class EditHabitDialog extends AppCompatDialogFragment
@OnClick(R.id.buttonSave)
void onSaveButtonClick()
{
int type = getTypeFromArguments();
if (!namePanel.validate()) return;
int type = typePanel.getType();
if (type == Habit.YES_NO_HABIT && !frequencyPanel.validate()) return;
if (type == Habit.NUMBER_HABIT && !targetPanel.validate()) return;
@ -204,22 +203,36 @@ public class EditHabitDialog extends AppCompatDialogFragment
private void populateForm()
{
Habit habit = modelFactory.buildHabit();
habit.setFrequency(Frequency.DAILY);
habit.setColor(prefs.getDefaultHabitColor(habit.getColor()));
habit.setType(getTypeFromArguments());
habit.setType(Habit.YES_NO_HABIT);
habit.setFrequency(Frequency.DAILY);
if (originalHabit != null) habit.copyFrom(originalHabit);
if (habit.isNumerical()) frequencyPanel.setVisibility(GONE);
else targetPanel.setVisibility(GONE);
namePanel.populateFrom(habit);
typePanel.setType(habit.getType());
typePanel.setEnabled(originalHabit == null);
setPanelsForType(habit.getType());
frequencyPanel.setFrequency(habit.getFrequency());
targetPanel.setTargetValue(habit.getTargetValue());
targetPanel.setUnit(habit.getUnit());
if (habit.hasReminder()) reminderPanel.setReminder(habit.getReminder());
}
private void setPanelsForType(Integer type)
{
if (typePanel.getType() == Habit.NUMBER_HABIT)
{
targetPanel.setVisibility(VISIBLE);
frequencyPanel.setVisibility(GONE);
}
else
{
targetPanel.setVisibility(GONE);
frequencyPanel.setVisibility(VISIBLE);
}
}
private void setupNameController()
{
namePanel.setController(new NameDescriptionPanel.Controller()
@ -241,6 +254,19 @@ public class EditHabitDialog extends AppCompatDialogFragment
});
}
private void setupTypeController()
{
typePanel.setController(new TypePanel.Controller()
{
@Override
public void onTypeSelected(Integer previousType)
{
Integer currentType = typePanel.getType();
setPanelsForType(currentType);
}
});
}
private void setupReminderController()
{
reminderPanel.setController(new ReminderPanel.Controller()

@ -35,21 +35,9 @@ public class EditHabitDialogFactory
{
}
public EditHabitDialog createBoolean()
public EditHabitDialog create()
{
EditHabitDialog dialog = new EditHabitDialog();
Bundle args = new Bundle();
args.putInt(BUNDLE_HABIT_TYPE, Habit.YES_NO_HABIT);
dialog.setArguments(args);
return dialog;
}
public EditHabitDialog createNumerical()
{
EditHabitDialog dialog = new EditHabitDialog();
Bundle args = new Bundle();
args.putInt(BUNDLE_HABIT_TYPE, Habit.NUMBER_HABIT);
dialog.setArguments(args);
return dialog;
}
@ -61,7 +49,6 @@ public class EditHabitDialogFactory
EditHabitDialog dialog = new EditHabitDialog();
Bundle args = new Bundle();
args.putLong(BUNDLE_HABIT_ID, habit.getId());
args.putInt(BUNDLE_HABIT_TYPE, habit.getType());
dialog.setArguments(args);
return dialog;
}

@ -0,0 +1,108 @@
/*
* Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
*
* This file is part of Loop Habit Tracker.
*
* Loop Habit Tracker is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 3 of the License, or (at your
* option) any later version.
*
* Loop Habit Tracker is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
* or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
* more details.
*
* You should have received a copy of the GNU General Public License along
* with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package org.isoron.uhabits.activities.habits.edit.views;
import android.content.Context;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.AttributeSet;
import android.view.View;
import android.widget.FrameLayout;
import android.widget.Spinner;
import org.isoron.uhabits.R;
import org.isoron.uhabits.core.models.Habit;
import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.OnItemSelected;
public class TypePanel extends FrameLayout
{
@BindView(R.id.spinner)
Spinner spinner;
private Integer type;
@NonNull
private Controller controller;
public TypePanel(@NonNull Context context,
@Nullable AttributeSet attrs)
{
super(context, attrs);
View view = inflate(context, R.layout.edit_habit_type, null);
ButterKnife.bind(this, view);
addView(view);
setType(Habit.YES_NO_HABIT);
controller = new Controller() {};
}
@NonNull
public Integer getType()
{
return type;
}
public void setType(@NonNull Integer type)
{
this.type = type;
int position = getQuickSelectPosition(type);
spinner.setSelection(position);
}
@OnItemSelected(R.id.spinner)
public void onTypeSelected(int position)
{
if (position < 0 || position > 1) throw new IllegalArgumentException();
Integer previousType = type;
type = getTypeFromQuickSelectPosition(position);
controller.onTypeSelected(previousType);
}
public void setEnabled(boolean enabled)
{
spinner.setEnabled(enabled);
}
public void setController(@NonNull Controller controller) { this.controller = controller; }
public interface Controller
{
default void onTypeSelected(Integer previousType) {}
}
private Integer getTypeFromQuickSelectPosition(@NonNull Integer position)
{
if (position.equals(0)) return Habit.YES_NO_HABIT;
if (position.equals(1)) return Habit.NUMBER_HABIT;
return -1;
}
private int getQuickSelectPosition(@NonNull Integer type)
{
if (type.equals(Habit.YES_NO_HABIT)) return 0;
if (type.equals(Habit.NUMBER_HABIT)) return 1;
return -1;
}
}

@ -137,26 +137,9 @@ class ListHabitsScreen
activity.startActivity(intent)
}
fun showCreateBooleanHabitScreen() {
val dialog = editHabitDialogFactory.createBoolean()
activity.showDialog(dialog, "editHabit")
}
override fun showCreateHabitScreen() {
if (!preferences.isNumericalHabitsFeatureEnabled) {
showCreateBooleanHabitScreen()
return
}
val dialog = AlertDialog.Builder(activity)
.setTitle("Type of habit")
.setItems(R.array.habitTypes) { _, which ->
if (which == 0) showCreateBooleanHabitScreen()
else showCreateNumericalHabitScreen()
}
.create()
dialog.show()
val dialog = editHabitDialogFactory.create()
activity.showDialog(dialog, "editHabit")
}
override fun showDeleteConfirmationScreen(callback: OnConfirmedCallback) {
@ -236,11 +219,6 @@ class ListHabitsScreen
}
}
private fun showCreateNumericalHabitScreen() {
val dialog = editHabitDialogFactory.createNumerical()
activity.showDialog(dialog, "editHabit")
}
private fun onImportData(file: File, onFinished: () -> Unit) {
taskRunner.execute(importTaskFactory.create(file) { result ->
if (result == ImportDataTask.SUCCESS) {

@ -129,6 +129,14 @@ class HabitCardView(
numberPanel = numberPanelFactory.create().apply {
visibility = GONE
onIncrement = { timestamp ->
triggerRipple(timestamp)
habit?.let { behavior.onIncrement(it, timestamp)}
}
onDecrement = { timestamp ->
triggerRipple(timestamp)
habit?.let { behavior.onDecrement(it, timestamp)}
}
onEdit = { timestamp ->
triggerRipple(timestamp)
habit?.let { behavior.onEdit(it, timestamp) }

@ -21,7 +21,9 @@ package org.isoron.uhabits.activities.habits.list.views
import android.content.*
import android.graphics.*
import android.support.v4.view.GestureDetectorCompat
import android.text.*
import android.util.Log
import android.view.*
import android.view.View.*
import com.google.auto.factory.*
@ -53,9 +55,7 @@ fun Double.toShortString(): String = when {
class NumberButtonView(
@Provided @ActivityContext context: Context,
@Provided val preferences: Preferences
) : View(context),
OnClickListener,
OnLongClickListener {
) : View(context) {
var color = 0
set(value) {
@ -81,23 +81,33 @@ class NumberButtonView(
invalidate()
}
var onIncrement: () -> Unit = {}
var onDecrement: () -> Unit = {}
var onEdit: () -> Unit = {}
private var drawer: Drawer = Drawer(context)
init {
setOnClickListener(this)
setOnLongClickListener(this)
}
override fun onClick(v: View) {
if (preferences.isShortToggleEnabled) onEdit()
else showMessage(R.string.long_press_to_edit)
}
override fun onLongClick(v: View): Boolean {
onEdit()
return true
}
private val detector: GestureDetector = GestureDetector(
context,
object: GestureDetector.SimpleOnGestureListener()
{
override fun onDown(e: MotionEvent?): Boolean = true
override fun onSingleTapConfirmed(e: MotionEvent?): Boolean {
onIncrement()
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
return true
}
override fun onDoubleTap(e: MotionEvent?): Boolean {
onDecrement()
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
return true
}
override fun onLongPress(e: MotionEvent?) {
performHapticFeedback(HapticFeedbackConstants.LONG_PRESS)
onEdit()
}
})
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
@ -110,6 +120,11 @@ class NumberButtonView(
setMeasuredDimension(width, height)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
detector.onTouchEvent(event)
return true
}
private inner class Drawer(context: Context) {
private val em: Float

@ -57,6 +57,18 @@ class NumberPanelView(
setupButtons()
}
var onIncrement: (Timestamp) -> Unit = {}
set(value) {
field = value
setupButtons()
}
var onDecrement: (Timestamp) -> Unit = {}
set(value) {
field = value
setupButtons()
}
var onEdit: (Timestamp) -> Unit = {}
set(value) {
field = value
@ -78,6 +90,8 @@ class NumberPanelView(
button.color = color
button.threshold = threshold
button.units = units
button.onIncrement = { onIncrement(timestamp) }
button.onDecrement = { onDecrement(timestamp) }
button.onEdit = { onEdit(timestamp) }
}
}

@ -34,6 +34,11 @@
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
<org.isoron.uhabits.activities.habits.edit.views.TypePanel
android:id="@+id/typePanel"
android:layout_width="match_parent"
android:layout_height="wrap_content" />
<org.isoron.uhabits.activities.habits.edit.views.FrequencyPanel
android:id="@+id/frequencyPanel"
android:layout_width="match_parent"

@ -0,0 +1,40 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
~ Copyright (C) 2016 Álinson Santos Xavier <isoron@gmail.com>
~
~ This file is part of Loop Habit Tracker.
~
~ Loop Habit Tracker is free software: you can redistribute it and/or modify
~ it under the terms of the GNU General Public License as published by the
~ Free Software Foundation, either version 3 of the License, or (at your
~ option) any later version.
~
~ Loop Habit Tracker is distributed in the hope that it will be useful, but
~ WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
~ or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
~ more details.
~
~ You should have received a copy of the GNU General Public License along
~ with this program. If not, see <http://www.gnu.org/licenses/>.
-->
<LinearLayout style="@style/dialogFormRow"
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:paddingTop="12dp"
android:paddingBottom="12dp"
android:orientation="horizontal">
<TextView
style="@style/dialogFormLabel"
android:text="@string/type"/>
<android.support.v7.widget.AppCompatSpinner
android:id="@+id/spinner"
android:layout_width="wrap_content"
android:layout_height="25dp"
android:entries="@array/habitTypes"
android:minWidth="400dp"
android:theme="@style/dialogFormText"/>
</LinearLayout>

@ -80,7 +80,7 @@
</string-array>
<string-array name="habitTypes" translatable="false">
<item>Yes or No</item>
<item>Checked/Unchecked</item>
<item>Number</item>
</string-array>

@ -45,6 +45,7 @@
<string name="history">History</string>
<string name="clear">Clear</string>
<string name="description_hint">Question (Did you … today?)</string>
<string name="type">Type</string>
<string name="repeat">Repeat</string>
<string name="times_every">times in</string>
<string name="days">days</string>

@ -78,6 +78,26 @@ public class ListHabitsBehavior
screen.showHabitScreen(h);
}
public void onIncrement(@NonNull Habit habit, Timestamp timestamp)
{
CheckmarkList checkmarks = habit.getCheckmarks();
double oldValue = checkmarks.getValues(timestamp, timestamp)[0];
commandRunner.execute(
new CreateRepetitionCommand(habit, timestamp, (int)(oldValue + 1000)),
habit.getId());
}
public void onDecrement(@NonNull Habit habit, Timestamp timestamp)
{
CheckmarkList checkmarks = habit.getCheckmarks();
double oldValue = checkmarks.getValues(timestamp, timestamp)[0];
double newValue = oldValue - 1000;
if (newValue < 0) return;
commandRunner.execute(
new CreateRepetitionCommand(habit, timestamp, (int)newValue),
habit.getId());
}
public void onEdit(@NonNull Habit habit, Timestamp timestamp)
{
CheckmarkList checkmarks = habit.getCheckmarks();

@ -20,6 +20,7 @@
package org.isoron.uhabits.core.ui.screens.habits.list;
import org.isoron.uhabits.core.*;
import org.isoron.uhabits.core.commands.CreateRepetitionCommand;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.utils.*;
@ -36,6 +37,7 @@ import static org.hamcrest.MatcherAssert.assertThat;
import static org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.COULD_NOT_EXPORT;
import static org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.COULD_NOT_GENERATE_BUG_REPORT;
import static org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior.Message.DATABASE_REPAIRED;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertFalse;
import static org.junit.Assert.assertTrue;
import static org.mockito.Mockito.any;
@ -177,4 +179,33 @@ public class ListHabitsBehaviorTest extends BaseUnitTest
assertFalse(habit1.isCompletedToday());
}
@Test
public void testOnIncrement()
{
assertTrue(habit2.isCompletedToday());
assertEquals(habit2.getRepetitions().getNewest().getValue(), 100);
behavior.onIncrement(habit2, DateUtils.getToday());
assertEquals(habit2.getRepetitions().getNewest().getValue(), 1100);
}
@Test
public void testOnDecrement_belowZero() {
assertTrue(habit2.isCompletedToday());
assertEquals(habit2.getRepetitions().getNewest().getValue(), 100);
behavior.onDecrement(habit2, DateUtils.getToday());
assertEquals(habit2.getRepetitions().getNewest().getValue(), 100);
}
@Test
public void testOnDecrement()
{
assertTrue(habit2.isCompletedToday());
commandRunner.execute(
new CreateRepetitionCommand(habit2, DateUtils.getToday(), 4000),
habit2.getId());
assertEquals(habit2.getRepetitions().getNewest().getValue(), 4000);
behavior.onDecrement(habit2, DateUtils.getToday());
assertEquals(habit2.getRepetitions().getNewest().getValue(), 3000);
}
}
Loading…
Cancel
Save