Skip to content

fix: repair four defects the app hit on a live Firebase project - #23

Merged
duuyguyiilmaz merged 1 commit into
mainfrom
fix/ui-validation-and-session
Sep 1, 2026
Merged

duuyguyiilmaz merged 1 commit into
mainfrom
fix/ui-validation-and-session

Conversation

@duuyguyiilmaz

Copy link
Copy Markdown
Owner

Running the app against real Firestore surfaced four problems that no test covered, because each lives in the gap between a ViewModel's decision and what the user actually meets.

The password toggle showed the inverted icon

The field used the legacy passwordToggleEnabled attribute, whose default icon reports the action — open eye while the password is hidden, meaning "tap to reveal". Read as state, which is how people read it, that is backwards. Both screens now use endIconMode="password_toggle" with a state_checked selector: crossed-out eye while hidden, open eye while visible.

Every auth failure collapsed into "Tekrar deneyin."

The mapping matched on Firebase's English error sentence ("password is invalid", "no user record"). Those strings are not API; they changed, and the match silently stopped hitting — so a wrong password and a dropped connection produced the same useless text. Mapping now keys on FirebaseAuthException.errorCode.

ERROR_INVALID_CREDENTIAL is the case that mattered most: with email enumeration protection on, Firebase returns it for both a wrong password and an unknown account, and nothing recognised it.

Leaving the app meant signing in again

Firebase persists the session to disk, but the launcher only skipped the form when a "keep me signed in" checkbox had been ticked — so an unticked box left the user signed in yet facing the login screen at every start. The box is gone; the session now lasts until the sign-out button in Profile, which is the only place that should end it.

The leaderboard error followed the user across tabs

Its retry snackbar attaches to MainActivity's CoordinatorLayout, not to the fragment, so switching tabs destroyed the fragment and left the snackbar behind. Combined with LENGTH_INDEFINITE it never went away, and it sat over the upload form — the note could not be submitted at all. The snackbar is now held and dismissed in onStop and whenever a load succeeds. ProfileFragment carried the identical defect and is fixed the same way.


Tests

114 → 129, all green, lint clean.

  • AuthErrorMessagesTest pins each error code to its own message, including the ERROR_INVALID_CREDENTIAL regression and the split between the sign-in and register fallbacks.
  • PasswordToggleTest inflates both screens under Robolectric and asserts the icon reports state — dropping endIconDrawable would leave a working button with the wrong icon and break nothing else.

Verified on a device

Emulator, against the live project: the app opens straight to the feed without asking to sign in; the leaderboard error clears on tab change and the upload form is usable; feed and leaderboard both load from the server.

Not a code change, but worth recording

Both composite indexes in firestore.indexes.json were missing from the live project. The feed only looked healthy because the contribution gate meant its query was never built — the first upload unlocked the gate and it failed too. Deploying step 6 of the README's Getting started is not optional.

🤖 Generated with Claude Code

Running the app against real Firestore surfaced four problems that no test
covered, because each one lives in the gap between a ViewModel's decision and
what the user actually meets.

**The password toggle showed the inverted icon.** The field used the legacy
`passwordToggleEnabled` attribute, whose default icon reports the *action*
(open eye while hidden, meaning "tap to reveal"). Read as state — which is how
people read it — that is backwards. Both screens now use `endIconMode` with a
`state_checked` selector: crossed-out eye while hidden, open eye while visible.

**Every auth failure collapsed into "Tekrar deneyin."** The mapping matched on
Firebase's English error *sentence* ("password is invalid", "no user record").
Those strings are not API; they changed, and the match silently stopped hitting
— so a wrong password and a dropped connection produced the same useless text.
Mapping now keys on `FirebaseAuthException.errorCode`. `ERROR_INVALID_CREDENTIAL`
is the case that mattered most: with email enumeration protection on, Firebase
returns it for both a wrong password and an unknown account, and nothing
recognised it.

**Leaving the app meant signing in again.** Firebase persists the session to
disk, but the launcher only skipped the form when a "keep me signed in" checkbox
had been ticked — so an untended box left the user signed in yet facing the
login screen at every start. The box is gone; the session now lasts until the
sign-out button in Profile, which is the only place that should end it.

**The leaderboard error followed the user across tabs.** Its retry snackbar
attaches to MainActivity's CoordinatorLayout, not to the fragment, so switching
tabs destroyed the fragment and left the snackbar. Combined with
LENGTH_INDEFINITE it never went away, and it sat over the upload form — the note
could not be submitted at all. The snackbar is now held and dismissed in
`onStop` and whenever a load succeeds. ProfileFragment carried the identical
defect and is fixed the same way.

Tests: 114 -> 129. `AuthErrorMessagesTest` pins each error code to its own
message; `PasswordToggleTest` inflates both screens under Robolectric and
asserts the icon reports state, since dropping `endIconDrawable` would leave a
working button with the wrong icon and break nothing else.

Not a code change, but worth recording: both composite indexes in
firestore.indexes.json were missing from the live project. The feed only looked
healthy because the contribution gate meant its query was never built; the first
upload unlocked the gate and it failed too. Deploying step 6 of the README's
Getting started is not optional.

Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
@duuyguyiilmaz
duuyguyiilmaz merged commit 2a36ea0 into main Sep 1, 2026
2 checks passed
@duuyguyiilmaz
duuyguyiilmaz deleted the fix/ui-validation-and-session branch September 1, 2026 14:41
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant