From 796d58a727cfd3fa4a8d12985c2828b599d0957f Mon Sep 17 00:00:00 2001 From: demolaf Date: Wed, 15 Jul 2026 14:20:00 +0100 Subject: [PATCH 1/5] fix(auth): allow customizing top app bar colors via AuthUITheme --- .../auth/configuration/theme/AuthUITheme.kt | 17 +++++- .../auth/ui/screens/email/ResetPasswordUI.kt | 3 +- .../ui/screens/email/SignInEmailLinkUI.kt | 3 +- .../ui/auth/ui/screens/email/SignInUI.kt | 3 +- .../ui/auth/ui/screens/email/SignUpUI.kt | 3 +- .../ui/screens/phone/EnterPhoneNumberUI.kt | 3 +- .../screens/phone/EnterVerificationCodeUI.kt | 3 +- .../configuration/theme/AuthUIThemeTest.kt | 56 +++++++++++++++++++ 8 files changed, 83 insertions(+), 8 deletions(-) diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt index 79e78f80f..2d733789c 100644 --- a/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt +++ b/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt @@ -19,6 +19,7 @@ import androidx.compose.material3.ColorScheme import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Shapes +import androidx.compose.material3.TopAppBarColors import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.Typography import androidx.compose.material3.darkColorScheme @@ -81,6 +82,12 @@ class AuthUITheme( * ``` */ val providerButtonShape: Shape? = null, + + /** + * Custom colors for the top app bar shown on auth screens. If null, falls back to + * colors derived from [colorScheme] (see [AuthUITheme.topAppBarColors]). + */ + val topAppBarColors: TopAppBarColors? = null, ) { /** @@ -91,6 +98,7 @@ class AuthUITheme( * @param shapes The shapes to use. Defaults to this theme's shapes. * @param providerStyles Custom styling for individual providers. Defaults to this theme's provider styles. * @param providerButtonShape Default shape for provider buttons. Defaults to this theme's provider button shape. + * @param topAppBarColors Custom top app bar colors. Defaults to this theme's top app bar colors. * @return A new AuthUITheme instance with the specified properties. */ fun copy( @@ -99,13 +107,15 @@ class AuthUITheme( shapes: Shapes = this.shapes, providerStyles: Map = this.providerStyles, providerButtonShape: Shape? = this.providerButtonShape, + topAppBarColors: TopAppBarColors? = this.topAppBarColors, ): AuthUITheme { return AuthUITheme( colorScheme = colorScheme, typography = typography, shapes = shapes, providerStyles = providerStyles, - providerButtonShape = providerButtonShape + providerButtonShape = providerButtonShape, + topAppBarColors = topAppBarColors ) } @@ -118,6 +128,7 @@ class AuthUITheme( if (shapes != other.shapes) return false if (providerStyles != other.providerStyles) return false if (providerButtonShape != other.providerButtonShape) return false + if (topAppBarColors != other.topAppBarColors) return false return true } @@ -128,12 +139,14 @@ class AuthUITheme( result = 31 * result + shapes.hashCode() result = 31 * result + providerStyles.hashCode() result = 31 * result + (providerButtonShape?.hashCode() ?: 0) + result = 31 * result + (topAppBarColors?.hashCode() ?: 0) return result } override fun toString(): String { return "AuthUITheme(colorScheme=$colorScheme, typography=$typography, shapes=$shapes, " + - "providerStyles=$providerStyles, providerButtonShape=$providerButtonShape)" + "providerStyles=$providerStyles, providerButtonShape=$providerButtonShape, " + + "topAppBarColors=$topAppBarColors)" } /** diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt index 8b73f2c2d..7120fd004 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt @@ -52,6 +52,7 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme +import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.ui.components.AuthTextField import com.firebase.ui.auth.ui.components.TermsAndPrivacyForm @@ -130,7 +131,7 @@ fun ResetPasswordUI( } } }, - colors = AuthUITheme.topAppBarColors + colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt index 14e045827..f3a1a91bd 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt @@ -57,6 +57,7 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme +import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.ui.components.AuthTextField import com.firebase.ui.auth.ui.components.TermsAndPrivacyForm @@ -141,7 +142,7 @@ fun SignInEmailLinkUI( } } }, - colors = AuthUITheme.topAppBarColors + colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt index eabde87a1..7f1e18908 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt @@ -66,6 +66,7 @@ import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.DefaultAuthUIStringProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme +import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.configuration.validators.PasswordValidator import com.firebase.ui.auth.credentialmanager.PasswordCredentialCancelledException @@ -170,7 +171,7 @@ fun SignInUI( } } }, - colors = AuthUITheme.topAppBarColors + colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt index 6ff0d19f4..0c2807698 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt @@ -47,6 +47,7 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme +import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.configuration.validators.GeneralFieldValidator import com.firebase.ui.auth.configuration.validators.PasswordValidator @@ -120,7 +121,7 @@ fun SignUpUI( } } }, - colors = AuthUITheme.topAppBarColors + colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt index ef8bfe545..5cd90eebc 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt @@ -48,6 +48,7 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme +import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.PhoneNumberValidator import com.firebase.ui.auth.data.CountryData import com.firebase.ui.auth.ui.components.AuthTextField @@ -99,7 +100,7 @@ fun EnterPhoneNumberUI( } } }, - colors = AuthUITheme.topAppBarColors + colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt index 122e73a87..f79c62819 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt @@ -51,6 +51,7 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme +import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.VerificationCodeValidator import com.firebase.ui.auth.ui.components.TermsAndPrivacyForm import com.firebase.ui.auth.ui.components.VerificationCodeInputField @@ -103,7 +104,7 @@ fun EnterVerificationCodeUI( } } }, - colors = AuthUITheme.topAppBarColors + colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt index 46e6a1dc8..38dfc769b 100644 --- a/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt +++ b/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt @@ -3,10 +3,13 @@ package com.firebase.ui.auth.configuration.theme import android.content.Context import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.material3.ColorScheme +import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Shapes import androidx.compose.material3.ShapeDefaults import androidx.compose.material3.Text +import androidx.compose.material3.TopAppBarColors +import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.Typography import androidx.compose.material3.darkColorScheme import androidx.compose.material3.lightColorScheme @@ -313,6 +316,59 @@ class AuthUIThemeTest { assertThat(observedProviderStyles?.get("google.com")?.backgroundColor).isEqualTo(Color.Red) } + // ======================================================================== + // topAppBarColors Tests + // ======================================================================== + + @Test + fun `Default theme has null topAppBarColors`() { + assertThat(AuthUITheme.Default.topAppBarColors).isNull() + } + + @OptIn(ExperimentalMaterial3Api::class) + @Test + fun `Copy with custom topAppBarColors applies correctly`() { + lateinit var customColors: TopAppBarColors + var observedColors: TopAppBarColors? = null + + composeTestRule.setContent { + customColors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Red, + titleContentColor = Color.White, + navigationIconContentColor = Color.White, + ) + val customTheme = AuthUITheme.Default.copy(topAppBarColors = customColors) + + CompositionLocalProvider( + LocalAuthUITheme provides customTheme + ) { + observedColors = LocalAuthUITheme.current.topAppBarColors + } + } + + composeTestRule.waitForIdle() + + assertThat(observedColors).isEqualTo(customColors) + } + + @OptIn(ExperimentalMaterial3Api::class) + @Test + fun `Resolved topAppBarColors falls back to default when theme value is null`() { + var resolvedColors: TopAppBarColors? = null + var defaultColors: TopAppBarColors? = null + + composeTestRule.setContent { + AuthUITheme(theme = AuthUITheme.Default) { + defaultColors = AuthUITheme.topAppBarColors + resolvedColors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + } + } + + composeTestRule.waitForIdle() + + assertThat(resolvedColors).isEqualTo(defaultColors) + } + // ======================================================================== // fromMaterialTheme Tests // ======================================================================== From 52b9650742e4a5985e8cda03eee67e4568727266 Mon Sep 17 00:00:00 2001 From: demolaf Date: Wed, 15 Jul 2026 14:41:46 +0100 Subject: [PATCH 2/5] sample(app): demo custom topAppBarColors in HighLevelApiDemoActivity --- .../android/demo/HighLevelApiDemoActivity.kt | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt index 8aabec3b0..7b5eff83c 100644 --- a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt +++ b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt @@ -26,6 +26,7 @@ import androidx.compose.material3.TextButton import androidx.compose.material3.TooltipAnchorPosition import androidx.compose.material3.TooltipBox import androidx.compose.material3.TooltipDefaults +import androidx.compose.material3.TopAppBarColors import androidx.compose.material3.rememberTooltipState import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue @@ -71,7 +72,15 @@ class HighLevelApiDemoActivity : ComponentActivity() { val emailLink = intent.getStringExtra(EmailLinkConstants.EXTRA_EMAIL_LINK) val customTheme = AuthUITheme.Default.copy( - providerButtonShape = ShapeDefaults.ExtraLarge + providerButtonShape = ShapeDefaults.ExtraLarge, + topAppBarColors = TopAppBarColors( + containerColor = Color(0xFF2E7D32), + scrolledContainerColor = Color(0xFF2E7D32), + navigationIconContentColor = Color.White, + titleContentColor = Color.White, + actionIconContentColor = Color.White, + subtitleContentColor = Color.White, + ) ) class CustomAuthUIStringProvider( From 284730fdd84f70c36b2e74b165a6fe5519a09eb9 Mon Sep 17 00:00:00 2001 From: demolaf Date: Wed, 15 Jul 2026 15:10:33 +0100 Subject: [PATCH 3/5] docs(auth): document topAppBarColors customization --- auth/README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/auth/README.md b/auth/README.md index e4311d8f3..289067cc7 100644 --- a/auth/README.md +++ b/auth/README.md @@ -1546,6 +1546,30 @@ val configuration = authUIConfiguration { } ``` +### Customizing the Top App Bar + +Override the colors used by the top app bar shown on auth screens: + +```kotlin +val customTheme = AuthUITheme.Default.copy( + topAppBarColors = TopAppBarColors( + containerColor = Color(0xFF2E7D32), + scrolledContainerColor = Color(0xFF2E7D32), + navigationIconContentColor = Color.White, + titleContentColor = Color.White, + actionIconContentColor = Color.White, + subtitleContentColor = Color.White, + ) +) + +val configuration = authUIConfiguration { + providers { provider(AuthProvider.Email()) } + theme = customTheme +} +``` + +If left unset (`null`), the top app bar falls back to colors derived from `colorScheme`'s `primary`/`onPrimary`. + ### Screen Transitions Customize the animations when navigating between screens using the `AuthUITransitions` object: From 73765d95fb9e59444205f6f90389a04e1414dff8 Mon Sep 17 00:00:00 2001 From: demolaf Date: Wed, 15 Jul 2026 15:26:40 +0100 Subject: [PATCH 4/5] sample(app): use adaptive theme and Firebase brand color for demo top app bar --- .../android/demo/HighLevelApiDemoActivity.kt | 234 +++++++++--------- 1 file changed, 117 insertions(+), 117 deletions(-) diff --git a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt index 7b5eff83c..eb1455928 100644 --- a/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt +++ b/app/src/main/java/com/firebaseui/android/demo/HighLevelApiDemoActivity.kt @@ -71,18 +71,6 @@ class HighLevelApiDemoActivity : ComponentActivity() { val authUI = FirebaseAuthUI.getInstance() val emailLink = intent.getStringExtra(EmailLinkConstants.EXTRA_EMAIL_LINK) - val customTheme = AuthUITheme.Default.copy( - providerButtonShape = ShapeDefaults.ExtraLarge, - topAppBarColors = TopAppBarColors( - containerColor = Color(0xFF2E7D32), - scrolledContainerColor = Color(0xFF2E7D32), - navigationIconContentColor = Color.White, - titleContentColor = Color.White, - actionIconContentColor = Color.White, - subtitleContentColor = Color.White, - ) - ) - class CustomAuthUIStringProvider( private val defaultProvider: AuthUIStringProvider ) : AuthUIStringProvider by defaultProvider { @@ -94,124 +82,136 @@ class HighLevelApiDemoActivity : ComponentActivity() { val customStringProvider = CustomAuthUIStringProvider(DefaultAuthUIStringProvider(applicationContext)) - val configuration = authUIConfiguration { - context = applicationContext - theme = customTheme - logo = AuthUIAsset.Resource(R.drawable.firebase_auth) - tosUrl = "https://policies.google.com/terms" - privacyPolicyUrl = "https://policies.google.com/privacy" - isAnonymousUpgradeEnabled = false - isMfaEnabled = false - stringProvider = customStringProvider - transitions = AuthUITransitions( - enterTransition = { slideInHorizontally { it } }, - exitTransition = { slideOutHorizontally { -it } }, - popEnterTransition = { slideInHorizontally { -it } }, - popExitTransition = { slideOutHorizontally { it } } + setContent { + val customTheme = AuthUITheme.Adaptive.copy( + providerButtonShape = ShapeDefaults.ExtraLarge, + topAppBarColors = TopAppBarColors( + containerColor = Color(0xFFFFA000), + scrolledContainerColor = Color(0xFFFFA000), + navigationIconContentColor = Color.Black, + titleContentColor = Color.Black, + actionIconContentColor = Color.Black, + subtitleContentColor = Color.Black, + ) ) - providers { - provider(AuthProvider.Anonymous) - provider( - AuthProvider.Google( - scopes = listOf("email"), - serverClientId = "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com", - ) + + val configuration = authUIConfiguration { + context = applicationContext + theme = customTheme + logo = AuthUIAsset.Resource(R.drawable.firebase_auth) + tosUrl = "https://policies.google.com/terms" + privacyPolicyUrl = "https://policies.google.com/privacy" + isAnonymousUpgradeEnabled = false + isMfaEnabled = false + stringProvider = customStringProvider + transitions = AuthUITransitions( + enterTransition = { slideInHorizontally { it } }, + exitTransition = { slideOutHorizontally { -it } }, + popEnterTransition = { slideInHorizontally { -it } }, + popExitTransition = { slideOutHorizontally { it } } ) - provider( - AuthProvider.Email( - isDisplayNameRequired = true, - isEmailLinkForceSameDeviceEnabled = false, - isEmailLinkSignInEnabled = true, - emailLinkActionCodeSettings = actionCodeSettings { - url = "https://flutterfire-e2e-tests.firebaseapp.com" - handleCodeInApp = true - setAndroidPackageName( - "com.firebaseui.android.demo", - true, - null - ) - }, - isNewAccountsAllowed = true, - minimumPasswordLength = 8, - passwordValidationRules = listOf( - PasswordRule.MinimumLength(8), - PasswordRule.RequireLowercase, - PasswordRule.RequireUppercase, - ), + providers { + provider(AuthProvider.Anonymous) + provider( + AuthProvider.Google( + scopes = listOf("email"), + serverClientId = "406099696497-a12gakvts4epfk5pkio7dphc1anjiggc.apps.googleusercontent.com", + ) ) - ) - provider( - AuthProvider.Phone( - defaultNumber = null, - defaultCountryCode = null, - allowedCountries = emptyList(), - smsCodeLength = 6, - timeout = 120L, - isInstantVerificationEnabled = true + provider( + AuthProvider.Email( + isDisplayNameRequired = true, + isEmailLinkForceSameDeviceEnabled = false, + isEmailLinkSignInEnabled = true, + emailLinkActionCodeSettings = actionCodeSettings { + url = "https://flutterfire-e2e-tests.firebaseapp.com" + handleCodeInApp = true + setAndroidPackageName( + "com.firebaseui.android.demo", + true, + null + ) + }, + isNewAccountsAllowed = true, + minimumPasswordLength = 8, + passwordValidationRules = listOf( + PasswordRule.MinimumLength(8), + PasswordRule.RequireLowercase, + PasswordRule.RequireUppercase, + ), + ) ) - ) - provider( - AuthProvider.Facebook() - ) - provider( - AuthProvider.Twitter( - customParameters = emptyMap() + provider( + AuthProvider.Phone( + defaultNumber = null, + defaultCountryCode = null, + allowedCountries = emptyList(), + smsCodeLength = 6, + timeout = 120L, + isInstantVerificationEnabled = true + ) ) - ) - provider( - AuthProvider.Apple( - customParameters = emptyMap(), - locale = null + provider( + AuthProvider.Facebook() ) - ) - provider( - AuthProvider.Microsoft( - scopes = emptyList(), - tenant = "", - customParameters = emptyMap(), + provider( + AuthProvider.Twitter( + customParameters = emptyMap() + ) ) - ) - provider( - AuthProvider.Github( - scopes = emptyList(), - customParameters = emptyMap(), + provider( + AuthProvider.Apple( + customParameters = emptyMap(), + locale = null + ) ) - ) - provider( - AuthProvider.Yahoo( - scopes = emptyList(), - customParameters = emptyMap(), + provider( + AuthProvider.Microsoft( + scopes = emptyList(), + tenant = "", + customParameters = emptyMap(), + ) ) - ) - provider( - AuthProvider.GenericOAuth( - providerName = "LINE", - providerId = "oidc.line", - scopes = emptyList(), - customParameters = emptyMap(), - buttonLabel = "Sign in with LINE", - buttonIcon = AuthUIAsset.Resource(R.drawable.ic_line_logo_24dp), - buttonColor = Color(0xFF06C755), - contentColor = Color.White + provider( + AuthProvider.Github( + scopes = emptyList(), + customParameters = emptyMap(), + ) ) - ) - provider( - AuthProvider.GenericOAuth( - providerName = "Discord", - providerId = "oidc.discord", - scopes = emptyList(), - customParameters = emptyMap(), - buttonLabel = "Sign in with Discord", - buttonIcon = AuthUIAsset.Resource(R.drawable.ic_discord_24dp), - buttonColor = Color(0xFF5865F2), - contentColor = Color.White + provider( + AuthProvider.Yahoo( + scopes = emptyList(), + customParameters = emptyMap(), + ) ) - ) + provider( + AuthProvider.GenericOAuth( + providerName = "LINE", + providerId = "oidc.line", + scopes = emptyList(), + customParameters = emptyMap(), + buttonLabel = "Sign in with LINE", + buttonIcon = AuthUIAsset.Resource(R.drawable.ic_line_logo_24dp), + buttonColor = Color(0xFF06C755), + contentColor = Color.White + ) + ) + provider( + AuthProvider.GenericOAuth( + providerName = "Discord", + providerId = "oidc.discord", + scopes = emptyList(), + customParameters = emptyMap(), + buttonLabel = "Sign in with Discord", + buttonIcon = AuthUIAsset.Resource(R.drawable.ic_discord_24dp), + buttonColor = Color(0xFF5865F2), + contentColor = Color.White + ) + ) + } } - } - setContent { - AuthUITheme { + AuthUITheme(theme = customTheme) { Surface( modifier = Modifier.fillMaxSize(), color = MaterialTheme.colorScheme.background From 8aa50f05c11eaf1371a785b1920266f5deba465c Mon Sep 17 00:00:00 2001 From: demolaf Date: Wed, 15 Jul 2026 16:50:03 +0100 Subject: [PATCH 5/5] fix(auth): wire topAppBarColors into MFA screen and dedupe resolution logic --- .../auth/configuration/theme/AuthUITheme.kt | 9 ++++++ .../auth/ui/screens/MfaEnrollmentDefaults.kt | 4 ++- .../auth/ui/screens/email/ResetPasswordUI.kt | 3 +- .../ui/screens/email/SignInEmailLinkUI.kt | 3 +- .../ui/auth/ui/screens/email/SignInUI.kt | 3 +- .../ui/auth/ui/screens/email/SignUpUI.kt | 3 +- .../ui/screens/phone/EnterPhoneNumberUI.kt | 3 +- .../screens/phone/EnterVerificationCodeUI.kt | 3 +- .../configuration/theme/AuthUIThemeTest.kt | 28 +++++++++++++++++-- 9 files changed, 44 insertions(+), 15 deletions(-) diff --git a/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt b/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt index 2d733789c..b063abb2b 100644 --- a/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt +++ b/auth/src/main/java/com/firebase/ui/auth/configuration/theme/AuthUITheme.kt @@ -249,6 +249,15 @@ class AuthUITheme( titleContentColor = MaterialTheme.colorScheme.onPrimary, navigationIconContentColor = MaterialTheme.colorScheme.onPrimary, ) + + /** + * Resolves the top app bar colors to use for the current [LocalAuthUITheme], falling back + * to [topAppBarColors] when the current theme doesn't specify its own. + */ + @OptIn(ExperimentalMaterial3Api::class) + @get:Composable + val resolvedTopAppBarColors: TopAppBarColors + get() = LocalAuthUITheme.current.topAppBarColors ?: topAppBarColors } } diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/MfaEnrollmentDefaults.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/MfaEnrollmentDefaults.kt index 61f1151a6..1cbb45949 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/MfaEnrollmentDefaults.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/MfaEnrollmentDefaults.kt @@ -53,6 +53,7 @@ import com.firebase.ui.auth.configuration.AuthUIConfiguration import com.firebase.ui.auth.configuration.MfaFactor import com.firebase.ui.auth.configuration.string_provider.AuthUIStringProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider +import com.firebase.ui.auth.configuration.theme.AuthUITheme import com.firebase.ui.auth.mfa.MfaEnrollmentContentState import com.firebase.ui.auth.mfa.MfaEnrollmentStep import com.firebase.ui.auth.mfa.toMfaErrorMessage @@ -253,7 +254,8 @@ private fun SelectFactorUI( Scaffold( topBar = { TopAppBar( - title = { Text(stringProvider.mfaManageFactorsTitle) } + title = { Text(stringProvider.mfaManageFactorsTitle) }, + colors = AuthUITheme.resolvedTopAppBarColors ) } ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt index 7120fd004..9d94b6e03 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/ResetPasswordUI.kt @@ -52,7 +52,6 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme -import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.ui.components.AuthTextField import com.firebase.ui.auth.ui.components.TermsAndPrivacyForm @@ -131,7 +130,7 @@ fun ResetPasswordUI( } } }, - colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + colors = AuthUITheme.resolvedTopAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt index f3a1a91bd..0a27749dc 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInEmailLinkUI.kt @@ -57,7 +57,6 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme -import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.ui.components.AuthTextField import com.firebase.ui.auth.ui.components.TermsAndPrivacyForm @@ -142,7 +141,7 @@ fun SignInEmailLinkUI( } } }, - colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + colors = AuthUITheme.resolvedTopAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt index 7f1e18908..3093f23f1 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignInUI.kt @@ -66,7 +66,6 @@ import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.DefaultAuthUIStringProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme -import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.configuration.validators.PasswordValidator import com.firebase.ui.auth.credentialmanager.PasswordCredentialCancelledException @@ -171,7 +170,7 @@ fun SignInUI( } } }, - colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + colors = AuthUITheme.resolvedTopAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt index 0c2807698..c05a1c03c 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/email/SignUpUI.kt @@ -47,7 +47,6 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme -import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.EmailValidator import com.firebase.ui.auth.configuration.validators.GeneralFieldValidator import com.firebase.ui.auth.configuration.validators.PasswordValidator @@ -121,7 +120,7 @@ fun SignUpUI( } } }, - colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + colors = AuthUITheme.resolvedTopAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt index 5cd90eebc..21e0d5ae5 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterPhoneNumberUI.kt @@ -48,7 +48,6 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme -import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.PhoneNumberValidator import com.firebase.ui.auth.data.CountryData import com.firebase.ui.auth.ui.components.AuthTextField @@ -100,7 +99,7 @@ fun EnterPhoneNumberUI( } } }, - colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + colors = AuthUITheme.resolvedTopAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt index f79c62819..b678ab4fe 100644 --- a/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt +++ b/auth/src/main/java/com/firebase/ui/auth/ui/screens/phone/EnterVerificationCodeUI.kt @@ -51,7 +51,6 @@ import com.firebase.ui.auth.configuration.authUIConfiguration import com.firebase.ui.auth.configuration.auth_provider.AuthProvider import com.firebase.ui.auth.configuration.string_provider.LocalAuthUIStringProvider import com.firebase.ui.auth.configuration.theme.AuthUITheme -import com.firebase.ui.auth.configuration.theme.LocalAuthUITheme import com.firebase.ui.auth.configuration.validators.VerificationCodeValidator import com.firebase.ui.auth.ui.components.TermsAndPrivacyForm import com.firebase.ui.auth.ui.components.VerificationCodeInputField @@ -104,7 +103,7 @@ fun EnterVerificationCodeUI( } } }, - colors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + colors = AuthUITheme.resolvedTopAppBarColors ) }, ) { innerPadding -> diff --git a/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt b/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt index 38dfc769b..cb62ee879 100644 --- a/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt +++ b/auth/src/test/java/com/firebase/ui/auth/configuration/theme/AuthUIThemeTest.kt @@ -353,14 +353,14 @@ class AuthUIThemeTest { @OptIn(ExperimentalMaterial3Api::class) @Test - fun `Resolved topAppBarColors falls back to default when theme value is null`() { + fun `resolvedTopAppBarColors falls back to default when theme value is null`() { var resolvedColors: TopAppBarColors? = null var defaultColors: TopAppBarColors? = null composeTestRule.setContent { AuthUITheme(theme = AuthUITheme.Default) { defaultColors = AuthUITheme.topAppBarColors - resolvedColors = LocalAuthUITheme.current.topAppBarColors ?: AuthUITheme.topAppBarColors + resolvedColors = AuthUITheme.resolvedTopAppBarColors } } @@ -369,6 +369,30 @@ class AuthUIThemeTest { assertThat(resolvedColors).isEqualTo(defaultColors) } + @OptIn(ExperimentalMaterial3Api::class) + @Test + fun `resolvedTopAppBarColors uses the theme's custom value when set`() { + lateinit var customColors: TopAppBarColors + var resolvedColors: TopAppBarColors? = null + + composeTestRule.setContent { + customColors = TopAppBarDefaults.topAppBarColors( + containerColor = Color.Red, + titleContentColor = Color.White, + navigationIconContentColor = Color.White, + ) + val customTheme = AuthUITheme.Default.copy(topAppBarColors = customColors) + + AuthUITheme(theme = customTheme) { + resolvedColors = AuthUITheme.resolvedTopAppBarColors + } + } + + composeTestRule.waitForIdle() + + assertThat(resolvedColors).isEqualTo(customColors) + } + // ======================================================================== // fromMaterialTheme Tests // ========================================================================