diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt index a2f329d71..88d456125 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/edit/EditHabitActivity.kt @@ -85,6 +85,7 @@ class EditHabitActivity : AppCompatActivity() { var reminderMin = -1 var reminderDays: WeekdayList = WeekdayList.EVERY_DAY var targetType = NumericalHabitType.AT_LEAST + var increment = 0.0 override fun onCreate(state: Bundle?) { super.onCreate(state) @@ -105,6 +106,7 @@ class EditHabitActivity : AppCompatActivity() { freqNum = habit.frequency.numerator freqDen = habit.frequency.denominator targetType = habit.targetType + increment = habit.increment habit.reminder?.let { reminderHour = it.hour reminderMin = it.minute @@ -128,6 +130,7 @@ class EditHabitActivity : AppCompatActivity() { reminderHour = state.getInt("reminderHour") reminderMin = state.getInt("reminderMin") reminderDays = WeekdayList(state.getInt("reminderDays")) + increment = state.getDouble("increment") } updateColors() @@ -137,6 +140,7 @@ class EditHabitActivity : AppCompatActivity() { binding.unitOuterBox.visibility = View.GONE binding.targetOuterBox.visibility = View.GONE binding.targetTypeOuterBox.visibility = View.GONE + binding.incrementOuterBox.visibility = View.GONE } HabitType.NUMERICAL -> { binding.nameInput.hint = getString(R.string.measurable_short_example) @@ -254,6 +258,23 @@ class EditHabitActivity : AppCompatActivity() { for (fragment in supportFragmentManager.fragments) { (fragment as DialogFragment).dismiss() } + + populateWidgetAction() + binding.widgetActionPicker.setOnClickListener { + val builder = AlertDialog.Builder(this) + val arrayAdapter = ArrayAdapter(this, android.R.layout.select_dialog_item) + arrayAdapter.add(getString(R.string.widget_action_dialog)) + arrayAdapter.add(getString(R.string.widget_action_increment)) + builder.setAdapter(arrayAdapter) { dialog, which -> + increment = when (which) { + 1 -> 1.0 + else -> 0.0 + } + populateWidgetAction() + dialog.dismiss() + } + builder.show() + } } private fun save() { @@ -281,6 +302,7 @@ class EditHabitActivity : AppCompatActivity() { habit.targetValue = binding.targetInput.text.toString().toDouble() habit.targetType = targetType habit.unit = binding.unitInput.text.trim().toString() + habit.increment = binding.incrementInput.text.toString().toDouble() } habit.type = habitType @@ -341,6 +363,20 @@ class EditHabitActivity : AppCompatActivity() { } } + @SuppressLint("StringFormatMatches") + private fun populateWidgetAction() { + binding.widgetActionPicker.text = when (increment) { + 0.0 -> getString(R.string.widget_action_dialog) + else -> getString(R.string.widget_action_increment) + } + binding.incrementInput.setText(increment.toString()) + if (increment != 0.0) { + binding.incrementRightBox.visibility = View.VISIBLE + } else { + binding.incrementRightBox.visibility = View.GONE + } + } + private fun populateTargetType() { binding.targetTypePicker.text = when (targetType) { NumericalHabitType.AT_MOST -> getString(R.string.target_type_at_most) @@ -375,6 +411,7 @@ class EditHabitActivity : AppCompatActivity() { putInt("reminderHour", reminderHour) putInt("reminderMin", reminderMin) putInt("reminderDays", reminderDays.toInteger()) + putDouble("increment", increment) } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt index 038cfe3a4..96ece8753 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/intents/PendingIntentFactory.kt @@ -146,6 +146,18 @@ class PendingIntentFactory FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT ) + fun incrementNumerical(habit: Habit, timestamp: Long?): PendingIntent = + getBroadcast( + context, + 2, + Intent(context, WidgetReceiver::class.java).apply { + data = Uri.parse(habit.uriString) + action = WidgetReceiver.ACTION_INCREMENT_NUMERICAL + if (timestamp != null) putExtra("timestamp", timestamp) + }, + FLAG_IMMUTABLE or FLAG_UPDATE_CURRENT + ) + fun updateWidgets(): PendingIntent = getBroadcast( context, diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt index fc44eefbc..680374e29 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/receivers/WidgetReceiver.kt @@ -99,6 +99,17 @@ class WidgetReceiver : BroadcastReceiver() { widgetUpdater.updateWidgets() widgetUpdater.scheduleStartDayWidgetUpdate() } + ACTION_INCREMENT_NUMERICAL -> { + Log.d( + TAG, + String.format( + "onIncrementNumerical habit=%d timestamp=%d", + data!!.habit.id, + data.timestamp.unixTime + ) + ) + controller.onIncrement(data.habit, data.timestamp, (data.habit.increment * 1000).toInt()) + } } } catch (e: RuntimeException) { Log.e("WidgetReceiver", "could not process intent", e) @@ -116,6 +127,7 @@ class WidgetReceiver : BroadcastReceiver() { const val ACTION_DISMISS_REMINDER = "org.isoron.uhabits.ACTION_DISMISS_REMINDER" const val ACTION_REMOVE_REPETITION = "org.isoron.uhabits.ACTION_REMOVE_REPETITION" const val ACTION_TOGGLE_REPETITION = "org.isoron.uhabits.ACTION_TOGGLE_REPETITION" + const val ACTION_INCREMENT_NUMERICAL = "org.isoron.uhabits.ACTION_INCREMENT_NUMERICAL" const val ACTION_UPDATE_WIDGETS_VALUE = "org.isoron.uhabits.ACTION_UPDATE_WIDGETS_VALUE" private const val TAG = "WidgetReceiver" var lastReceivedIntent: Intent? = null diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt index 017f67a29..08b2c8301 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/CheckmarkWidget.kt @@ -41,7 +41,11 @@ open class CheckmarkWidget( override fun getOnClickPendingIntent(context: Context): PendingIntent? { return if (habit.isNumerical) { - pendingIntentFactory.showNumberPicker(habit, DateUtils.getTodayWithOffset()) + if (habit.increment == 0.0) { + pendingIntentFactory.showNumberPicker(habit, DateUtils.getTodayWithOffset()) + } else { + pendingIntentFactory.incrementNumerical(habit, null) + } } else { pendingIntentFactory.toggleCheckmark(habit, null) } diff --git a/uhabits-android/src/main/res/layout/activity_edit_habit.xml b/uhabits-android/src/main/res/layout/activity_edit_habit.xml index 75dddb551..acf06dee1 100644 --- a/uhabits-android/src/main/res/layout/activity_edit_habit.xml +++ b/uhabits-android/src/main/res/layout/activity_edit_habit.xml @@ -208,6 +208,47 @@ + + + + + + + + + + + + + + + diff --git a/uhabits-android/src/main/res/values/strings.xml b/uhabits-android/src/main/res/values/strings.xml index 9fec1cbca..34b47e281 100644 --- a/uhabits-android/src/main/res/values/strings.xml +++ b/uhabits-android/src/main/res/values/strings.xml @@ -118,6 +118,9 @@ Developers Version %s Frequency + Widget Click Action + Open Dialog + Increment Checkmark Checkmark Stack Widget Frequency Stack Widget @@ -212,6 +215,7 @@ e.g. Exercise Color e.g. 15 + e.g. 2.0 e.g. Run e.g. How many miles did you run today? e.g. miles diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt index be6c9634b..328b8cd40 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/Constants.kt @@ -20,4 +20,4 @@ package org.isoron.uhabits.core const val DATABASE_FILENAME = "uhabits.db" -const val DATABASE_VERSION = 25 +const val DATABASE_VERSION = 26 diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt index a06d01ec9..c7bc1a510 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Habit.kt @@ -39,7 +39,8 @@ data class Habit( val computedEntries: EntryList, val originalEntries: EntryList, val scores: ScoreList, - val streaks: StreakList + val streaks: StreakList, + var increment: Double = 0.0 ) { init { if (uuid == null) this.uuid = UUID.randomUUID().toString().replace("-", "") @@ -119,6 +120,7 @@ data class Habit( this.type = other.type this.unit = other.unit this.uuid = other.uuid + this.increment = other.increment } override fun equals(other: Any?): Boolean { diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt index dc0386799..b9b761185 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/HabitRecord.kt @@ -88,6 +88,9 @@ class HabitRecord { @field:Column var uuid: String? = null + @field:Column + var increment: Double? = 0.0 + fun copyFrom(model: Habit) { id = model.id name = model.name @@ -114,6 +117,7 @@ class HabitRecord { reminderMin = reminder!!.minute reminderDays = reminder.days.toInteger() } + increment = model.increment } fun copyTo(habit: Habit) { @@ -137,5 +141,6 @@ class HabitRecord { WeekdayList(reminderDays!!) ) } + habit.increment = increment!! } } diff --git a/uhabits-core/src/jvmMain/resources/migrations/26.sql b/uhabits-core/src/jvmMain/resources/migrations/26.sql new file mode 100644 index 000000000..da37dfd5f --- /dev/null +++ b/uhabits-core/src/jvmMain/resources/migrations/26.sql @@ -0,0 +1 @@ +alter table Habits add column increment; \ No newline at end of file