Skip to content
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 @@ -74,6 +74,10 @@ interface TreeTrackerDAO {
@Query("SELECT * FROM user WHERE power_user = 1")
suspend fun getPowerUser(): UserEntity?

@Query("DELETE FROM user WHERE wallet = :wallet")
suspend fun deleteUserByWallet(wallet: String): Int


@Query("UPDATE user SET power_user = :isPowerUser WHERE _id = :userId")
suspend fun updatePowerUserStatus(userId: Long, isPowerUser: Boolean)

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ val appModule = module {

viewModel { OrgPickerViewModel(get()) }

viewModel { UserSelectViewModel(null, get(), get(), get()) }
viewModel { UserSelectViewModel(null, get(), get(), get(), get()) }

viewModel { DevOptionsViewModel(get(), get()) }

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ import org.greenstand.android.TreeTracker.messages.individualmeassagelist.Indivi
import org.greenstand.android.TreeTracker.messages.survey.SurveyScreen
import org.greenstand.android.TreeTracker.orgpicker.AddOrgScreen
import org.greenstand.android.TreeTracker.orgpicker.OrgPickerScreen
import org.greenstand.android.TreeTracker.profile.DeleteProfileScreen
import org.greenstand.android.TreeTracker.profile.ProfileScreen
import org.greenstand.android.TreeTracker.profile.ProfileSelectScreen
import org.greenstand.android.TreeTracker.sessionnote.SessionNoteScreen
Expand Down Expand Up @@ -81,6 +82,13 @@ sealed class NavRoute : KoinComponent {
override val route: String = "signup-flow"
}

object DeleteProfile : NavRoute() {
override val content: @Composable (NavBackStackEntry) -> Unit = {
DeleteProfileScreen()
}
override val route: String = "delete-profile"
}

object Org : NavRoute() {
override val content: @Composable (NavBackStackEntry) -> Unit = {
OrgPickerScreen()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,11 @@ class UserRepo(
suspend fun getUserWithWallet(wallet: String): User? {
return createUser(dao.getUserByWallet(wallet))
}
suspend fun deleteUser(wallet: String): Boolean {
val deletedRows = dao.deleteUserByWallet(wallet)
return deletedRows > 0
}


suspend fun checkForUnreadMessagesPerUser(wallet: String): Boolean {
return messagesDao.getUnreadMessageCountForWallet(wallet) >= 1
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,108 @@
package org.greenstand.android.TreeTracker.profile

import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.res.stringResource
import androidx.lifecycle.viewmodel.compose.viewModel
import org.greenstand.android.TreeTracker.R
import org.greenstand.android.TreeTracker.models.NavRoute
import org.greenstand.android.TreeTracker.root.LocalNavHostController
import org.greenstand.android.TreeTracker.root.LocalViewModelFactory
import org.greenstand.android.TreeTracker.userselect.DeleteProfileState
import org.greenstand.android.TreeTracker.userselect.UserSelect
import org.greenstand.android.TreeTracker.userselect.UserSelectState
import org.greenstand.android.TreeTracker.userselect.UserSelectViewModel
import org.greenstand.android.TreeTracker.view.AppButtonColors
import org.greenstand.android.TreeTracker.view.AppColors.Red
import org.greenstand.android.TreeTracker.view.UserButton
import org.greenstand.android.TreeTracker.view.dialogs.CustomDialog

@Composable
fun DeleteProfileScreen() {
val navController = LocalNavHostController.current
val viewModel: UserSelectViewModel = viewModel(factory = LocalViewModelFactory.current)
val state by viewModel.state.collectAsState(UserSelectState())
Box(
modifier = Modifier
.fillMaxSize()
) {
UserSelect(
navigationButtonColors = AppButtonColors.ProgressGreen,
isCreateUserEnabled = true,
isNotificationEnabled = true,
onNavigateForward = { user ->
viewModel.selectUser(user)
viewModel.updateDeleteProfileState(DeleteProfileState.SHOWDIALOG)
}
)

if (state.deleteProfileState == DeleteProfileState.SHOWDIALOG) {
CustomDialog(
title = stringResource(R.string.delete_account_title),
textContent = stringResource(R.string.delete_account_dialog_message),
onPositiveClick = {
viewModel.deleteUser()
},
onNegativeClick = {
viewModel.updateDeleteProfileState(DeleteProfileState.DISMISSDIALOG)
},
content = {
state.selectedUser?.let { user ->
UserButton(
user = user,
isSelected = false,
buttonColors = AppButtonColors.Default,
selectedColor = Red,
onClick = {
}
)
}

}

)
}
if ((state.deleteProfileState == DeleteProfileState.ACCOUNTDELETEDLOCALLY ) || (state.deleteProfileState == DeleteProfileState.ACCOUNTDELETEDANDADMINREQUESTED )) {
CustomDialog(
title = stringResource(R.string.account_deleted),
textContent = stringResource(R.string.account_deleted_message),
onPositiveClick = {
viewModel.deleteUser()
if(state.selectedUser?.isPowerUser == true){
navController.navigate(NavRoute.SignupFlow.route) {
popUpTo(navController.graph.id) {
inclusive = true
}
launchSingleTop = true
}

} else {
navController.navigate(NavRoute.Settings.route) {
popUpTo(NavRoute.Settings.route) { inclusive = true }
launchSingleTop = true
}
}
},
content = {
state.selectedUser?.let { user ->
UserButton(
user = user,
isSelected = false,
buttonColors = AppButtonColors.Default,
selectedColor = Red,
onClick = {
}
)
}

}

)
}

}
}
Original file line number Diff line number Diff line change
Expand Up @@ -84,7 +84,7 @@ fun ProfileScreen(
ActionBar(
centerAction = {
Text(
text = stringResource(id = R.string.settings),
text = stringResource(id = R.string.profile_title),
color = AppColors.Green,
fontWeight = FontWeight.Bold,
style = CustomTheme.typography.large,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ fun Host() {
NavRoute.Settings,
NavRoute.Profile,
NavRoute.ProfileSelect,
NavRoute.DeleteProfile,
NavRoute.DevOptions,
).forEach { addNavRoute(it) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -129,7 +129,9 @@ fun SettingsScreen() {
iconResId = R.drawable.delete, // Replace with your delete icon
titleResId = R.string.delete_account_title,
descriptionResId = R.string.delete_account_description,
onClick = { /* Handle delete account click */ }
onClick = {
navController.navigate(NavRoute.DeleteProfile.route)
}
)
}
if (state.showPrivacyPolicyDialog == true) {
Expand All @@ -141,7 +143,12 @@ fun SettingsScreen() {
textContent = stringResource(R.string.logout_dialog_message),
onPositiveClick = {
viewModel.logout()
navController.navigate(NavRoute.SignupFlow.route)
navController.navigate(NavRoute.SignupFlow.route) {
popUpTo(navController.graph.id) {
inclusive = true
}
launchSingleTop = true
}
},
onNegativeClick = {
viewModel.updateLogoutDialogVisibility(false)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import org.greenstand.android.TreeTracker.models.UserRepo
import org.greenstand.android.TreeTracker.models.location.LocationDataCapturer
import org.greenstand.android.TreeTracker.models.messages.MessagesRepo
import org.greenstand.android.TreeTracker.models.setupflow.CaptureSetupScopeManager
import org.greenstand.android.TreeTracker.models.user.User
import org.greenstand.android.TreeTracker.preferences.Preferences
Expand All @@ -38,11 +39,20 @@ data class UserSelectState(
val users: List<User> = emptyList(),
val selectedUser: User? = null,
val editMode: Boolean = false,
val deleteProfileState: DeleteProfileState = DeleteProfileState.INITIAL
)
enum class DeleteProfileState(){
INITIAL,
SHOWDIALOG,
DISMISSDIALOG,
ACCOUNTDELETEDLOCALLY,
ACCOUNTDELETEDANDADMINREQUESTED
}

class UserSelectViewModel(
userId: Long?,
private val userRepo: UserRepo,
private val messageRepo: MessagesRepo,
locationDataCapturer: LocationDataCapturer,
private val prefs: Preferences,
) : ViewModel() {
Expand Down Expand Up @@ -76,7 +86,19 @@ class UserSelectViewModel(
selectedUser = user
)
}

fun deleteUser(){
viewModelScope.launch {
if(userRepo.deleteUser(_state.value.selectedUser?.wallet ?: "") ){
_state.value = _state.value.copy(deleteProfileState = DeleteProfileState.ACCOUNTDELETEDLOCALLY)
messageRepo.saveMessage(
wallet = _state.value.selectedUser?.wallet ?: "",
to = "admin",
body = "Hi admin, I would like to delete my account with the wallet ${_state.value.selectedUser?.wallet} I understand that all my data will be lost."
)
messageRepo.syncMessages()
}
}
}
// 🔁 Toggle edit mode
fun updateEditEnabled() {
_state.value = _state.value.copy(editMode = !_state.value.editMode)
Expand Down Expand Up @@ -109,12 +131,16 @@ class UserSelectViewModel(
userRepo.updateUser(user)
}
}

fun updateDeleteProfileState(deleteProfileState: DeleteProfileState) {
_state.value= _state.value.copy(deleteProfileState = deleteProfileState)
}
}

class UserSelectViewModelFactory(private val userId: Long) :
ViewModelProvider.Factory, KoinComponent {
@Suppress("UNCHECKED_CAST")
override fun <T : ViewModel> create(modelClass: Class<T>): T {
return UserSelectViewModel(userId, get(), get(),get(),) as T
return UserSelectViewModel(userId, get(), get(),get(), get()) as T
}
}
6 changes: 4 additions & 2 deletions app/src/main/res/values/strings.xml
Original file line number Diff line number Diff line change
Expand Up @@ -180,10 +180,12 @@ Privacy Policy
<string name="logout_title">Log out</string>
<string name="logout_description">Log out from your account.</string>
<string name="delete_account_title">Delete Account</string>
<string name="account_deleted">Account Deleted</string>
<string name="account_deleted_message">All your Data has been deleted</string>
<string name="delete_account_description">Initiate the process to delete your account completely.</string>
<string name="logout_dialog_title">Are you sure you want to logout?</string>
<string name="delete_dialog_description">If you logout you will have to re-enter email or phone number again to access all trees captured and your account</string>
<string name="delete_account_dialog_message">Are you sure you want your account deleted? \n This is irreversible and you would loose all your data.</string>
<string name="delete_account_dialog_title">Are you sure you want to delete this account?</string>
<string name="delete_account_dialog_message">Are you sure you want your account deleted? \n This is irreversible and you would loose all your data. \n You need to be connected to the internet for this to be completed.</string>
<string name="logout_dialog_message"> Are you sure you want to log out from your account?</string>

<string name="no_gps_device_header">No GPS found on device</string>
Expand Down