diff --git a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java
index f0354a5d5..de54d565c 100644
--- a/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java
+++ b/android/uhabits-android/src/androidTest/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetViewTest.java
@@ -53,6 +53,7 @@ public class CheckmarkWidgetViewTest extends BaseViewTest
float percentage = (float) score;
view.setActiveColor(PaletteUtils.getAndroidTestColor(0));
+ view.setCheckmarkState(habit.getCheckmarks().getTodayValue());
view.setCheckmarkValue(habit.getCheckmarks().getTodayValue());
view.setPercentage(percentage);
view.setName(habit.getName());
diff --git a/android/uhabits-android/src/main/AndroidManifest.xml b/android/uhabits-android/src/main/AndroidManifest.xml
index 9a3e7961f..f2dbda768 100644
--- a/android/uhabits-android/src/main/AndroidManifest.xml
+++ b/android/uhabits-android/src/main/AndroidManifest.xml
@@ -84,7 +84,17 @@
+
+
+
+
+
+
@@ -174,7 +184,14 @@
-
+
+
+
+
+
+
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt
index d0e959311..e9328cf44 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt
@@ -69,6 +69,9 @@ class NumberPickerFactory
val v = picker.value + 0.05 * picker2.value
callback.onNumberPicked(v)
}
+ .setOnDismissListener{
+ callback.onNumberPickerDismissed()
+ }
.create()
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt
index 676e55a4f..ca2204c06 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/IntentParser.kt
@@ -36,6 +36,11 @@ class IntentParser
return CheckmarkIntentData(parseHabit(uri), parseTimestamp(intent))
}
+ fun copyIntentData(source: Intent, destination: Intent) {
+ destination.data = source.data;
+ destination.putExtra("timestamp", source.getLongExtra("timestamp", DateUtils.getToday().unixTime))
+ }
+
private fun parseHabit(uri: Uri): Habit {
val habit = habits.getById(parseId(uri)) ?:
throw IllegalArgumentException("habit not found")
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
index 0901a0836..cb2f84532 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt
@@ -103,4 +103,19 @@ class PendingIntentFactory
if (timestamp != null) putExtra("timestamp", timestamp)
},
FLAG_UPDATE_CURRENT)
+
+ fun setNumericalValue(widgetContext: Context,
+ habit: Habit,
+ numericalValue: Int,
+ timestamp: Long?):
+ PendingIntent =
+ getBroadcast(
+ widgetContext, 2,
+ Intent(widgetContext, WidgetReceiver::class.java).apply {
+ data = Uri.parse(habit.uriString)
+ action = WidgetReceiver.ACTION_SET_NUMERICAL_VALUE
+ putExtra("numericalValue", numericalValue);
+ if (timestamp != null) putExtra("timestamp", timestamp)
+ },
+ FLAG_UPDATE_CURRENT)
}
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java
index c13d62d2d..20e0f65a7 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.java
@@ -27,6 +27,7 @@ import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.widgets.*;
import org.isoron.uhabits.intents.*;
import org.isoron.uhabits.sync.*;
+import org.isoron.uhabits.widgets.activities.*;
import dagger.*;
@@ -49,6 +50,9 @@ public class WidgetReceiver extends BroadcastReceiver
public static final String ACTION_TOGGLE_REPETITION =
"org.isoron.uhabits.ACTION_TOGGLE_REPETITION";
+ public static final String ACTION_SET_NUMERICAL_VALUE =
+ "org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE";
+
private static final String TAG = "WidgetReceiver";
@Override
@@ -104,6 +108,14 @@ public class WidgetReceiver extends BroadcastReceiver
controller.onRemoveRepetition(data.getHabit(),
data.getTimestamp());
break;
+ case ACTION_SET_NUMERICAL_VALUE:
+ Intent numberSelectorIntent = new Intent(context, NumericalCheckmarkWidgetActivity.class);
+ numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
+ numberSelectorIntent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK);
+ numberSelectorIntent.setAction(NumericalCheckmarkWidgetActivity.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY);
+ parser.copyIntentData(intent,numberSelectorIntent);
+ context.startActivity(numberSelectorIntent);
+ break;
}
}
catch (RuntimeException e)
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt
index ad159eab6..588a7fa25 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt
@@ -19,33 +19,58 @@
package org.isoron.uhabits.widgets
+import android.app.*
import android.content.*
import android.view.*
import org.isoron.uhabits.core.models.*
import org.isoron.uhabits.utils.*
import org.isoron.uhabits.widgets.views.*
-class CheckmarkWidget(
+open class CheckmarkWidget(
context: Context,
widgetId: Int,
- private val habit: Habit
+ protected val habit: Habit
) : BaseWidget(context, widgetId) {
- override fun getOnClickPendingIntent(context: Context) =
+ override fun getOnClickPendingIntent(context: Context): PendingIntent {
+ return if (habit.isNumerical) {
+ pendingIntentFactory.setNumericalValue(context, habit, 10, null)
+ } else {
pendingIntentFactory.toggleCheckmark(habit, null)
+ }
+ }
override fun refreshData(v: View) {
(v as CheckmarkWidgetView).apply {
setBackgroundAlpha(preferedBackgroundAlpha)
- setPercentage(habit.scores.todayValue.toFloat())
+
setActiveColor(PaletteUtils.getColor(context, habit.color))
setName(habit.name)
setCheckmarkValue(habit.checkmarks.todayValue)
+ if (habit.isNumerical) {
+ setNumerical(true)
+ setCheckmarkState(getNumericalCheckmarkState())
+ } else {
+ setCheckmarkState(habit.checkmarks.todayValue)
+ }
+ setPercentage(habit.scores.todayValue.toFloat())
refresh()
}
}
- override fun buildView() = CheckmarkWidgetView(context)
+ override fun buildView(): View {
+ return CheckmarkWidgetView(context)
+ }
+
override fun getDefaultHeight() = 125
override fun getDefaultWidth() = 125
+
+ private fun getNumericalCheckmarkState(): Int {
+ return if (habit.isCompletedToday) {
+ Checkmark.CHECKED_EXPLICITLY
+ } else {
+ Checkmark.UNCHECKED
+ }
+ }
+
}
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt
new file mode 100644
index 000000000..cc1b22421
--- /dev/null
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt
@@ -0,0 +1,76 @@
+/*
+ * Copyright (C) 2016-2020 Álinson Santos Xavier
+ *
+ * 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 .
+ */
+
+package org.isoron.uhabits.widgets.activities
+
+import android.app.*
+import android.content.*
+import android.os.*
+import android.view.*
+import android.widget.FrameLayout
+import org.isoron.uhabits.*
+import org.isoron.uhabits.activities.*
+import org.isoron.uhabits.activities.common.dialogs.*
+import org.isoron.uhabits.core.ui.screens.habits.list.*
+import org.isoron.uhabits.core.ui.widgets.*
+import org.isoron.uhabits.intents.*
+import org.isoron.uhabits.widgets.*
+
+class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPickerCallback {
+
+ private lateinit var behavior: WidgetBehavior
+ private lateinit var data: IntentParser.CheckmarkIntentData
+ private lateinit var widgetUpdater: WidgetUpdater
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ requestWindowFeature(Window.FEATURE_NO_TITLE)
+ setContentView(FrameLayout(this))
+ val app = this.applicationContext as HabitsApplication
+ val component = app.component
+ val parser = app.component.intentParser
+ data = parser.parseCheckmarkIntent(intent)
+ behavior = WidgetBehavior(component.habitList, component.commandRunner, component.notificationTray)
+ widgetUpdater = component.widgetUpdater
+ showNumberSelector(this)
+ }
+
+ override fun onNumberPicked(newValue: Double) {
+ behavior.setNumericValue(data.habit, data.timestamp, (newValue * 1000).toInt())
+ widgetUpdater.updateWidgets()
+ finish()
+ }
+
+ override fun onNumberPickerDismissed() {
+ finish()
+ }
+
+ private fun showNumberSelector(context: Context) {
+ val app = this.applicationContext as HabitsApplication
+ AndroidThemeSwitcher(this, app.component.preferences).apply()
+ val numberPickerFactory = NumberPickerFactory(context)
+ numberPickerFactory.create(data.habit.checkmarks.today!!.value.toDouble() / 1000,
+ data.habit.unit,
+ this).show()
+ }
+
+ companion object {
+ const val ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY = "org.isoron.uhabits.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY"
+ }
+}
\ No newline at end of file
diff --git a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java
index f241d5a32..68971ca55 100644
--- a/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java
+++ b/android/uhabits-android/src/main/java/org/isoron/uhabits/widgets/views/CheckmarkWidgetView.java
@@ -28,26 +28,30 @@ import androidx.annotation.Nullable;
import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*;
+import org.isoron.uhabits.activities.habits.list.views.*;
import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.utils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
-public class CheckmarkWidgetView extends HabitWidgetView
-{
- private int activeColor;
+public class CheckmarkWidgetView extends HabitWidgetView {
+ protected int activeColor;
- private float percentage;
+ protected float percentage;
@Nullable
- private String name;
+ protected String name;
- private RingView ring;
+ protected RingView ring;
- private TextView label;
+ protected TextView label;
- private int checkmarkValue;
+ protected int checkmarkValue;
+
+ protected int checkmarkState;
+
+ protected boolean isNumerical;
public CheckmarkWidgetView(Context context)
{
@@ -67,14 +71,11 @@ public class CheckmarkWidgetView extends HabitWidgetView
StyledResources res = new StyledResources(getContext());
- String text;
int bgColor;
int fgColor;
- switch (checkmarkValue)
- {
+ switch (checkmarkState) {
case Checkmark.CHECKED_EXPLICITLY:
- text = getResources().getString(R.string.fa_check);
bgColor = activeColor;
fgColor = res.getColor(R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f);
@@ -83,15 +84,9 @@ public class CheckmarkWidgetView extends HabitWidgetView
break;
case Checkmark.CHECKED_IMPLICITLY:
- text = getResources().getString(R.string.fa_check);
- bgColor = res.getColor(R.attr.cardBgColor);
- fgColor = res.getColor(R.attr.mediumContrastTextColor);
- setShadowAlpha(0x00);
- break;
-
case Checkmark.UNCHECKED:
default:
- text = getResources().getString(R.string.fa_times);
+ getResources().getString(R.string.fa_times);
bgColor = res.getColor(R.attr.cardBgColor);
fgColor = res.getColor(R.attr.mediumContrastTextColor);
setShadowAlpha(0x00);
@@ -101,7 +96,7 @@ public class CheckmarkWidgetView extends HabitWidgetView
ring.setPercentage(percentage);
ring.setColor(fgColor);
ring.setBackgroundColor(bgColor);
- ring.setText(text);
+ ring.setText(getText());
label.setText(name);
label.setTextColor(fgColor);
@@ -110,6 +105,25 @@ public class CheckmarkWidgetView extends HabitWidgetView
postInvalidate();
}
+ public void setCheckmarkState(int checkmarkState)
+ {
+ this.checkmarkState = checkmarkState;
+ }
+
+ protected String getText()
+ {
+ if (isNumerical) return NumberButtonViewKt.toShortString(checkmarkValue / 1000.0);
+ switch (checkmarkState) {
+ case Checkmark.CHECKED_EXPLICITLY:
+ case Checkmark.CHECKED_IMPLICITLY:
+ return getResources().getString(R.string.fa_check);
+
+ case Checkmark.UNCHECKED:
+ default:
+ return getResources().getString(R.string.fa_times);
+ }
+ }
+
public void setActiveColor(int activeColor)
{
this.activeColor = activeColor;
@@ -130,6 +144,11 @@ public class CheckmarkWidgetView extends HabitWidgetView
this.percentage = percentage;
}
+ public void setNumerical(boolean isNumerical)
+ {
+ this.isNumerical = isNumerical;
+ }
+
@Override
@NonNull
protected Integer getInnerLayoutId()
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java
index a290b56d9..3f5e79782 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/models/Habit.java
@@ -327,9 +327,9 @@ public class Habit
if (isNumerical())
{
if(getTargetType() == AT_LEAST)
- return todayCheckmark >= data.targetValue;
+ return todayCheckmark / 1000.0 >= data.targetValue;
else
- return todayCheckmark <= data.targetValue;
+ return todayCheckmark / 1000.0 <= data.targetValue;
}
else return (todayCheckmark != UNCHECKED);
}
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java
index 11491e5bf..d293cb3c8 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.java
@@ -177,6 +177,8 @@ public class ListHabitsBehavior
public interface NumberPickerCallback
{
void onNumberPicked(double newValue);
+
+ default void onNumberPickerDismissed() {}
}
public interface Screen
diff --git a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java
index 1bcc97782..46966cecf 100644
--- a/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java
+++ b/android/uhabits-core/src/main/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.java
@@ -73,4 +73,11 @@ public class WidgetBehavior
new ToggleRepetitionCommand(habitList, habit, timestamp),
habit.getId());
}
+
+ public void setNumericValue(@NonNull Habit habit, Timestamp timestamp, int newValue) {
+ commandRunner.execute(
+ new CreateRepetitionCommand(habit, timestamp, newValue),
+ habit.getId());
+ }
+
}
diff --git a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java
index 89d39dce5..e99e954c0 100644
--- a/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java
+++ b/android/uhabits-core/src/test/java/org/isoron/uhabits/core/models/HabitTest.java
@@ -102,19 +102,19 @@ public class HabitTest extends BaseUnitTest
h.setTargetValue(100.0);
assertFalse(h.isCompletedToday());
- h.getRepetitions().toggle(getToday(), 200);
+ h.getRepetitions().toggle(getToday(), 200_000);
assertTrue(h.isCompletedToday());
- h.getRepetitions().toggle(getToday(), 100);
+ h.getRepetitions().toggle(getToday(), 100_000);
assertTrue(h.isCompletedToday());
- h.getRepetitions().toggle(getToday(), 50);
+ h.getRepetitions().toggle(getToday(), 50_000);
assertFalse(h.isCompletedToday());
h.setTargetType(Habit.AT_MOST);
- h.getRepetitions().toggle(getToday(), 200);
+ h.getRepetitions().toggle(getToday(), 200_000);
assertFalse(h.isCompletedToday());
- h.getRepetitions().toggle(getToday(), 100);
+ h.getRepetitions().toggle(getToday(), 100_000);
assertTrue(h.isCompletedToday());
- h.getRepetitions().toggle(getToday(), 50);
+ h.getRepetitions().toggle(getToday(), 50_000);
assertTrue(h.isCompletedToday());
}