Skip to content

feat(mobile): onboarding and Firebase authentication - #43

Merged
GRACENOBLE merged 5 commits into
mainfrom
37-feat-mobile-auth
Jun 24, 2026
Merged

GRACENOBLE merged 5 commits into
mainfrom
37-feat-mobile-auth

Conversation

@GRACENOBLE

@GRACENOBLE GRACENOBLE commented Jun 24, 2026 •

Copy link
Copy Markdown
Member

Part of #37

Summary

  • Navigation: AppNavGraph (Navigation Compose) with three routes — onboarding, login/register, home; start destination is computed by combining DataStore onboarding flag with Firebase auth state, so the app always routes correctly on cold start without a splash screen delay
  • Auth layer: AuthRepository interface + FirebaseAuthRepository implementing email/password sign-in, registration (with displayName set via updateProfile), Google Sign-In via Credential Manager API, and sign-out
  • Onboarding: single welcome screen backed by DataStoreOnboardingRepository; completion is persisted so it only shows on first launch
  • Screens: Login (email+password + Google), Register (name/email/password/confirm), Home (shows user name, sign-out button)
  • State management: AuthViewModel (Idle/Loading/Success/Error + currentUser StateFlow) and AppViewModel (resolves start destination); both use ViewModel factory pattern for manual injection
  • Dependencies added: Navigation Compose 2.9.0, firebase-auth-ktx (BOM), Credential Manager 1.5.0, googleid 1.1.1, DataStore Preferences 1.1.7, lifecycle-viewmodel-compose 2.9.0

Architecture

Follows the same Firebase-first pattern as the web app:

  • Firebase handles all sign-in flows on the client
  • Firebase ID token is available from FirebaseUser.getIdToken() for backend API calls
  • No DI framework — ViewModel factories used for manual injection

Test plan

  • Add GOOGLE_WEB_CLIENT_ID=<your-web-oauth-client-id> to mobile/local.properties (from Firebase Console → Authentication → Google → Web SDK configuration)
  • Add the SHA-1 / SHA-256 fingerprint to Firebase Console → Project settings → Android app
  • ./gradlew assembleDebug — builds cleanly
  • ./gradlew lint && ./gradlew test — 0 issues, 39 unit tests pass
  • On emulator/device: first launch shows onboarding → Get Started → Login; subsequent launches skip onboarding
  • Email registration and sign-in work end-to-end
  • Google Sign-In popup completes and lands on Home screen
  • Sign out returns to Login; back button does not go back to Home

Notes

  • connectedAndroidTest (instrumented tests) require a connected emulator — compile-verified but not run in CI yet
  • The Greeting composable in MainActivity is retained for the existing @Preview — it can be removed in a follow-up cleanup

Summary by CodeRabbit

  • New Features

    • Added onboarding, sign-in, registration, and home screens for a full app login flow.
    • Added Google sign-in support and persistent onboarding status.
    • App now routes users to the right start screen based on onboarding and sign-in state.
  • Bug Fixes

    • Improved loading and error handling across authentication screens.
    • Sign-in and registration buttons now stay disabled until required fields are filled.

- Navigation Compose NavHost with three routes: onboarding, auth
  (login/register), and home; start destination is resolved by combining
  DataStore onboarding flag with Firebase auth state so the app routes
  correctly on every cold start

- AuthRepository interface + FirebaseAuthRepository: signInWithEmail,
  registerWithEmail (creates user + sets displayName), signInWithGoogle
  via Credential Manager API, and signOut

- AuthViewModel exposes AuthUiState (Idle / Loading / Success / Error),
  currentUser StateFlow, and clearError(); uses ViewModel factory pattern
  for manual injection (no DI framework)

- AppViewModel combines authStateFlow + hasSeenOnboarding into a single
  StartDestination StateFlow (null while initialising); nav graph waits
  until resolved before showing anything

- OnboardingScreen with "Get Started" CTA; completion writes to DataStore
  via DataStoreOnboardingRepository so it is only shown once

- LoginScreen: email + password fields, Google sign-in button, error
  Snackbar, link to Register

- RegisterScreen: name / email / password / confirm-password fields with
  client-side password-match guard, error Snackbar, link to Login

- HomeScreen: shows displayName (falls back to email), sign-out button;
  displayName is derived from FirebaseUser in AppNavGraph so the screen
  stays logic-free

- 39 unit tests (AuthViewModel, OnboardingViewModel, AppViewModel) using
  fake repository stubs; 18 instrumented test stubs for all screens

- Dependencies added: navigation-compose 2.9.0, firebase-auth-ktx (BOM),
  credentials 1.5.0 + credentials-play-services-auth, googleid 1.1.1,
  datastore-preferences 1.1.7, lifecycle-viewmodel-compose 2.9.0
@github-actions github-actions Bot added area: mobile Android app (Kotlin + Jetpack Compose) type: chore Cleanup or maintenance tasks labels Jun 24, 2026
@coderabbitai

coderabbitai Bot commented Jun 24, 2026 •

Copy link
Copy Markdown

Review Change Stack

Warning

Review limit reached

@GRACENOBLE, we couldn't start this review because you've reached your PR review rate limit.

More reviews will be available in 3 minutes. Learn how PR review limits work.

Your organization has run out of usage credits. Purchase more credits in the billing tab to continue.

⌛ How to resolve this issue?

After more reviews become available, a review can be triggered using the @coderabbitai review command as a PR comment. Alternatively, push new commits to this PR.

To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based credits.

🚦 How do rate limits work?

CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability.

For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window.

Please see our Fair Usage Limits Policy for further information.

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 89cc2b31-e9ca-4117-81ff-7ae74fc56c5f

📥 Commits

Reviewing files that changed from the base of the PR and between fefd49c and 2ed6425.

📒 Files selected for processing (18)
  • mobile/app/build.gradle.kts
  • mobile/app/src/androidTest/java/com/company/template/auth/LoginScreenTest.kt
  • mobile/app/src/androidTest/java/com/company/template/auth/RegisterScreenTest.kt
  • mobile/app/src/androidTest/java/com/company/template/home/HomeScreenTest.kt
  • mobile/app/src/main/java/com/company/template/MainActivity.kt
  • mobile/app/src/main/java/com/company/template/auth/AuthRepository.kt
  • mobile/app/src/main/java/com/company/template/auth/AuthViewModel.kt
  • mobile/app/src/main/java/com/company/template/auth/FirebaseAuthRepository.kt
  • mobile/app/src/main/java/com/company/template/auth/LoginScreen.kt
  • mobile/app/src/main/java/com/company/template/auth/RegisterScreen.kt
  • mobile/app/src/main/java/com/company/template/auth/User.kt
  • mobile/app/src/main/java/com/company/template/navigation/AppNavGraph.kt
  • mobile/app/src/main/java/com/company/template/navigation/AppViewModel.kt
  • mobile/app/src/main/java/com/company/template/onboarding/DataStoreOnboardingRepository.kt
  • mobile/app/src/main/java/com/company/template/onboarding/OnboardingViewModel.kt
  • mobile/app/src/test/java/com/company/template/auth/AuthViewModelTest.kt
  • mobile/app/src/test/java/com/company/template/navigation/AppViewModelTest.kt
  • mobile/app/src/test/java/com/company/template/onboarding/OnboardingViewModelTest.kt
📝 Walkthrough

Walkthrough

Adds a complete authentication and onboarding flow to the Android mobile template. Introduces OnboardingRepository with a DataStore implementation, Firebase-backed AuthRepository with email and Google sign-in, composable screens for onboarding, login, register, and home, a reactive AppNavGraph driven by AppViewModel, and full unit plus instrumented test coverage.

Changes

Auth, Onboarding & Navigation Flow

Layer / File(s) Summary
Dependency catalog and build config
mobile/gradle/libs.versions.toml, mobile/app/build.gradle.kts
Adds version refs and library coordinates for navigation-compose, Firebase Auth KTX, AndroidX Credentials, Google ID, DataStore Preferences, Coil, and lifecycle Compose artifacts; injects GOOGLE_WEB_CLIENT_ID into BuildConfig.
Onboarding repository, DataStore implementation, and ViewModel
mobile/app/src/main/java/com/company/template/onboarding/OnboardingRepository.kt, .../DataStoreOnboardingRepository.kt, .../OnboardingViewModel.kt, mobile/app/src/test/.../OnboardingViewModelTest.kt
Defines OnboardingRepository interface; implements it via DataStoreOnboardingRepository backed by named preferences DataStore; wraps in OnboardingViewModel with a coroutine-based markSeen and factory; unit tests validate initial state and mark-seen transitions.
Auth contract, FirebaseAuthRepository, AuthUiState, and AuthViewModel
mobile/app/src/main/java/com/company/template/auth/AuthRepository.kt, .../FirebaseAuthRepository.kt, .../AuthViewModel.kt, mobile/app/src/test/.../AuthViewModelTest.kt
Defines AuthRepository interface; implements it in FirebaseAuthRepository using callbackFlow for auth state, Credential Manager for Google ID token, and Firebase for sign-in/registration; introduces AuthUiState sealed type and AuthViewModel with state machine transitions and password validation; unit tests cover all uiState transitions.
OnboardingScreen and instrumented tests
mobile/app/src/main/java/com/company/template/onboarding/OnboardingScreen.kt, mobile/app/src/androidTest/.../OnboardingScreenTest.kt
Adds OnboardingScreen composable with a centered welcome column and Get Started button; instrumented tests assert heading/button presence and callback invocation.
LoginScreen, RegisterScreen, and instrumented tests
mobile/app/src/main/java/com/company/template/auth/LoginScreen.kt, .../RegisterScreen.kt, mobile/app/src/androidTest/.../LoginScreenTest.kt, .../RegisterScreenTest.kt
Adds LoginScreen with saveable state, error/loading/disabled-button behavior, and register navigation; adds RegisterScreen with four-field form and loading indicator; instrumented tests cover heading display, button states, error messages, navigation links, and field-typing flows.
HomeScreen and instrumented tests
mobile/app/src/main/java/com/company/template/home/HomeScreen.kt, mobile/app/src/androidTest/.../HomeScreenTest.kt
Adds HomeScreen rendering a welcome headline, optional display name, and a styled Sign Out button; tests assert heading/name display, sign-out visibility, callback invocation, and empty-name behavior.
AppViewModel, AppNavGraph, MainActivity wiring, and navigation tests
mobile/app/src/main/java/com/company/template/navigation/AppViewModel.kt, .../AppNavGraph.kt, .../MainActivity.kt, mobile/app/src/test/.../AppViewModelTest.kt
Introduces StartDestination enum and AppViewModel combining onboarding and auth flows into a startDestination StateFlow; AppNavGraph wires all four destinations with LaunchedEffect-driven home navigation on auth success; MainActivity instantiates repositories lazily and injects both ViewModels; unit tests validate ONBOARDING/LOGIN routing and dynamic transitions.

Sequence Diagram(s)

sequenceDiagram
  actor User
  participant MainActivity
  participant AppViewModel
  participant AppNavGraph
  participant AuthViewModel
  participant FirebaseAuthRepository
  participant FirebaseAuth
  participant CredentialManager

  MainActivity->>AppViewModel: initialize(authRepo, onboardingRepo)
  AppViewModel-->>AppNavGraph: startDestination = ONBOARDING | LOGIN | HOME

  rect rgba(70, 130, 180, 0.5)
    Note over User, AppNavGraph: Email Sign-In Flow
    User->>AppNavGraph: enters email + password, taps Sign In
    AppNavGraph->>AuthViewModel: signIn(email, password)
    AuthViewModel->>FirebaseAuthRepository: signInWithEmail(email, password)
    FirebaseAuthRepository->>FirebaseAuth: signInWithEmailAndPassword().await()
    FirebaseAuth-->>FirebaseAuthRepository: Result<Unit>
    FirebaseAuthRepository-->>AuthViewModel: Result<Unit>
    AuthViewModel-->>AppNavGraph: uiState = Success
    AppNavGraph->>AppNavGraph: LaunchedEffect → navigate to HOME, clear back stack
  end

  rect rgba(60, 179, 113, 0.5)
    Note over User, AppNavGraph: Google Sign-In Flow
    User->>AppNavGraph: taps Google Sign-In
    AppNavGraph->>AuthViewModel: signInWithGoogle(activity)
    AuthViewModel->>FirebaseAuthRepository: signInWithGoogle(activity)
    FirebaseAuthRepository->>CredentialManager: getCredential(GetGoogleIdOption)
    CredentialManager-->>FirebaseAuthRepository: GoogleIdTokenCredential
    FirebaseAuthRepository->>FirebaseAuth: signInWithCredential(GoogleAuthProvider)
    FirebaseAuth-->>FirebaseAuthRepository: Result<Unit>
    FirebaseAuthRepository-->>AuthViewModel: Result<Unit>
    AuthViewModel-->>AppNavGraph: uiState = Success → navigate to HOME
  end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested labels

area: mobile

Poem

🐇 Hop hop, the bunny cheers today,
Firebase and flows now light the way!
Onboarding seen? Then login's the door,
Google or email — try both, try more.
NavGraph hops true through every state,
Auth is complete — the template is great! 🥕

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: adding onboarding and Firebase authentication to the mobile app.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch 37-feat-mobile-auth

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

- Add "Continue with Google" OutlinedButton with inline Google G logo
  (four-colour vector, no resource file required) above the email/password
  fields with an OR divider
- Wire onSignInWithGoogle callback through AppNavGraph; activity reference
  obtained from LocalContext so LoginScreen stays activity-independent
- Add onSignInWithGoogle parameter to LoginScreen and update all call
  sites and previews
- Add instrumented tests: button visibility, click callback, existing
  tests updated with new parameter

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 14

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@mobile/app/build.gradle.kts`:
- Line 31: The GOOGLE_WEB_CLIENT_ID buildConfigField currently falls back to an
empty string, which lets the app compile with a broken auth configuration.
Update the Gradle configuration in build.gradle.kts to validate the property
before using it, and fail the build during configuration if the value is missing
or blank, especially for release variants. Use the existing localProps lookup
and the GOOGLE_WEB_CLIENT_ID buildConfigField definition as the entry points for
the change.

In
`@mobile/app/src/androidTest/java/com/company/template/auth/LoginScreenTest.kt`:
- Around line 23-35: The LoginScreen test is using onNodeWithText("Sign In"),
which is ambiguous because it matches both the heading and the CTA button.
Update the test in LoginScreenTest to target the sign-in button by semantics
instead of raw text, using a button-specific matcher or a dedicated test tag on
the CTA before asserting or performing click actions.

In `@mobile/app/src/androidTest/java/com/company/template/home/HomeScreenTest.kt`:
- Around line 62-71: The HomeScreen empty-display-name test still only verifies
the heading, so it can pass even if the name text is rendered; update
homeScreen_emptyDisplayName_doesNotShowNameText in HomeScreenTest to explicitly
assert that a non-empty name like "Alice" does not exist when HomeScreen is
composed with an empty displayName. Keep the existing heading check if needed,
but add the missing negative assertion against the name text using the Compose
test rule.

In `@mobile/app/src/main/java/com/company/template/auth/AuthRepository.kt`:
- Around line 7-12: Move Activity handling out of the auth boundary by changing
AuthRepository.signInWithGoogle and the corresponding AuthViewModel flow so the
auth layer accepts a UI-produced credential/token result instead of
android.app.Activity. Keep the Activity usage in the UI layer, update the
ViewModel to receive the Google sign-in result and forward only the credential
data to the repository, and adjust any implementations/tests that currently
depend on Activity.

In `@mobile/app/src/main/java/com/company/template/auth/AuthViewModel.kt`:
- Around line 59-62: The sign-out flow in AuthViewModel.signOut() only calls
repo.signOut() and leaves the auth screen state unchanged, so reset the
ViewModel’s auth uiState back to a non-success state as part of sign-out. Update
the signOut coroutine to clear AuthUiState.Success before or after
repo.signOut(), using the existing uiState state holder in AuthViewModel so
AppNavGraph no longer treats the user as authenticated after logout.

In
`@mobile/app/src/main/java/com/company/template/auth/FirebaseAuthRepository.kt`:
- Around line 95-97: signOut() currently only calls FirebaseAuth.signOut(), so
the previous Google credential can still be reused. Update
FirebaseAuthRepository.signOut() to also clear Credential Manager state by
calling CredentialManager.clearCredentialState(...) as part of the logout flow,
and thread in the needed Context or CredentialManager dependency through this
path so the cleanup can happen when signing out.

In `@mobile/app/src/main/java/com/company/template/auth/LoginScreen.kt`:
- Around line 39-72: The LoginScreen composable is holding mutable form state
and clearing errors inline, which violates the rule that UI functions stay pure.
Move email and password state out of LoginScreen into the ViewModel or parent
caller, and drive both fields via state plus explicit events instead of
rememberSaveable and direct mutation. Also replace the inline onClearError()
calls in the OutlinedTextField onValueChange handlers with a dispatched UI event
handled outside the composable, using LoginScreen and the AuthUiState flow as
the main touchpoints.
- Around line 32-38: The LoginScreen UI currently only exposes email/password
sign-in and register navigation, so the Google auth flow is unreachable from
this screen. Update LoginScreen to accept a dedicated Google sign-in callback,
add a clear CTA that invokes it, and wire it through the existing screen
composable alongside onSignIn and onNavigateToRegister. Also update the
instrumented test coverage for LoginScreen to assert the new Google sign-in
action is rendered and triggers the new callback.

In `@mobile/app/src/main/java/com/company/template/auth/RegisterScreen.kt`:
- Around line 41-123: RegisterScreen is owning form state with rememberSaveable
and mutating error state inside the Composable, which violates the rule that UI
functions stay pure. Move name, email, password, and confirmPassword state out
of RegisterScreen into the ViewModel or caller, and pass the current values plus
change callbacks down as parameters. Also remove the in-field onClearError side
effects from the OutlinedTextField onValueChange handlers and let the
caller/ViewModel handle error clearing and submission logic.

In `@mobile/app/src/main/java/com/company/template/navigation/AppNavGraph.kt`:
- Around line 57-63: The onboarding flow only navigates in the OnboardingScreen
onGetStarted callback and never writes the seen flag, so persist it first by
calling OnboardingRepository.markSeen() from the ViewModel or the calling
composable before navigation, then navigate to ROUTE_LOGIN. Keep the composable
free of business logic by hoisting this work out of AppNavGraph/OnboardingScreen
and wiring the callback to a state/action in AppViewModel or its caller.

In
`@mobile/app/src/main/java/com/company/template/onboarding/DataStoreOnboardingRepository.kt`:
- Around line 18-19: The hasSeenOnboarding() flow in
DataStoreOnboardingRepository should handle DataStore read failures before
mapping, because context.dataStore.data can throw IOException and break
onboarding state resolution. Update the flow pipeline in hasSeenOnboarding() to
catch read errors on the data source, emit emptyPreferences() when an
IOException occurs, and then continue with the existing map logic so the default
false value is still returned safely.

In
`@mobile/app/src/main/java/com/company/template/onboarding/OnboardingViewModel.kt`:
- Around line 15-19: The OnboardingViewModel.markSeen coroutine currently lets
repo.markSeen() throw and skip onComplete(), so update markSeen to surface
failures instead of silently failing. Wrap the repo.markSeen() call in error
handling and either add an explicit error callback parameter or return/report
the exception so callers can react, while keeping the existing success path that
invokes onComplete().

In
`@mobile/app/src/test/java/com/company/template/navigation/AppViewModelTest.kt`:
- Around line 105-116: The `startDestination is Home when user is signed in`
test does not cover the signed-in branch because it sets
`fakeAuth.setUser(null)` and only asserts `StartDestination.LOGIN`, duplicating
the null-user case. Update this test in `AppViewModelTest` to exercise the
non-null auth path by configuring `fakeAuth` to emit a signed-in user state
before calling `createViewModel()`, then assert that
`viewModel.startDestination` resolves to `StartDestination.HOME` while keeping
the existing onboarding setup.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: defaults

Review profile: CHILL

Plan: Pro

Run ID: 31342138-d931-4bf0-ac16-c4de07020620

📥 Commits

Reviewing files that changed from the base of the PR and between a9940c6 and fefd49c.

📒 Files selected for processing (22)
  • mobile/app/build.gradle.kts
  • mobile/app/src/androidTest/java/com/company/template/auth/LoginScreenTest.kt
  • mobile/app/src/androidTest/java/com/company/template/auth/RegisterScreenTest.kt
  • mobile/app/src/androidTest/java/com/company/template/home/HomeScreenTest.kt
  • mobile/app/src/androidTest/java/com/company/template/onboarding/OnboardingScreenTest.kt
  • mobile/app/src/main/java/com/company/template/MainActivity.kt
  • mobile/app/src/main/java/com/company/template/auth/AuthRepository.kt
  • mobile/app/src/main/java/com/company/template/auth/AuthViewModel.kt
  • mobile/app/src/main/java/com/company/template/auth/FirebaseAuthRepository.kt
  • mobile/app/src/main/java/com/company/template/auth/LoginScreen.kt
  • mobile/app/src/main/java/com/company/template/auth/RegisterScreen.kt
  • mobile/app/src/main/java/com/company/template/home/HomeScreen.kt
  • mobile/app/src/main/java/com/company/template/navigation/AppNavGraph.kt
  • mobile/app/src/main/java/com/company/template/navigation/AppViewModel.kt
  • mobile/app/src/main/java/com/company/template/onboarding/DataStoreOnboardingRepository.kt
  • mobile/app/src/main/java/com/company/template/onboarding/OnboardingRepository.kt
  • mobile/app/src/main/java/com/company/template/onboarding/OnboardingScreen.kt
  • mobile/app/src/main/java/com/company/template/onboarding/OnboardingViewModel.kt
  • mobile/app/src/test/java/com/company/template/auth/AuthViewModelTest.kt
  • mobile/app/src/test/java/com/company/template/navigation/AppViewModelTest.kt
  • mobile/app/src/test/java/com/company/template/onboarding/OnboardingViewModelTest.kt
  • mobile/gradle/libs.versions.toml

Comment thread mobile/app/build.gradle.kts
Comment thread mobile/app/src/androidTest/java/com/company/template/auth/LoginScreenTest.kt Outdated
Comment thread mobile/app/src/androidTest/java/com/company/template/auth/RegisterScreenTest.kt Outdated
Comment thread mobile/app/src/main/java/com/company/template/auth/RegisterScreen.kt Outdated
Comment thread mobile/app/src/main/java/com/company/template/onboarding/OnboardingViewModel.kt Outdated
Comment thread mobile/app/src/test/java/com/company/template/navigation/AppViewModelTest.kt Outdated
GRACENOBLE and others added 3 commits June 24, 2026 19:50
…s.json

- Pass applicationContext into FirebaseAuthRepository so it can read
  the default_web_client_id string resource generated by the
  google-services plugin from google-services.json
- resolveWebClientId() tries the generated resource first, then falls
  back to BuildConfig.GOOGLE_WEB_CLIENT_ID (local.properties)
- Handle NoCredentialException by launching Settings.ACTION_ADD_ACCOUNT
  so users with no Google account on device are guided to add one
- GOOGLE_WEB_CLIENT_ID retained in BuildConfig as fallback for
  environments where google-services.json lacks the web OAuth client
GetGoogleIdOption uses the One Tap UX which gets suppressed by Google
based on authorization history and dismissal count, causing
NoCredentialException even when a Google account exists on the device.

GetSignInWithGoogleOption is designed for explicit button-triggered
sign-in flows and always shows the full account picker without
suppression or filtering by prior authorization status.
- Introduce User domain type so authStateFlow emits User? instead of
  FirebaseUser?, enabling JVM-only tests without Android framework deps
- Remove Activity from AuthRepository interface; move CredentialManager
  and Google token fetching into AuthViewModel.signInWithGoogle()
- FirebaseAuthRepository.signOut() now clears CredentialManager state
  to prevent stale Google account reuse on next sign-in
- AuthViewModel.signOut() resets _uiState to Idle (was leaving
  AuthUiState.Success latched, causing nav loop back to Home)
- Hoist LoginScreen/RegisterScreen form state to AuthViewModel via
  LoginFormState/RegisterFormState; screens receive state + callbacks
- AppNavGraph calls appViewModel.markOnboardingSeen() before navigating
  away from onboarding so sign-out does not re-show onboarding
- AppViewModel.markOnboardingSeen() added for nav graph to call
- DataStoreOnboardingRepository.hasSeenOnboarding() catches IOException
  and emits emptyPreferences() as a safe fallback
- OnboardingViewModel.markSeen() uses runCatching so onComplete is not
  silently skipped on DataStore failure
- build.gradle.kts: release assembleRelease/bundleRelease tasks fail
  fast if GOOGLE_WEB_CLIENT_ID is absent from local.properties
- Add LoginTestTags.SIGN_IN_BUTTON and RegisterTestTags.CREATE_ACCOUNT_BUTTON
  test tags to disambiguate nodes that share text with headings
- Fix AppViewModelTest HOME branch: was setting user=null and asserting
  LOGIN — now sets a real User object and asserts HOME
- HomeScreenTest: assert empty displayName does not render a name node

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
@GRACENOBLE
GRACENOBLE merged commit 610ba54 into main Jun 24, 2026
3 checks passed
@GRACENOBLE
GRACENOBLE deleted the 37-feat-mobile-auth branch June 24, 2026 17:32
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

area: mobile Android app (Kotlin + Jetpack Compose) type: chore Cleanup or maintenance tasks

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant