@@ -8,6 +8,7 @@ import androidx.compose.animation.SharedTransitionScope
8
8
import androidx.compose.foundation.layout.Arrangement
9
9
import androidx.compose.foundation.layout.Box
10
10
import androidx.compose.foundation.layout.Column
11
+ import androidx.compose.foundation.layout.Row
11
12
import androidx.compose.foundation.layout.fillMaxWidth
12
13
import androidx.compose.foundation.layout.imePadding
13
14
import androidx.compose.foundation.layout.padding
@@ -16,8 +17,10 @@ import androidx.compose.foundation.rememberScrollState
16
17
import androidx.compose.foundation.text.KeyboardActions
17
18
import androidx.compose.foundation.text.KeyboardOptions
18
19
import androidx.compose.foundation.verticalScroll
20
+ import androidx.compose.material3.Checkbox
19
21
import androidx.compose.material3.OutlinedTextField
20
22
import androidx.compose.material3.Text
23
+ import androidx.compose.material3.TextButton
21
24
import androidx.compose.runtime.Composable
22
25
import androidx.compose.runtime.LaunchedEffect
23
26
import androidx.compose.runtime.getValue
@@ -29,11 +32,15 @@ import androidx.compose.ui.focus.focusProperties
29
32
import androidx.compose.ui.focus.focusRequester
30
33
import androidx.compose.ui.platform.LocalContext
31
34
import androidx.compose.ui.platform.LocalSoftwareKeyboardController
35
+ import androidx.compose.ui.platform.LocalUriHandler
32
36
import androidx.compose.ui.res.dimensionResource
33
37
import androidx.compose.ui.res.stringResource
38
+ import androidx.compose.ui.text.LinkAnnotation
39
+ import androidx.compose.ui.text.buildAnnotatedString
34
40
import androidx.compose.ui.text.input.ImeAction
35
41
import androidx.compose.ui.text.input.KeyboardCapitalization
36
42
import androidx.compose.ui.text.input.KeyboardType
43
+ import androidx.compose.ui.text.withLink
37
44
import androidx.compose.ui.tooling.preview.Preview
38
45
import androidx.hilt.navigation.compose.hiltViewModel
39
46
import androidx.lifecycle.SavedStateHandle
@@ -66,6 +73,7 @@ fun SharedTransitionScope.RegisterScreen(
66
73
val environment by environmentViewModel.environment.collectAsStateWithLifecycle()
67
74
val username by viewModel.username.collectAsStateWithLifecycle()
68
75
val email by viewModel.email.collectAsStateWithLifecycle()
76
+ val hasAcceptedTerms by viewModel.hasAcceptedTerms.collectAsStateWithLifecycle()
69
77
val randomCode by viewModel.randomCode.collectAsStateWithLifecycle()
70
78
val isWaitingForRandomCode by viewModel.isWaitingForRandomCode.collectAsStateWithLifecycle()
71
79
val canSubmit by viewModel.canSubmit.collectAsStateWithLifecycle()
@@ -80,7 +88,7 @@ fun SharedTransitionScope.RegisterScreen(
80
88
modifier = Modifier
81
89
.verticalScroll(rememberScrollState())
82
90
.fillMaxWidth()
83
- .padding(horizontal = dimensionResource(R .dimen.spacing_medium ))
91
+ .padding(horizontal = dimensionResource(R .dimen.spacing_large ))
84
92
.imePadding()
85
93
) {
86
94
Logo (
@@ -105,11 +113,12 @@ fun SharedTransitionScope.RegisterScreen(
105
113
)
106
114
}
107
115
108
- val textFieldModifier = Modifier
116
+ val fieldModifier = Modifier
109
117
.widthIn(
110
118
dimensionResource(R .dimen.form_min_width),
111
119
dimensionResource(R .dimen.form_max_width)
112
120
)
121
+ .fillMaxWidth()
113
122
.padding(bottom = dimensionResource(R .dimen.spacing_large))
114
123
115
124
OutlinedTextField (
@@ -124,7 +133,7 @@ fun SharedTransitionScope.RegisterScreen(
124
133
imeAction = ImeAction .Next
125
134
),
126
135
onValueChange = viewModel::updateUsername,
127
- modifier = textFieldModifier
136
+ modifier = fieldModifier
128
137
.focusRequester(usernameFocus)
129
138
.focusProperties { next = emailFocus }
130
139
.sharedElement(
@@ -153,17 +162,59 @@ fun SharedTransitionScope.RegisterScreen(
153
162
}
154
163
}),
155
164
onValueChange = viewModel::updateEmail,
156
- modifier = textFieldModifier .focusRequester(emailFocus)
165
+ modifier = fieldModifier .focusRequester(emailFocus)
157
166
)
158
167
159
168
AnimatedVisibility (isWaitingForRandomCode) {
160
169
RandomCodeInput (
161
170
randomCode = randomCode,
162
171
onValueChange = viewModel::updateRandomCode,
163
- modifier = textFieldModifier
172
+ modifier = fieldModifier
173
+ )
174
+ }
175
+
176
+ Row (
177
+ verticalAlignment = Alignment .CenterVertically ,
178
+ modifier = fieldModifier
179
+ ) {
180
+ Checkbox (
181
+ checked = hasAcceptedTerms,
182
+ enabled = ! isWaitingForRandomCode,
183
+ onCheckedChange = viewModel::updateHasAcceptedTerms
184
+ )
185
+
186
+ Text (
187
+ text = buildAnnotatedString {
188
+ withLink(LinkAnnotation .Clickable (" terms" ) {
189
+ viewModel.updateHasAcceptedTerms(! hasAcceptedTerms)
190
+ }) {
191
+ append(stringResource(R .string.register_terms_acceptance))
192
+ }
193
+ },
194
+ modifier = Modifier .focusProperties { canFocus = false }
164
195
)
165
196
}
166
197
198
+ Row (
199
+ horizontalArrangement = Arrangement .spacedBy(
200
+ space = dimensionResource(R .dimen.spacing_small),
201
+ alignment = Alignment .CenterHorizontally
202
+ ),
203
+ modifier = fieldModifier
204
+ ) {
205
+ val uriHandler = LocalUriHandler .current
206
+ val termsUri = stringResource(R .string.info_url_terms_of_service)
207
+ val privacyUri = stringResource(R .string.info_url_privacy_policy)
208
+
209
+ TextButton (onClick = { uriHandler.openUri(termsUri) }) {
210
+ Text (stringResource(R .string.register_terms_of_service))
211
+ }
212
+
213
+ TextButton (onClick = { uriHandler.openUri(privacyUri) }) {
214
+ Text (stringResource(R .string.register_privacy_policy))
215
+ }
216
+ }
217
+
167
218
SubmitOrCancel (
168
219
submitLabel = stringResource(R .string.register_submit),
169
220
canSubmit = canSubmit,
0 commit comments