Auto-save notes when dismissing checkmark and number dialogs

Previously, when a user entered notes for a habit entry, then dismissed the
dialog (either intentionally or, as often the case for me, accidentally), any
changes to the notes would be lost.

This change seeks to avoid data loss by auto-saving notes when the dialog is
closed. This handles a several data loss scenarios:

- pressing the back button
- clicking outside the dialog box
- rotating the screen
- turning off the screen

(To be honest, I have done all of these at least once by accident, and some
dozens of times.)

As part of this change, the NumberDialog now trims whitespace from notes when
manually saving to be consistent with CheckmarkDialog.
This commit is contained in:
Jesse Johnson 2025-12-02 15:14:56 -08:00
parent 2b24759d6f
commit cc645f537e
No known key found for this signature in database
GPG Key ID: 8A6A7E86EE7FE496
2 changed files with 40 additions and 4 deletions

View File

@ -20,6 +20,7 @@
package org.isoron.uhabits.activities.common.dialogs
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.view.LayoutInflater
import android.view.View.GONE
@ -37,11 +38,17 @@ import org.isoron.uhabits.utils.sres
class CheckmarkDialog : AppCompatDialogFragment() {
var onToggle: (Int, String) -> Unit = { _, _ -> }
var onDismiss: () -> Unit = {}
private var dismissedViaSaveAction = false
private var originalNotes: String = ""
private var originalValue: Int = 0
private lateinit var view: CheckmarkPopupBinding
override fun onCreateDialog(savedInstanceState: Bundle?): Dialog {
val appComponent = (requireActivity().application as HabitsApplication).component
val prefs = appComponent.preferences
val view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context))
view = CheckmarkPopupBinding.inflate(LayoutInflater.from(context))
val color = requireArguments().getInt("color")
arrayOf(view.yesBtn, view.skipBtn).forEach {
it.setTextColor(color)
@ -52,7 +59,9 @@ class CheckmarkDialog : AppCompatDialogFragment() {
arrayOf(view.yesBtn, view.noBtn, view.skipBtn, view.unknownBtn).forEach {
it.typeface = getFontAwesome(requireContext())
}
view.notes.setText(requireArguments().getString("notes")!!)
originalNotes = requireArguments().getString("notes")!!
originalValue = requireArguments().getInt("value")
view.notes.setText(originalNotes)
if (!prefs.isSkipEnabled) view.skipBtn.visibility = GONE
if (!prefs.areQuestionMarksEnabled) view.unknownBtn.visibility = GONE
view.booleanButtons.visibility = VISIBLE
@ -62,6 +71,7 @@ class CheckmarkDialog : AppCompatDialogFragment() {
setBackgroundDrawableResource(android.R.color.transparent)
}
fun onClick(v: Int) {
dismissedViaSaveAction = true
val notes = view.notes.text.toString().trim()
onToggle(v, notes)
requireDialog().dismiss()
@ -77,4 +87,16 @@ class CheckmarkDialog : AppCompatDialogFragment() {
return dialog
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
if (!dismissedViaSaveAction) {
val currentNotes = view.notes.text.toString().trim()
if (currentNotes != originalNotes) {
onToggle(originalValue, currentNotes)
}
}
onDismiss()
}
}

View File

@ -1,6 +1,7 @@
package org.isoron.uhabits.activities.common.dialogs
import android.app.Dialog
import android.content.DialogInterface
import android.os.Bundle
import android.provider.Settings
import android.text.method.DigitsKeyListener
@ -28,6 +29,7 @@ class NumberDialog : AppCompatDialogFragment() {
var onToggle: (Double, String) -> Unit = { _, _ -> }
var onDismiss: () -> Unit = {}
private var dismissedViaSaveAction = false
private var originalNotes: String = ""
private var originalValue: Double = 0.0
private lateinit var view: CheckmarkPopupBinding
@ -88,10 +90,21 @@ class NumberDialog : AppCompatDialogFragment() {
dialog.window?.apply {
setBackgroundDrawableResource(android.R.color.transparent)
}
dialog.setOnDismissListener { onDismiss() }
return dialog
}
override fun onDismiss(dialog: DialogInterface) {
super.onDismiss(dialog)
if (!dismissedViaSaveAction) {
val currentNotes = view.notes.text.toString().trim()
if (currentNotes != originalNotes) {
onToggle(originalValue, currentNotes)
}
}
onDismiss()
}
private fun fixDecimalSeparator(view: CheckmarkPopupBinding) {
// https://stackoverflow.com/a/34256139
val separator = DecimalFormatSymbols.getInstance().decimalSeparator
@ -108,6 +121,7 @@ class NumberDialog : AppCompatDialogFragment() {
}
fun save() {
dismissedViaSaveAction = true
var value = originalValue
try {
val numberFormat = NumberFormat.getInstance()
@ -120,7 +134,7 @@ class NumberDialog : AppCompatDialogFragment() {
} catch (e: ParseException) {
// NOP
}
val notes = view.notes.text.toString()
val notes = view.notes.text.toString().trim()
val location = view.saveBtn.getCenter()
onToggle(value, notes)
requireDialog().dismiss()