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
7 changes: 4 additions & 3 deletions .github/workflows/android.yml
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ on:
jobs:
build:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- uses: actions/checkout@v4

Expand All @@ -18,13 +19,13 @@ jobs:
~/.gradle/wrapper
key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}

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

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

- name: Print Logs
Expand Down
52 changes: 52 additions & 0 deletions .github/workflows/e2e_test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,52 @@
name: E2E Tests (Firebase Emulator)

on:
- pull_request
- push

jobs:
e2e-tests:
runs-on: ubuntu-latest
timeout-minutes: 45
steps:
- 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: Firebase Emulator Cache
uses: actions/cache@v4
with:
path: ~/.cache/firebase/emulators
key: firebase-emulators-v3-${{ runner.os }}

- name: Install Node.js 20
uses: actions/setup-node@v4
with:
node-version: '20'

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

- name: Install Firebase Tools
run: |
npm i -g firebase-tools

- name: Start Firebase Auth Emulator
run: ./scripts/start-firebase-emulator.sh

- name: Run E2E Tests
run: |
./gradlew e2eTest

- name: Print Logs
if: failure()
run: ./scripts/print_build_logs.sh
Original file line number Diff line number Diff line change
Expand Up @@ -257,7 +257,7 @@ class FirebaseAuthUI private constructor(
* @throws AuthException.UnknownException for other errors
* @since 10.0.0
*/
suspend fun signOut(context: Context) {
fun signOut(context: Context) {
try {
// Update state to loading
updateAuthState(AuthState.Loading("Signing out..."))
Expand Down Expand Up @@ -452,7 +452,7 @@ class FirebaseAuthUI private constructor(
*/
@JvmStatic
@RestrictTo(RestrictTo.Scope.TESTS)
internal fun clearInstanceCache() {
fun clearInstanceCache() {
instanceCache.clear()
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ abstract class PasswordRule {
}

override fun getErrorMessage(stringProvider: AuthUIStringProvider): String {
return stringProvider.passwordTooShort.format(value)
return stringProvider.passwordTooShort(value)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -86,7 +86,7 @@ interface AuthUIStringProvider {
val passwordsDoNotMatch: String

/** Error message when password doesn't meet minimum length requirement. Should support string formatting with minimum length parameter. */
val passwordTooShort: String
fun passwordTooShort(minimumLength: Int): String

/** Error message when password is missing at least one uppercase letter (A-Z) */
val passwordMissingUppercase: String
Expand All @@ -102,14 +102,17 @@ interface AuthUIStringProvider {

// Email Authentication Strings
/** Title for email signup form */
val titleRegisterEmail: String
val signupPageTitle: String

/** Hint for email input field */
val emailHint: String

/** Hint for password input field */
val passwordHint: String

/** Hint for confirm password input field */
val confirmPasswordHint: String

/** Hint for new password input field */
val newPasswordHint: String

Expand All @@ -125,6 +128,24 @@ interface AuthUIStringProvider {
/** Trouble signing in link text */
val troubleSigningIn: String

/** Title for recover password page */
val recoverPasswordPageTitle: String

/** Button text for reset password */
val sendButtonText: String

/** Title for recover password link sent dialog */
val recoverPasswordLinkSentDialogTitle: String

/** Body for recover password link sent dialog */
fun recoverPasswordLinkSentDialogBody(email: String): String

/** Title for email sign in link sent dialog */
val emailSignInLinkSentDialogTitle: String

/** Body for email sign in link sent dialog */
fun emailSignInLinkSentDialogBody(email: String): String

// Phone Authentication Strings
/** Phone number entry form title */
val verifyPhoneNumberTitle: String
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,8 @@ import com.firebase.ui.auth.R
import java.util.Locale

class DefaultAuthUIStringProvider(
private val context: Context,
private val locale: Locale? = null,
context: Context,
locale: Locale? = null,
) : AuthUIStringProvider {
/**
* Allows overriding locale.
Expand Down Expand Up @@ -95,8 +95,10 @@ class DefaultAuthUIStringProvider(
get() = localizedContext.getString(R.string.fui_error_invalid_password)
override val passwordsDoNotMatch: String
get() = localizedContext.getString(R.string.fui_passwords_do_not_match)
override val passwordTooShort: String
get() = localizedContext.getString(R.string.fui_error_password_too_short)

override fun passwordTooShort(minimumLength: Int): String =
localizedContext.getString(R.string.fui_error_password_too_short, minimumLength)

override val passwordMissingUppercase: String
get() = localizedContext.getString(R.string.fui_error_password_missing_uppercase)
override val passwordMissingLowercase: String
Expand All @@ -109,12 +111,14 @@ class DefaultAuthUIStringProvider(
/**
* Email Authentication Strings
*/
override val titleRegisterEmail: String
override val signupPageTitle: String
get() = localizedContext.getString(R.string.fui_title_register_email)
override val emailHint: String
get() = localizedContext.getString(R.string.fui_email_hint)
override val passwordHint: String
get() = localizedContext.getString(R.string.fui_password_hint)
override val confirmPasswordHint: String
get() = localizedContext.getString(R.string.fui_confirm_password_hint)
override val newPasswordHint: String
get() = localizedContext.getString(R.string.fui_new_password_hint)
override val nameHint: String
Expand All @@ -126,6 +130,24 @@ class DefaultAuthUIStringProvider(
override val troubleSigningIn: String
get() = localizedContext.getString(R.string.fui_trouble_signing_in)

override val recoverPasswordPageTitle: String
get() = localizedContext.getString(R.string.fui_title_recover_password_activity)

override val sendButtonText: String
get() = localizedContext.getString(R.string.fui_button_text_send)

override val recoverPasswordLinkSentDialogTitle: String
get() = localizedContext.getString(R.string.fui_title_confirm_recover_password)

override fun recoverPasswordLinkSentDialogBody(email: String): String =
localizedContext.getString(R.string.fui_confirm_recovery_body, email)

override val emailSignInLinkSentDialogTitle: String
get() = localizedContext.getString(R.string.fui_email_link_header)

override fun emailSignInLinkSentDialogBody(email: String): String =
localizedContext.getString(R.string.fui_email_link_email_sent, email)

/**
* Phone Authentication Strings
*/
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,27 @@ fun AuthTextField(
keyboardActions = keyboardActions,
visualTransformation = if (isSecureTextField && !passwordVisible)
PasswordVisualTransformation() else visualTransformation,
leadingIcon = leadingIcon,
leadingIcon = leadingIcon ?: when {
validator is EmailValidator -> {
{
Icon(
imageVector = Icons.Default.Email,
contentDescription = ""
)
}
}

isSecureTextField -> {
{
Icon(
imageVector = Icons.Default.Lock,
contentDescription = ""
)
}
}

else -> null
},
trailingIcon = trailingIcon ?: {
if (isSecureTextField) {
IconButton(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,24 +17,22 @@ package com.firebase.ui.auth.compose.ui.screens
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.rememberScrollState
import androidx.compose.foundation.verticalScroll
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.layout.safeDrawingPadding
import androidx.compose.foundation.layout.size
import androidx.compose.foundation.layout.width
import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.filled.Email
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
import androidx.compose.material3.CircularProgressIndicator
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.TopAppBar
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable
import androidx.compose.runtime.derivedStateOf
import androidx.compose.runtime.mutableStateOf
Expand Down Expand Up @@ -83,24 +81,25 @@ fun ResetPasswordUI(
AlertDialog(
title = {
Text(
text = "Reset Link Sent",
text = stringProvider.recoverPasswordLinkSentDialogTitle,
style = MaterialTheme.typography.headlineSmall
)
},
text = {
Text(
text = "Check your email $email",
text = stringProvider.recoverPasswordLinkSentDialogBody(email),
style = MaterialTheme.typography.bodyMedium,
textAlign = TextAlign.Start
)
},
confirmButton = {
TextButton(
onClick = {
onGoToSignIn()
isDialogVisible.value = false
}
) {
Text("Dismiss")
Text(stringProvider.dismissAction)
}
},
onDismissRequest = {
Expand All @@ -114,7 +113,7 @@ fun ResetPasswordUI(
topBar = {
TopAppBar(
title = {
Text("Recover Password")
Text(stringProvider.recoverPasswordPageTitle)
},
colors = AuthUITheme.topAppBarColors
)
Expand All @@ -124,7 +123,8 @@ fun ResetPasswordUI(
modifier = Modifier
.padding(innerPadding)
.safeDrawingPadding()
.padding(horizontal = 16.dp),
.padding(horizontal = 16.dp)
.verticalScroll(rememberScrollState()),
) {
AuthTextField(
value = email,
Expand All @@ -135,12 +135,6 @@ fun ResetPasswordUI(
},
onValueChange = { text ->
onEmailChange(text)
},
leadingIcon = {
Icon(
imageVector = Icons.Default.Email,
contentDescription = ""
)
}
)
Spacer(modifier = Modifier.height(8.dp))
Expand All @@ -154,7 +148,7 @@ fun ResetPasswordUI(
},
enabled = !isLoading,
) {
Text("Sign In")
Text(stringProvider.signInDefault.uppercase())
}
Spacer(modifier = Modifier.width(16.dp))
Button(
Expand All @@ -169,7 +163,7 @@ fun ResetPasswordUI(
.size(16.dp)
)
} else {
Text("Send")
Text(stringProvider.sendButtonText.uppercase())
}
}
}
Expand Down
Loading