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
2 changes: 2 additions & 0 deletions auth/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,8 @@ dependencies {
implementation("androidx.lifecycle:lifecycle-viewmodel-ktx:2.2.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("androidx.navigation:navigation-compose:2.8.3")
implementation("com.google.zxing:core:3.5.3")
implementation("com.google.android.libraries.identity.googleid:googleid:1.1.1")
annotationProcessor(Config.Libs.Androidx.lifecycleCompiler)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,87 @@ interface AuthUIStringProvider {
/** Loading progress text */
val progressDialogLoading: String

/** Label shown when the user is signed in. String should contain a single %s placeholder. */
fun signedInAs(userIdentifier: String): String

/** Action text for managing multi-factor authentication settings. */
val manageMfaAction: String

/** Action text for signing out. */
val signOutAction: String

/** Instruction shown when the user must verify their email. Accepts the email value. */
fun verifyEmailInstruction(email: String): String

/** Action text for resending the verification email. */
val resendVerificationEmailAction: String

/** Action text once the user has verified their email. */
val verifiedEmailAction: String

/** Message shown when profile completion is required. */
val profileCompletionMessage: String

/** Message listing missing profile fields. Accepts a comma-separated list. */
fun profileMissingFieldsMessage(fields: String): String

/** Action text for skipping an optional step. */
val skipAction: String

/** Action text for removing an item (for example, an MFA factor). */
val removeAction: String

/** Action text for navigating back. */
val backAction: String

/** Action text for confirming verification. */
val verifyAction: String

/** Action text for choosing a different factor during MFA challenge. */
val useDifferentMethodAction: String

/** Action text for confirming recovery codes have been saved. */
val recoveryCodesSavedAction: String

/** Label for secret key text displayed during TOTP setup. */
val secretKeyLabel: String

/** Label for verification code input fields. */
val verificationCodeLabel: String

/** Generic identity verified confirmation message. */
val identityVerifiedMessage: String

/** Title for the manage MFA screen. */
val mfaManageFactorsTitle: String

/** Helper description for the manage MFA screen. */
val mfaManageFactorsDescription: String

/** Header for the list of currently enrolled MFA factors. */
val mfaActiveMethodsTitle: String

/** Header for the list of available MFA factors to enroll. */
val mfaAddNewMethodTitle: String

/** Message shown when all factors are already enrolled. */
val mfaAllMethodsEnrolledMessage: String

/** Label for SMS MFA factor. */
val smsAuthenticationLabel: String

/** Label for authenticator-app MFA factor. */
val totpAuthenticationLabel: String

/** Label used when the factor type is unknown. */
val unknownMethodLabel: String

/** Label describing the enrollment date. Accepts a formatted date string. */
fun enrolledOnDateLabel(date: String): String

/** Description displayed during authenticator app setup. */
val setupAuthenticatorDescription: String

/** Network error message */
val noInternet: String

Expand Down Expand Up @@ -339,4 +420,20 @@ interface AuthUIStringProvider {

/** Generic error message for MFA enrollment failures */
val mfaErrorGeneric: String

// Re-authentication Dialog
/** Title displayed in the re-authentication dialog. */
val reauthDialogTitle: String

/** Descriptive message shown in the re-authentication dialog. */
val reauthDialogMessage: String

/** Label showing the account email being re-authenticated. */
fun reauthAccountLabel(email: String): String

/** Error message shown when the provided password is incorrect. */
val incorrectPasswordError: String

/** General error message for re-authentication failures. */
val reauthGenericError: String
}
Original file line number Diff line number Diff line change
Expand Up @@ -235,6 +235,87 @@ class DefaultAuthUIStringProvider(
get() = localizedContext.getString(R.string.fui_required_field)
override val progressDialogLoading: String
get() = localizedContext.getString(R.string.fui_progress_dialog_loading)

override fun signedInAs(userIdentifier: String): String =
localizedContext.getString(R.string.fui_signed_in_as, userIdentifier)

override val manageMfaAction: String
get() = localizedContext.getString(R.string.fui_manage_mfa_action)

override val signOutAction: String
get() = localizedContext.getString(R.string.fui_sign_out_action)

override fun verifyEmailInstruction(email: String): String =
localizedContext.getString(R.string.fui_verify_email_instruction, email)

override val resendVerificationEmailAction: String
get() = localizedContext.getString(R.string.fui_resend_verification_email_action)

override val verifiedEmailAction: String
get() = localizedContext.getString(R.string.fui_verified_email_action)

override val profileCompletionMessage: String
get() = localizedContext.getString(R.string.fui_profile_completion_message)

override fun profileMissingFieldsMessage(fields: String): String =
localizedContext.getString(R.string.fui_profile_missing_fields_message, fields)

override val skipAction: String
get() = localizedContext.getString(R.string.fui_skip_action)

override val removeAction: String
get() = localizedContext.getString(R.string.fui_remove_action)

override val backAction: String
get() = localizedContext.getString(R.string.fui_back_action)

override val verifyAction: String
get() = localizedContext.getString(R.string.fui_verify_action)

override val useDifferentMethodAction: String
get() = localizedContext.getString(R.string.fui_use_different_method_action)

override val recoveryCodesSavedAction: String
get() = localizedContext.getString(R.string.fui_recovery_codes_saved_action)

override val secretKeyLabel: String
get() = localizedContext.getString(R.string.fui_secret_key_label)

override val verificationCodeLabel: String
get() = localizedContext.getString(R.string.fui_verification_code_label)

override val identityVerifiedMessage: String
get() = localizedContext.getString(R.string.fui_identity_verified_message)

override val mfaManageFactorsTitle: String
get() = localizedContext.getString(R.string.fui_mfa_manage_factors_title)

override val mfaManageFactorsDescription: String
get() = localizedContext.getString(R.string.fui_mfa_manage_factors_description)

override val mfaActiveMethodsTitle: String
get() = localizedContext.getString(R.string.fui_mfa_active_methods_title)

override val mfaAddNewMethodTitle: String
get() = localizedContext.getString(R.string.fui_mfa_add_new_method_title)

override val mfaAllMethodsEnrolledMessage: String
get() = localizedContext.getString(R.string.fui_mfa_all_methods_enrolled_message)

override val smsAuthenticationLabel: String
get() = localizedContext.getString(R.string.fui_mfa_label_sms_authentication)

override val totpAuthenticationLabel: String
get() = localizedContext.getString(R.string.fui_mfa_label_totp_authentication)

override val unknownMethodLabel: String
get() = localizedContext.getString(R.string.fui_mfa_label_unknown_method)

override fun enrolledOnDateLabel(date: String): String =
localizedContext.getString(R.string.fui_mfa_enrolled_on, date)

override val setupAuthenticatorDescription: String
get() = localizedContext.getString(R.string.fui_mfa_setup_authenticator_description)
override val noInternet: String
get() = localizedContext.getString(R.string.fui_no_internet)

Expand Down Expand Up @@ -319,4 +400,19 @@ class DefaultAuthUIStringProvider(
get() = localizedContext.getString(R.string.fui_mfa_error_network)
override val mfaErrorGeneric: String
get() = localizedContext.getString(R.string.fui_mfa_error_generic)

override val reauthDialogTitle: String
get() = localizedContext.getString(R.string.fui_reauth_dialog_title)

override val reauthDialogMessage: String
get() = localizedContext.getString(R.string.fui_reauth_dialog_message)

override fun reauthAccountLabel(email: String): String =
localizedContext.getString(R.string.fui_reauth_account_label, email)

override val incorrectPasswordError: String
get() = localizedContext.getString(R.string.fui_incorrect_password_error)

override val reauthGenericError: String
get() = localizedContext.getString(R.string.fui_reauth_generic_error)
}
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,9 @@ data class MfaEnrollmentContentState(
/** Optional error message to display. `null` if no error. */
val error: String? = null,

/** The last exception encountered during enrollment, if available. */
val exception: Exception? = null,

/** Callback to navigate to the previous step. */
val onBackClick: () -> Unit = {},

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,13 @@
* limitations under the License.
*/

package com.firebase.composeapp.ui.components
package com.firebase.ui.auth.compose.ui.components

import android.graphics.Bitmap
import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.size
import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
Expand All @@ -34,13 +33,16 @@ import com.google.zxing.WriterException
import com.google.zxing.qrcode.QRCodeWriter

/**
* Composable that displays a QR code image generated from the provided content.
* Renders a QR code from the provided content string.
*
* @param content The string content to encode in the QR code (e.g., TOTP URI)
* @param modifier Modifier to be applied to the QR code image
* @param size The size (width and height) of the QR code image
* @param foregroundColor The color of the QR code pixels (default: black)
* @param backgroundColor The background color of the QR code (default: white)
* This component is typically used to display TOTP enrollment URIs. The QR code is generated on the
* fly and memoized for the given [content].
*
* @param content The string content to encode into the QR code (for example the TOTP URI).
* @param modifier Optional [Modifier] applied to the QR container.
* @param size The size of the QR code square in density-independent pixels.
* @param foregroundColor Color used to render the QR pixels (defaults to black).
* @param backgroundColor Background color for the QR code (defaults to white).
*/
@Composable
fun QrCodeImage(
Expand All @@ -53,7 +55,7 @@ fun QrCodeImage(
val bitmap = remember(content, size, foregroundColor, backgroundColor) {
generateQrCodeBitmap(
content = content,
sizePx = (size.value * 2).toInt(), // 2x for better resolution
sizePx = (size.value * 2).toInt(), // Render at 2x for better scaling quality.
foregroundColor = foregroundColor,
backgroundColor = backgroundColor
)
Expand All @@ -75,15 +77,6 @@ fun QrCodeImage(
}
}

/**
* Generates a QR code bitmap from the provided content.
*
* @param content The string to encode
* @param sizePx The size of the bitmap in pixels
* @param foregroundColor The color for the QR code pixels
* @param backgroundColor The background color
* @return A Bitmap containing the QR code, or null if generation fails
*/
private fun generateQrCodeBitmap(
content: String,
sizePx: Int,
Expand All @@ -93,7 +86,7 @@ private fun generateQrCodeBitmap(
return try {
val qrCodeWriter = QRCodeWriter()
val hints = mapOf(
EncodeHintType.MARGIN to 1 // Minimal margin
EncodeHintType.MARGIN to 1 // Small margin keeps QR code compact while remaining scannable.
)

val bitMatrix = qrCodeWriter.encode(
Expand Down Expand Up @@ -132,7 +125,6 @@ private fun generateQrCodeBitmap(

bitmap
} catch (e: WriterException) {
e.printStackTrace()
null
}
}
Loading
Loading