Skip to content

Store the sign-out notice in the write that clears the session - #78

Merged
dadachi merged 1 commit into
mainfrom
fix/sign-out-notice
Oct 13, 2026
Merged

dadachi merged 1 commit into
mainfrom
fix/sign-out-notice

Conversation

@dadachi

@dadachi dadachi commented Oct 13, 2026

Copy link
Copy Markdown
Contributor

Phase 2 follow-up (bug fixes). Port of NativeAppTemplate-Android #110.

Problem

After you change the email or delete the account in Settings → Edit Profile, onboarding should show a snackbar ("check your email" / "account deleted"). Whether it does depends on a race.

Cause

ShopkeeperEditViewModel set isEmailUpdated / isMyAccountDeleted from viewModelScope after the session was cleared:

  • email change: logout() then setIsEmailUpdated(true)
  • deletion: clearSession() then setIsMyAccountDeleted(true)

Clearing the session routes to onboarding, which pops Edit Profile and cancels its viewModelScope. If that happens before the next suspension point returns, the flag write never runs. On the Pixel the timing happened to win (both snackbars showed in #77's device check), because Free has no FCM token deletion after the clear, unlike paid. The race is still there, and the unit test below reproduces it deterministically.

Fix

  • New SignOutNotice enum (EMAIL_UPDATED, ACCOUNT_DELETED).
  • LoginRepository.logout(notice) and clearSession(notice) take the notice (default null, so the other callers are unchanged).
  • NativeAppTemplatePreferencesDataSource.clearSession(isEmailUpdated, isMyAccountDeleted) writes the notice in the same DataStore write that clears the session.
  • ShopkeeperEditViewModel passes the notice and no longer sets the flags itself. logout already clears the session (now with the notice) when the request fails, so the email-change message also shows when the sign-out request fails.

Tests

  • Reproduction (ShopkeeperEditViewModelTest): updateShopkeeper_withANewEmail_whenTheScreenClosesOnSignOut_stillReportsTheEmailChange and deleteShopkeeper_whenTheScreenClosesOnSignOut_stillReportsTheDeletion. TestLoginRepository.onSessionCleared lets a test cancel the view model's scope and then yield(), as the onboarding route does. Both failed on the unchanged main code with an AssertionError (flag false). I added only the hook to the double first, with no API change, ran them red, and then made the fix.
  • LoginRepositoryImplTest, backed by a store that records every DataStore write:
    • logout_withANotice_storesItInTheWriteThatSignsOut and clearSession_withANotice_storesItInTheWriteThatSignsOut: the first write with isLoggedIn == false already carries the notice.
    • logout_withANotice_whenTheServerRejectsIt_stillStoresTheNotice
    • logout_withoutANotice_clearsAnEarlierOne
  • Red checks:
    • Clearing first and then setting the flag in a second write turned both ...InTheWriteThatSignsOut tests red. An earlier version that observed userData missed this in the logout case because the StateFlow conflated the two writes. That is why the test records writes instead.
    • Making clearSession always write false turned three notice tests red.
    • Keeping earlier flags (flag || it.flag) turned logout_withoutANotice_clearsAnEarlierOne red.

Local checks

  • ./scripts/pre-push (spotless, lint, R8 minify, unit tests): passed. 406 tests (app + model), 0 failures.
  • ./gradlew :app:assembleRelease: passed.

Device check (Pixel, com.nativeapptemplate.nativeapptemplatefree debug build, local API)

With a throwaway shopkeeper (signed up in the app, confirmed via the API, deleted at the end):

  • Email change: onboarding shows "A message with a confirmation link has been sent to your new email address…".
  • Signed in again and deleted the account: onboarding shows "Account deleted successfully.", and the server record is gone.
  • After dismissing and cold-relaunching, no message comes back.

The app is left signed in as shopkeeper1.

🤖 Generated with Claude Code

https://claude.ai/code/session_01K5hZEFqXhBsUQwSWsgR6eH

ShopkeeperEditViewModel set isEmailUpdated / isMyAccountDeleted from
viewModelScope after the session was cleared. Clearing the session
routes to onboarding, which pops Edit Profile and cancels that scope,
so the flag write could be lost and the "check your email" / "account
deleted" snackbar would not show.

New SignOutNotice; logout(notice) and clearSession(notice) store it in
the same DataStore write that clears the session. Port of
NativeAppTemplate-Android #110.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01K5hZEFqXhBsUQwSWsgR6eH
@dadachi
dadachi merged commit 992066d into main Oct 13, 2026
1 check passed
@dadachi
dadachi deleted the fix/sign-out-notice branch October 13, 2026 01:37
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