Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Make the dialog type for the Native Google Sign In configurable #832

Merged
merged 3 commits into from
Jan 12, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package io.github.jan.supabase.compose.auth
import android.app.Activity
import android.content.Context
import android.content.ContextWrapper
import com.google.android.libraries.identity.googleid.GetGoogleIdOption
import com.google.android.libraries.identity.googleid.GetSignInWithGoogleOption

internal fun getSignInWithGoogleOptions(
internal fun getGoogleButtonOptions(
config: GoogleLoginConfig?,
nonce: String? = null
): GetSignInWithGoogleOption {
Expand All @@ -14,6 +15,19 @@ internal fun getSignInWithGoogleOptions(
return signInWithGoogleOption.build()
}

internal fun getGoogleBottomSheetOptions(
config: GoogleLoginConfig?,
filterByAuthorizedAccounts: Boolean = true,
nonce: String? = null
): GetGoogleIdOption {
val googleIdOption: GetGoogleIdOption = GetGoogleIdOption.Builder()
.setFilterByAuthorizedAccounts(filterByAuthorizedAccounts)
.setServerClientId(config?.serverClientId ?: error("Trying to use Google Auth without setting the serverClientId"))
.setNonce(nonce)
.build()
return googleIdOption
}

internal fun Context.getActivity(): Activity? = when (this) {
is Activity -> this
is ContextWrapper -> baseContext.getActivity()
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package io.github.jan.supabase.compose.auth.composable

import android.app.Activity
import android.content.Context
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
Expand All @@ -15,14 +17,23 @@ import androidx.credentials.exceptions.GetCredentialException
import com.google.android.libraries.identity.googleid.GoogleIdTokenCredential
import com.google.android.libraries.identity.googleid.GoogleIdTokenParsingException
import io.github.jan.supabase.compose.auth.ComposeAuth
import io.github.jan.supabase.compose.auth.GoogleLoginConfig
import io.github.jan.supabase.compose.auth.applicationContext
import io.github.jan.supabase.compose.auth.getActivity
import io.github.jan.supabase.compose.auth.getSignInWithGoogleOptions
import io.github.jan.supabase.compose.auth.getGoogleBottomSheetOptions
import io.github.jan.supabase.compose.auth.getGoogleButtonOptions
import io.github.jan.supabase.compose.auth.hash
import io.github.jan.supabase.compose.auth.signInWithGoogle
import io.github.jan.supabase.logging.d
import io.github.jan.supabase.logging.e

private data class GoogleRequestOptions(
val config: GoogleLoginConfig?,
val nonce: String?,
val filterByAuthorizedAccounts: Boolean = false,
val type: GoogleDialogType
)

/**
* Composable function that implements Native Google Auth.
*
Expand All @@ -33,12 +44,20 @@ import io.github.jan.supabase.logging.e
* @return [NativeSignInState]
*/
@Composable
actual fun ComposeAuth.rememberSignInWithGoogle(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit): NativeSignInState {
return signInWithCM(onResult, fallback)
actual fun ComposeAuth.rememberSignInWithGoogle(
onResult: (NativeSignInResult) -> Unit,
type: GoogleDialogType,
fallback: suspend () -> Unit)
: NativeSignInState {
return signInWithCM(onResult, type, fallback)
}

@Composable
internal fun ComposeAuth.signInWithCM(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit): NativeSignInState{
internal fun ComposeAuth.signInWithCM(
onResult: (NativeSignInResult) -> Unit,
type: GoogleDialogType,
fallback: suspend () -> Unit
): NativeSignInState{
val state = remember { NativeSignInState(serializer) }
val context = LocalContext.current

Expand All @@ -50,7 +69,11 @@ internal fun ComposeAuth.signInWithCM(onResult: (NativeSignInResult) -> Unit, fa
if (activity != null && config.googleLoginConfig != null) {
val hashedNonce = status.nonce?.hash()
ComposeAuth.logger.d { "Starting Google Sign In Flow${if(hashedNonce != null) " with hashed nonce: $hashedNonce" else ""}" }
val response = makeRequest(context, activity, config, hashedNonce)
val response = makeRequest(
context,
activity,
GoogleRequestOptions(config = config.googleLoginConfig, nonce = hashedNonce, type = type)
)
if(response == null) {
onResult.invoke(NativeSignInResult.ClosedByUser)
ComposeAuth.logger.d { "Google Sign In Flow was closed by user" }
Expand Down Expand Up @@ -136,27 +159,34 @@ internal actual suspend fun handleGoogleSignOut() {
}

private suspend fun tryRequest(
context: android.content.Context,
activity: android.app.Activity,
config: ComposeAuth.Config,
nonce: String?
context: Context,
activity: Activity,
options: GoogleRequestOptions
): GetCredentialResponse {
val option = when(options.type) {
GoogleDialogType.BOTTOM_SHEET -> getGoogleBottomSheetOptions(options.config, options.filterByAuthorizedAccounts, options.nonce)
GoogleDialogType.DIALOG -> getGoogleButtonOptions(options.config, options.nonce)
}
val request = GetCredentialRequest.Builder()
.addCredentialOption(getSignInWithGoogleOptions(config.googleLoginConfig, nonce))
.addCredentialOption(option)
.build()
return CredentialManager.create(context).getCredential(activity, request)
}

private suspend fun makeRequest(
context: android.content.Context,
activity: android.app.Activity,
config: ComposeAuth.Config,
nonce: String?
context: Context,
activity: Activity,
options: GoogleRequestOptions
): GetCredentialResponse? {
return try {
ComposeAuth.logger.d { "Trying to get Google ID Token Credential" }
tryRequest(context, activity, config, nonce)
tryRequest(context, activity, options)
} catch(e: GetCredentialCancellationException) {
return null
} catch(e: GetCredentialException) {
if(options.type == GoogleDialogType.BOTTOM_SHEET) {
ComposeAuth.logger.d { "Error while trying to get Google ID Token Credential. Retrying without only authorized accounts" }
tryRequest(context, activity, options)
} else null
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import io.github.jan.supabase.compose.auth.defaultLoginBehavior
* @return [NativeSignInState]
*/
@Composable
actual fun ComposeAuth.rememberSignInWithGoogle(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit): NativeSignInState = defaultLoginBehavior(fallback)
actual fun ComposeAuth.rememberSignInWithGoogle(
onResult: (NativeSignInResult) -> Unit,
type: GoogleDialogType,
fallback: suspend () -> Unit
): NativeSignInState = defaultLoginBehavior(fallback)

internal actual suspend fun handleGoogleSignOut() = Unit
Original file line number Diff line number Diff line change
@@ -1,10 +1,25 @@
@file:Suppress("MatchingDeclarationName")
package io.github.jan.supabase.compose.auth.composable

import androidx.compose.runtime.Composable
import io.github.jan.supabase.auth.providers.Google
import io.github.jan.supabase.compose.auth.ComposeAuth
import io.github.jan.supabase.compose.auth.fallbackLogin

/**
* Enum class for the type of Google Dialog
*/
enum class GoogleDialogType {
Fixed Show fixed Hide fixed
/**
* A bottom sheet dialog
*/
BOTTOM_SHEET,
/**
* A standard dialog
*/
DIALOG
}

/**
* Composable function that implements Native Google Auth.
*
Expand All @@ -17,6 +32,7 @@ import io.github.jan.supabase.compose.auth.fallbackLogin
@Composable
expect fun ComposeAuth.rememberSignInWithGoogle(
onResult: (NativeSignInResult) -> Unit = {},
type: GoogleDialogType = GoogleDialogType.DIALOG,
fallback: suspend () -> Unit = {
fallbackLogin(Google)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,10 @@ import io.github.jan.supabase.compose.auth.defaultLoginBehavior
* @return [NativeSignInState]
*/
@Composable
actual fun ComposeAuth.rememberSignInWithGoogle(onResult: (NativeSignInResult) -> Unit, fallback: suspend () -> Unit): NativeSignInState = defaultLoginBehavior(fallback)
actual fun ComposeAuth.rememberSignInWithGoogle(
onResult: (NativeSignInResult) -> Unit,
type: GoogleDialogType,
fallback: suspend () -> Unit
): NativeSignInState = defaultLoginBehavior(fallback)

internal actual suspend fun handleGoogleSignOut() = Unit
Loading