Update checkmark widget for numerical support

Co-authored-by: Alinson S. Xavier <git@axavier.org>
pull/605/head
Thomas S 5 years ago committed by Alinson S. Xavier
parent a8e77b8df8
commit 96d23bdf22

@ -53,6 +53,7 @@ public class CheckmarkWidgetViewTest extends BaseViewTest
float percentage = (float) score; float percentage = (float) score;
view.setActiveColor(PaletteUtils.getAndroidTestColor(0)); view.setActiveColor(PaletteUtils.getAndroidTestColor(0));
view.setCheckmarkState(habit.getCheckmarks().getTodayValue());
view.setCheckmarkValue(habit.getCheckmarks().getTodayValue()); view.setCheckmarkValue(habit.getCheckmarks().getTodayValue());
view.setPercentage(percentage); view.setPercentage(percentage);
view.setName(habit.getName()); view.setName(habit.getName());

@ -84,7 +84,17 @@
</activity> </activity>
<activity <activity
android:name=".notifications.SnoozeDelayPickerActivity" android:name=".widgets.activities.NumericalCheckmarkWidgetActivity"
android:label="NumericalCheckmarkWidget"
android:noHistory="true"
android:excludeFromRecents="true"
android:theme="@style/Theme.AppCompat.Light.Dialog">
<intent-filter>
<action android:name="org.isoron.uhabits.ACTION_SHOW_NUMERICAL_VALUE_ACTIVITY"/>
</intent-filter>
</activity>
<activity android:name=".notifications.SnoozeDelayPickerActivity"
android:excludeFromRecents="true" android:excludeFromRecents="true"
android:launchMode="singleInstance" android:launchMode="singleInstance"
android:theme="@android:style/Theme.Translucent.NoTitleBar" /> android:theme="@android:style/Theme.Translucent.NoTitleBar" />
@ -174,7 +184,14 @@
<receiver android:name=".receivers.WidgetReceiver"> <receiver android:name=".receivers.WidgetReceiver">
<intent-filter> <intent-filter>
<category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.DEFAULT"/>
<action android:name="org.isoron.uhabits.ACTION_SET_NUMERICAL_VALUE"/>
<data
android:host="org.isoron.uhabits"
android:scheme="content"/>
</intent-filter>
<intent-filter>
<category android:name="android.intent.category.DEFAULT"/>
<action android:name="org.isoron.uhabits.ACTION_TOGGLE_REPETITION" /> <action android:name="org.isoron.uhabits.ACTION_TOGGLE_REPETITION" />

@ -69,6 +69,9 @@ class NumberPickerFactory
val v = picker.value + 0.05 * picker2.value val v = picker.value + 0.05 * picker2.value
callback.onNumberPicked(v) callback.onNumberPicked(v)
} }
.setOnDismissListener{
callback.onNumberPickerDismissed()
}
.create() .create()
dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE) dialog.window?.setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE)

@ -36,6 +36,11 @@ class IntentParser
return CheckmarkIntentData(parseHabit(uri), parseTimestamp(intent)) 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 { private fun parseHabit(uri: Uri): Habit {
val habit = habits.getById(parseId(uri)) ?: val habit = habits.getById(parseId(uri)) ?:
throw IllegalArgumentException("habit not found") throw IllegalArgumentException("habit not found")

@ -103,4 +103,19 @@ class PendingIntentFactory
if (timestamp != null) putExtra("timestamp", timestamp) if (timestamp != null) putExtra("timestamp", timestamp)
}, },
FLAG_UPDATE_CURRENT) 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)
} }

@ -27,6 +27,7 @@ import org.isoron.uhabits.core.preferences.*;
import org.isoron.uhabits.core.ui.widgets.*; import org.isoron.uhabits.core.ui.widgets.*;
import org.isoron.uhabits.intents.*; import org.isoron.uhabits.intents.*;
import org.isoron.uhabits.sync.*; import org.isoron.uhabits.sync.*;
import org.isoron.uhabits.widgets.activities.*;
import dagger.*; import dagger.*;
@ -49,6 +50,9 @@ public class WidgetReceiver extends BroadcastReceiver
public static final String ACTION_TOGGLE_REPETITION = public static final String ACTION_TOGGLE_REPETITION =
"org.isoron.uhabits.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"; private static final String TAG = "WidgetReceiver";
@Override @Override
@ -104,6 +108,14 @@ public class WidgetReceiver extends BroadcastReceiver
controller.onRemoveRepetition(data.getHabit(), controller.onRemoveRepetition(data.getHabit(),
data.getTimestamp()); data.getTimestamp());
break; 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) catch (RuntimeException e)

@ -19,33 +19,58 @@
package org.isoron.uhabits.widgets package org.isoron.uhabits.widgets
import android.app.*
import android.content.* import android.content.*
import android.view.* import android.view.*
import org.isoron.uhabits.core.models.* import org.isoron.uhabits.core.models.*
import org.isoron.uhabits.utils.* import org.isoron.uhabits.utils.*
import org.isoron.uhabits.widgets.views.* import org.isoron.uhabits.widgets.views.*
class CheckmarkWidget( open class CheckmarkWidget(
context: Context, context: Context,
widgetId: Int, widgetId: Int,
private val habit: Habit protected val habit: Habit
) : BaseWidget(context, widgetId) { ) : 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) pendingIntentFactory.toggleCheckmark(habit, null)
}
}
override fun refreshData(v: View) { override fun refreshData(v: View) {
(v as CheckmarkWidgetView).apply { (v as CheckmarkWidgetView).apply {
setBackgroundAlpha(preferedBackgroundAlpha) setBackgroundAlpha(preferedBackgroundAlpha)
setPercentage(habit.scores.todayValue.toFloat())
setActiveColor(PaletteUtils.getColor(context, habit.color)) setActiveColor(PaletteUtils.getColor(context, habit.color))
setName(habit.name) setName(habit.name)
setCheckmarkValue(habit.checkmarks.todayValue) setCheckmarkValue(habit.checkmarks.todayValue)
if (habit.isNumerical) {
setNumerical(true)
setCheckmarkState(getNumericalCheckmarkState())
} else {
setCheckmarkState(habit.checkmarks.todayValue)
}
setPercentage(habit.scores.todayValue.toFloat())
refresh() refresh()
} }
} }
override fun buildView() = CheckmarkWidgetView(context) override fun buildView(): View {
return CheckmarkWidgetView(context)
}
override fun getDefaultHeight() = 125 override fun getDefaultHeight() = 125
override fun getDefaultWidth() = 125 override fun getDefaultWidth() = 125
private fun getNumericalCheckmarkState(): Int {
return if (habit.isCompletedToday) {
Checkmark.CHECKED_EXPLICITLY
} else {
Checkmark.UNCHECKED
}
}
} }

@ -0,0 +1,76 @@
/*
* Copyright (C) 2016-2020 Á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.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"
}
}

@ -28,26 +28,30 @@ import androidx.annotation.Nullable;
import org.isoron.androidbase.utils.*; import org.isoron.androidbase.utils.*;
import org.isoron.uhabits.*; import org.isoron.uhabits.*;
import org.isoron.uhabits.activities.habits.list.views.*;
import org.isoron.uhabits.core.models.*; import org.isoron.uhabits.core.models.*;
import org.isoron.uhabits.activities.common.views.*; import org.isoron.uhabits.activities.common.views.*;
import org.isoron.uhabits.utils.*; import org.isoron.uhabits.utils.*;
import static org.isoron.androidbase.utils.InterfaceUtils.getDimension; import static org.isoron.androidbase.utils.InterfaceUtils.getDimension;
public class CheckmarkWidgetView extends HabitWidgetView public class CheckmarkWidgetView extends HabitWidgetView {
{ protected int activeColor;
private int activeColor;
private float percentage; protected float percentage;
@Nullable @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) public CheckmarkWidgetView(Context context)
{ {
@ -67,14 +71,11 @@ public class CheckmarkWidgetView extends HabitWidgetView
StyledResources res = new StyledResources(getContext()); StyledResources res = new StyledResources(getContext());
String text;
int bgColor; int bgColor;
int fgColor; int fgColor;
switch (checkmarkValue) switch (checkmarkState) {
{
case Checkmark.CHECKED_EXPLICITLY: case Checkmark.CHECKED_EXPLICITLY:
text = getResources().getString(R.string.fa_check);
bgColor = activeColor; bgColor = activeColor;
fgColor = res.getColor(R.attr.highContrastReverseTextColor); fgColor = res.getColor(R.attr.highContrastReverseTextColor);
setShadowAlpha(0x4f); setShadowAlpha(0x4f);
@ -83,15 +84,9 @@ public class CheckmarkWidgetView extends HabitWidgetView
break; break;
case Checkmark.CHECKED_IMPLICITLY: 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: case Checkmark.UNCHECKED:
default: default:
text = getResources().getString(R.string.fa_times); getResources().getString(R.string.fa_times);
bgColor = res.getColor(R.attr.cardBgColor); bgColor = res.getColor(R.attr.cardBgColor);
fgColor = res.getColor(R.attr.mediumContrastTextColor); fgColor = res.getColor(R.attr.mediumContrastTextColor);
setShadowAlpha(0x00); setShadowAlpha(0x00);
@ -101,7 +96,7 @@ public class CheckmarkWidgetView extends HabitWidgetView
ring.setPercentage(percentage); ring.setPercentage(percentage);
ring.setColor(fgColor); ring.setColor(fgColor);
ring.setBackgroundColor(bgColor); ring.setBackgroundColor(bgColor);
ring.setText(text); ring.setText(getText());
label.setText(name); label.setText(name);
label.setTextColor(fgColor); label.setTextColor(fgColor);
@ -110,6 +105,25 @@ public class CheckmarkWidgetView extends HabitWidgetView
postInvalidate(); 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) public void setActiveColor(int activeColor)
{ {
this.activeColor = activeColor; this.activeColor = activeColor;
@ -130,6 +144,11 @@ public class CheckmarkWidgetView extends HabitWidgetView
this.percentage = percentage; this.percentage = percentage;
} }
public void setNumerical(boolean isNumerical)
{
this.isNumerical = isNumerical;
}
@Override @Override
@NonNull @NonNull
protected Integer getInnerLayoutId() protected Integer getInnerLayoutId()

@ -327,9 +327,9 @@ public class Habit
if (isNumerical()) if (isNumerical())
{ {
if(getTargetType() == AT_LEAST) if(getTargetType() == AT_LEAST)
return todayCheckmark >= data.targetValue; return todayCheckmark / 1000.0 >= data.targetValue;
else else
return todayCheckmark <= data.targetValue; return todayCheckmark / 1000.0 <= data.targetValue;
} }
else return (todayCheckmark != UNCHECKED); else return (todayCheckmark != UNCHECKED);
} }

@ -177,6 +177,8 @@ public class ListHabitsBehavior
public interface NumberPickerCallback public interface NumberPickerCallback
{ {
void onNumberPicked(double newValue); void onNumberPicked(double newValue);
default void onNumberPickerDismissed() {}
} }
public interface Screen public interface Screen

@ -73,4 +73,11 @@ public class WidgetBehavior
new ToggleRepetitionCommand(habitList, habit, timestamp), new ToggleRepetitionCommand(habitList, habit, timestamp),
habit.getId()); habit.getId());
} }
public void setNumericValue(@NonNull Habit habit, Timestamp timestamp, int newValue) {
commandRunner.execute(
new CreateRepetitionCommand(habit, timestamp, newValue),
habit.getId());
}
} }

@ -102,19 +102,19 @@ public class HabitTest extends BaseUnitTest
h.setTargetValue(100.0); h.setTargetValue(100.0);
assertFalse(h.isCompletedToday()); assertFalse(h.isCompletedToday());
h.getRepetitions().toggle(getToday(), 200); h.getRepetitions().toggle(getToday(), 200_000);
assertTrue(h.isCompletedToday()); assertTrue(h.isCompletedToday());
h.getRepetitions().toggle(getToday(), 100); h.getRepetitions().toggle(getToday(), 100_000);
assertTrue(h.isCompletedToday()); assertTrue(h.isCompletedToday());
h.getRepetitions().toggle(getToday(), 50); h.getRepetitions().toggle(getToday(), 50_000);
assertFalse(h.isCompletedToday()); assertFalse(h.isCompletedToday());
h.setTargetType(Habit.AT_MOST); h.setTargetType(Habit.AT_MOST);
h.getRepetitions().toggle(getToday(), 200); h.getRepetitions().toggle(getToday(), 200_000);
assertFalse(h.isCompletedToday()); assertFalse(h.isCompletedToday());
h.getRepetitions().toggle(getToday(), 100); h.getRepetitions().toggle(getToday(), 100_000);
assertTrue(h.isCompletedToday()); assertTrue(h.isCompletedToday());
h.getRepetitions().toggle(getToday(), 50); h.getRepetitions().toggle(getToday(), 50_000);
assertTrue(h.isCompletedToday()); assertTrue(h.isCompletedToday());
} }

Loading…
Cancel
Save