Skip to content

Commit 9b94b8f

Browse files
committed
feat: delete profile feature
1 parent 47141d5 commit 9b94b8f

File tree

10 files changed

+169
-8
lines changed

10 files changed

+169
-8
lines changed

app/src/main/java/org/greenstand/android/TreeTracker/database/TreeTrackerDAO.kt

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -74,6 +74,10 @@ interface TreeTrackerDAO {
7474
@Query("SELECT * FROM user WHERE power_user = 1")
7575
suspend fun getPowerUser(): UserEntity?
7676

77+
@Query("DELETE FROM user WHERE wallet = :wallet")
78+
suspend fun deleteUserByWallet(wallet: String): Int
79+
80+
7781
@Query("UPDATE user SET power_user = :isPowerUser WHERE _id = :userId")
7882
suspend fun updatePowerUserStatus(userId: Long, isPowerUser: Boolean)
7983

app/src/main/java/org/greenstand/android/TreeTracker/di/AppModule.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -106,7 +106,7 @@ val appModule = module {
106106

107107
viewModel { OrgPickerViewModel(get()) }
108108

109-
viewModel { UserSelectViewModel(null, get(), get(), get()) }
109+
viewModel { UserSelectViewModel(null, get(), get(), get(), get()) }
110110

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

app/src/main/java/org/greenstand/android/TreeTracker/models/NavRoute.kt

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,7 @@ import org.greenstand.android.TreeTracker.messages.individualmeassagelist.Indivi
3939
import org.greenstand.android.TreeTracker.messages.survey.SurveyScreen
4040
import org.greenstand.android.TreeTracker.orgpicker.AddOrgScreen
4141
import org.greenstand.android.TreeTracker.orgpicker.OrgPickerScreen
42+
import org.greenstand.android.TreeTracker.profile.DeleteProfileScreen
4243
import org.greenstand.android.TreeTracker.profile.ProfileScreen
4344
import org.greenstand.android.TreeTracker.profile.ProfileSelectScreen
4445
import org.greenstand.android.TreeTracker.sessionnote.SessionNoteScreen
@@ -81,6 +82,13 @@ sealed class NavRoute : KoinComponent {
8182
override val route: String = "signup-flow"
8283
}
8384

85+
object DeleteProfile : NavRoute() {
86+
override val content: @Composable (NavBackStackEntry) -> Unit = {
87+
DeleteProfileScreen()
88+
}
89+
override val route: String = "delete-profile"
90+
}
91+
8492
object Org : NavRoute() {
8593
override val content: @Composable (NavBackStackEntry) -> Unit = {
8694
OrgPickerScreen()

app/src/main/java/org/greenstand/android/TreeTracker/models/user/UserRepo.kt

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,11 @@ class UserRepo(
5454
suspend fun getUserWithWallet(wallet: String): User? {
5555
return createUser(dao.getUserByWallet(wallet))
5656
}
57+
suspend fun deleteUser(wallet: String): Boolean {
58+
val deletedRows = dao.deleteUserByWallet(wallet)
59+
return deletedRows > 0
60+
}
61+
5762

5863
suspend fun checkForUnreadMessagesPerUser(wallet: String): Boolean {
5964
return messagesDao.getUnreadMessageCountForWallet(wallet) >= 1
Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package org.greenstand.android.TreeTracker.profile
2+
3+
import androidx.compose.foundation.layout.Box
4+
import androidx.compose.foundation.layout.fillMaxSize
5+
import androidx.compose.runtime.Composable
6+
import androidx.compose.runtime.collectAsState
7+
import androidx.compose.runtime.getValue
8+
import androidx.compose.ui.Modifier
9+
import androidx.compose.ui.res.stringResource
10+
import androidx.lifecycle.viewmodel.compose.viewModel
11+
import org.greenstand.android.TreeTracker.R
12+
import org.greenstand.android.TreeTracker.models.NavRoute
13+
import org.greenstand.android.TreeTracker.root.LocalNavHostController
14+
import org.greenstand.android.TreeTracker.root.LocalViewModelFactory
15+
import org.greenstand.android.TreeTracker.userselect.DeleteProfileState
16+
import org.greenstand.android.TreeTracker.userselect.UserSelect
17+
import org.greenstand.android.TreeTracker.userselect.UserSelectState
18+
import org.greenstand.android.TreeTracker.userselect.UserSelectViewModel
19+
import org.greenstand.android.TreeTracker.view.AppButtonColors
20+
import org.greenstand.android.TreeTracker.view.AppColors.Red
21+
import org.greenstand.android.TreeTracker.view.UserButton
22+
import org.greenstand.android.TreeTracker.view.dialogs.CustomDialog
23+
24+
@Composable
25+
fun DeleteProfileScreen() {
26+
val navController = LocalNavHostController.current
27+
val viewModel: UserSelectViewModel = viewModel(factory = LocalViewModelFactory.current)
28+
val state by viewModel.state.collectAsState(UserSelectState())
29+
Box(
30+
modifier = Modifier
31+
.fillMaxSize()
32+
) {
33+
UserSelect(
34+
navigationButtonColors = AppButtonColors.ProgressGreen,
35+
isCreateUserEnabled = true,
36+
isNotificationEnabled = true,
37+
onNavigateForward = { user ->
38+
viewModel.selectUser(user)
39+
viewModel.updateDeleteProfileState(DeleteProfileState.SHOWDIALOG)
40+
}
41+
)
42+
43+
if (state.deleteProfileState == DeleteProfileState.SHOWDIALOG) {
44+
CustomDialog(
45+
title = stringResource(R.string.delete_account_title),
46+
textContent = stringResource(R.string.delete_account_dialog_message),
47+
onPositiveClick = {
48+
viewModel.deleteUser()
49+
},
50+
onNegativeClick = {
51+
viewModel.updateDeleteProfileState(DeleteProfileState.DISMISSDIALOG)
52+
},
53+
content = {
54+
state.selectedUser?.let { user ->
55+
UserButton(
56+
user = user,
57+
isSelected = false,
58+
buttonColors = AppButtonColors.Default,
59+
selectedColor = Red,
60+
onClick = {
61+
}
62+
)
63+
}
64+
65+
}
66+
67+
)
68+
}
69+
if ((state.deleteProfileState == DeleteProfileState.ACCOUNTDELETEDLOCALLY ) || (state.deleteProfileState == DeleteProfileState.ACCOUNTDELETEDANDADMINREQUESTED )) {
70+
CustomDialog(
71+
title = stringResource(R.string.account_deleted),
72+
textContent = stringResource(R.string.account_deleted_message),
73+
onPositiveClick = {
74+
viewModel.deleteUser()
75+
if(state.selectedUser?.isPowerUser == true){
76+
navController.navigate(NavRoute.SignupFlow.route) {
77+
popUpTo(navController.graph.id) {
78+
inclusive = true
79+
}
80+
launchSingleTop = true
81+
}
82+
83+
} else {
84+
navController.navigate(NavRoute.Settings.route) {
85+
popUpTo(NavRoute.Settings.route) { inclusive = true }
86+
launchSingleTop = true
87+
}
88+
}
89+
},
90+
content = {
91+
state.selectedUser?.let { user ->
92+
UserButton(
93+
user = user,
94+
isSelected = false,
95+
buttonColors = AppButtonColors.Default,
96+
selectedColor = Red,
97+
onClick = {
98+
}
99+
)
100+
}
101+
102+
}
103+
104+
)
105+
}
106+
107+
}
108+
}

app/src/main/java/org/greenstand/android/TreeTracker/profile/ProfileScreen.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ fun ProfileScreen(
8484
ActionBar(
8585
centerAction = {
8686
Text(
87-
text = stringResource(id = R.string.settings),
87+
text = stringResource(id = R.string.profile_title),
8888
color = AppColors.Green,
8989
fontWeight = FontWeight.Bold,
9090
style = CustomTheme.typography.large,

app/src/main/java/org/greenstand/android/TreeTracker/root/Host.kt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,7 @@ fun Host() {
5555
NavRoute.Settings,
5656
NavRoute.Profile,
5757
NavRoute.ProfileSelect,
58+
NavRoute.DeleteProfile,
5859
NavRoute.DevOptions,
5960
).forEach { addNavRoute(it) }
6061
}

app/src/main/java/org/greenstand/android/TreeTracker/settings/SettingsScreen.kt

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -129,7 +129,9 @@ fun SettingsScreen() {
129129
iconResId = R.drawable.delete, // Replace with your delete icon
130130
titleResId = R.string.delete_account_title,
131131
descriptionResId = R.string.delete_account_description,
132-
onClick = { /* Handle delete account click */ }
132+
onClick = {
133+
navController.navigate(NavRoute.DeleteProfile.route)
134+
}
133135
)
134136
}
135137
if (state.showPrivacyPolicyDialog == true) {
@@ -141,7 +143,12 @@ fun SettingsScreen() {
141143
textContent = stringResource(R.string.logout_dialog_message),
142144
onPositiveClick = {
143145
viewModel.logout()
144-
navController.navigate(NavRoute.SignupFlow.route)
146+
navController.navigate(NavRoute.SignupFlow.route) {
147+
popUpTo(navController.graph.id) {
148+
inclusive = true
149+
}
150+
launchSingleTop = true
151+
}
145152
},
146153
onNegativeClick = {
147154
viewModel.updateLogoutDialogVisibility(false)

app/src/main/java/org/greenstand/android/TreeTracker/userselect/UserSelectViewModel.kt

Lines changed: 28 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,7 @@ import kotlinx.coroutines.flow.onEach
2727
import kotlinx.coroutines.launch
2828
import org.greenstand.android.TreeTracker.models.UserRepo
2929
import org.greenstand.android.TreeTracker.models.location.LocationDataCapturer
30+
import org.greenstand.android.TreeTracker.models.messages.MessagesRepo
3031
import org.greenstand.android.TreeTracker.models.setupflow.CaptureSetupScopeManager
3132
import org.greenstand.android.TreeTracker.models.user.User
3233
import org.greenstand.android.TreeTracker.preferences.Preferences
@@ -38,11 +39,20 @@ data class UserSelectState(
3839
val users: List<User> = emptyList(),
3940
val selectedUser: User? = null,
4041
val editMode: Boolean = false,
42+
val deleteProfileState: DeleteProfileState = DeleteProfileState.INITIAL
4143
)
44+
enum class DeleteProfileState(){
45+
INITIAL,
46+
SHOWDIALOG,
47+
DISMISSDIALOG,
48+
ACCOUNTDELETEDLOCALLY,
49+
ACCOUNTDELETEDANDADMINREQUESTED
50+
}
4251

4352
class UserSelectViewModel(
4453
userId: Long?,
4554
private val userRepo: UserRepo,
55+
private val messageRepo: MessagesRepo,
4656
locationDataCapturer: LocationDataCapturer,
4757
private val prefs: Preferences,
4858
) : ViewModel() {
@@ -76,7 +86,19 @@ class UserSelectViewModel(
7686
selectedUser = user
7787
)
7888
}
79-
89+
fun deleteUser(){
90+
viewModelScope.launch {
91+
if(userRepo.deleteUser(_state.value.selectedUser?.wallet ?: "") ){
92+
_state.value = _state.value.copy(deleteProfileState = DeleteProfileState.ACCOUNTDELETEDLOCALLY)
93+
messageRepo.saveMessage(
94+
wallet = _state.value.selectedUser?.wallet ?: "",
95+
to = "admin",
96+
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."
97+
)
98+
messageRepo.syncMessages()
99+
}
100+
}
101+
}
80102
// 🔁 Toggle edit mode
81103
fun updateEditEnabled() {
82104
_state.value = _state.value.copy(editMode = !_state.value.editMode)
@@ -109,12 +131,16 @@ class UserSelectViewModel(
109131
userRepo.updateUser(user)
110132
}
111133
}
134+
135+
fun updateDeleteProfileState(deleteProfileState: DeleteProfileState) {
136+
_state.value= _state.value.copy(deleteProfileState = deleteProfileState)
137+
}
112138
}
113139

114140
class UserSelectViewModelFactory(private val userId: Long) :
115141
ViewModelProvider.Factory, KoinComponent {
116142
@Suppress("UNCHECKED_CAST")
117143
override fun <T : ViewModel> create(modelClass: Class<T>): T {
118-
return UserSelectViewModel(userId, get(), get(),get(),) as T
144+
return UserSelectViewModel(userId, get(), get(),get(), get()) as T
119145
}
120146
}

app/src/main/res/values/strings.xml

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -180,10 +180,12 @@ Privacy Policy
180180
<string name="logout_title">Log out</string>
181181
<string name="logout_description">Log out from your account.</string>
182182
<string name="delete_account_title">Delete Account</string>
183+
<string name="account_deleted">Account Deleted</string>
184+
<string name="account_deleted_message">All your Data has been deleted</string>
183185
<string name="delete_account_description">Initiate the process to delete your account completely.</string>
184186
<string name="logout_dialog_title">Are you sure you want to logout?</string>
185-
<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>
186-
<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>
187+
<string name="delete_account_dialog_title">Are you sure you want to delete this account?</string>
188+
<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>
187189
<string name="logout_dialog_message"> Are you sure you want to log out from your account?</string>
188190

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

0 commit comments

Comments
 (0)