Skip to content

Commit 788b235

Browse files
authored
Merge pull request #1142 from Greenstand/1141-show-privacy-dialog-from-settings
feat: view privacy policy from settings
2 parents 0a92661 + 46bcdaa commit 788b235

File tree

6 files changed

+194
-95
lines changed

6 files changed

+194
-95
lines changed

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

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,7 @@ import org.greenstand.android.TreeTracker.orgpicker.OrgPickerViewModel
7171
import org.greenstand.android.TreeTracker.permissions.PermissionViewModel
7272
import org.greenstand.android.TreeTracker.preferences.Preferences
7373
import org.greenstand.android.TreeTracker.sessionnote.SessionNoteViewModel
74+
import org.greenstand.android.TreeTracker.settings.SettingsViewModel
7475
import org.greenstand.android.TreeTracker.treeheight.TreeHeightSelectionViewModel
7576
import org.greenstand.android.TreeTracker.usecases.CheckForInternetUseCase
7677
import org.greenstand.android.TreeTracker.usecases.CreateFakeTreesUseCase
@@ -125,6 +126,8 @@ val appModule = module {
125126

126127
viewModel { PermissionViewModel(get()) }
127128

129+
viewModel { SettingsViewModel(get()) }
130+
128131
single { UserRepo(get(), get(), get(), get(), get(), get()) }
129132

130133
factory<TreeCapturer> { CaptureFlowScopeManager.getData().get() }

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

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import org.greenstand.android.TreeTracker.orgpicker.AddOrgViewModel
2626
import org.greenstand.android.TreeTracker.orgpicker.OrgPickerViewModel
2727
import org.greenstand.android.TreeTracker.permissions.PermissionViewModel
2828
import org.greenstand.android.TreeTracker.sessionnote.SessionNoteViewModel
29+
import org.greenstand.android.TreeTracker.settings.SettingsViewModel
2930
import org.greenstand.android.TreeTracker.signup.SignupViewModel
3031
import org.greenstand.android.TreeTracker.splash.SplashScreenViewModel
3132
import org.greenstand.android.TreeTracker.treeheight.TreeHeightSelectionViewModel
@@ -55,6 +56,7 @@ class TreeTrackerViewModelFactory : ViewModelProvider.NewInstanceFactory(), Koin
5556
modelClass.isAssignableFrom(AddOrgViewModel::class.java) -> get<AddOrgViewModel>() as T
5657
modelClass.isAssignableFrom(SessionNoteViewModel::class.java) -> get<SessionNoteViewModel>() as T
5758
modelClass.isAssignableFrom(DevOptionsViewModel::class.java) -> get<DevOptionsViewModel>() as T
59+
modelClass.isAssignableFrom(SettingsViewModel::class.java) -> get<SettingsViewModel>() as T
5860
else -> throw RuntimeException("Unable to create instance of ${modelClass.simpleName}. Did you forget to update the TreeTrackerViewModelFactory?")
5961
}
6062
}

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

Lines changed: 60 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,8 @@ import androidx.compose.material.Scaffold
99
import androidx.compose.material.SnackbarHostState
1010
import androidx.compose.material.Text
1111
import androidx.compose.runtime.Composable
12+
import androidx.compose.runtime.collectAsState
13+
import androidx.compose.runtime.getValue
1214
import androidx.compose.runtime.remember
1315
import androidx.compose.runtime.rememberCoroutineScope
1416
import androidx.compose.ui.Alignment
@@ -23,16 +25,22 @@ import androidx.compose.ui.unit.dp
2325
import androidx.compose.ui.unit.sp
2426
import androidx.compose.ui.res.stringResource
2527
import androidx.compose.ui.text.style.TextAlign
28+
import androidx.lifecycle.viewmodel.compose.viewModel
2629
import kotlinx.coroutines.launch
2730
import org.greenstand.android.TreeTracker.R
2831
import org.greenstand.android.TreeTracker.models.NavRoute
2932
import org.greenstand.android.TreeTracker.root.LocalNavHostController
33+
import org.greenstand.android.TreeTracker.root.LocalViewModelFactory
3034
import org.greenstand.android.TreeTracker.signup.Credential
3135
import org.greenstand.android.TreeTracker.theme.CustomTheme
36+
import org.greenstand.android.TreeTracker.userselect.UserSelectState
37+
import org.greenstand.android.TreeTracker.userselect.UserSelectViewModel
38+
import org.greenstand.android.TreeTracker.userselect.UserSelectViewModelFactory
3239
import org.greenstand.android.TreeTracker.view.ActionBar
3340
import org.greenstand.android.TreeTracker.view.AppColors
3441
import org.greenstand.android.TreeTracker.view.ArrowButton
3542
import org.greenstand.android.TreeTracker.view.LanguageButton
43+
import org.greenstand.android.TreeTracker.view.dialogs.PrivacyPolicyDialog
3644
import org.greenstand.android.TreeTracker.view.TopBarTitle
3745

3846
@Composable
@@ -41,6 +49,10 @@ fun SettingsScreen() {
4149
val focusRequester = remember { FocusRequester() }
4250
val context = LocalContext.current
4351
val scope = rememberCoroutineScope()
52+
val viewModel: SettingsViewModel = viewModel(factory = LocalViewModelFactory.current)
53+
54+
val state by viewModel.state.collectAsState(SettingsState())
55+
4456

4557
Scaffold(
4658
topBar = {
@@ -55,56 +67,66 @@ fun SettingsScreen() {
5567
)
5668
},
5769

58-
)
70+
)
5971
},
6072
bottomBar = {
61-
ActionBar(
62-
leftAction = {
63-
ArrowButton(isLeft = true) {
64-
navController.popBackStack()
65-
}
66-
},
73+
ActionBar(
74+
leftAction = {
75+
ArrowButton(isLeft = true) {
76+
navController.popBackStack()
77+
}
78+
},
6779

6880
)
6981
}
7082
) {
71-
Column(
83+
Box(
7284
modifier = Modifier
7385
.fillMaxSize()
74-
.padding(start = 20.dp,end= 20.dp)
7586
) {
76-
SettingsItem(
77-
iconResId = R.drawable.account, // Replace with your profile icon
78-
titleResId = R.string.profile_title,
79-
descriptionResId = R.string.profile_description,
80-
onClick = {
81-
navController.navigate(NavRoute.ProfileSelect.route)
82-
}
83-
)
84-
Divider(color = Color.White)
87+
Column(
88+
modifier = Modifier
89+
.fillMaxSize()
90+
.padding(start = 20.dp, end = 20.dp)
91+
) {
92+
SettingsItem(
93+
iconResId = R.drawable.account, // Replace with your profile icon
94+
titleResId = R.string.profile_title,
95+
descriptionResId = R.string.profile_description,
96+
onClick = {
97+
navController.navigate(NavRoute.ProfileSelect.route)
98+
}
99+
)
100+
Divider(color = Color.White)
85101

86-
SettingsItem(
87-
iconResId = R.drawable.privacy_policy, // Replace with your privacy icon
88-
titleResId = R.string.privacy_title,
89-
descriptionResId = R.string.privacy_description,
90-
onClick = { /* Handle privacy click */ }
91-
)
92-
Divider(color = Color.White)
102+
SettingsItem(
103+
iconResId = R.drawable.privacy_policy, // Replace with your privacy icon
104+
titleResId = R.string.privacy_title,
105+
descriptionResId = R.string.privacy_description,
106+
onClick = {
107+
viewModel.setPrivacyDialogVisibility(true)
108+
}
109+
)
110+
Divider(color = Color.White)
93111

94-
SettingsItem(
95-
iconResId = R.drawable.logout, // Replace with your logout icon
96-
titleResId = R.string.logout_title,
97-
descriptionResId = R.string.logout_description,
98-
onClick = { /* Handle logout click */ }
99-
)
100-
Divider(color = Color.White)
112+
SettingsItem(
113+
iconResId = R.drawable.logout, // Replace with your logout icon
114+
titleResId = R.string.logout_title,
115+
descriptionResId = R.string.logout_description,
116+
onClick = { /* Handle logout click */ }
117+
)
118+
Divider(color = Color.White)
101119

102-
SettingsItem(
103-
iconResId = R.drawable.delete, // Replace with your delete icon
104-
titleResId = R.string.delete_account_title,
105-
descriptionResId = R.string.delete_account_description,
106-
onClick = { /* Handle delete account click */ }
107-
)
120+
SettingsItem(
121+
iconResId = R.drawable.delete, // Replace with your delete icon
122+
titleResId = R.string.delete_account_title,
123+
descriptionResId = R.string.delete_account_description,
124+
onClick = { /* Handle delete account click */ }
125+
)
126+
}
127+
if (state.showPrivacyPolicyDialog == true) {
128+
PrivacyPolicyDialog(settingsViewModel = viewModel)
129+
}
108130
}
109131
}
110132
}
Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
package org.greenstand.android.TreeTracker.settings
2+
3+
4+
import androidx.lifecycle.ViewModel
5+
import androidx.lifecycle.viewModelScope
6+
import kotlinx.coroutines.flow.Flow
7+
import kotlinx.coroutines.flow.MutableStateFlow
8+
import kotlinx.coroutines.launch
9+
import org.greenstand.android.TreeTracker.models.UserRepo
10+
11+
data class SettingsState(
12+
val showPrivacyPolicyDialog: Boolean? = null,
13+
)
14+
15+
class SettingsViewModel(
16+
private val userRepo: UserRepo,
17+
) : ViewModel() {
18+
19+
private val _state = MutableStateFlow(SettingsState())
20+
val state: Flow<SettingsState> = _state
21+
22+
init {
23+
24+
}
25+
26+
fun setPrivacyDialogVisibility(show: Boolean) {
27+
viewModelScope.launch {
28+
_state.value = _state.value.copy(
29+
showPrivacyPolicyDialog = show
30+
)
31+
}
32+
}
33+
}

app/src/main/java/org/greenstand/android/TreeTracker/signup/CredentialEntryView.kt

Lines changed: 3 additions & 57 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,7 @@ import kotlinx.coroutines.launch
7070
import org.greenstand.android.TreeTracker.R
7171
import org.greenstand.android.TreeTracker.models.NavRoute
7272
import org.greenstand.android.TreeTracker.root.LocalNavHostController
73+
import org.greenstand.android.TreeTracker.settings.SettingsViewModel
7374
import org.greenstand.android.TreeTracker.theme.CustomTheme
7475
import org.greenstand.android.TreeTracker.utilities.Constants
7576
import org.greenstand.android.TreeTracker.view.ActionBar
@@ -81,6 +82,7 @@ import org.greenstand.android.TreeTracker.view.ArrowButton
8182
import org.greenstand.android.TreeTracker.view.BorderedTextField
8283
import org.greenstand.android.TreeTracker.view.CustomSnackbar
8384
import org.greenstand.android.TreeTracker.view.LanguageButton
85+
import org.greenstand.android.TreeTracker.view.dialogs.PrivacyPolicyDialog
8486
import org.greenstand.android.TreeTracker.view.TopBarTitle
8587
import org.greenstand.android.TreeTracker.view.TreeTrackerButton
8688
import org.greenstand.android.TreeTracker.view.UserButton
@@ -176,7 +178,7 @@ fun CredentialEntryView(viewModel: SignupViewModel, state: SignUpState) {
176178
ViewWebMapText(isVisible = state.isInternetAvailable, onClick = navigateToWebPage)
177179
}
178180
if (state.showPrivacyDialog == true) {
179-
PrivacyPolicyDialog(viewModel = viewModel)
181+
PrivacyPolicyDialog(signupViewModel = viewModel)
180182
}
181183
}
182184
}
@@ -340,62 +342,6 @@ fun ExistingUserDialog(
340342
)
341343
}
342344

343-
@Composable
344-
fun PrivacyPolicyDialog(
345-
viewModel: SignupViewModel,
346-
) {
347-
Column(
348-
modifier = Modifier
349-
.padding(start = 30.dp, end = 30.dp, top = 10.dp, bottom = 40.dp)
350-
.fillMaxSize()
351-
.padding(2.dp)
352-
.border(1.dp, color = Green, shape = RoundedCornerShape(percent = 10))
353-
.clip(RoundedCornerShape(percent = 10))
354-
.background(color = AppColors.Gray)
355-
.padding(10.dp),
356-
) {
357-
Row(
358-
modifier = Modifier
359-
.weight(0.8f)
360-
.fillMaxWidth()
361-
.padding(bottom = 4.dp),
362-
horizontalArrangement = Arrangement.Start,
363-
verticalAlignment = Alignment.CenterVertically
364-
) {
365-
Image(
366-
painter = painterResource(id = R.drawable.greenstand_logo),
367-
contentDescription = null,
368-
modifier = Modifier
369-
.size(width = 20.dp, height = 20.dp)
370-
)
371-
Spacer(modifier = Modifier.width(5.dp))
372-
Text(
373-
text = stringResource(R.string.privacy_policy),
374-
color = CustomTheme.textColors.primaryText,
375-
style = CustomTheme.typography.large,
376-
fontWeight = FontWeight.Bold,
377-
)
378-
}
379-
Text(
380-
text = stringResource(id = R.string.policy_text_blob),
381-
modifier = Modifier
382-
.padding(bottom = 15.dp)
383-
.weight(9f)
384-
.verticalScroll(rememberScrollState())
385-
)
386-
ApprovalButton(
387-
modifier = Modifier
388-
.weight(0.8f)
389-
.size(50.dp)
390-
.align(CenterHorizontally),
391-
onClick = {
392-
viewModel.closePrivacyPolicyDialog()
393-
},
394-
approval = true
395-
)
396-
}
397-
}
398-
399345
@Preview
400346
@Composable
401347
fun SignupScreen_Preview(
Lines changed: 93 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
package org.greenstand.android.TreeTracker.view.dialogs
2+
3+
import androidx.compose.foundation.Image
4+
import androidx.compose.foundation.background
5+
import androidx.compose.foundation.border
6+
import androidx.compose.foundation.layout.Arrangement
7+
import androidx.compose.foundation.layout.Column
8+
import androidx.compose.foundation.layout.Row
9+
import androidx.compose.foundation.layout.Spacer
10+
import androidx.compose.foundation.layout.fillMaxSize
11+
import androidx.compose.foundation.layout.fillMaxWidth
12+
import androidx.compose.foundation.layout.padding
13+
import androidx.compose.foundation.layout.size
14+
import androidx.compose.foundation.layout.width
15+
import androidx.compose.foundation.rememberScrollState
16+
import androidx.compose.foundation.shape.RoundedCornerShape
17+
import androidx.compose.foundation.verticalScroll
18+
import androidx.compose.material.Text
19+
import androidx.compose.runtime.Composable
20+
import androidx.compose.ui.Alignment
21+
import androidx.compose.ui.Modifier
22+
import androidx.compose.ui.draw.clip
23+
import androidx.compose.ui.res.painterResource
24+
import androidx.compose.ui.res.stringResource
25+
import androidx.compose.ui.text.font.FontWeight
26+
import androidx.compose.ui.unit.dp
27+
import org.greenstand.android.TreeTracker.R
28+
import org.greenstand.android.TreeTracker.settings.SettingsViewModel
29+
import org.greenstand.android.TreeTracker.signup.SignupViewModel
30+
import org.greenstand.android.TreeTracker.theme.CustomTheme
31+
import org.greenstand.android.TreeTracker.view.AppColors
32+
import org.greenstand.android.TreeTracker.view.ApprovalButton
33+
34+
@Composable
35+
fun PrivacyPolicyDialog(
36+
signupViewModel: SignupViewModel? = null,
37+
settingsViewModel: SettingsViewModel? = null
38+
) {
39+
Column(
40+
modifier = Modifier.Companion
41+
.padding(start = 30.dp, end = 30.dp, top = 10.dp, bottom = 40.dp)
42+
.fillMaxSize()
43+
.padding(2.dp)
44+
.border(1.dp, color = AppColors.Green, shape = RoundedCornerShape(percent = 10))
45+
.clip(RoundedCornerShape(percent = 10))
46+
.background(color = AppColors.Gray)
47+
.padding(10.dp),
48+
) {
49+
Row(
50+
modifier = Modifier.Companion
51+
.weight(0.8f)
52+
.fillMaxWidth()
53+
.padding(bottom = 4.dp),
54+
horizontalArrangement = Arrangement.Start,
55+
verticalAlignment = Alignment.Companion.CenterVertically
56+
) {
57+
Image(
58+
painter = painterResource(id = R.drawable.greenstand_logo),
59+
contentDescription = null,
60+
modifier = Modifier.Companion
61+
.size(width = 20.dp, height = 20.dp)
62+
)
63+
Spacer(modifier = Modifier.Companion.width(5.dp))
64+
Text(
65+
text = stringResource(R.string.privacy_policy),
66+
color = CustomTheme.textColors.primaryText,
67+
style = CustomTheme.typography.large,
68+
fontWeight = FontWeight.Companion.Bold,
69+
)
70+
}
71+
Text(
72+
text = stringResource(id = R.string.policy_text_blob),
73+
modifier = Modifier.Companion
74+
.padding(bottom = 15.dp)
75+
.weight(9f)
76+
.verticalScroll(rememberScrollState())
77+
)
78+
ApprovalButton(
79+
modifier = Modifier.Companion
80+
.weight(0.8f)
81+
.size(50.dp)
82+
.align(Alignment.Companion.CenterHorizontally),
83+
onClick = {
84+
if (signupViewModel != null) {
85+
signupViewModel.closePrivacyPolicyDialog()
86+
} else {
87+
settingsViewModel?.setPrivacyDialogVisibility(false)
88+
}
89+
},
90+
approval = true
91+
)
92+
}
93+
}

0 commit comments

Comments
 (0)