Skip to content

Commit

Permalink
Finishing Delete account functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
mirzemehdi committed Jan 27, 2024
1 parent 1b559e1 commit 9d66035
Show file tree
Hide file tree
Showing 7 changed files with 181 additions and 98 deletions.
19 changes: 17 additions & 2 deletions shared/src/commonMain/kotlin/data/repository/UserRepository.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package data.repository

import dev.gitlive.firebase.Firebase
import dev.gitlive.firebase.auth.auth
import domain.model.AuthProvider
import domain.model.User
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.IO
Expand All @@ -27,12 +28,26 @@ class UserRepository(private val backgroundScope: CoroutineContext = Dispatchers
}

suspend fun deleteAccount() = withContext(backgroundScope) {
val currentUser=Firebase.auth.currentUser
currentUser?.providerData?.forEach {
val currentUser = Firebase.auth.currentUser
currentUser?.providerData?.forEach {
AppLogger.e("ProviderId: ${it.providerId}")

}
currentUser?.delete()
}

fun getCurrentUserProviders(): List<AuthProvider> {
val currentUser = Firebase.auth.currentUser
return currentUser?.providerData?.mapNotNull {
val providerId = it.providerId
AppLogger.d("ProviderId: $providerId")
when (providerId) {
"google.com" -> AuthProvider.GOOGLE
"apple.com" -> AuthProvider.APPLE
"github.com" -> AuthProvider.GITHUB
else -> null
}
} ?: emptyList()
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,10 @@ import androidx.compose.material3.Button
import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color
Expand Down Expand Up @@ -43,6 +47,7 @@ fun AuthUiHelperButtonsAndFirebaseAuth(
authProviders: List<AuthProvider> = AuthProvider.values().asList(),
onFirebaseResult: (Result<FirebaseUser?>) -> Unit,
) {
val isExistOnlyOneAuthProvider by remember { mutableStateOf(authProviders.size == 1) }
Column(
modifier = modifier,
verticalArrangement = Arrangement.spacedBy(14.dp)
Expand All @@ -54,6 +59,7 @@ fun AuthUiHelperButtonsAndFirebaseAuth(
if (authProviders.contains(AuthProvider.GOOGLE)) {
//Google Sign-In Button and authentication with Firebase
GoogleButtonUiContainerFirebase(onResult = onFirebaseResult) {
LaunchedEffect(Unit) { if (isExistOnlyOneAuthProvider) this@GoogleButtonUiContainerFirebase.onClick() }
GoogleSignInButton(
modifier = Modifier.fillMaxWidth().height(height),
text = Strings.btn_sign_in_with_google,
Expand All @@ -67,6 +73,7 @@ fun AuthUiHelperButtonsAndFirebaseAuth(
if (authProviders.contains(AuthProvider.APPLE)) {
//Apple Sign-In Button and authentication with Firebase
AppleButtonUiContainer(onResult = onFirebaseResult) {
LaunchedEffect(Unit) { if (isExistOnlyOneAuthProvider) this@AppleButtonUiContainer.onClick() }
AppleSignInButton(
modifier = Modifier.fillMaxWidth().height(height),
text = Strings.btn_sign_in_with_apple,
Expand All @@ -78,6 +85,7 @@ fun AuthUiHelperButtonsAndFirebaseAuth(
if (authProviders.contains(AuthProvider.GITHUB)) {
//Github Sign-In Button and authentication with Firebase
GithubButtonUiContainer(onResult = onFirebaseResult) {
LaunchedEffect(Unit) { if (isExistOnlyOneAuthProvider) this@GithubButtonUiContainer.onClick() }
GithubSignInButton(
modifier = Modifier.fillMaxWidth().height(height),
text = Strings.btn_sign_in_with_github,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,13 +21,18 @@ import androidx.compose.material3.ButtonDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.ModalBottomSheet
import androidx.compose.material3.Scaffold
import androidx.compose.material3.SnackbarHost
import androidx.compose.material3.SnackbarHostState
import androidx.compose.material3.Text
import androidx.compose.material3.TextButton
import androidx.compose.material3.rememberModalBottomSheetState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
Expand All @@ -39,6 +44,7 @@ import androidx.compose.ui.unit.sp
import coil3.compose.AsyncImage
import coil3.compose.AsyncImagePainter
import dev.gitlive.firebase.auth.FirebaseUser
import domain.model.AuthProvider
import domain.model.User
import org.jetbrains.compose.resources.ExperimentalResourceApi
import org.jetbrains.compose.resources.painterResource
Expand All @@ -59,29 +65,48 @@ fun ProfileScreen(modifier: Modifier = Modifier, uiStateHolder: ProfileUiStateHo
val uiState by uiStateHolder.profileScreenUiState.asState()
if (uiState.reAuthenticateUserViewShown) {
SocialLoginsBottomSheet(
isLoading = uiState.isDeleteInProgress,
authProviders = uiState.currentUserAuthProviderList,
onDismiss = uiStateHolder::onDismissReAuthenticateView,
onResult = uiStateHolder::onUserReAuthenticatedResult
)
}

if (uiState.isLoading) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
MyAppCircularProgressIndicator()
}
}
if (uiState.deleteUserDialogShown) {
DeleteUserConfirmationDialog(
onConfirm = uiStateHolder::onConfirmDeleteAccount,
onDismiss = uiStateHolder::onDismissDeleteUserConfirmationDialog
)
}
uiState.currentUser?.let { currentUser ->
ProfileScreen(
modifier = modifier.fillMaxSize(),
currentUser = currentUser,
onClickLogOut = uiStateHolder::onClickLogOut,
onClickDeleteAccount = uiStateHolder::onClickDeleteAccount
)

val snackbarHostState = remember { SnackbarHostState() }
Scaffold(modifier = modifier.fillMaxSize(),
snackbarHost = {
SnackbarHost(hostState = snackbarHostState)
}
) {
LaunchedEffect(uiState.message){
uiState.message?.let { message->
snackbarHostState.showSnackbar(message)
uiStateHolder.onMessageIsShown()
}
}
uiState.currentUser?.let { currentUser ->
ProfileScreen(
modifier = Modifier.fillMaxSize(),
currentUser = currentUser,
onClickLogOut = uiStateHolder::onClickLogOut,
onClickDeleteAccount = uiStateHolder::onClickDeleteAccount
)
}

}


if (uiState.isLoading) {
Box(modifier = Modifier.fillMaxSize(), contentAlignment = Alignment.Center) {
MyAppCircularProgressIndicator()
}
}
}

Expand Down Expand Up @@ -150,20 +175,22 @@ private fun ProfileScreen(
)
)

Text(
modifier = Modifier
.clip(ButtonDefaults.textShape)
.clickable(
interactionSource = remember { MutableInteractionSource() },
indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
onClick = {}
)
.padding(horizontal = 16.dp, vertical = 4.dp),
text = Strings.edit_profile,
style = MaterialTheme.typography.bodySmall.copy(
color = MaterialTheme.colorScheme.secondary
)
)
//TODO Implement Edit Profile

// Text(
// modifier = Modifier
// .clip(ButtonDefaults.textShape)
// .clickable(
// interactionSource = remember { MutableInteractionSource() },
// indication = rememberRipple(color = MaterialTheme.colorScheme.primary),
// onClick = {}
// )
// .padding(horizontal = 16.dp, vertical = 4.dp),
// text = Strings.edit_profile,
// style = MaterialTheme.typography.bodySmall.copy(
// color = MaterialTheme.colorScheme.secondary
// )
// )

BasicInfo(
modifier = Modifier.fillMaxWidth().padding(top = 24.dp),
Expand Down Expand Up @@ -221,7 +248,12 @@ private fun BasicInfo(modifier: Modifier = Modifier, currentUser: User) {

@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun SocialLoginsBottomSheet(onDismiss: () -> Unit, onResult: (Result<FirebaseUser?>) -> Unit) {
fun SocialLoginsBottomSheet(
isLoading: Boolean = false,
authProviders: List<AuthProvider>,
onDismiss: () -> Unit,
onResult: (Result<FirebaseUser?>) -> Unit,
) {
ModalBottomSheet(

windowInsets = WindowInsets(0),
Expand All @@ -230,7 +262,11 @@ fun SocialLoginsBottomSheet(onDismiss: () -> Unit, onResult: (Result<FirebaseUse
onDismissRequest = { onDismiss() }
) {
Box(modifier = Modifier.padding(40.dp)) {
AuthUiHelperButtonsAndFirebaseAuth(onFirebaseResult = onResult)
AuthUiHelperButtonsAndFirebaseAuth(
onFirebaseResult = onResult,
authProviders = authProviders
)
if (isLoading) MyAppCircularProgressIndicator(modifier = Modifier.align(Alignment.Center))
}
}

Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,14 @@
package presentation.screens.account.profile

import domain.model.AuthProvider
import domain.model.User

data class ProfileScreenUiState(
val currentUser: User? = null,
val isLoading: Boolean = true,
val isDeleteInProgress: Boolean = false,
val deleteUserDialogShown: Boolean = false,
val reAuthenticateUserViewShown: Boolean = false,
val currentUserAuthProviderList: List<AuthProvider> = emptyList(),
val message: String? = null,
)
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,6 @@ import kotlinx.coroutines.flow.update
import kotlinx.coroutines.launch
import presentation.theme.strings.Strings
import util.UiStateHolder
import util.logging.AppLogger
import util.uiStateHolderScope

class ProfileUiStateHolder(private val userRepository: UserRepository) : UiStateHolder() {
Expand Down Expand Up @@ -41,22 +40,47 @@ class ProfileUiStateHolder(private val userRepository: UserRepository) : UiState
}

fun onConfirmDeleteAccount() = uiStateHolderScope.launch {
_profileScreenUiState.update { it.copy(reAuthenticateUserViewShown = true, deleteUserDialogShown = false) }
_profileScreenUiState.update {
it.copy(
reAuthenticateUserViewShown = true,
deleteUserDialogShown = false,
currentUserAuthProviderList = userRepository.getCurrentUserProviders()
)
}
}

fun onDismissReAuthenticateView() = uiStateHolderScope.launch {
_profileScreenUiState.update { it.copy(reAuthenticateUserViewShown = false) }
}

fun onMessageIsShown() = uiStateHolderScope.launch {
_profileScreenUiState.update { it.copy(message = null) }
}

fun onUserReAuthenticatedResult(result: Result<FirebaseUser?>) = uiStateHolderScope.launch {
_profileScreenUiState.update { it.copy(reAuthenticateUserViewShown = false) }
result.onSuccess {user->
if (user!=null) userRepository.deleteAccount()
else{
AppLogger.e("User is null")
_profileScreenUiState.update { it.copy(isDeleteInProgress = true) }
result.onSuccess { user ->
val userMessage = if (user != null) {
userRepository.deleteAccount()
Strings.msg_success_delete_user
} else
Strings.error_msg_no_signed_in_user
_profileScreenUiState.update {
it.copy(
isDeleteInProgress = false,
reAuthenticateUserViewShown = false,
message = userMessage
)
}

}.onFailure { error ->
_profileScreenUiState.update {
it.copy(
isDeleteInProgress = false,
reAuthenticateUserViewShown = false,
message = error.message
)
}
}.onFailure {
AppLogger.e(it.message)
}

}
Expand Down
Loading

0 comments on commit 9d66035

Please sign in to comment.