From ae690e09ca8e6d224e2ea213b2f852d09163a8f0 Mon Sep 17 00:00:00 2001 From: Edric Date: Tue, 16 Apr 2024 16:52:57 +0800 Subject: [PATCH] Add CompositionLocals for Firebase auth user data See #368 and #585 * Scaffold `:core:auth:compose` module * Include module in settings script * Add composable to provide CompositionLocals --- core/auth/compose/.gitignore | 1 + core/auth/compose/build.gradle.kts | 43 +++++++++++++++++++ core/auth/compose/consumer-rules.pro | 0 core/auth/compose/proguard-rules.pro | 21 +++++++++ .../auth/compose/src/main/AndroidManifest.xml | 2 + .../studybuddy/core/auth/UserLocals.kt | 42 ++++++++++++++++++ settings.gradle.kts | 1 + 7 files changed, 110 insertions(+) create mode 100644 core/auth/compose/.gitignore create mode 100644 core/auth/compose/build.gradle.kts create mode 100644 core/auth/compose/consumer-rules.pro create mode 100644 core/auth/compose/proguard-rules.pro create mode 100644 core/auth/compose/src/main/AndroidManifest.xml create mode 100644 core/auth/compose/src/main/kotlin/com/edricchan/studybuddy/core/auth/UserLocals.kt diff --git a/core/auth/compose/.gitignore b/core/auth/compose/.gitignore new file mode 100644 index 000000000..42afabfd2 --- /dev/null +++ b/core/auth/compose/.gitignore @@ -0,0 +1 @@ +/build \ No newline at end of file diff --git a/core/auth/compose/build.gradle.kts b/core/auth/compose/build.gradle.kts new file mode 100644 index 000000000..9bc930af3 --- /dev/null +++ b/core/auth/compose/build.gradle.kts @@ -0,0 +1,43 @@ +plugins { + com.edricchan.studybuddy.library.`android-compose` +} + +android { + namespace = "com.edricchan.studybuddy.core.auth" + + defaultConfig { + consumerProguardFiles("consumer-rules.pro") + } + + buildTypes { + release { + isMinifyEnabled = false + proguardFiles( + getDefaultProguardFile("proguard-android-optimize.txt"), + "proguard-rules.pro" + ) + } + } +} + +dependencies { + implementation(projects.ui.theming.compose) + + // Firebase dependencies + api(platform(libs.firebase.bom)) + api(libs.firebase.auth.ktx) + implementation(libs.playServices.auth) + + // Compose dependencies + implementation(libs.bundles.androidx.compose) + implementation(libs.androidx.lifecycle.runtime.compose) + + debugImplementation(libs.bundles.androidx.compose.tooling) + + testImplementation(libs.junit) + androidTestImplementation(libs.androidx.test.ext) + androidTestImplementation(libs.androidx.test.espresso.core) + + // Compose rule support + androidTestImplementation(libs.androidx.compose.ui.test.junit4) +} diff --git a/core/auth/compose/consumer-rules.pro b/core/auth/compose/consumer-rules.pro new file mode 100644 index 000000000..e69de29bb diff --git a/core/auth/compose/proguard-rules.pro b/core/auth/compose/proguard-rules.pro new file mode 100644 index 000000000..481bb4348 --- /dev/null +++ b/core/auth/compose/proguard-rules.pro @@ -0,0 +1,21 @@ +# Add project specific ProGuard rules here. +# You can control the set of applied configuration files using the +# proguardFiles setting in build.gradle. +# +# For more details, see +# http://developer.android.com/guide/developing/tools/proguard.html + +# If your project uses WebView with JS, uncomment the following +# and specify the fully qualified class name to the JavaScript interface +# class: +#-keepclassmembers class fqcn.of.javascript.interface.for.webview { +# public *; +#} + +# Uncomment this to preserve the line number information for +# debugging stack traces. +#-keepattributes SourceFile,LineNumberTable + +# If you keep the line number information, uncomment this to +# hide the original source file name. +#-renamesourcefileattribute SourceFile \ No newline at end of file diff --git a/core/auth/compose/src/main/AndroidManifest.xml b/core/auth/compose/src/main/AndroidManifest.xml new file mode 100644 index 000000000..8072ee00d --- /dev/null +++ b/core/auth/compose/src/main/AndroidManifest.xml @@ -0,0 +1,2 @@ + + diff --git a/core/auth/compose/src/main/kotlin/com/edricchan/studybuddy/core/auth/UserLocals.kt b/core/auth/compose/src/main/kotlin/com/edricchan/studybuddy/core/auth/UserLocals.kt new file mode 100644 index 000000000..b3a10a533 --- /dev/null +++ b/core/auth/compose/src/main/kotlin/com/edricchan/studybuddy/core/auth/UserLocals.kt @@ -0,0 +1,42 @@ +package com.edricchan.studybuddy.core.auth + +import androidx.compose.runtime.Composable +import androidx.compose.runtime.CompositionLocal +import androidx.compose.runtime.CompositionLocalProvider +import androidx.compose.runtime.ProvidableCompositionLocal +import androidx.compose.runtime.compositionLocalOf +import androidx.compose.runtime.getValue +import androidx.lifecycle.compose.collectAsStateWithLifecycle +import com.google.firebase.Firebase +import com.google.firebase.auth.FirebaseUser +import com.google.firebase.auth.auth +import kotlinx.coroutines.flow.Flow + +/** [CompositionLocal] of the currently signed-in [FirebaseUser], or `null`. */ +val LocalCurrentUser: ProvidableCompositionLocal = + compositionLocalOf { Firebase.auth.currentUser } + +/** [CompositionLocal] of whether there's a currently signed-in [FirebaseUser]. */ +val LocalIsSignedIn: ProvidableCompositionLocal = + compositionLocalOf { Firebase.auth.currentUser != null } + +/** + * Provides the [LocalCurrentUser] and [LocalIsSignedIn] composition locals with the + * given [userFlow]. + * + * The [userFlow] will be collected as a state and used for [LocalCurrentUser]. + */ +@Composable +fun ProvideCurrentUser( + initialUser: FirebaseUser? = Firebase.auth.currentUser, + userFlow: Flow, + content: @Composable () -> Unit +) { + val user by userFlow.collectAsStateWithLifecycle(initialValue = initialUser) + + CompositionLocalProvider( + LocalCurrentUser provides user, + LocalIsSignedIn provides (user != null), + content = content + ) +} diff --git a/settings.gradle.kts b/settings.gradle.kts index e69ea3f66..48db1385f 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -115,6 +115,7 @@ include( ":ui:widgets:compose:navigation", ":ui:widgets:compose:option-bottom-sheet", ":ui:widgets:modal-bottom-sheet", + ":core:auth:compose", ":core:auth:gms", ":core:deeplink", ":core:di",