@@ -52,6 +52,7 @@ import com.firebase.ui.auth.compose.configuration.MfaConfiguration
5252import com.firebase.ui.auth.compose.configuration.auth_provider.AuthProvider
5353import com.firebase.ui.auth.compose.configuration.auth_provider.rememberSignInWithFacebookLauncher
5454import com.firebase.ui.auth.compose.configuration.auth_provider.signInWithEmailLink
55+ import com.firebase.ui.auth.compose.configuration.string_provider.AuthUIStringProvider
5556import com.firebase.ui.auth.compose.configuration.string_provider.DefaultAuthUIStringProvider
5657import com.firebase.ui.auth.compose.configuration.theme.AuthUIAsset
5758import com.firebase.ui.auth.compose.ui.components.ErrorRecoveryDialog
@@ -109,103 +110,6 @@ fun FirebaseAuthScreen(
109110 )
110111 }
111112
112- // Handle email link sign-in (deep links)
113- LaunchedEffect (emailLink) {
114- if (emailLink != null && emailProvider != null ) {
115- try {
116- EmailLinkPersistenceManager .retrieveSessionRecord(context)?.email?.let { email ->
117- authUI.signInWithEmailLink(
118- context = context,
119- config = configuration,
120- provider = emailProvider,
121- email = email,
122- emailLink = emailLink
123- )
124- }
125- } catch (e: Exception ) {
126- Log .e(" FirebaseAuthScreen" , " Failed to complete email link sign-in" , e)
127- }
128-
129- if (navController.currentBackStackEntry?.destination?.route != AuthRoute .Email .route) {
130- navController.navigate(AuthRoute .Email .route)
131- }
132- }
133- }
134-
135- // Synchronise auth state changes with navigation stack.
136- LaunchedEffect (authState) {
137- val state = authState
138- val currentRoute = navController.currentBackStackEntry?.destination?.route
139- when (state) {
140- is AuthState .Success -> {
141- pendingResolver.value = null
142- pendingLinkingCredential.value = null
143-
144- state.result?.let { result ->
145- if (state.user.uid != lastSuccessfulUserId.value) {
146- onSignInSuccess(result)
147- lastSuccessfulUserId.value = state.user.uid
148- }
149- }
150-
151- if (currentRoute != AuthRoute .Success .route) {
152- navController.navigate(AuthRoute .Success .route) {
153- popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
154- launchSingleTop = true
155- }
156- }
157- }
158-
159- is AuthState .RequiresEmailVerification ,
160- is AuthState .RequiresProfileCompletion -> {
161- pendingResolver.value = null
162- pendingLinkingCredential.value = null
163- if (currentRoute != AuthRoute .Success .route) {
164- navController.navigate(AuthRoute .Success .route) {
165- popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
166- launchSingleTop = true
167- }
168- }
169- }
170-
171- is AuthState .RequiresMfa -> {
172- pendingResolver.value = state.resolver
173- if (currentRoute != AuthRoute .MfaChallenge .route) {
174- navController.navigate(AuthRoute .MfaChallenge .route) {
175- launchSingleTop = true
176- }
177- }
178- }
179-
180- is AuthState .Cancelled -> {
181- pendingResolver.value = null
182- pendingLinkingCredential.value = null
183- lastSuccessfulUserId.value = null
184- if (currentRoute != AuthRoute .MethodPicker .route) {
185- navController.navigate(AuthRoute .MethodPicker .route) {
186- popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
187- launchSingleTop = true
188- }
189- }
190- onSignInCancelled()
191- }
192-
193- is AuthState .Idle -> {
194- pendingResolver.value = null
195- pendingLinkingCredential.value = null
196- lastSuccessfulUserId.value = null
197- if (currentRoute != AuthRoute .MethodPicker .route) {
198- navController.navigate(AuthRoute .MethodPicker .route) {
199- popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
200- launchSingleTop = true
201- }
202- }
203- }
204-
205- else -> Unit
206- }
207- }
208-
209113 Scaffold (modifier = modifier) { innerPadding ->
210114 Surface (
211115 modifier = Modifier
@@ -379,6 +283,103 @@ fun FirebaseAuthScreen(
379283 }
380284 }
381285
286+ // Handle email link sign-in (deep links)
287+ LaunchedEffect (emailLink) {
288+ if (emailLink != null && emailProvider != null ) {
289+ try {
290+ EmailLinkPersistenceManager .retrieveSessionRecord(context)?.email?.let { email ->
291+ authUI.signInWithEmailLink(
292+ context = context,
293+ config = configuration,
294+ provider = emailProvider,
295+ email = email,
296+ emailLink = emailLink
297+ )
298+ }
299+ } catch (e: Exception ) {
300+ Log .e(" FirebaseAuthScreen" , " Failed to complete email link sign-in" , e)
301+ }
302+
303+ if (navController.currentBackStackEntry?.destination?.route != AuthRoute .Email .route) {
304+ navController.navigate(AuthRoute .Email .route)
305+ }
306+ }
307+ }
308+
309+ // Synchronise auth state changes with navigation stack.
310+ LaunchedEffect (authState) {
311+ val state = authState
312+ val currentRoute = navController.currentBackStackEntry?.destination?.route
313+ when (state) {
314+ is AuthState .Success -> {
315+ pendingResolver.value = null
316+ pendingLinkingCredential.value = null
317+
318+ state.result?.let { result ->
319+ if (state.user.uid != lastSuccessfulUserId.value) {
320+ onSignInSuccess(result)
321+ lastSuccessfulUserId.value = state.user.uid
322+ }
323+ }
324+
325+ if (currentRoute != AuthRoute .Success .route) {
326+ navController.navigate(AuthRoute .Success .route) {
327+ popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
328+ launchSingleTop = true
329+ }
330+ }
331+ }
332+
333+ is AuthState .RequiresEmailVerification ,
334+ is AuthState .RequiresProfileCompletion -> {
335+ pendingResolver.value = null
336+ pendingLinkingCredential.value = null
337+ if (currentRoute != AuthRoute .Success .route) {
338+ navController.navigate(AuthRoute .Success .route) {
339+ popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
340+ launchSingleTop = true
341+ }
342+ }
343+ }
344+
345+ is AuthState .RequiresMfa -> {
346+ pendingResolver.value = state.resolver
347+ if (currentRoute != AuthRoute .MfaChallenge .route) {
348+ navController.navigate(AuthRoute .MfaChallenge .route) {
349+ launchSingleTop = true
350+ }
351+ }
352+ }
353+
354+ is AuthState .Cancelled -> {
355+ pendingResolver.value = null
356+ pendingLinkingCredential.value = null
357+ lastSuccessfulUserId.value = null
358+ if (currentRoute != AuthRoute .MethodPicker .route) {
359+ navController.navigate(AuthRoute .MethodPicker .route) {
360+ popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
361+ launchSingleTop = true
362+ }
363+ }
364+ onSignInCancelled()
365+ }
366+
367+ is AuthState .Idle -> {
368+ pendingResolver.value = null
369+ pendingLinkingCredential.value = null
370+ lastSuccessfulUserId.value = null
371+ if (currentRoute != AuthRoute .MethodPicker .route) {
372+ navController.navigate(AuthRoute .MethodPicker .route) {
373+ popUpTo(AuthRoute .MethodPicker .route) { inclusive = true }
374+ launchSingleTop = true
375+ }
376+ }
377+ }
378+
379+ else -> Unit
380+ }
381+ }
382+
382383 val errorState = authState as ? AuthState .Error
383384 if (isErrorDialogVisible.value && errorState != null ) {
384385 ErrorRecoveryDialog (
@@ -438,7 +439,7 @@ private sealed class AuthRoute(val route: String) {
438439
439440data class AuthSuccessUiContext (
440441 val authUI : FirebaseAuthUI ,
441- val stringProvider : com.firebase.ui.auth.compose.configuration.string_provider. AuthUIStringProvider ,
442+ val stringProvider : AuthUIStringProvider ,
442443 val onSignOut : () -> Unit ,
443444 val onManageMfa : () -> Unit ,
444445 val onReloadUser : () -> Unit
@@ -447,7 +448,7 @@ data class AuthSuccessUiContext(
447448@Composable
448449private fun SuccessDestination (
449450 authState : AuthState ,
450- stringProvider : com.firebase.ui.auth.compose.configuration.string_provider. AuthUIStringProvider ,
451+ stringProvider : AuthUIStringProvider ,
451452 uiContext : AuthSuccessUiContext
452453) {
453454 when (authState) {
@@ -491,7 +492,7 @@ private fun SuccessDestination(
491492@Composable
492493private fun AuthSuccessContent (
493494 authUI : FirebaseAuthUI ,
494- stringProvider : com.firebase.ui.auth.compose.configuration.string_provider. AuthUIStringProvider ,
495+ stringProvider : AuthUIStringProvider ,
495496 onSignOut : () -> Unit ,
496497 onManageMfa : () -> Unit
497498) {
@@ -524,7 +525,7 @@ private fun AuthSuccessContent(
524525@Composable
525526private fun EmailVerificationContent (
526527 authUI : FirebaseAuthUI ,
527- stringProvider : com.firebase.ui.auth.compose.configuration.string_provider. AuthUIStringProvider ,
528+ stringProvider : AuthUIStringProvider ,
528529 onCheckStatus : () -> Unit ,
529530 onSignOut : () -> Unit
530531) {
@@ -558,7 +559,7 @@ private fun EmailVerificationContent(
558559@Composable
559560private fun ProfileCompletionContent (
560561 missingFields : List <String >,
561- stringProvider : com.firebase.ui.auth.compose.configuration.string_provider. AuthUIStringProvider
562+ stringProvider : AuthUIStringProvider
562563) {
563564 Column (
564565 modifier = Modifier .fillMaxSize(),
0 commit comments