#44 first try at firebase use-cases

This commit is contained in:
reyniersbram 2023-04-05 21:46:51 +02:00
parent 27c45842f2
commit 46824f4498
16 changed files with 294 additions and 7 deletions

View file

@ -8,6 +8,9 @@ plugins {
// Protobuf
id 'com.google.protobuf' version '0.8.17'
// Firebase
id 'com.google.gms.google-services'
}
android {
@ -108,13 +111,13 @@ dependencies {
debugImplementation "androidx.compose.ui:ui-tooling:$compose_version"
//Firebase
// implementation platform('com.google.firebase:firebase-bom:30.4.1')
// implementation 'com.google.firebase:firebase-crashlytics-ktx'
// implementation 'com.google.firebase:firebase-analytics-ktx'
// implementation 'com.google.firebase:firebase-auth-ktx'
// implementation 'com.google.firebase:firebase-firestore-ktx'
// implementation 'com.google.firebase:firebase-perf-ktx'
// implementation 'com.google.firebase:firebase-config-ktx'
implementation platform('com.google.firebase:firebase-bom:31.3.0')
implementation 'com.google.firebase:firebase-crashlytics-ktx'
implementation 'com.google.firebase:firebase-analytics-ktx'
implementation 'com.google.firebase:firebase-auth-ktx'
implementation 'com.google.firebase:firebase-firestore-ktx'
implementation 'com.google.firebase:firebase-perf-ktx'
implementation 'com.google.firebase:firebase-config-ktx'
}

39
app/google-services.json Normal file
View file

@ -0,0 +1,39 @@
{
"project_info": {
"project_number": "692936961909",
"project_id": "studeez-1cff2",
"storage_bucket": "studeez-1cff2.appspot.com"
},
"client": [
{
"client_info": {
"mobilesdk_app_id": "1:692936961909:android:28a567b1634fc3bdf3ed3c",
"android_client_info": {
"package_name": "be.ugent.sel.studeez"
}
},
"oauth_client": [
{
"client_id": "692936961909-vdbv9g03mt55uqes4prtbipr6vg8b48j.apps.googleusercontent.com",
"client_type": 3
}
],
"api_key": [
{
"current_key": "AIzaSyCbbg5F_rTrnwUHLDgCWSx4KCECozkvgVE"
}
],
"services": {
"appinvite_service": {
"other_platform_oauth_client": [
{
"client_id": "692936961909-vdbv9g03mt55uqes4prtbipr6vg8b48j.apps.googleusercontent.com",
"client_type": 3
}
]
}
}
}
],
"configuration_version": "1"
}

View file

@ -0,0 +1,3 @@
package be.ugent.sel.studeez.data.local.models
data class User(val id: String = "", val isAnonymous: Boolean = true)

View file

@ -0,0 +1,27 @@
/*
Copyright 2022 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package be.ugent.sel.studeez.domain
import com.google.firebase.perf.ktx.trace
import com.google.firebase.perf.metrics.Trace
/**
* Trace a block with Firebase performance.
*
* Supports both suspend and regular methods.
*/
inline fun <T> trace(name: String, block: Trace.() -> T): T = Trace.create(name).trace(block)

View file

@ -0,0 +1,34 @@
/*
Copyright 2022 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package be.ugent.sel.studeez.domain.account
import be.ugent.sel.studeez.data.local.models.User
import kotlinx.coroutines.flow.Flow
interface AccountService {
val currentUserId: String
val hasUser: Boolean
val currentUser: Flow<User>
suspend fun authenticate(email: String, password: String)
suspend fun sendRecoveryEmail(email: String)
suspend fun createAnonymousAccount()
suspend fun linkAccount(email: String, password: String)
suspend fun deleteAccount()
suspend fun signOut()
}

View file

@ -0,0 +1,84 @@
/*
Copyright 2022 Google LLC
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
https://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package be.ugent.sel.studeez.domain.account
import be.ugent.sel.studeez.data.local.models.User
import be.ugent.sel.studeez.domain.trace
import com.google.firebase.auth.EmailAuthProvider
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.channels.awaitClose
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.callbackFlow
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class AccountServiceImpl @Inject constructor(
private val auth: FirebaseAuth
) : AccountService {
override val currentUserId: String
get() = auth.currentUser?.uid.orEmpty()
override val hasUser: Boolean
get() = auth.currentUser != null
override val currentUser: Flow<User>
get() = callbackFlow {
val listener =
FirebaseAuth.AuthStateListener { auth ->
this.trySend(auth.currentUser?.let { User(it.uid, it.isAnonymous) } ?: User())
}
auth.addAuthStateListener(listener)
awaitClose { auth.removeAuthStateListener(listener) }
}
override suspend fun authenticate(email: String, password: String) {
auth.signInWithEmailAndPassword(email, password).await()
}
override suspend fun sendRecoveryEmail(email: String) {
auth.sendPasswordResetEmail(email).await()
}
override suspend fun createAnonymousAccount() {
auth.signInAnonymously().await()
}
override suspend fun linkAccount(email: String, password: String): Unit =
trace(LINK_ACCOUNT_TRACE) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
override suspend fun deleteAccount() {
auth.currentUser!!.delete().await()
}
override suspend fun signOut() {
if (auth.currentUser!!.isAnonymous) {
auth.currentUser!!.delete()
}
auth.signOut()
// Sign the user back in anonymously.
createAnonymousAccount()
}
companion object {
private const val LINK_ACCOUNT_TRACE = "linkAccount"
}
}

View file

@ -0,0 +1,13 @@
package be.ugent.sel.studeez.domain.account
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class AuthenticateUseCase @Inject constructor(
private val auth: FirebaseAuth,
) {
suspend operator fun invoke(email: String, password: String) {
auth.signInWithEmailAndPassword(email, password).await()
}
}

View file

@ -0,0 +1,13 @@
package be.ugent.sel.studeez.domain.account
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class CreateAnonymousAccountUseCase @Inject constructor(
private val auth: FirebaseAuth,
) {
suspend operator fun invoke() {
auth.signInAnonymously().await()
}
}

View file

@ -0,0 +1,13 @@
package be.ugent.sel.studeez.domain.account
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class DeleteAccountUseCase @Inject constructor(
private val auth: FirebaseAuth,
) {
suspend operator fun invoke() {
auth.currentUser!!.delete().await()
}
}

View file

@ -0,0 +1,22 @@
package be.ugent.sel.studeez.domain.account
import be.ugent.sel.studeez.domain.trace
import com.google.firebase.auth.EmailAuthProvider
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class LinkAccountUseCase @Inject constructor(
private val auth: FirebaseAuth,
) {
suspend operator fun invoke(email: String, password: String): Unit =
trace(LINK_ACCOUNT_TRACE) {
val credential = EmailAuthProvider.getCredential(email, password)
auth.currentUser!!.linkWithCredential(credential).await()
}
companion object {
private const val LINK_ACCOUNT_TRACE = "linkAccount"
}
}

View file

@ -0,0 +1,13 @@
package be.ugent.sel.studeez.domain.account
import com.google.firebase.auth.FirebaseAuth
import kotlinx.coroutines.tasks.await
import javax.inject.Inject
class SendRecoveryEmailUseCase @Inject constructor(
private val auth: FirebaseAuth,
) {
suspend operator fun invoke(email: String) {
auth.sendPasswordResetEmail(email).await()
}
}

View file

@ -0,0 +1,18 @@
package be.ugent.sel.studeez.domain.account
import com.google.firebase.auth.FirebaseAuth
import javax.inject.Inject
class SignOutUseCase @Inject constructor(
private val auth: FirebaseAuth,
private val createAnonymousAccountUseCase: CreateAnonymousAccountUseCase,
) {
suspend operator fun invoke() {
if (auth.currentUser!!.isAnonymous) {
auth.currentUser!!.delete()
}
auth.signOut()
createAnonymousAccountUseCase()
}
}

View file

@ -6,6 +6,10 @@ buildscript {
espressoVersion = '3.4.0'
kotlinVersion = '1.6.10'
}
dependencies {
classpath 'com.google.gms:google-services:4.3.15'
}
}// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id 'com.android.application' version '7.4.2' apply false
@ -15,3 +19,4 @@ plugins {
// Hilt
id 'com.google.dagger.hilt.android' version '2.44' apply false
}