Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 16 additions & 4 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,25 @@ jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: set up JDK 17
uses: actions/setup-java@v1
- uses: actions/checkout@v4

- name: Cache Gradle packages
uses: actions/cache@v3
with:
path: |
~/.gradle/caches
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}

- name: Set up JDK 17
uses: actions/setup-java@v4
with:
java-version: 17
java-version: '17'
distribution: 'temurin'

- name: Build with Gradle
run: ./scripts/build.sh

- name: Print Logs
if: failure()
run: ./scripts/print_build_logs.sh
278 changes: 278 additions & 0 deletions auth/src/main/java/com/firebase/ui/auth/compose/AuthProviderButton.kt
Original file line number Diff line number Diff line change
@@ -0,0 +1,278 @@
package com.firebase.ui.auth.compose

import androidx.compose.foundation.Image
import androidx.compose.material3.Icon
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Star
import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.firebase.ui.auth.compose.configuration.AuthProvider
import com.firebase.ui.auth.compose.configuration.Provider
import com.firebase.ui.auth.compose.configuration.stringprovider.AuthUIStringProvider
import com.firebase.ui.auth.compose.configuration.stringprovider.DefaultAuthUIStringProvider
import com.firebase.ui.auth.compose.configuration.theme.AuthUIAsset
import com.firebase.ui.auth.compose.configuration.theme.AuthUITheme

/**
* A customizable button for an authentication provider.
*
* This button displays the icon and name of an authentication provider (e.g., Google, Facebook).
* It is designed to be used within a list of sign-in options. The button's appearance can be
* customized using the [style] parameter, and its text is localized via the [stringProvider].
*
* **Example usage:**
* ```kotlin
* AuthProviderButton(
* provider = AuthProvider.Facebook(),
* onClick = { /* Handle Facebook sign-in */ },
* stringProvider = DefaultAuthUIStringProvider(LocalContext.current)
* )
* ```
*
* @param modifier A modifier for the button
* @param provider The provider to represent.
* @param onClick A callback when the button is clicked
* @param enabled If the button is enabled. Defaults to true.
* @param style Optional custom styling for the button.
* @param stringProvider The [AuthUIStringProvider] for localized strings
*
* @since 10.0.0
*/
@Composable
fun AuthProviderButton(
modifier: Modifier = Modifier,
provider: AuthProvider,
onClick: () -> Unit,
enabled: Boolean = true,
style: AuthUITheme.ProviderStyle? = null,
stringProvider: AuthUIStringProvider,
) {
val providerStyle = resolveProviderStyle(provider, style)
val providerText = resolveProviderLabel(provider, stringProvider)

Button(
modifier = modifier,
colors = ButtonDefaults.buttonColors(
containerColor = providerStyle.backgroundColor,
contentColor = providerStyle.contentColor,
),
shape = providerStyle.shape,
elevation = ButtonDefaults.buttonElevation(
defaultElevation = providerStyle.elevation
),
onClick = onClick,
enabled = enabled,
) {
Row(
verticalAlignment = Alignment.CenterVertically
) {
val providerIcon = providerStyle.icon
if (providerIcon != null) {
val iconTint = providerStyle.iconTint
if (iconTint != null) {
Icon(
painter = providerIcon.painter,
contentDescription = providerText,
tint = iconTint
)
} else {
Image(
painter = providerIcon.painter,
contentDescription = providerText
)
}
Spacer(modifier = Modifier.width(8.dp))
}
Text(
text = providerText
)
}
}
}

internal fun resolveProviderStyle(
provider: AuthProvider,
style: AuthUITheme.ProviderStyle?,
): AuthUITheme.ProviderStyle {
if (style != null) return style

val defaultStyle =
AuthUITheme.Default.providerStyles[provider.providerId] ?: AuthUITheme.ProviderStyle.Empty

return if (provider is AuthProvider.GenericOAuth) {
AuthUITheme.ProviderStyle(
icon = provider.buttonIcon ?: defaultStyle.icon,
backgroundColor = provider.buttonColor ?: defaultStyle.backgroundColor,
contentColor = provider.contentColor ?: defaultStyle.contentColor,
)
} else {
defaultStyle
}
}

internal fun resolveProviderLabel(
provider: AuthProvider,
stringProvider: AuthUIStringProvider
): String = when (provider) {
is AuthProvider.GenericOAuth -> provider.buttonLabel
else -> when (Provider.fromId(provider.providerId)) {
Provider.GOOGLE -> stringProvider.signInWithGoogle
Provider.FACEBOOK -> stringProvider.signInWithFacebook
Provider.TWITTER -> stringProvider.signInWithTwitter
Provider.GITHUB -> stringProvider.signInWithGithub
Provider.EMAIL -> stringProvider.signInWithEmail
Provider.PHONE -> stringProvider.signInWithPhone
Provider.ANONYMOUS -> stringProvider.signInAnonymously
Provider.MICROSOFT -> stringProvider.signInWithMicrosoft
Provider.YAHOO -> stringProvider.signInWithYahoo
Provider.APPLE -> stringProvider.signInWithApple
null -> "Unknown Provider"
}
}

@Preview(showBackground = true)
@Composable
private fun PreviewAuthProviderButton() {
val context = LocalContext.current
Column(
modifier = Modifier
.fillMaxSize(),
verticalArrangement = Arrangement.Center,
horizontalAlignment = Alignment.CenterHorizontally
) {
AuthProviderButton(
provider = AuthProvider.Email(
actionCodeSettings = null,
passwordValidationRules = emptyList()
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Phone(
defaultNumber = null,
defaultCountryCode = null,
allowedCountries = null,
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Google(
scopes = emptyList(),
serverClientId = null
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Facebook(),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Twitter(
customParameters = emptyMap()
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Github(
customParameters = emptyMap()
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Microsoft(
tenant = null,
customParameters = emptyMap()
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Yahoo(
customParameters = emptyMap()
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Apple(
locale = null,
customParameters = emptyMap()
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.Anonymous,
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.GenericOAuth(
providerId = "google.com",
scopes = emptyList(),
customParameters = emptyMap(),
buttonLabel = "Generic Provider",
buttonIcon = AuthUIAsset.Vector(Icons.Default.Star),
buttonColor = Color.Gray,
contentColor = Color.White
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.GenericOAuth(
providerId = "google.com",
scopes = emptyList(),
customParameters = emptyMap(),
buttonLabel = "Custom Style",
buttonIcon = AuthUIAsset.Vector(Icons.Default.Star),
buttonColor = Color.Gray,
contentColor = Color.White
),
onClick = {},
style = AuthUITheme.ProviderStyle(
icon = AuthUITheme.Default.providerStyles[Provider.MICROSOFT.id]?.icon,
backgroundColor = AuthUITheme.Default.providerStyles[Provider.MICROSOFT.id]!!.backgroundColor,
contentColor = AuthUITheme.Default.providerStyles[Provider.MICROSOFT.id]!!.contentColor,
iconTint = Color.Red,
shape = RoundedCornerShape(24.dp),
elevation = 6.dp
),
stringProvider = DefaultAuthUIStringProvider(context)
)
AuthProviderButton(
provider = AuthProvider.GenericOAuth(
providerId = "unknown_provider",
scopes = emptyList(),
customParameters = emptyMap(),
buttonLabel = "Unsupported Provider",
buttonIcon = null,
buttonColor = null,
contentColor = null,
),
onClick = {},
stringProvider = DefaultAuthUIStringProvider(context)
)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,10 @@
package com.firebase.ui.auth.compose.configuration

import android.content.Context
import android.graphics.Color
import androidx.compose.ui.graphics.Color
import android.util.Log
import androidx.compose.ui.graphics.vector.ImageVector
import com.firebase.ui.auth.AuthUI
import com.firebase.ui.auth.R
import com.firebase.ui.auth.compose.configuration.theme.AuthUIAsset
import com.firebase.ui.auth.util.Preconditions
import com.firebase.ui.auth.util.data.PhoneNumberUtils
import com.firebase.ui.auth.util.data.ProviderAvailability
Expand Down Expand Up @@ -55,7 +54,13 @@ internal enum class Provider(val id: String) {
ANONYMOUS("anonymous"),
MICROSOFT("microsoft.com"),
YAHOO("yahoo.com"),
APPLE("apple.com"),
APPLE("apple.com");

companion object {
fun fromId(id: String): Provider? {
return entries.find { it.id == id }
}
}
}

/**
Expand Down Expand Up @@ -446,12 +451,17 @@ abstract class AuthProvider(open val providerId: String) {
/**
* An optional icon for the provider button.
*/
val buttonIcon: ImageVector?,
val buttonIcon: AuthUIAsset?,

/**
* An optional background color for the provider button.
*/
val buttonColor: Color?
val buttonColor: Color?,

/**
* An optional content color for the provider button.
*/
val contentColor: Color?
) : OAuthProvider(
providerId = providerId,
scopes = scopes,
Expand Down
Loading