From d38f83e96135080a5ff9276e3f127477cab7091e Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Mon, 13 Sep 2021 07:05:17 -0700 Subject: [PATCH] Added a notes field and implemented dialog for numeric habits --- .../common/dialogs/NumberPickerFactory.kt | 11 ++- .../habits/list/ListHabitsScreen.kt | 3 +- .../habits/list/views/CheckmarkButtonView.kt | 6 ++ .../habits/list/views/CheckmarkPanelView.kt | 10 +++ .../habits/list/views/HabitCardListAdapter.kt | 3 +- .../habits/list/views/HabitCardListView.kt | 2 + .../habits/list/views/HabitCardView.kt | 9 ++- .../habits/list/views/NumberButtonView.kt | 16 +++- .../habits/list/views/NumberPanelView.kt | 10 +++ .../habits/show/ShowHabitActivity.kt | 3 +- .../NumericalCheckmarkWidgetActivity.kt | 5 +- .../main/res/layout/number_picker_dialog.xml | 73 +++++++++++++------ .../src/main/res/values/strings.xml | 1 + .../java/org/isoron/uhabits/core/Constants.kt | 2 +- .../core/commands/CreateRepetitionCommand.kt | 3 +- .../uhabits/core/io/HabitBullCSVImporter.kt | 3 +- .../isoron/uhabits/core/io/LoopDBImporter.kt | 4 +- .../org/isoron/uhabits/core/models/Entry.kt | 1 + .../core/models/sqlite/records/EntryRecord.kt | 6 +- .../screens/habits/list/HabitCardListCache.kt | 29 +++++++- .../screens/habits/list/ListHabitsBehavior.kt | 19 +++-- .../screens/habits/show/views/HistoryCard.kt | 10 ++- .../uhabits/core/ui/widgets/WidgetBehavior.kt | 22 ++++-- .../src/jvmMain/resources/migrations/25.sql | 1 + .../commands/CreateRepetitionCommandTest.kt | 2 +- .../habits/list/ListHabitsBehaviorTest.kt | 6 +- 26 files changed, 200 insertions(+), 60 deletions(-) create mode 100644 uhabits-core/src/jvmMain/resources/migrations/25.sql diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt index 1ca119a77..e62abc1a5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/NumberPickerFactory.kt @@ -47,6 +47,7 @@ class NumberPickerFactory fun create( value: Double, unit: String, + notes: String, callback: ListHabitsBehavior.NumberPickerCallback ): AlertDialog { val inflater = LayoutInflater.from(context) @@ -54,6 +55,7 @@ class NumberPickerFactory val picker = view.findViewById(R.id.picker) val picker2 = view.findViewById(R.id.picker2) + val etNotes = view.findViewById(R.id.etNotes) val watcherFilter: InputFilter = SeparatorWatcherInputFilter(picker2) val numberPickerInputText = getNumberPickerInputText(picker) @@ -77,13 +79,18 @@ class NumberPickerFactory picker2.setFormatter { v -> String.format("%02d", v) } picker2.value = intValue % 100 + etNotes.setText(notes) val dialog = AlertDialog.Builder(context) .setView(view) .setTitle(R.string.change_value) - .setPositiveButton(android.R.string.ok) { _, _ -> + .setPositiveButton(R.string.save) { _, _ -> picker.clearFocus() val v = picker.value + 0.01 * picker2.value - callback.onNumberPicked(v) + val note = etNotes.text.toString() + callback.onNumberPicked(v, note) + } + .setNegativeButton(R.string.cancel) { _, _ -> + callback.onNumberPickerDismissed() } .setOnDismissListener { callback.onNumberPickerDismissed() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt index 58ad6a031..7746285de 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/ListHabitsScreen.kt @@ -225,9 +225,10 @@ class ListHabitsScreen override fun showNumberPicker( value: Double, unit: String, + notes: String, callback: ListHabitsBehavior.NumberPickerCallback ) { - numberPickerFactory.create(value, unit, callback).show() + numberPickerFactory.create(value, unit, notes, callback).show() } private fun getExecuteString(command: Command): String? { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt index 339cc46b4..26735f865 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkButtonView.kt @@ -71,6 +71,12 @@ class CheckmarkButtonView( invalidate() } + var hasNotes = false + set(value) { + field = value + invalidate() + } + var onToggle: (Int) -> Unit = {} private var drawer = Drawer() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt index 136ea0050..9dba30f31 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt @@ -54,6 +54,12 @@ class CheckmarkPanelView( setupButtons() } + var notes = BooleanArray(0) + set(values) { + field = values + setupButtons() + } + var onToggle: (Timestamp, Int) -> Unit = { _, _ -> } set(value) { field = value @@ -72,6 +78,10 @@ class CheckmarkPanelView( index + dataOffset < values.size -> values[index + dataOffset] else -> UNKNOWN } + button.hasNotes = when { + index + dataOffset < notes.size -> notes[index + dataOffset] + else -> false + } button.color = color button.onToggle = { value -> onToggle(timestamp, value) } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt index a780bad08..b8770d0cb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListAdapter.kt @@ -124,8 +124,9 @@ class HabitCardListAdapter @Inject constructor( val habit = cache.getHabitByPosition(position) val score = cache.getScore(habit!!.id!!) val checkmarks = cache.getCheckmarks(habit.id!!) + val notesIndicators = cache.getNoteIndicators(habit.id!!) val selected = selected.contains(habit) - listView!!.bindCardView(holder, habit, score, checkmarks, selected) + listView!!.bindCardView(holder, habit, score, checkmarks, notesIndicators, selected) } override fun onViewAttachedToWindow(holder: HabitCardViewHolder) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt index 58ee2b36a..c8b3915b9 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardListView.kt @@ -87,6 +87,7 @@ class HabitCardListView( habit: Habit, score: Double, checkmarks: IntArray, + notesIndicators: BooleanArray, selected: Boolean ): View { val cardView = holder.itemView as HabitCardView @@ -98,6 +99,7 @@ class HabitCardListView( cardView.score = score cardView.unit = habit.unit cardView.threshold = habit.targetValue / habit.frequency.denominator + cardView.notes = notesIndicators val detector = GestureDetector(context, CardViewGestureDetector(holder)) cardView.setOnTouchListener { _, ev -> diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt index d6e7a2ad3..1d3b8c685 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/HabitCardView.kt @@ -115,6 +115,13 @@ class HabitCardView( numberPanel.threshold = value } + var notes + get() = numberPanel.notes + set(values) { + checkmarkPanel.notes = values + numberPanel.notes = values + } + var checkmarkPanel: CheckmarkPanelView private var numberPanel: NumberPanelView private var innerFrame: LinearLayout @@ -143,7 +150,7 @@ class HabitCardView( checkmarkPanel = checkmarkPanelFactory.create().apply { onToggle = { timestamp, value -> triggerRipple(timestamp) - habit?.let { behavior.onToggle(it, timestamp, value) } + habit?.let { behavior.onToggle(it, timestamp, value, "") } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt index 405bf606d..7e386df48 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonView.kt @@ -101,6 +101,11 @@ class NumberButtonView( field = value invalidate() } + var hasNotes = false + set(value) { + field = value + invalidate() + } var onEdit: () -> Unit = {} private var drawer: Drawer = Drawer(context) @@ -111,8 +116,7 @@ class NumberButtonView( } override fun onClick(v: View) { - if (preferences.isShortToggleEnabled) onEdit() - else showMessage(resources.getString(R.string.long_press_to_edit)) + onEdit() } override fun onLongClick(v: View): Boolean { @@ -153,6 +157,8 @@ class NumberButtonView( textAlign = Paint.Align.CENTER } + private val pNotesIndicator: Paint = Paint() + init { em = pNumber.measureText("m") lowContrast = sres.getColor(R.attr.contrast40) @@ -200,6 +206,7 @@ class NumberButtonView( pNumber.color = activeColor pNumber.typeface = typeface pUnit.color = activeColor + pNotesIndicator.color = activeColor if (units.isBlank()) { rect.set(0f, 0f, width.toFloat(), height.toFloat()) @@ -211,6 +218,11 @@ class NumberButtonView( rect.offset(0f, 1.3f * em) canvas.drawText(units, rect.centerX(), rect.centerY(), pUnit) } + + if (hasNotes) { + val cy = 0.8f * em + canvas.drawCircle(width.toFloat() - cy, cy, 8f, pNotesIndicator) + } } } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt index 0a5339ce0..329df6212 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/NumberPanelView.kt @@ -72,6 +72,12 @@ class NumberPanelView( setupButtons() } + var notes = BooleanArray(0) + set(values) { + field = values + setupButtons() + } + var onEdit: (Timestamp) -> Unit = {} set(value) { field = value @@ -90,6 +96,10 @@ class NumberPanelView( index + dataOffset < values.size -> values[index + dataOffset] else -> 0.0 } + button.hasNotes = when { + index + dataOffset < notes.size -> notes[index + dataOffset] + else -> false + } button.color = color button.targetType = targetType button.threshold = threshold diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt index 202adb88d..5ecfeea66 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/ShowHabitActivity.kt @@ -164,9 +164,10 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { override fun showNumberPicker( value: Double, unit: String, + notes: String, callback: ListHabitsBehavior.NumberPickerCallback, ) { - NumberPickerFactory(this@ShowHabitActivity).create(value, unit, callback).show() + NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, callback).show() } override fun showEditHabitScreen(habit: Habit) { diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt index 696fa8c81..cdc516e9a 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/activities/NumericalCheckmarkWidgetActivity.kt @@ -60,8 +60,8 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi SystemUtils.unlockScreen(this) } - override fun onNumberPicked(newValue: Double) { - behavior.setValue(data.habit, data.timestamp, (newValue * 1000).toInt()) + override fun onNumberPicked(newValue: Double, notes: String) { + behavior.setValue(data.habit, data.timestamp, (newValue * 1000).toInt(), notes) widgetUpdater.updateWidgets() finish() } @@ -79,6 +79,7 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi numberPickerFactory.create( entry.value / 1000.0, data.habit.unit, + entry.notes, this ).show() } diff --git a/uhabits-android/src/main/res/layout/number_picker_dialog.xml b/uhabits-android/src/main/res/layout/number_picker_dialog.xml index 4a9ffb4ee..8fc33e764 100644 --- a/uhabits-android/src/main/res/layout/number_picker_dialog.xml +++ b/uhabits-android/src/main/res/layout/number_picker_dialog.xml @@ -19,33 +19,64 @@ --> - + - + + + + + + + - + + + android:orientation="vertical" + android:padding="30dp"> + + + + - + \ No newline at end of file diff --git a/uhabits-android/src/main/res/values/strings.xml b/uhabits-android/src/main/res/values/strings.xml index 13767b3df..36be8d1b3 100644 --- a/uhabits-android/src/main/res/values/strings.xml +++ b/uhabits-android/src/main/res/values/strings.xml @@ -55,6 +55,7 @@ Clear Reminder Save + Cancel Streaks You have no active habits You\'re all done for today! 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 1388cb5f8..be6c9634b 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 = 24 +const val DATABASE_VERSION = 25 diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.kt index cf0081152..3dd71c14e 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/commands/CreateRepetitionCommand.kt @@ -28,10 +28,11 @@ data class CreateRepetitionCommand( val habit: Habit, val timestamp: Timestamp, val value: Int, + val notes: String, ) : Command { override fun run() { val entries = habit.originalEntries - entries.add(Entry(timestamp, value)) + entries.add(Entry(timestamp, value, notes)) habit.recompute() habitList.resort() } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt index bdf7b70c9..ee94cdbd0 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/HabitBullCSVImporter.kt @@ -77,7 +77,8 @@ class HabitBullCSVImporter logger.info("Creating habit: $name") } if (parseInt(cols[4]) == 1) { - h.originalEntries.add(Entry(timestamp, Entry.YES_MANUAL)) + val notes = cols[5] ?: "" + h.originalEntries.add(Entry(timestamp, Entry.YES_MANUAL, notes)) } } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt index 0969cd849..3e060f311 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/io/LoopDBImporter.kt @@ -101,8 +101,8 @@ class LoopDBImporter for (r in entryRecords) { val t = Timestamp(r.timestamp!!) - val (_, value) = habit!!.originalEntries.get(t) - if (value != r.value) CreateRepetitionCommand(habitList, habit, t, r.value!!).run() + val (_, value, notes) = habit!!.originalEntries.get(t) + if (value != r.value || notes != r.notes) CreateRepetitionCommand(habitList, habit, t, r.value!!, r.notes!!).run() } runner.notifyListeners(command) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Entry.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Entry.kt index e7aefb8a6..88d0593ef 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Entry.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Entry.kt @@ -21,6 +21,7 @@ package org.isoron.uhabits.core.models data class Entry( val timestamp: Timestamp, val value: Int, + val notes: String = "", ) { companion object { /** diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt index eb2bf858f..648cce117 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/sqlite/records/EntryRecord.kt @@ -41,12 +41,16 @@ class EntryRecord { @field:Column var id: Long? = null + + @field:Column + var notes: String? = null fun copyFrom(entry: Entry) { timestamp = entry.timestamp.unixTime value = entry.value + notes = entry.notes } fun toEntry(): Entry { - return Entry(Timestamp(timestamp!!), value!!) + return Entry(Timestamp(timestamp!!), value!!, notes!!) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt index a1490421a..d8076c514 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCache.kt @@ -78,6 +78,11 @@ class HabitCardListCache @Inject constructor( return data.checkmarks[habitId]!! } + @Synchronized + fun getNoteIndicators(habitId: Long): BooleanArray { + return data.notesIndicators[habitId]!! + } + @Synchronized fun hasNoHabit(): Boolean { return allHabits.isEmpty @@ -163,6 +168,7 @@ class HabitCardListCache @Inject constructor( data.habits.removeAt(position) data.idToHabit.remove(id) data.checkmarks.remove(id) + data.notesIndicators.remove(id) data.scores.remove(id) listener.onItemRemoved(position) } @@ -207,6 +213,7 @@ class HabitCardListCache @Inject constructor( val habits: MutableList val checkmarks: HashMap val scores: HashMap + val notesIndicators: HashMap @Synchronized fun copyCheckmarksFrom(oldData: CacheData) { @@ -217,6 +224,15 @@ class HabitCardListCache @Inject constructor( } } + @Synchronized + fun copyNoteIndicatorsFrom(oldData: CacheData) { + val empty = BooleanArray(checkmarkCount) + for (id in idToHabit.keys) { + if (oldData.notesIndicators.containsKey(id)) notesIndicators[id] = + oldData.notesIndicators[id]!! else notesIndicators[id] = empty + } + } + @Synchronized fun copyScoresFrom(oldData: CacheData) { for (id in idToHabit.keys) { @@ -241,6 +257,7 @@ class HabitCardListCache @Inject constructor( habits = LinkedList() checkmarks = HashMap() scores = HashMap() + notesIndicators = HashMap() } } @@ -271,6 +288,7 @@ class HabitCardListCache @Inject constructor( newData.fetchHabits() newData.copyScoresFrom(data) newData.copyCheckmarksFrom(data) + newData.copyNoteIndicatorsFrom(data) val today = getTodayWithOffset() val dateFrom = today.minus(checkmarkCount - 1) if (runner != null) runner!!.publishProgress(this, -1) @@ -280,10 +298,14 @@ class HabitCardListCache @Inject constructor( if (targetId != null && targetId != habit.id) continue newData.scores[habit.id] = habit.scores[today].value val list: MutableList = ArrayList() - for ((_, value) in habit.computedEntries.getByInterval(dateFrom, today)) + val notesList: MutableList = ArrayList() + for ((_, value, note) in habit.computedEntries.getByInterval(dateFrom, today)) { list.add(value) + if (note.isNotEmpty()) notesList.add(true) else notesList.add(false) + } val entries = list.toTypedArray() newData.checkmarks[habit.id] = ArrayUtils.toPrimitive(entries) + newData.notesIndicators[habit.id] = notesList.toBooleanArray() runner!!.publishProgress(this, position) } } @@ -311,6 +333,7 @@ class HabitCardListCache @Inject constructor( data.idToHabit[id] = habit data.scores[id] = newData.scores[id]!! data.checkmarks[id] = newData.checkmarks[id]!! + data.notesIndicators[id] = newData.notesIndicators[id]!! listener.onItemInserted(position) } @@ -338,14 +361,18 @@ class HabitCardListCache @Inject constructor( private fun performUpdate(id: Long, position: Int) { val oldScore = data.scores[id]!! val oldCheckmarks = data.checkmarks[id] + val oldNoteIndicators = data.notesIndicators[id] val newScore = newData.scores[id]!! val newCheckmarks = newData.checkmarks[id]!! + val newNoteIndicators = newData.notesIndicators[id]!! var unchanged = true if (oldScore != newScore) unchanged = false if (!Arrays.equals(oldCheckmarks, newCheckmarks)) unchanged = false + if (!Arrays.equals(oldNoteIndicators, newNoteIndicators)) unchanged = false if (unchanged) return data.scores[id] = newScore data.checkmarks[id] = newCheckmarks + data.notesIndicators[id] = newNoteIndicators listener.onItemChanged(position) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt index 89fb09af4..2d00b8fbf 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehavior.kt @@ -47,14 +47,16 @@ open class ListHabitsBehavior @Inject constructor( } fun onEdit(habit: Habit, timestamp: Timestamp?) { - val entries = habit.computedEntries - val oldValue = entries.get(timestamp!!).value.toDouble() + val entries = habit.computedEntries.get(timestamp!!) + val oldValue = entries.value.toDouble() + val notes = entries.notes screen.showNumberPicker( oldValue / 1000, - habit.unit - ) { newValue: Double -> + habit.unit, + notes + ) { newValue: Double, newNotes:String, -> val value = (newValue * 1000).roundToInt() - commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value)) + commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) } } @@ -104,9 +106,9 @@ open class ListHabitsBehavior @Inject constructor( if (prefs.isFirstRun) onFirstRun() } - fun onToggle(habit: Habit, timestamp: Timestamp?, value: Int) { + fun onToggle(habit: Habit, timestamp: Timestamp?, value: Int, notes: String) { commandRunner.run( - CreateRepetitionCommand(habitList, habit, timestamp!!, value) + CreateRepetitionCommand(habitList, habit, timestamp!!, value, notes) ) } @@ -131,7 +133,7 @@ open class ListHabitsBehavior @Inject constructor( } fun interface NumberPickerCallback { - fun onNumberPicked(newValue: Double) + fun onNumberPicked(newValue: Double, notes: String) fun onNumberPickerDismissed() {} } @@ -142,6 +144,7 @@ open class ListHabitsBehavior @Inject constructor( fun showNumberPicker( value: Double, unit: String, + notes: String, callback: NumberPickerCallback ) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt index 3ce83c8b3..358e776aa 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/screens/habits/show/views/HistoryCard.kt @@ -64,7 +64,8 @@ class HistoryCardPresenter( if (habit.isNumerical) { val entries = habit.computedEntries val oldValue = entries.get(timestamp).value - screen.showNumberPicker(oldValue / 1000.0, habit.unit) { newValue: Double -> + val notes = entries.get(timestamp).notes + screen.showNumberPicker(oldValue / 1000.0, habit.unit, notes) { newValue: Double, newNotes: String -> val thousands = (newValue * 1000).roundToInt() commandRunner.run( CreateRepetitionCommand( @@ -72,11 +73,14 @@ class HistoryCardPresenter( habit, timestamp, thousands, + newNotes, ), ) } } else { - val currentValue = habit.computedEntries.get(timestamp).value + val entry = habit.computedEntries.get(timestamp) + val currentValue = entry.value + val notes = entry.notes val nextValue = Entry.nextToggleValue( value = currentValue, isSkipEnabled = preferences.isSkipEnabled, @@ -88,6 +92,7 @@ class HistoryCardPresenter( habit, timestamp, nextValue, + notes, ), ) } @@ -154,6 +159,7 @@ class HistoryCardPresenter( fun showNumberPicker( value: Double, unit: String, + notes: String, callback: ListHabitsBehavior.NumberPickerCallback, ) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.kt index 164ca04f3..d36420d57 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/widgets/WidgetBehavior.kt @@ -46,31 +46,37 @@ class WidgetBehavior @Inject constructor( } fun onToggleRepetition(habit: Habit, timestamp: Timestamp) { - val currentValue = habit.originalEntries.get(timestamp).value + val entry = habit.computedEntries.get(timestamp) + val currentValue = entry.value + val notes = entry.notes val newValue = nextToggleValue( value = currentValue, isSkipEnabled = preferences.isSkipEnabled, areQuestionMarksEnabled = preferences.areQuestionMarksEnabled ) - setValue(habit, timestamp, newValue) + setValue(habit, timestamp, newValue, notes) notificationTray.cancel(habit) } fun onIncrement(habit: Habit, timestamp: Timestamp, amount: Int) { - val currentValue = habit.computedEntries.get(timestamp).value - setValue(habit, timestamp, currentValue + amount) + val entry = habit.computedEntries.get(timestamp) + val currentValue = entry.value + val notes = entry.notes + setValue(habit, timestamp, currentValue + amount, notes) notificationTray.cancel(habit) } fun onDecrement(habit: Habit, timestamp: Timestamp, amount: Int) { - val currentValue = habit.computedEntries.get(timestamp).value - setValue(habit, timestamp, currentValue - amount) + val entry = habit.computedEntries.get(timestamp) + val currentValue = entry.value + val notes = entry.notes + setValue(habit, timestamp, currentValue - amount, notes) notificationTray.cancel(habit) } - fun setValue(habit: Habit, timestamp: Timestamp?, newValue: Int) { + fun setValue(habit: Habit, timestamp: Timestamp?, newValue: Int, notes: String = "") { commandRunner.run( - CreateRepetitionCommand(habitList, habit, timestamp!!, newValue) + CreateRepetitionCommand(habitList, habit, timestamp!!, newValue, notes) ) } } diff --git a/uhabits-core/src/jvmMain/resources/migrations/25.sql b/uhabits-core/src/jvmMain/resources/migrations/25.sql new file mode 100644 index 000000000..627a686d5 --- /dev/null +++ b/uhabits-core/src/jvmMain/resources/migrations/25.sql @@ -0,0 +1 @@ +alter table Repetitions add column notes text; \ No newline at end of file diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt index fade73e69..974af722b 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/commands/CreateRepetitionCommandTest.kt @@ -38,7 +38,7 @@ class CreateRepetitionCommandTest : BaseUnitTest() { habit = fixtures.createShortHabit() habitList.add(habit) today = getToday() - command = CreateRepetitionCommand(habitList, habit, today, 100) + command = CreateRepetitionCommand(habitList, habit, today, 100, "") } @Test diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt index b81d96284..22548314d 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/ListHabitsBehaviorTest.kt @@ -79,8 +79,8 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnEdit() { behavior.onEdit(habit2, getToday()) - verify(screen).showNumberPicker(eq(0.1), eq("miles"), picker.capture()) - picker.lastValue.onNumberPicked(100.0) + verify(screen).showNumberPicker(eq(0.1), eq("miles"), "", picker.capture()) + picker.lastValue.onNumberPicked(100.0, "") val today = getTodayWithOffset() assertThat(habit2.computedEntries.get(today).value, equalTo(100000)) } @@ -160,7 +160,7 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnToggle() { assertTrue(habit1.isCompletedToday()) - behavior.onToggle(habit1, getToday(), Entry.NO) + behavior.onToggle(habit1, getToday(), Entry.NO, "") assertFalse(habit1.isCompletedToday()) } }