Skip to content
Merged
Show file tree
Hide file tree
Changes from 4 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