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 01/15] 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()) } } From d6441701415c9b6e8799a27c1eb72d3ee3864897 Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Tue, 14 Sep 2021 07:28:41 -0700 Subject: [PATCH 02/15] Implement dialog for Yes/No Habits --- .../common/dialogs/CheckmarkDialog.kt | 50 +++++++++++++++++++ .../common/dialogs/NumberPickerFactory.kt | 2 +- .../habits/list/ListHabitsScreen.kt | 9 ++++ .../habits/list/views/CheckmarkButtonView.kt | 13 ++++- .../habits/list/views/CheckmarkPanelView.kt | 7 +++ .../habits/list/views/HabitCardView.kt | 8 ++- .../habits/list/views/NumberButtonView.kt | 2 +- .../habits/show/ShowHabitActivity.kt | 8 +++ .../src/main/res/layout/checkmark_dialog.xml | 18 +++++++ .../src/main/res/values/strings.xml | 2 +- .../screens/habits/list/ListHabitsBehavior.kt | 40 +++++++++++---- .../screens/habits/show/views/HistoryCard.kt | 4 ++ 12 files changed, 146 insertions(+), 17 deletions(-) create mode 100644 uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt create mode 100644 uhabits-android/src/main/res/layout/checkmark_dialog.xml diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt new file mode 100644 index 000000000..7b7853d3b --- /dev/null +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt @@ -0,0 +1,50 @@ +package org.isoron.uhabits.activities.common.dialogs + +import androidx.appcompat.app.AlertDialog +import android.content.Context +import android.view.LayoutInflater +import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE +import android.widget.EditText +import org.isoron.uhabits.R +import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior +import org.isoron.uhabits.inject.ActivityContext +import javax.inject.Inject + +class CheckmarkDialog +@Inject constructor( + @ActivityContext private val context: Context +) { + + fun create( + notes: String, + callback: ListHabitsBehavior.CheckMarkDialogCallback + ): AlertDialog { + val inflater = LayoutInflater.from(context) + val view = inflater.inflate(R.layout.checkmark_dialog, null) + + val etNotes = view.findViewById(R.id.etNotes) + + etNotes.setText(notes) + val dialog = AlertDialog.Builder(context) + .setView(view) + .setTitle(R.string.edit_notes) + .setPositiveButton(R.string.save) { _, _ -> + val note = etNotes.text.toString() + callback.onNotesSaved(note) + } + .setNegativeButton(android.R.string.cancel) { _, _ -> + callback.onNotesDismissed() + } + .setOnDismissListener { + callback.onNotesDismissed() + } + .create() + + dialog.setOnShowListener { + etNotes.requestFocus() + dialog.window?.setSoftInputMode(SOFT_INPUT_STATE_ALWAYS_VISIBLE) + } + + return dialog + } +} \ No newline at end of file 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 e62abc1a5..58db019a3 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 @@ -89,7 +89,7 @@ class NumberPickerFactory val note = etNotes.text.toString() callback.onNumberPicked(v, note) } - .setNegativeButton(R.string.cancel) { _, _ -> + .setNegativeButton(android.R.string.cancel) { _, _ -> callback.onNumberPickerDismissed() } .setOnDismissListener { 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 7746285de..ea2ad85b0 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 @@ -25,6 +25,7 @@ import android.content.Intent import androidx.appcompat.app.AppCompatActivity import dagger.Lazy import org.isoron.uhabits.R +import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog import org.isoron.uhabits.activities.common.dialogs.ColorPickerDialogFactory import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory @@ -89,6 +90,7 @@ class ListHabitsScreen private val importTaskFactory: ImportDataTaskFactory, private val colorPickerFactory: ColorPickerDialogFactory, private val numberPickerFactory: NumberPickerFactory, + private val checkMarkDialog: CheckmarkDialog, private val behavior: Lazy ) : CommandRunner.Listener, ListHabitsBehavior.Screen, @@ -231,6 +233,13 @@ class ListHabitsScreen numberPickerFactory.create(value, unit, notes, callback).show() } + override fun showCheckmarkDialog( + notes: String, + callback: ListHabitsBehavior.CheckMarkDialogCallback + ) { + checkMarkDialog.create(notes, callback).show() + } + private fun getExecuteString(command: Command): String? { when (command) { is ArchiveHabitsCommand -> { 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 26735f865..bd1b45715 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 @@ -39,7 +39,6 @@ import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.getFontAwesome -import org.isoron.uhabits.utils.showMessage import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.toMeasureSpec import javax.inject.Inject @@ -78,6 +77,8 @@ class CheckmarkButtonView( } var onToggle: (Int) -> Unit = {} + + var onEdit: () -> Unit = {} private var drawer = Drawer() init { @@ -99,7 +100,7 @@ class CheckmarkButtonView( override fun onClick(v: View) { if (preferences.isShortToggleEnabled) performToggle() - else showMessage(resources.getString(R.string.long_press_to_toggle)) + else onEdit() } override fun onLongClick(v: View): Boolean { @@ -133,6 +134,8 @@ class CheckmarkButtonView( textAlign = Paint.Align.CENTER } + private val pNotesIndicator: Paint = Paint() + fun draw(canvas: Canvas) { paint.color = when (value) { YES_MANUAL, YES_AUTO, SKIP -> color @@ -142,6 +145,7 @@ class CheckmarkButtonView( } else -> lowContrastColor } + pNotesIndicator.color = color val id = when (value) { SKIP -> R.string.fa_skipped NO -> R.string.fa_times @@ -176,6 +180,11 @@ class CheckmarkButtonView( paint.style = Paint.Style.FILL canvas.drawText(label, rect.centerX(), rect.centerY(), paint) } + + 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/CheckmarkPanelView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/list/views/CheckmarkPanelView.kt index 9dba30f31..dabbdc9c0 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 @@ -66,6 +66,12 @@ class CheckmarkPanelView( setupButtons() } + var onEdit: (Timestamp) -> Unit = {} + set(value) { + field = value + setupButtons() + } + override fun createButton(): CheckmarkButtonView = buttonFactory.create() @Synchronized @@ -84,6 +90,7 @@ class CheckmarkPanelView( } button.color = color button.onToggle = { value -> onToggle(timestamp, value) } + button.onEdit = { onEdit(timestamp) } } } } 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 1d3b8c685..82dc31930 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 @@ -116,7 +116,7 @@ class HabitCardView( } var notes - get() = numberPanel.notes + get() = checkmarkPanel.notes set(values) { checkmarkPanel.notes = values numberPanel.notes = values @@ -150,7 +150,11 @@ 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) } + } + onEdit = { timestamp -> + triggerRipple(timestamp) + habit?.let { behavior.onEdit(it, timestamp) } } } 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 7e386df48..3213e5a68 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 @@ -206,7 +206,7 @@ class NumberButtonView( pNumber.color = activeColor pNumber.typeface = typeface pUnit.color = activeColor - pNotesIndicator.color = activeColor + pNotesIndicator.color = color if (units.isBlank()) { rect.set(0f, 0f, width.toFloat(), height.toFloat()) 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 5ecfeea66..9dd01b521 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 @@ -32,6 +32,7 @@ import org.isoron.uhabits.HabitsApplication import org.isoron.uhabits.R import org.isoron.uhabits.activities.AndroidThemeSwitcher import org.isoron.uhabits.activities.HabitsDirFinder +import org.isoron.uhabits.activities.common.dialogs.CheckmarkDialog import org.isoron.uhabits.activities.common.dialogs.ConfirmDeleteDialog import org.isoron.uhabits.activities.common.dialogs.HistoryEditorDialog import org.isoron.uhabits.activities.common.dialogs.NumberPickerFactory @@ -170,6 +171,13 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, callback).show() } + override fun showCheckmarkDialog( + notes: String, + callback: ListHabitsBehavior.CheckMarkDialogCallback + ) { + CheckmarkDialog(this@ShowHabitActivity).create(notes, callback).show() + } + override fun showEditHabitScreen(habit: Habit) { startActivity(IntentFactory().startEditActivity(this@ShowHabitActivity, habit)) } diff --git a/uhabits-android/src/main/res/layout/checkmark_dialog.xml b/uhabits-android/src/main/res/layout/checkmark_dialog.xml new file mode 100644 index 000000000..765b23776 --- /dev/null +++ b/uhabits-android/src/main/res/layout/checkmark_dialog.xml @@ -0,0 +1,18 @@ + + + + + + + \ 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 36be8d1b3..c908816c1 100644 --- a/uhabits-android/src/main/res/values/strings.xml +++ b/uhabits-android/src/main/res/values/strings.xml @@ -55,7 +55,6 @@ Clear Reminder Save - Cancel Streaks You have no active habits You\'re all done for today! @@ -233,4 +232,5 @@ No app was found to support this action Extend day a few hours past midnight Wait until 3:00 AM to show a new day. Useful if you typically go to sleep after midnight. Requires app restart. + Edit notes 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 2d00b8fbf..5d0bff931 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 @@ -22,6 +22,7 @@ import org.isoron.uhabits.core.commands.CommandRunner import org.isoron.uhabits.core.commands.CreateRepetitionCommand import org.isoron.uhabits.core.models.Habit import org.isoron.uhabits.core.models.HabitList +import org.isoron.uhabits.core.models.HabitType import org.isoron.uhabits.core.models.Timestamp import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.tasks.ExportCSVTask @@ -48,15 +49,24 @@ open class ListHabitsBehavior @Inject constructor( fun onEdit(habit: Habit, timestamp: Timestamp?) { val entries = habit.computedEntries.get(timestamp!!) - val oldValue = entries.value.toDouble() val notes = entries.notes - screen.showNumberPicker( - oldValue / 1000, - habit.unit, - notes - ) { newValue: Double, newNotes:String, -> - val value = (newValue * 1000).roundToInt() - commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) + if (habit.type == HabitType.NUMERICAL) { + val oldValue = entries.value.toDouble() + screen.showNumberPicker( + oldValue / 1000, + habit.unit, + notes + ) { newValue: Double, newNotes:String, -> + val value = (newValue * 1000).roundToInt() + commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) + } + } else { + val value = entries.value + screen.showCheckmarkDialog( + notes + ) { newNotes -> + commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) + } } } @@ -106,9 +116,10 @@ open class ListHabitsBehavior @Inject constructor( if (prefs.isFirstRun) onFirstRun() } - fun onToggle(habit: Habit, timestamp: Timestamp?, value: Int, notes: String) { + fun onToggle(habit: Habit, timestamp: Timestamp?, value: Int) { + val notes = habit.computedEntries.get(timestamp!!).notes commandRunner.run( - CreateRepetitionCommand(habitList, habit, timestamp!!, value, notes) + CreateRepetitionCommand(habitList, habit, timestamp, value, notes) ) } @@ -137,6 +148,11 @@ open class ListHabitsBehavior @Inject constructor( fun onNumberPickerDismissed() {} } + fun interface CheckMarkDialogCallback { + fun onNotesSaved(notes: String) + fun onNotesDismissed() {} + } + interface Screen { fun showHabitScreen(h: Habit) fun showIntroScreen() @@ -147,6 +163,10 @@ open class ListHabitsBehavior @Inject constructor( notes: String, callback: NumberPickerCallback ) + fun showCheckmarkDialog( + notes: String, + callback: CheckMarkDialogCallback + ) fun showSendBugReportToDeveloperScreen(log: String) fun showSendFileScreen(filename: String) 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 358e776aa..899734956 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 @@ -162,5 +162,9 @@ class HistoryCardPresenter( notes: String, callback: ListHabitsBehavior.NumberPickerCallback, ) + fun showCheckmarkDialog( + notes: String, + callback: ListHabitsBehavior.CheckMarkDialogCallback, + ) } } From 36c1504c6a19aec1d3ba037cc917219480166b08 Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Tue, 14 Sep 2021 23:03:34 -0700 Subject: [PATCH 03/15] Add dialog and notes indicator for HistoryChart --- .../isoron/platform/gui/AndroidDataView.kt | 37 +++++++------ .../common/dialogs/HistoryEditorDialog.kt | 4 +- .../habits/show/views/HistoryCardView.kt | 1 + .../isoron/uhabits/widgets/HistoryWidget.kt | 2 + .../kotlin/org/isoron/platform/gui/View.kt | 2 + .../screens/habits/show/views/HistoryCard.kt | 53 +++++++++++++------ .../uhabits/core/ui/views/HistoryChart.kt | 26 +++++++-- 7 files changed, 91 insertions(+), 34 deletions(-) diff --git a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt index df5d5e184..0a8c5ee68 100644 --- a/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt +++ b/uhabits-android/src/main/java/org/isoron/platform/gui/AndroidDataView.kt @@ -49,23 +49,12 @@ class AndroidDataView( override fun onShowPress(e: MotionEvent?) = Unit override fun onSingleTapUp(e: MotionEvent?): Boolean { - val x: Float - val y: Float - try { - val pointerId = e!!.getPointerId(0) - x = e.getX(pointerId) - y = e.getY(pointerId) - } catch (ex: RuntimeException) { - // Android often throws IllegalArgumentException here. Apparently, - // the pointer id may become invalid shortly after calling - // e.getPointerId. - return false - } - view?.onClick(x / canvas.innerDensity, y / canvas.innerDensity) - return true + return handleClick(e, true) } - override fun onLongPress(e: MotionEvent?) = Unit + override fun onLongPress(e: MotionEvent?) { + handleClick(e) + } override fun onScroll( e1: MotionEvent?, @@ -137,4 +126,22 @@ class AndroidDataView( } } } + + private fun handleClick(e: MotionEvent?, isSingleTap: Boolean = false): Boolean { + val x: Float + val y: Float + try { + val pointerId = e!!.getPointerId(0) + x = e.getX(pointerId) + y = e.getY(pointerId) + } catch (ex: RuntimeException) { + // Android often throws IllegalArgumentException here. Apparently, + // the pointer id may become invalid shortly after calling + // e.getPointerId. + return false + } + if (isSingleTap) view?.onClick(x / canvas.innerDensity, y / canvas.innerDensity) + else view?.onLongClick(x / canvas.innerDensity, y / canvas.innerDensity) + return true + } } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt index 5edae637f..c040da2ac 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt @@ -63,9 +63,10 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener { paletteColor = habit.color, series = emptyList(), defaultSquare = HistoryChart.Square.OFF, + hasNotes = emptyList(), theme = themeSwitcher.currentTheme, today = DateUtils.getTodayWithOffset().toLocalDate(), - onDateClickedListener = onDateClickedListener ?: OnDateClickedListener { }, + onDateClickedListener = onDateClickedListener ?: OnDateClickedListener { _, _ -> }, padding = 10.0, ) dataView = AndroidDataView(context!!, null) @@ -103,6 +104,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener { ) chart?.series = model.series chart?.defaultSquare = model.defaultSquare + chart?.hasNotes = model.hasNotes dataView.postInvalidate() } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt index f429e1718..345789cca 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt @@ -44,6 +44,7 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont dateFormatter = JavaLocalDateFormatter(Locale.getDefault()), series = state.series, defaultSquare = state.defaultSquare, + hasNotes = state.hasNotes, firstWeekday = state.firstWeekday, ) binding.chart.postInvalidate() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt index c8d4dce44..7d520bec5 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt @@ -59,6 +59,7 @@ class HistoryWidget( val historyChart = (this.view as HistoryChart) historyChart.series = model.series historyChart.defaultSquare = model.defaultSquare + historyChart.hasNotes = model.hasNotes } } @@ -74,6 +75,7 @@ class HistoryWidget( firstWeekday = prefs.firstWeekday, series = listOf(), defaultSquare = HistoryChart.Square.OFF, + hasNotes = listOf(), ) } ).apply { diff --git a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/View.kt b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/View.kt index b58e1affe..c6ee60b65 100644 --- a/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/View.kt +++ b/uhabits-core/src/commonMain/kotlin/org/isoron/platform/gui/View.kt @@ -23,6 +23,8 @@ interface View { fun draw(canvas: Canvas) fun onClick(x: Double, y: Double) { } + fun onLongClick(x: Double, y: Double) { + } } interface DataView : View { 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 899734956..66a3c214a 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 @@ -46,6 +46,7 @@ data class HistoryCardState( val firstWeekday: DayOfWeek, val series: List, val defaultSquare: HistoryChart.Square, + val hasNotes: List, val theme: Theme, val today: LocalDate, ) @@ -58,7 +59,7 @@ class HistoryCardPresenter( val screen: Screen, ) : OnDateClickedListener { - override fun onDateClicked(date: LocalDate) { + override fun onDateClicked(date: LocalDate, isLongClick: Boolean) { val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() if (habit.isNumerical) { @@ -81,20 +82,34 @@ class HistoryCardPresenter( val entry = habit.computedEntries.get(timestamp) val currentValue = entry.value val notes = entry.notes - val nextValue = Entry.nextToggleValue( - value = currentValue, - isSkipEnabled = preferences.isSkipEnabled, - areQuestionMarksEnabled = preferences.areQuestionMarksEnabled - ) - commandRunner.run( - CreateRepetitionCommand( - habitList, - habit, - timestamp, - nextValue, - notes, - ), - ) + if (!isLongClick) { + val nextValue = Entry.nextToggleValue( + value = currentValue, + isSkipEnabled = preferences.isSkipEnabled, + areQuestionMarksEnabled = preferences.areQuestionMarksEnabled + ) + commandRunner.run( + CreateRepetitionCommand( + habitList, + habit, + timestamp, + nextValue, + notes, + ), + ) + return + } + screen.showCheckmarkDialog(notes) { newNotes -> + commandRunner.run( + CreateRepetitionCommand( + habitList, + habit, + timestamp, + currentValue, + newNotes, + ), + ) + } } } @@ -142,6 +157,13 @@ class HistoryCardPresenter( else HistoryChart.Square.OFF + val hasNotes = entries.map { + when (it.notes) { + "" -> false + else -> true + } + } + return HistoryCardState( color = habit.color, firstWeekday = firstWeekday, @@ -149,6 +171,7 @@ class HistoryCardPresenter( theme = theme, series = series, defaultSquare = defaultSquare + hasNotes = hasNotes, ) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt index f0da7a196..150713056 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt @@ -33,7 +33,7 @@ import kotlin.math.min import kotlin.math.round fun interface OnDateClickedListener { - fun onDateClicked(date: LocalDate) + fun onDateClicked(date: LocalDate, isLongClick: Boolean) } class HistoryChart( @@ -42,9 +42,10 @@ class HistoryChart( var paletteColor: PaletteColor, var series: List, var defaultSquare: Square, + var hasNotes: List, var theme: Theme, var today: LocalDate, - var onDateClickedListener: OnDateClickedListener = OnDateClickedListener { }, + var onDateClickedListener: OnDateClickedListener = OnDateClickedListener { _, _ -> }, var padding: Double = 0.0, ) : DataView { @@ -72,6 +73,14 @@ class HistoryChart( get() = squareSpacing + squareSize override fun onClick(x: Double, y: Double) { + onDateClicked(x, y, false) + } + + override fun onLongClick(x: Double, y: Double) { + onDateClicked(x, y, true) + } + + private fun onDateClicked(x: Double, y: Double, isLongClick: Boolean) { if (width <= 0.0) throw IllegalStateException("onClick must be called after draw(canvas)") val col = ((x - padding) / squareSize).toInt() val row = ((y - padding) / squareSize).toInt() @@ -79,7 +88,7 @@ class HistoryChart( if (row == 0 || col == nColumns) return val clickedDate = topLeftDate.plus(offset) if (clickedDate.isNewerThan(today)) return - onDateClickedListener.onDateClicked(clickedDate) + onDateClickedListener.onDateClicked(clickedDate, isLongClick) } override fun draw(canvas: Canvas) { @@ -191,7 +200,9 @@ class HistoryChart( ) { val value = if (offset >= series.size) defaultSquare else series[offset] + val notes = if (offset >= hasNotes.size) false else hasNotes[offset] val squareColor: Color + val circleColor: Color val color = theme.color(paletteColor.paletteIndex) squareColor = when (value) { Square.ON -> { @@ -235,5 +246,14 @@ class HistoryChart( canvas.setColor(textColor) canvas.setTextAlign(TextAlign.CENTER) canvas.drawText(date.day.toString(), x + width / 2, y + width / 2) + + if (notes) { + circleColor = when (value) { + Square.ON -> theme.lowContrastTextColor + else -> color + } + canvas.setColor(circleColor) + canvas.fillCircle(x + width - width / 5, y + width / 5, width / 12) + } } } From a9fddf99638ebc6b77eb0cd7fc2f37f398b074e6 Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Mon, 20 Sep 2021 03:47:59 -0700 Subject: [PATCH 04/15] Update tests and fix formatting. --- .../habits/list/views/NumberButtonViewTest.kt | 2 +- .../isoron/uhabits/performance/PerformanceTest.kt | 2 +- .../activities/common/dialogs/CheckmarkDialog.kt | 4 ++-- .../habits/list/views/NumberButtonView.kt | 3 +-- .../org/isoron/uhabits/core/io/LoopDBImporter.kt | 3 ++- .../core/models/sqlite/records/EntryRecord.kt | 3 ++- .../ui/screens/habits/list/ListHabitsBehavior.kt | 2 +- .../ui/screens/habits/show/views/HistoryCard.kt | 13 +++++-------- .../uhabits/core/ui/widgets/WidgetBehavior.kt | 12 ++++++++---- .../screens/habits/list/HabitCardListCacheTest.kt | 2 +- .../screens/habits/list/ListHabitsBehaviorTest.kt | 4 ++-- .../uhabits/core/ui/views/HistoryChartTest.kt | 12 ++++++++---- .../uhabits/core/ui/widgets/WidgetBehaviorTest.kt | 10 +++++----- 13 files changed, 39 insertions(+), 33 deletions(-) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt index 75166bfab..ea1571889 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt @@ -119,7 +119,7 @@ class NumberButtonViewTest : BaseViewTest() { fun testClick_shortToggleDisabled() { prefs.isShortToggleEnabled = false view.performClick() - assertFalse(edited) + assertTrue(edited) } @Test diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.kt index 10ad56057..d2debb851 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/performance/PerformanceTest.kt @@ -61,7 +61,7 @@ class PerformanceTest : BaseAndroidTest() { val habit = fixtures.createEmptyHabit() for (i in 0..4999) { val timestamp: Timestamp = Timestamp(i * DAY_LENGTH) - CreateRepetitionCommand(habitList, habit, timestamp, 1).run() + CreateRepetitionCommand(habitList, habit, timestamp, 1, "").run() } db.setTransactionSuccessful() db.endTransaction() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt index 7b7853d3b..156864caa 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt @@ -1,10 +1,10 @@ package org.isoron.uhabits.activities.common.dialogs -import androidx.appcompat.app.AlertDialog import android.content.Context import android.view.LayoutInflater import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE import android.widget.EditText +import androidx.appcompat.app.AlertDialog import org.isoron.uhabits.R import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior import org.isoron.uhabits.inject.ActivityContext @@ -47,4 +47,4 @@ class CheckmarkDialog return dialog } -} \ No newline at end of file +} 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 3213e5a68..dbb930710 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 @@ -35,7 +35,6 @@ import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.InterfaceUtils.getDimension import org.isoron.uhabits.utils.dim import org.isoron.uhabits.utils.getFontAwesome -import org.isoron.uhabits.utils.showMessage import org.isoron.uhabits.utils.sres import java.lang.Double.max import java.text.DecimalFormat @@ -219,7 +218,7 @@ class NumberButtonView( canvas.drawText(units, rect.centerX(), rect.centerY(), pUnit) } - if (hasNotes) { + if (hasNotes) { val cy = 0.8f * em canvas.drawCircle(width.toFloat() - cy, cy, 8f, pNotesIndicator) } 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 3e060f311..918c2084d 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 @@ -102,7 +102,8 @@ class LoopDBImporter for (r in entryRecords) { val t = Timestamp(r.timestamp!!) val (_, value, notes) = habit!!.originalEntries.get(t) - if (value != r.value || notes != r.notes) CreateRepetitionCommand(habitList, habit, t, r.value!!, r.notes!!).run() + val oldNotes = r.notes ?: "" + if (value != r.value || notes != oldNotes) CreateRepetitionCommand(habitList, habit, t, r.value!!, oldNotes).run() } runner.notifyListeners(command) 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 648cce117..aaf8fe9f9 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 @@ -51,6 +51,7 @@ class EntryRecord { } fun toEntry(): Entry { - return Entry(Timestamp(timestamp!!), value!!, notes!!) + val notes = notes ?: "" + return Entry(Timestamp(timestamp!!), value!!, notes) } } 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 5d0bff931..ced89ad79 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 @@ -56,7 +56,7 @@ open class ListHabitsBehavior @Inject constructor( oldValue / 1000, habit.unit, notes - ) { newValue: Double, newNotes:String, -> + ) { newValue: Double, newNotes: String, -> val value = (newValue * 1000).roundToInt() commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) } 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 66a3c214a..8b944d7b9 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 @@ -62,10 +62,10 @@ class HistoryCardPresenter( override fun onDateClicked(date: LocalDate, isLongClick: Boolean) { val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() + val entries = habit.computedEntries + val oldValue = entries.get(timestamp).value + val notes = entries.get(timestamp).notes if (habit.isNumerical) { - val entries = habit.computedEntries - val oldValue = entries.get(timestamp).value - 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( @@ -79,12 +79,9 @@ class HistoryCardPresenter( ) } } else { - val entry = habit.computedEntries.get(timestamp) - val currentValue = entry.value - val notes = entry.notes if (!isLongClick) { val nextValue = Entry.nextToggleValue( - value = currentValue, + value = oldValue, isSkipEnabled = preferences.isSkipEnabled, areQuestionMarksEnabled = preferences.areQuestionMarksEnabled ) @@ -105,7 +102,7 @@ class HistoryCardPresenter( habitList, habit, timestamp, - currentValue, + oldValue, newNotes, ), ) 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 d36420d57..65dff6dd2 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 @@ -37,16 +37,20 @@ class WidgetBehavior @Inject constructor( ) { fun onAddRepetition(habit: Habit, timestamp: Timestamp?) { notificationTray.cancel(habit) - setValue(habit, timestamp, Entry.YES_MANUAL) + val entry = habit.originalEntries.get(timestamp!!) + val notes = entry.notes + setValue(habit, timestamp, Entry.YES_MANUAL, notes) } fun onRemoveRepetition(habit: Habit, timestamp: Timestamp?) { notificationTray.cancel(habit) - setValue(habit, timestamp, Entry.NO) + val entry = habit.originalEntries.get(timestamp!!) + val notes = entry.notes + setValue(habit, timestamp, Entry.NO, notes) } fun onToggleRepetition(habit: Habit, timestamp: Timestamp) { - val entry = habit.computedEntries.get(timestamp) + val entry = habit.originalEntries.get(timestamp) val currentValue = entry.value val notes = entry.notes val newValue = nextToggleValue( @@ -74,7 +78,7 @@ class WidgetBehavior @Inject constructor( notificationTray.cancel(habit) } - fun setValue(habit: Habit, timestamp: Timestamp?, newValue: Int, notes: String = "") { + fun setValue(habit: Habit, timestamp: Timestamp?, newValue: Int, notes: String) { commandRunner.run( CreateRepetitionCommand(habitList, habit, timestamp!!, newValue, notes) ) diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt index af3132dde..97da833a5 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/screens/habits/list/HabitCardListCacheTest.kt @@ -70,7 +70,7 @@ class HabitCardListCacheTest : BaseUnitTest() { @Test fun testCommandListener_single() { val h2 = habitList.getByPosition(2) - commandRunner.run(CreateRepetitionCommand(habitList, h2, today, Entry.NO)) + commandRunner.run(CreateRepetitionCommand(habitList, h2, today, Entry.NO, "")) verify(listener).onItemChanged(2) verify(listener).onRefreshFinished() verifyNoMoreInteractions(listener) 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 22548314d..df58affa6 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,7 +79,7 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnEdit() { behavior.onEdit(habit2, getToday()) - verify(screen).showNumberPicker(eq(0.1), eq("miles"), "", picker.capture()) + verify(screen).showNumberPicker(eq(0.1), eq("miles"), eq(""), 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()) } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt index a53135f9b..84ecc9bfb 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt @@ -72,6 +72,10 @@ class HistoryChartTest { 1 -> DIMMED else -> OFF } + }, + hasNotes = MutableList(85) { + index: Int -> + index % 3 == 0 } ) @@ -86,20 +90,20 @@ class HistoryChartTest { // Click top left date view.onClick(20.0, 46.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26)) + verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26), false) reset(dateClickedListener) view.onClick(2.0, 28.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26)) + verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26), false) reset(dateClickedListener) // Click date in the middle view.onClick(163.0, 113.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 12, 10)) + verify(dateClickedListener).onDateClicked(LocalDate(2014, 12, 10), false) reset(dateClickedListener) // Click today view.onClick(336.0, 37.0) - verify(dateClickedListener).onDateClicked(LocalDate(2015, 1, 25)) + verify(dateClickedListener).onDateClicked(LocalDate(2015, 1, 25), false) reset(dateClickedListener) // Click header diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt index 18a06c8da..d58ef1979 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/widgets/WidgetBehaviorTest.kt @@ -58,7 +58,7 @@ class WidgetBehaviorTest : BaseUnitTest() { fun testOnAddRepetition() { behavior.onAddRepetition(habit, today) verify(commandRunner).run( - CreateRepetitionCommand(habitList, habit, today, Entry.YES_MANUAL) + CreateRepetitionCommand(habitList, habit, today, Entry.YES_MANUAL, "") ) verify(notificationTray).cancel(habit) verifyZeroInteractions(preferences) @@ -68,7 +68,7 @@ class WidgetBehaviorTest : BaseUnitTest() { fun testOnRemoveRepetition() { behavior.onRemoveRepetition(habit, today) verify(commandRunner).run( - CreateRepetitionCommand(habitList, habit, today, Entry.NO) + CreateRepetitionCommand(habitList, habit, today, Entry.NO, "") ) verify(notificationTray).cancel(habit) verifyZeroInteractions(preferences) @@ -94,7 +94,7 @@ class WidgetBehaviorTest : BaseUnitTest() { behavior.onToggleRepetition(habit, today) verify(preferences).isSkipEnabled verify(commandRunner).run( - CreateRepetitionCommand(habitList, habit, today, nextValue) + CreateRepetitionCommand(habitList, habit, today, nextValue, "") ) verify(notificationTray).cancel( habit @@ -110,7 +110,7 @@ class WidgetBehaviorTest : BaseUnitTest() { habit.recompute() behavior.onIncrement(habit, today, 100) verify(commandRunner).run( - CreateRepetitionCommand(habitList, habit, today, 600) + CreateRepetitionCommand(habitList, habit, today, 600, "") ) verify(notificationTray).cancel(habit) verifyZeroInteractions(preferences) @@ -123,7 +123,7 @@ class WidgetBehaviorTest : BaseUnitTest() { habit.recompute() behavior.onDecrement(habit, today, 100) verify(commandRunner).run( - CreateRepetitionCommand(habitList, habit, today, 400) + CreateRepetitionCommand(habitList, habit, today, 400, "") ) verify(notificationTray).cancel(habit) verifyZeroInteractions(preferences) From 7cc4b66dfdcc645effedd402bd413a1dbbe408a0 Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Tue, 21 Sep 2021 02:35:30 -0700 Subject: [PATCH 05/15] Update HabitBullCSV test to accept notes --- uhabits-core/assets/test/habitbull.csv | 2 +- uhabits-core/assets/test/habitbull2.csv | 4 ++-- .../org/isoron/uhabits/core/io/HabitBullCSVImporter.kt | 4 +++- .../java/org/isoron/uhabits/core/io/ImportTest.kt | 10 ++++++++++ 4 files changed, 16 insertions(+), 4 deletions(-) diff --git a/uhabits-core/assets/test/habitbull.csv b/uhabits-core/assets/test/habitbull.csv index 977a8e8df..014b7d656 100644 --- a/uhabits-core/assets/test/habitbull.csv +++ b/uhabits-core/assets/test/habitbull.csv @@ -1,5 +1,5 @@ HabitName,HabitDescription,HabitCategory,CalendarDate,Value,CommentText -Breed dragons,with love and fire,Diet & Food,2016-03-18,1, +Breed dragons,with love and fire,Diet & Food,2016-03-18,1,text Breed dragons,with love and fire,Diet & Food,2016-03-19,1, Breed dragons,with love and fire,Diet & Food,2016-03-21,1, Reduce sleep,only 2 hours per day,Time Management,2016-03-15,1, diff --git a/uhabits-core/assets/test/habitbull2.csv b/uhabits-core/assets/test/habitbull2.csv index 890632bbd..9296b1ebc 100644 --- a/uhabits-core/assets/test/habitbull2.csv +++ b/uhabits-core/assets/test/habitbull2.csv @@ -1,7 +1,7 @@ HabitName,HabitDescription,HabitCategory,CalendarDate,Value,CommentText H1,,C1,11/5/2020,1, H2,,C2,11/5/2020,-2150000000, -H3,Habit 3,C3,4/11/2019,1, +H3,Habit 3,C3,4/11/2019,1,text H3,Habit 3,C3,4/12/2019,1, H3,Habit 3,C3,4/13/2019,0, H3,Habit 3,C3,4/14/2019,1, @@ -65,7 +65,7 @@ H3,Habit 3,C3,6/10/2019,1, H3,Habit 3,C3,6/11/2019,1, H3,Habit 3,C3,6/12/2019,1, H3,Habit 3,C3,6/13/2019,1, -H3,Habit 3,C3,6/14/2019,0, +H3,Habit 3,C3,6/14/2019,0,Habit 3 notes H3,Habit 3,C3,6/15/2019,1, H4,Habit 4,C4,11/6/2020,1, H4,Habit 4,C4,11/9/2020,1, 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 ee94cdbd0..140122db7 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 @@ -76,9 +76,11 @@ class HabitBullCSVImporter map[name] = h logger.info("Creating habit: $name") } + val notes = cols[5] ?: "" if (parseInt(cols[4]) == 1) { - val notes = cols[5] ?: "" h.originalEntries.add(Entry(timestamp, Entry.YES_MANUAL, notes)) + } else { + h.originalEntries.add(Entry(timestamp, Entry.NO, notes)) } } } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt index 6a8bd0c4f..daad1784e 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/io/ImportTest.kt @@ -54,6 +54,7 @@ class ImportTest : BaseUnitTest() { assertTrue(isChecked(habit, 2016, 3, 18)) assertTrue(isChecked(habit, 2016, 3, 19)) assertFalse(isChecked(habit, 2016, 3, 20)) + assertTrue(isNotesEqual(habit, 2016, 3, 18, "text")) } @Test @@ -68,6 +69,8 @@ class ImportTest : BaseUnitTest() { assertTrue(isChecked(habit, 2019, 4, 11)) assertTrue(isChecked(habit, 2019, 5, 7)) assertFalse(isChecked(habit, 2019, 6, 14)) + assertTrue(isNotesEqual(habit, 2019, 4, 11, "text")) + assertTrue(isNotesEqual(habit, 2019, 6, 14, "Habit 3 notes")) } @Test @@ -127,6 +130,13 @@ class ImportTest : BaseUnitTest() { return h.originalEntries.get(timestamp).value == Entry.YES_MANUAL } + private fun isNotesEqual(h: Habit, year: Int, month: Int, day: Int, notes: String): Boolean { + val date = getStartOfTodayCalendar() + date.set(year, month - 1, day) + val timestamp = Timestamp(date) + return h.originalEntries.get(timestamp).notes == notes + } + @Throws(IOException::class) private fun importFromFile(assetFilename: String) { val file = File.createTempFile("asset", "") From af7f60fc4d016875882652ee088acb455354250b Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Wed, 29 Sep 2021 08:22:15 -0700 Subject: [PATCH 06/15] Address review comments --- .../habits/list/views/NumberButtonViewTest.kt | 10 +-- .../common/dialogs/HistoryEditorDialog.kt | 2 +- .../habits/list/views/CheckmarkButtonView.kt | 12 +-- .../habits/list/views/CheckmarkPanelView.kt | 4 +- .../habits/list/views/HabitCardListView.kt | 2 +- .../habits/list/views/HabitCardView.kt | 8 +- .../habits/list/views/NumberButtonView.kt | 9 +- .../habits/list/views/NumberPanelView.kt | 4 +- .../isoron/uhabits/utils/ViewExtensions.kt | 12 +++ .../isoron/uhabits/core/models/EntryList.kt | 2 +- .../screens/habits/list/HabitCardListCache.kt | 6 +- .../screens/habits/list/ListHabitsBehavior.kt | 12 ++- .../screens/habits/show/views/HistoryCard.kt | 87 +++++++++++-------- .../uhabits/core/ui/views/HistoryChart.kt | 13 ++- .../uhabits/core/ui/widgets/WidgetBehavior.kt | 15 ++-- .../uhabits/core/ui/views/HistoryChartTest.kt | 39 ++++++++- 16 files changed, 138 insertions(+), 99 deletions(-) diff --git a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt index ea1571889..935fc7028 100644 --- a/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt +++ b/uhabits-android/src/androidTest/java/org/isoron/uhabits/activities/habits/list/views/NumberButtonViewTest.kt @@ -116,15 +116,7 @@ class NumberButtonViewTest : BaseViewTest() { } @Test - fun testClick_shortToggleDisabled() { - prefs.isShortToggleEnabled = false - view.performClick() - assertTrue(edited) - } - - @Test - fun testClick_shortToggleEnabled() { - prefs.isShortToggleEnabled = true + fun testClick() { view.performClick() assertTrue(edited) } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt index c040da2ac..55ed8093e 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt @@ -66,7 +66,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener { hasNotes = emptyList(), theme = themeSwitcher.currentTheme, today = DateUtils.getTodayWithOffset().toLocalDate(), - onDateClickedListener = onDateClickedListener ?: OnDateClickedListener { _, _ -> }, + onDateClickedListener = onDateClickedListener ?: object : OnDateClickedListener {}, padding = 10.0, ) dataView = AndroidDataView(context!!, null) 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 bd1b45715..498b80ab6 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 @@ -38,6 +38,7 @@ import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.dim +import org.isoron.uhabits.utils.drawNotesIndicator import org.isoron.uhabits.utils.getFontAwesome import org.isoron.uhabits.utils.sres import org.isoron.uhabits.utils.toMeasureSpec @@ -104,7 +105,8 @@ class CheckmarkButtonView( } override fun onLongClick(v: View): Boolean { - performToggle() + if (preferences.isShortToggleEnabled) onEdit() + else performToggle() return true } @@ -134,8 +136,6 @@ class CheckmarkButtonView( textAlign = Paint.Align.CENTER } - private val pNotesIndicator: Paint = Paint() - fun draw(canvas: Canvas) { paint.color = when (value) { YES_MANUAL, YES_AUTO, SKIP -> color @@ -145,7 +145,6 @@ class CheckmarkButtonView( } else -> lowContrastColor } - pNotesIndicator.color = color val id = when (value) { SKIP -> R.string.fa_skipped NO -> R.string.fa_times @@ -181,10 +180,7 @@ class CheckmarkButtonView( canvas.drawText(label, rect.centerX(), rect.centerY(), paint) } - if (hasNotes) { - val cy = 0.8f * em - canvas.drawCircle(width.toFloat() - cy, cy, 8f, pNotesIndicator) - } + drawNotesIndicator(canvas, color, em, hasNotes) } } } 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 dabbdc9c0..859cf734d 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,7 +54,7 @@ class CheckmarkPanelView( setupButtons() } - var notes = BooleanArray(0) + var notesIndicators = BooleanArray(0) set(values) { field = values setupButtons() @@ -85,7 +85,7 @@ class CheckmarkPanelView( else -> UNKNOWN } button.hasNotes = when { - index + dataOffset < notes.size -> notes[index + dataOffset] + index + dataOffset < notesIndicators.size -> notesIndicators[index + dataOffset] else -> false } button.color = color 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 c8b3915b9..8ce805098 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 @@ -99,7 +99,7 @@ class HabitCardListView( cardView.score = score cardView.unit = habit.unit cardView.threshold = habit.targetValue / habit.frequency.denominator - cardView.notes = notesIndicators + cardView.notesIndicators = 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 82dc31930..b04a92477 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,11 +115,11 @@ class HabitCardView( numberPanel.threshold = value } - var notes - get() = checkmarkPanel.notes + var notesIndicators + get() = checkmarkPanel.notesIndicators set(values) { - checkmarkPanel.notes = values - numberPanel.notes = values + checkmarkPanel.notesIndicators = values + numberPanel.notesIndicators = values } var checkmarkPanel: CheckmarkPanelView 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 dbb930710..b958dae8b 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 @@ -34,6 +34,7 @@ import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.inject.ActivityContext import org.isoron.uhabits.utils.InterfaceUtils.getDimension import org.isoron.uhabits.utils.dim +import org.isoron.uhabits.utils.drawNotesIndicator import org.isoron.uhabits.utils.getFontAwesome import org.isoron.uhabits.utils.sres import java.lang.Double.max @@ -156,8 +157,6 @@ class NumberButtonView( textAlign = Paint.Align.CENTER } - private val pNotesIndicator: Paint = Paint() - init { em = pNumber.measureText("m") lowContrast = sres.getColor(R.attr.contrast40) @@ -205,7 +204,6 @@ class NumberButtonView( pNumber.color = activeColor pNumber.typeface = typeface pUnit.color = activeColor - pNotesIndicator.color = color if (units.isBlank()) { rect.set(0f, 0f, width.toFloat(), height.toFloat()) @@ -218,10 +216,7 @@ class NumberButtonView( canvas.drawText(units, rect.centerX(), rect.centerY(), pUnit) } - if (hasNotes) { - val cy = 0.8f * em - canvas.drawCircle(width.toFloat() - cy, cy, 8f, pNotesIndicator) - } + drawNotesIndicator(canvas, color, em, hasNotes) } } } 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 329df6212..520401f65 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,7 +72,7 @@ class NumberPanelView( setupButtons() } - var notes = BooleanArray(0) + var notesIndicators = BooleanArray(0) set(values) { field = values setupButtons() @@ -97,7 +97,7 @@ class NumberPanelView( else -> 0.0 } button.hasNotes = when { - index + dataOffset < notes.size -> notes[index + dataOffset] + index + dataOffset < notesIndicators.size -> notesIndicators[index + dataOffset] else -> false } button.color = color diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt index bfa64ebf0..b6903b3b0 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/utils/ViewExtensions.kt @@ -22,7 +22,9 @@ package org.isoron.uhabits.utils import android.app.Activity import android.content.ActivityNotFoundException import android.content.Intent +import android.graphics.Canvas import android.graphics.Color +import android.graphics.Paint import android.graphics.drawable.ColorDrawable import android.os.Handler import android.view.LayoutInflater @@ -199,5 +201,15 @@ fun View.dim(id: Int) = InterfaceUtils.getDimension(context, id) fun View.sp(value: Float) = InterfaceUtils.spToPixels(context, value) fun View.dp(value: Float) = InterfaceUtils.dpToPixels(context, value) fun View.str(id: Int) = resources.getString(id) + +fun View.drawNotesIndicator(canvas: Canvas, color: Int, size: Float, hasNotes: Boolean) { + val pNotesIndicator = Paint() + pNotesIndicator.color = color + if (hasNotes) { + val cy = 0.8f * size + canvas.drawCircle(width.toFloat() - cy, cy, 8f, pNotesIndicator) + } +} + val View.sres: StyledResources get() = StyledResources(context) diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt index b11baea24..5212923b1 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/EntryList.kt @@ -100,7 +100,7 @@ open class EntryList { val intervals = buildIntervals(frequency, original) snapIntervalsTogether(intervals) val computed = buildEntriesFromInterval(original, intervals) - computed.filter { it.value != UNKNOWN }.forEach { add(it) } + computed.filter { it.value != UNKNOWN || it.notes.isNotEmpty() }.forEach { add(it) } } } 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 d8076c514..f1e306758 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 @@ -298,14 +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() - val notesList: MutableList = ArrayList() + val notesIndicators: MutableList = ArrayList() for ((_, value, note) in habit.computedEntries.getByInterval(dateFrom, today)) { list.add(value) - if (note.isNotEmpty()) notesList.add(true) else notesList.add(false) + notesIndicators.add(note.isNotEmpty()) } val entries = list.toTypedArray() newData.checkmarks[habit.id] = ArrayUtils.toPrimitive(entries) - newData.notesIndicators[habit.id] = notesList.toBooleanArray() + newData.notesIndicators[habit.id] = notesIndicators.toBooleanArray() runner!!.publishProgress(this, 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 ced89ad79..9139da08b 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 @@ -48,24 +48,22 @@ open class ListHabitsBehavior @Inject constructor( } fun onEdit(habit: Habit, timestamp: Timestamp?) { - val entries = habit.computedEntries.get(timestamp!!) - val notes = entries.notes + val entry = habit.computedEntries.get(timestamp!!) if (habit.type == HabitType.NUMERICAL) { - val oldValue = entries.value.toDouble() + val oldValue = entry.value.toDouble() screen.showNumberPicker( oldValue / 1000, habit.unit, - notes + entry.notes ) { newValue: Double, newNotes: String, -> val value = (newValue * 1000).roundToInt() commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) } } else { - val value = entries.value screen.showCheckmarkDialog( - notes + entry.notes ) { newNotes -> - commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) + commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, entry.value, newNotes)) } } } 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 8b944d7b9..a3b9c9587 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 @@ -59,50 +59,44 @@ class HistoryCardPresenter( val screen: Screen, ) : OnDateClickedListener { - override fun onDateClicked(date: LocalDate, isLongClick: Boolean) { + override fun onDateShortPress(date: LocalDate) { val timestamp = Timestamp.fromLocalDate(date) screen.showFeedback() - val entries = habit.computedEntries - val oldValue = entries.get(timestamp).value - val notes = entries.get(timestamp).notes if (habit.isNumerical) { - screen.showNumberPicker(oldValue / 1000.0, habit.unit, notes) { newValue: Double, newNotes: String -> - val thousands = (newValue * 1000).roundToInt() - commandRunner.run( - CreateRepetitionCommand( - habitList, - habit, - timestamp, - thousands, - newNotes, - ), - ) - } + showNumberPicker(timestamp) } else { - if (!isLongClick) { - val nextValue = Entry.nextToggleValue( - value = oldValue, - isSkipEnabled = preferences.isSkipEnabled, - areQuestionMarksEnabled = preferences.areQuestionMarksEnabled - ) - commandRunner.run( - CreateRepetitionCommand( - habitList, - habit, - timestamp, - nextValue, - notes, - ), - ) - return - } - screen.showCheckmarkDialog(notes) { newNotes -> + val entry = habit.computedEntries.get(timestamp) + val nextValue = Entry.nextToggleValue( + value = entry.value, + isSkipEnabled = preferences.isSkipEnabled, + areQuestionMarksEnabled = preferences.areQuestionMarksEnabled + ) + commandRunner.run( + CreateRepetitionCommand( + habitList, + habit, + timestamp, + nextValue, + entry.notes, + ), + ) + } + } + + override fun onDateLongPress(date: LocalDate) { + val timestamp = Timestamp.fromLocalDate(date) + screen.showFeedback() + if (habit.isNumerical) { + showNumberPicker(timestamp) + } else { + val entry = habit.computedEntries.get(timestamp) + screen.showCheckmarkDialog(entry.notes) { newNotes -> commandRunner.run( CreateRepetitionCommand( habitList, habit, timestamp, - oldValue, + entry.value, newNotes, ), ) @@ -110,6 +104,27 @@ class HistoryCardPresenter( } } + private fun showNumberPicker(timestamp: Timestamp) { + val entry = habit.computedEntries.get(timestamp) + val oldValue = entry.value + screen.showNumberPicker( + oldValue / 1000.0, + habit.unit, + entry.notes + ) { newValue: Double, newNotes: String -> + val thousands = (newValue * 1000).roundToInt() + commandRunner.run( + CreateRepetitionCommand( + habitList, + habit, + timestamp, + thousands, + newNotes, + ), + ) + } + } + fun onClickEditButton() { screen.showHistoryEditorDialog(this) } @@ -167,7 +182,7 @@ class HistoryCardPresenter( today = today.toLocalDate(), theme = theme, series = series, - defaultSquare = defaultSquare + defaultSquare = defaultSquare, hasNotes = hasNotes, ) } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt index 150713056..c7c9d443c 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt @@ -32,8 +32,9 @@ import kotlin.math.max import kotlin.math.min import kotlin.math.round -fun interface OnDateClickedListener { - fun onDateClicked(date: LocalDate, isLongClick: Boolean) +interface OnDateClickedListener { + fun onDateShortPress(date: LocalDate) {} + fun onDateLongPress(date: LocalDate) {} } class HistoryChart( @@ -45,7 +46,7 @@ class HistoryChart( var hasNotes: List, var theme: Theme, var today: LocalDate, - var onDateClickedListener: OnDateClickedListener = OnDateClickedListener { _, _ -> }, + var onDateClickedListener: OnDateClickedListener = object : OnDateClickedListener {}, var padding: Double = 0.0, ) : DataView { @@ -88,7 +89,11 @@ class HistoryChart( if (row == 0 || col == nColumns) return val clickedDate = topLeftDate.plus(offset) if (clickedDate.isNewerThan(today)) return - onDateClickedListener.onDateClicked(clickedDate, isLongClick) + if (isLongClick) { + onDateClickedListener.onDateLongPress(clickedDate) + } else { + onDateClickedListener.onDateShortPress(clickedDate) + } } override fun draw(canvas: Canvas) { 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 65dff6dd2..879b788be 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 @@ -38,43 +38,38 @@ class WidgetBehavior @Inject constructor( fun onAddRepetition(habit: Habit, timestamp: Timestamp?) { notificationTray.cancel(habit) val entry = habit.originalEntries.get(timestamp!!) - val notes = entry.notes - setValue(habit, timestamp, Entry.YES_MANUAL, notes) + setValue(habit, timestamp, Entry.YES_MANUAL, entry.notes) } fun onRemoveRepetition(habit: Habit, timestamp: Timestamp?) { notificationTray.cancel(habit) val entry = habit.originalEntries.get(timestamp!!) - val notes = entry.notes - setValue(habit, timestamp, Entry.NO, notes) + setValue(habit, timestamp, Entry.NO, entry.notes) } fun onToggleRepetition(habit: Habit, timestamp: Timestamp) { val entry = habit.originalEntries.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, notes) + setValue(habit, timestamp, newValue, entry.notes) notificationTray.cancel(habit) } fun onIncrement(habit: Habit, timestamp: Timestamp, amount: Int) { val entry = habit.computedEntries.get(timestamp) val currentValue = entry.value - val notes = entry.notes - setValue(habit, timestamp, currentValue + amount, notes) + setValue(habit, timestamp, currentValue + amount, entry.notes) notificationTray.cancel(habit) } fun onDecrement(habit: Habit, timestamp: Timestamp, amount: Int) { val entry = habit.computedEntries.get(timestamp) val currentValue = entry.value - val notes = entry.notes - setValue(habit, timestamp, currentValue - amount, notes) + setValue(habit, timestamp, currentValue - amount, entry.notes) notificationTray.cancel(habit) } diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt index 84ecc9bfb..627e29dca 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt @@ -90,20 +90,20 @@ class HistoryChartTest { // Click top left date view.onClick(20.0, 46.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26), false) + verify(dateClickedListener).onDateShortPress(LocalDate(2014, 10, 26)) reset(dateClickedListener) view.onClick(2.0, 28.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 10, 26), false) + verify(dateClickedListener).onDateShortPress(LocalDate(2014, 10, 26)) reset(dateClickedListener) // Click date in the middle view.onClick(163.0, 113.0) - verify(dateClickedListener).onDateClicked(LocalDate(2014, 12, 10), false) + verify(dateClickedListener).onDateShortPress(LocalDate(2014, 12, 10)) reset(dateClickedListener) // Click today view.onClick(336.0, 37.0) - verify(dateClickedListener).onDateClicked(LocalDate(2015, 1, 25), false) + verify(dateClickedListener).onDateShortPress(LocalDate(2015, 1, 25)) reset(dateClickedListener) // Click header @@ -115,6 +115,37 @@ class HistoryChartTest { verifyNoMoreInteractions(dateClickedListener) } + @Test + fun testLongClick() = runBlocking { + assertRenders(400, 200, "$base/base.png", view) + + // Click top left date + view.onLongClick(20.0, 46.0) + verify(dateClickedListener).onDateLongPress(LocalDate(2014, 10, 26)) + reset(dateClickedListener) + view.onLongClick(2.0, 28.0) + verify(dateClickedListener).onDateLongPress(LocalDate(2014, 10, 26)) + reset(dateClickedListener) + + // Click date in the middle + view.onLongClick(163.0, 113.0) + verify(dateClickedListener).onDateLongPress(LocalDate(2014, 12, 10)) + reset(dateClickedListener) + + // Click today + view.onLongClick(336.0, 37.0) + verify(dateClickedListener).onDateLongPress(LocalDate(2015, 1, 25)) + reset(dateClickedListener) + + // Click header + view.onLongClick(160.0, 15.0) + verifyNoMoreInteractions(dateClickedListener) + + // Click right axis + view.onLongClick(360.0, 60.0) + verifyNoMoreInteractions(dateClickedListener) + } + @Test fun testDrawWeekDay() = runBlocking { view.firstWeekday = DayOfWeek.MONDAY From 79e302f9225c681abb1933f3e6fdfa1ad1e4ed1c Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Thu, 30 Sep 2021 00:51:05 -0700 Subject: [PATCH 07/15] Change variable name --- .../activities/common/dialogs/HistoryEditorDialog.kt | 4 ++-- .../uhabits/activities/habits/show/views/HistoryCardView.kt | 2 +- .../main/java/org/isoron/uhabits/widgets/HistoryWidget.kt | 4 ++-- .../core/ui/screens/habits/show/views/HistoryCard.kt | 6 +++--- .../java/org/isoron/uhabits/core/ui/views/HistoryChart.kt | 6 +++--- .../org/isoron/uhabits/core/ui/views/HistoryChartTest.kt | 2 +- 6 files changed, 12 insertions(+), 12 deletions(-) diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt index 55ed8093e..21999d4e1 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/HistoryEditorDialog.kt @@ -63,7 +63,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener { paletteColor = habit.color, series = emptyList(), defaultSquare = HistoryChart.Square.OFF, - hasNotes = emptyList(), + notesIndicators = emptyList(), theme = themeSwitcher.currentTheme, today = DateUtils.getTodayWithOffset().toLocalDate(), onDateClickedListener = onDateClickedListener ?: object : OnDateClickedListener {}, @@ -104,7 +104,7 @@ class HistoryEditorDialog : AppCompatDialogFragment(), CommandRunner.Listener { ) chart?.series = model.series chart?.defaultSquare = model.defaultSquare - chart?.hasNotes = model.hasNotes + chart?.notesIndicators = model.notesIndicators dataView.postInvalidate() } diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt index 345789cca..74e566fbb 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/habits/show/views/HistoryCardView.kt @@ -44,7 +44,7 @@ class HistoryCardView(context: Context, attrs: AttributeSet) : LinearLayout(cont dateFormatter = JavaLocalDateFormatter(Locale.getDefault()), series = state.series, defaultSquare = state.defaultSquare, - hasNotes = state.hasNotes, + notesIndicators = state.notesIndicators, firstWeekday = state.firstWeekday, ) binding.chart.postInvalidate() diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt index 7d520bec5..25d8b7348 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/widgets/HistoryWidget.kt @@ -59,7 +59,7 @@ class HistoryWidget( val historyChart = (this.view as HistoryChart) historyChart.series = model.series historyChart.defaultSquare = model.defaultSquare - historyChart.hasNotes = model.hasNotes + historyChart.notesIndicators = model.notesIndicators } } @@ -75,7 +75,7 @@ class HistoryWidget( firstWeekday = prefs.firstWeekday, series = listOf(), defaultSquare = HistoryChart.Square.OFF, - hasNotes = listOf(), + notesIndicators = listOf(), ) } ).apply { 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 a3b9c9587..ae738f932 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 @@ -46,7 +46,7 @@ data class HistoryCardState( val firstWeekday: DayOfWeek, val series: List, val defaultSquare: HistoryChart.Square, - val hasNotes: List, + val notesIndicators: List, val theme: Theme, val today: LocalDate, ) @@ -169,7 +169,7 @@ class HistoryCardPresenter( else HistoryChart.Square.OFF - val hasNotes = entries.map { + val notesIndicators = entries.map { when (it.notes) { "" -> false else -> true @@ -183,7 +183,7 @@ class HistoryCardPresenter( theme = theme, series = series, defaultSquare = defaultSquare, - hasNotes = hasNotes, + notesIndicators = notesIndicators, ) } } diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt index c7c9d443c..afdc5d3b0 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/ui/views/HistoryChart.kt @@ -43,7 +43,7 @@ class HistoryChart( var paletteColor: PaletteColor, var series: List, var defaultSquare: Square, - var hasNotes: List, + var notesIndicators: List, var theme: Theme, var today: LocalDate, var onDateClickedListener: OnDateClickedListener = object : OnDateClickedListener {}, @@ -205,7 +205,7 @@ class HistoryChart( ) { val value = if (offset >= series.size) defaultSquare else series[offset] - val notes = if (offset >= hasNotes.size) false else hasNotes[offset] + val hasNotes = if (offset >= notesIndicators.size) false else notesIndicators[offset] val squareColor: Color val circleColor: Color val color = theme.color(paletteColor.paletteIndex) @@ -252,7 +252,7 @@ class HistoryChart( canvas.setTextAlign(TextAlign.CENTER) canvas.drawText(date.day.toString(), x + width / 2, y + width / 2) - if (notes) { + if (hasNotes) { circleColor = when (value) { Square.ON -> theme.lowContrastTextColor else -> color diff --git a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt index 627e29dca..8a9d523ab 100644 --- a/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt +++ b/uhabits-core/src/jvmTest/java/org/isoron/uhabits/core/ui/views/HistoryChartTest.kt @@ -73,7 +73,7 @@ class HistoryChartTest { else -> OFF } }, - hasNotes = MutableList(85) { + notesIndicators = MutableList(85) { index: Int -> index % 3 == 0 } From 71f400f587ccb14b1e94cd4fdf44d57fe6431ead Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Sat, 2 Oct 2021 11:06:51 -0700 Subject: [PATCH 08/15] improve numerical dialog design --- .../common/dialogs/NumberPickerFactory.kt | 3 +- .../habits/list/ListHabitsScreen.kt | 3 +- .../habits/show/ShowHabitActivity.kt | 3 +- .../NumericalCheckmarkWidgetActivity.kt | 1 + .../main/res/drawable/dialog_bg_input_box.xml | 29 ++++ .../main/res/layout/number_picker_dialog.xml | 128 +++++++++++------- uhabits-android/src/main/res/values/attrs.xml | 1 + .../src/main/res/values/strings.xml | 2 +- .../src/main/res/values/styles.xml | 27 ++++ .../isoron/uhabits/core/models/Timestamp.kt | 5 + .../screens/habits/list/ListHabitsBehavior.kt | 4 +- .../screens/habits/show/views/HistoryCard.kt | 4 +- .../isoron/uhabits/core/utils/DateFormats.kt | 3 + .../habits/list/ListHabitsBehaviorTest.kt | 2 +- 14 files changed, 160 insertions(+), 55 deletions(-) create mode 100644 uhabits-android/src/main/res/drawable/dialog_bg_input_box.xml 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 58db019a3..404c18e9c 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 @@ -48,6 +48,7 @@ class NumberPickerFactory value: Double, unit: String, notes: String, + dateString: String, callback: ListHabitsBehavior.NumberPickerCallback ): AlertDialog { val inflater = LayoutInflater.from(context) @@ -82,7 +83,7 @@ class NumberPickerFactory etNotes.setText(notes) val dialog = AlertDialog.Builder(context) .setView(view) - .setTitle(R.string.change_value) + .setTitle(dateString) .setPositiveButton(R.string.save) { _, _ -> picker.clearFocus() val v = picker.value + 0.01 * picker2.value 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 ea2ad85b0..f9a9bfef5 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 @@ -228,9 +228,10 @@ class ListHabitsScreen value: Double, unit: String, notes: String, + dateString: String, callback: ListHabitsBehavior.NumberPickerCallback ) { - numberPickerFactory.create(value, unit, notes, callback).show() + numberPickerFactory.create(value, unit, notes, dateString, callback).show() } override fun showCheckmarkDialog( 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 9dd01b521..e42cd57bf 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 @@ -166,9 +166,10 @@ class ShowHabitActivity : AppCompatActivity(), CommandRunner.Listener { value: Double, unit: String, notes: String, + dateString: String, callback: ListHabitsBehavior.NumberPickerCallback, ) { - NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, callback).show() + NumberPickerFactory(this@ShowHabitActivity).create(value, unit, notes, dateString, callback).show() } override fun showCheckmarkDialog( 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 cdc516e9a..c557ed942 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 @@ -80,6 +80,7 @@ class NumericalCheckmarkWidgetActivity : Activity(), ListHabitsBehavior.NumberPi entry.value / 1000.0, data.habit.unit, entry.notes, + today.toDialogDateString(), this ).show() } diff --git a/uhabits-android/src/main/res/drawable/dialog_bg_input_box.xml b/uhabits-android/src/main/res/drawable/dialog_bg_input_box.xml new file mode 100644 index 000000000..0f2a651a7 --- /dev/null +++ b/uhabits-android/src/main/res/drawable/dialog_bg_input_box.xml @@ -0,0 +1,29 @@ + + + + + + + + \ No newline at end of file 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 8fc33e764..0bfa7df54 100644 --- a/uhabits-android/src/main/res/layout/number_picker_dialog.xml +++ b/uhabits-android/src/main/res/layout/number_picker_dialog.xml @@ -19,63 +19,95 @@ --> + android:orientation="vertical" + android:layout_width="wrap_content" + android:layout_height="wrap_content" + android:paddingTop="12dp" + android:paddingStart="10dp" + android:paddingEnd="10dp"> - - - - - - - - + android:layout_height="wrap_content" + android:orientation="horizontal" + android:padding="5dp" + android:baselineAligned="false"> + + + + + + + + + + + + + + + + + + + + - - - - + android:orientation="horizontal" + android:padding="5dp" + android:baselineAligned="false"> + + + + + + + + + + + + diff --git a/uhabits-android/src/main/res/values/attrs.xml b/uhabits-android/src/main/res/values/attrs.xml index 081878e5b..b00eaf69b 100644 --- a/uhabits-android/src/main/res/values/attrs.xml +++ b/uhabits-android/src/main/res/values/attrs.xml @@ -43,6 +43,7 @@ + diff --git a/uhabits-android/src/main/res/values/strings.xml b/uhabits-android/src/main/res/values/strings.xml index c908816c1..6aeb30eb7 100644 --- a/uhabits-android/src/main/res/values/strings.xml +++ b/uhabits-android/src/main/res/values/strings.xml @@ -181,7 +181,7 @@ By status Export Press-and-hold to change the value - Change value + Value Calendar Unit Target Type diff --git a/uhabits-android/src/main/res/values/styles.xml b/uhabits-android/src/main/res/values/styles.xml index 0a3e9da10..46d40c46c 100644 --- a/uhabits-android/src/main/res/values/styles.xml +++ b/uhabits-android/src/main/res/values/styles.xml @@ -63,6 +63,7 @@ @color/grey_200 @color/grey_800 false + @color/white + + + + + diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt index feb118ce5..2233237c0 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/models/Timestamp.kt @@ -20,6 +20,7 @@ package org.isoron.uhabits.core.models import org.isoron.platform.time.LocalDate import org.isoron.uhabits.core.utils.DateFormats.Companion.getCSVDateFormat +import org.isoron.uhabits.core.utils.DateFormats.Companion.getDialogDateFormat import org.isoron.uhabits.core.utils.DateUtils import org.isoron.uhabits.core.utils.DateUtils.Companion.getStartOfTodayCalendar import org.isoron.uhabits.core.utils.DateUtils.Companion.truncate @@ -81,6 +82,10 @@ data class Timestamp(var unixTime: Long) : Comparable { return day } + fun toDialogDateString(): String { + return getDialogDateFormat().format(Date(unixTime)) + } + override fun toString(): String { return getCSVDateFormat().format(Date(unixTime)) } 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 9139da08b..124f17445 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 @@ -54,7 +54,8 @@ open class ListHabitsBehavior @Inject constructor( screen.showNumberPicker( oldValue / 1000, habit.unit, - entry.notes + entry.notes, + timestamp.toDialogDateString(), ) { newValue: Double, newNotes: String, -> val value = (newValue * 1000).roundToInt() commandRunner.run(CreateRepetitionCommand(habitList, habit, timestamp, value, newNotes)) @@ -159,6 +160,7 @@ open class ListHabitsBehavior @Inject constructor( value: Double, unit: String, notes: String, + dateString: String, callback: NumberPickerCallback ) fun showCheckmarkDialog( 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 ae738f932..5e71c4590 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 @@ -110,7 +110,8 @@ class HistoryCardPresenter( screen.showNumberPicker( oldValue / 1000.0, habit.unit, - entry.notes + entry.notes, + timestamp.toDialogDateString(), ) { newValue: Double, newNotes: String -> val thousands = (newValue * 1000).roundToInt() commandRunner.run( @@ -195,6 +196,7 @@ class HistoryCardPresenter( value: Double, unit: String, notes: String, + dateString: String, callback: ListHabitsBehavior.NumberPickerCallback, ) fun showCheckmarkDialog( diff --git a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateFormats.kt b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateFormats.kt index fc18d5374..8b7b4253b 100644 --- a/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateFormats.kt +++ b/uhabits-core/src/jvmMain/java/org/isoron/uhabits/core/utils/DateFormats.kt @@ -41,5 +41,8 @@ class DateFormats { @JvmStatic fun getCSVDateFormat(): SimpleDateFormat = fromSkeleton("yyyy-MM-dd", Locale.US) + + @JvmStatic fun getDialogDateFormat(): SimpleDateFormat = + fromSkeleton("MMM dd, yyyy", Locale.US) } } 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 df58affa6..8192583ad 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,7 +79,7 @@ class ListHabitsBehaviorTest : BaseUnitTest() { @Test fun testOnEdit() { behavior.onEdit(habit2, getToday()) - verify(screen).showNumberPicker(eq(0.1), eq("miles"), eq(""), picker.capture()) + verify(screen).showNumberPicker(eq(0.1), eq("miles"), eq(""), eq("Jan 25, 2015"), picker.capture()) picker.lastValue.onNumberPicked(100.0, "") val today = getTodayWithOffset() assertThat(habit2.computedEntries.get(today).value, equalTo(100000)) From 8036b10ee6db5cbb6b123ff5fa1b6473db886821 Mon Sep 17 00:00:00 2001 From: Bindu <56578479+vbh@users.noreply.github.com> Date: Sun, 3 Oct 2021 04:36:49 -0700 Subject: [PATCH 09/15] improve yes/no dialog design --- .../common/dialogs/CheckmarkDialog.kt | 93 ++++++++++++++++--- .../habits/list/ListHabitsScreen.kt | 5 +- .../habits/show/ShowHabitActivity.kt | 7 +- .../main/res/drawable/bg_select_button.xml | 14 +++ .../src/main/res/layout/checkmark_dialog.xml | 91 ++++++++++++++++-- .../src/main/res/values/strings.xml | 1 - .../src/main/res/values/styles.xml | 12 +++ .../screens/habits/list/ListHabitsBehavior.kt | 15 ++- .../screens/habits/show/views/HistoryCard.kt | 14 ++- 9 files changed, 224 insertions(+), 28 deletions(-) create mode 100644 uhabits-android/src/main/res/drawable/bg_select_button.xml diff --git a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt index 156864caa..800156a62 100644 --- a/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt +++ b/uhabits-android/src/main/java/org/isoron/uhabits/activities/common/dialogs/CheckmarkDialog.kt @@ -1,36 +1,63 @@ package org.isoron.uhabits.activities.common.dialogs import android.content.Context +import android.graphics.Color +import android.graphics.Typeface import android.view.LayoutInflater +import android.view.View import android.view.WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE -import android.widget.EditText +import android.widget.Button import androidx.appcompat.app.AlertDialog import org.isoron.uhabits.R +import org.isoron.uhabits.core.models.Entry.Companion.NO +import org.isoron.uhabits.core.models.Entry.Companion.SKIP +import org.isoron.uhabits.core.models.Entry.Companion.UNKNOWN +import org.isoron.uhabits.core.models.Entry.Companion.YES_AUTO +import org.isoron.uhabits.core.models.Entry.Companion.YES_MANUAL +import org.isoron.uhabits.core.models.PaletteColor +import org.isoron.uhabits.core.preferences.Preferences import org.isoron.uhabits.core.ui.screens.habits.list.ListHabitsBehavior +import org.isoron.uhabits.databinding.CheckmarkDialogBinding import org.isoron.uhabits.inject.ActivityContext +import org.isoron.uhabits.utils.InterfaceUtils +import org.isoron.uhabits.utils.StyledResources import javax.inject.Inject class CheckmarkDialog @Inject constructor( - @ActivityContext private val context: Context -) { + @ActivityContext private val context: Context, + private val preferences: Preferences, +) : View.OnClickListener { + + private lateinit var binding: CheckmarkDialogBinding + private lateinit var fontAwesome: Typeface + private val allButtons = mutableListOf