Description
Opening a filter for editing and going back without changing anything wrongly shows the "Discard changes?" confirmation dialog (added in #245).
Steps to reproduce
- Open an existing filter (or one with prefilled fields) in the filter edit screen.
- Background the app and return (onPause → onResume) — touch nothing.
- Press back.
- → "Discard changes?" appears, even though nothing was edited.
Cause
EditFilterFragment.render() pushes state into the fields via setTextIfDifferent(...) → EditText.setText(...). That setText fires the field's doAfterTextChanged watcher, which sends an Update… command, and the reducer flips isDirty = true. So a pure render is mistaken for a user edit.
The watcher is attached on onResume / detached on onPause (core/ui/base/.../TextViewExt.kt), so the spurious dirty reliably triggers after any onPause→onResume cycle where a render runs with the watcher attached.
Present on master since #245 (the same setTextIfDifferent + watcher pattern exists at a9baf26).
Fix
PR #247 makes the programmatic setText path watcher-safe: doAfterTextChanged returns a setter that suppresses the watcher while applying a render, and render() uses it instead of setText(). The isDirty-in-reducer design and TEA back-routing from #245 are unchanged. Verified on-device (SM-S948Q / Android 16): no spurious dirty after an onPause/onResume cycle, and a real edit still triggers the dialog.
Description
Opening a filter for editing and going back without changing anything wrongly shows the "Discard changes?" confirmation dialog (added in #245).
Steps to reproduce
Cause
EditFilterFragment.render()pushes state into the fields viasetTextIfDifferent(...) → EditText.setText(...). ThatsetTextfires the field'sdoAfterTextChangedwatcher, which sends anUpdate…command, and the reducer flipsisDirty = true. So a pure render is mistaken for a user edit.The watcher is attached on
onResume/ detached ononPause(core/ui/base/.../TextViewExt.kt), so the spurious dirty reliably triggers after any onPause→onResume cycle where a render runs with the watcher attached.Present on
mastersince #245 (the samesetTextIfDifferent+ watcher pattern exists at a9baf26).Fix
PR #247 makes the programmatic
setTextpath watcher-safe:doAfterTextChangedreturns a setter that suppresses the watcher while applying a render, andrender()uses it instead ofsetText(). TheisDirty-in-reducer design and TEA back-routing from #245 are unchanged. Verified on-device (SM-S948Q / Android 16): no spurious dirty after an onPause/onResume cycle, and a real edit still triggers the dialog.