Skip to content

Commit cd52df5

Browse files
authored
Merge pull request #5785 from vector-im/feature/adm/ftue-step-ordering
FTUE - Registration step ordering
2 parents 3d190bb + 636f7fd commit cd52df5

File tree

5 files changed

+175
-44
lines changed

5 files changed

+175
-44
lines changed

changelog.d/5783.wip

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
Reorders the registration steps to prioritise email, then terms for the FTUE onboarding

vector/src/main/java/im/vector/app/features/onboarding/ftueauth/FtueAuthVariant.kt

Lines changed: 61 additions & 44 deletions
Original file line numberDiff line numberDiff line change
@@ -131,24 +131,7 @@ class FtueAuthVariant(
131131
private fun handleOnboardingViewEvents(viewEvents: OnboardingViewEvents) {
132132
when (viewEvents) {
133133
is OnboardingViewEvents.RegistrationFlowResult -> {
134-
if (registrationShouldFallback(viewEvents)) {
135-
// Display a popup to propose use web fallback
136-
onRegistrationStageNotSupported()
137-
} else {
138-
if (viewEvents.isRegistrationStarted) {
139-
// Go on with registration flow
140-
handleRegistrationNavigation(viewEvents.flowResult)
141-
} else {
142-
if (vectorFeatures.isOnboardingCombinedRegisterEnabled()) {
143-
openCombinedRegister()
144-
} else {
145-
// First ask for login and password
146-
// I add a tag to indicate that this fragment is a registration stage.
147-
// This way it will be automatically popped in when starting the next registration stage
148-
openAuthLoginFragmentWithTag(FRAGMENT_REGISTRATION_STAGE_TAG)
149-
}
150-
}
151-
}
134+
onRegistrationFlow(viewEvents)
152135
}
153136
is OnboardingViewEvents.OutdatedHomeserver -> {
154137
MaterialAlertDialogBuilder(activity)
@@ -176,25 +159,33 @@ class FtueAuthVariant(
176159
is OnboardingViewEvents.OnServerSelectionDone -> onServerSelectionDone(viewEvents)
177160
is OnboardingViewEvents.OnSignModeSelected -> onSignModeSelected(viewEvents)
178161
is OnboardingViewEvents.OnLoginFlowRetrieved ->
179-
activity.addFragmentToBackstack(views.loginFragmentContainer,
162+
activity.addFragmentToBackstack(
163+
views.loginFragmentContainer,
180164
FtueAuthSignUpSignInSelectionFragment::class.java,
181-
option = commonOption)
165+
option = commonOption
166+
)
182167
is OnboardingViewEvents.OnWebLoginError -> onWebLoginError(viewEvents)
183168
is OnboardingViewEvents.OnForgetPasswordClicked ->
184-
activity.addFragmentToBackstack(views.loginFragmentContainer,
169+
activity.addFragmentToBackstack(
170+
views.loginFragmentContainer,
185171
FtueAuthResetPasswordFragment::class.java,
186-
option = commonOption)
172+
option = commonOption
173+
)
187174
is OnboardingViewEvents.OnResetPasswordSendThreePidDone -> {
188175
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
189-
activity.addFragmentToBackstack(views.loginFragmentContainer,
176+
activity.addFragmentToBackstack(
177+
views.loginFragmentContainer,
190178
FtueAuthResetPasswordMailConfirmationFragment::class.java,
191-
option = commonOption)
179+
option = commonOption
180+
)
192181
}
193182
is OnboardingViewEvents.OnResetPasswordMailConfirmationSuccess -> {
194183
supportFragmentManager.popBackStack(FRAGMENT_LOGIN_TAG, POP_BACK_STACK_EXCLUSIVE)
195-
activity.addFragmentToBackstack(views.loginFragmentContainer,
184+
activity.addFragmentToBackstack(
185+
views.loginFragmentContainer,
196186
FtueAuthResetPasswordSuccessFragment::class.java,
197-
option = commonOption)
187+
option = commonOption
188+
)
198189
}
199190
is OnboardingViewEvents.OnResetPasswordMailConfirmationSuccessDone -> {
200191
// Go back to the login fragment
@@ -221,11 +212,13 @@ class FtueAuthVariant(
221212
// This is handled by the Fragments
222213
Unit
223214
OnboardingViewEvents.OpenUseCaseSelection -> {
224-
activity.addFragmentToBackstack(views.loginFragmentContainer,
215+
activity.addFragmentToBackstack(
216+
views.loginFragmentContainer,
225217
FtueAuthUseCaseFragment::class.java,
226-
option = commonOption)
218+
option = commonOption
219+
)
227220
}
228-
OnboardingViewEvents.OpenCombinedRegister -> openCombinedRegister()
221+
OnboardingViewEvents.OpenCombinedRegister -> openStartCombinedRegister()
229222
is OnboardingViewEvents.OnAccountCreated -> onAccountCreated()
230223
OnboardingViewEvents.OnAccountSignedIn -> onAccountSignedIn()
231224
OnboardingViewEvents.OnChooseDisplayName -> onChooseDisplayName()
@@ -244,7 +237,21 @@ class FtueAuthVariant(
244237
}
245238
}
246239

247-
private fun openCombinedRegister() {
240+
private fun onRegistrationFlow(viewEvents: OnboardingViewEvents.RegistrationFlowResult) {
241+
when {
242+
registrationShouldFallback(viewEvents) -> displayFallbackWebDialog()
243+
viewEvents.isRegistrationStarted -> handleRegistrationNavigation(viewEvents.flowResult.orderedStages())
244+
vectorFeatures.isOnboardingCombinedRegisterEnabled() -> openStartCombinedRegister()
245+
else -> openAuthLoginFragmentWithTag(FRAGMENT_REGISTRATION_STAGE_TAG)
246+
}
247+
}
248+
249+
private fun FlowResult.orderedStages() = when {
250+
vectorFeatures.isOnboardingCombinedRegisterEnabled() -> missingStages.sortedWith(FtueMissingRegistrationStagesComparator())
251+
else -> missingStages
252+
}
253+
254+
private fun openStartCombinedRegister() {
248255
addRegistrationStageFragmentToBackstack(FtueAuthCombinedRegisterFragment::class.java)
249256
}
250257

@@ -254,14 +261,16 @@ class FtueAuthVariant(
254261
private fun OnboardingViewEvents.RegistrationFlowResult.containsUnsupportedRegistrationFlow() =
255262
flowResult.missingStages.any { !it.isSupported() }
256263

257-
private fun onRegistrationStageNotSupported() {
264+
private fun displayFallbackWebDialog() {
258265
MaterialAlertDialogBuilder(activity)
259266
.setTitle(R.string.app_name)
260267
.setMessage(activity.getString(R.string.login_registration_not_supported))
261268
.setPositiveButton(R.string.yes) { _, _ ->
262-
activity.addFragmentToBackstack(views.loginFragmentContainer,
269+
activity.addFragmentToBackstack(
270+
views.loginFragmentContainer,
263271
FtueAuthWebFragment::class.java,
264-
option = commonOption)
272+
option = commonOption
273+
)
265274
}
266275
.setNegativeButton(R.string.no, null)
267276
.show()
@@ -283,9 +292,11 @@ class FtueAuthVariant(
283292
when (OnboardingViewEvents.serverType) {
284293
ServerType.MatrixOrg -> Unit // In this case, we wait for the login flow
285294
ServerType.EMS,
286-
ServerType.Other -> activity.addFragmentToBackstack(views.loginFragmentContainer,
295+
ServerType.Other -> activity.addFragmentToBackstack(
296+
views.loginFragmentContainer,
287297
FtueAuthServerUrlFormFragment::class.java,
288-
option = commonOption)
298+
option = commonOption
299+
)
289300
ServerType.Unknown -> Unit /* Should not happen */
290301
}
291302
}
@@ -317,10 +328,12 @@ class FtueAuthVariant(
317328
}
318329

319330
private fun openAuthLoginFragmentWithTag(tag: String) {
320-
activity.addFragmentToBackstack(views.loginFragmentContainer,
331+
activity.addFragmentToBackstack(
332+
views.loginFragmentContainer,
321333
FtueAuthLoginFragment::class.java,
322334
tag = tag,
323-
option = commonOption)
335+
option = commonOption
336+
)
324337
}
325338

326339
private fun onLoginModeNotSupported(supportedTypes: List<String>) {
@@ -341,9 +354,11 @@ class FtueAuthVariant(
341354
}
342355

343356
private fun openAuthWebFragment() {
344-
activity.addFragmentToBackstack(views.loginFragmentContainer,
357+
activity.addFragmentToBackstack(
358+
views.loginFragmentContainer,
345359
FtueAuthWebFragment::class.java,
346-
option = commonOption)
360+
option = commonOption
361+
)
347362
}
348363

349364
/**
@@ -355,15 +370,15 @@ class FtueAuthVariant(
355370
?.let { onboardingViewModel.handle(OnboardingAction.LoginWithToken(it)) }
356371
}
357372

358-
private fun handleRegistrationNavigation(flowResult: FlowResult) {
373+
private fun handleRegistrationNavigation(remainingStages: List<Stage>) {
359374
// Complete all mandatory stages first
360-
val mandatoryStage = flowResult.missingStages.firstOrNull { it.mandatory }
375+
val mandatoryStage = remainingStages.firstOrNull { it.mandatory }
361376

362377
if (mandatoryStage != null) {
363378
doStage(mandatoryStage)
364379
} else {
365380
// Consider optional stages
366-
val optionalStage = flowResult.missingStages.firstOrNull { !it.mandatory && it !is Stage.Dummy }
381+
val optionalStage = remainingStages.firstOrNull { !it.mandatory && it !is Stage.Dummy }
367382
if (optionalStage == null) {
368383
// Should not happen...
369384
} else {
@@ -437,14 +452,16 @@ class FtueAuthVariant(
437452
}
438453

439454
private fun onChooseDisplayName() {
440-
activity.addFragmentToBackstack(views.loginFragmentContainer,
455+
activity.addFragmentToBackstack(
456+
views.loginFragmentContainer,
441457
FtueAuthChooseDisplayNameFragment::class.java,
442458
option = commonOption
443459
)
444460
}
445461

446462
private fun onChooseProfilePicture() {
447-
activity.addFragmentToBackstack(views.loginFragmentContainer,
463+
activity.addFragmentToBackstack(
464+
views.loginFragmentContainer,
448465
FtueAuthChooseProfilePictureFragment::class.java,
449466
option = commonOption
450467
)
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
/*
2+
* Copyright (c) 2022 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.features.onboarding.ftueauth
18+
19+
import org.matrix.android.sdk.api.auth.registration.Stage
20+
21+
class FtueMissingRegistrationStagesComparator : Comparator<Stage> {
22+
23+
override fun compare(a: Stage?, b: Stage?): Int {
24+
return (a?.toPriority() ?: 0) - (b?.toPriority() ?: 0)
25+
}
26+
27+
private fun Stage.toPriority() = when (this) {
28+
is Stage.Email -> 0
29+
is Stage.Msisdn -> 1
30+
is Stage.Terms -> 2
31+
is Stage.ReCaptcha -> 3
32+
is Stage.Other -> 4
33+
is Stage.Dummy -> 5
34+
}
35+
}
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
/*
2+
* Copyright (c) 2022 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.features.onboarding.ftueauth
18+
19+
import im.vector.app.test.fixtures.aDummyStage
20+
import im.vector.app.test.fixtures.aMsisdnStage
21+
import im.vector.app.test.fixtures.aRecaptchaStage
22+
import im.vector.app.test.fixtures.aTermsStage
23+
import im.vector.app.test.fixtures.anEmailStage
24+
import im.vector.app.test.fixtures.anOtherStage
25+
import org.amshove.kluent.shouldBeEqualTo
26+
import org.junit.Test
27+
28+
class FtueMissingRegistrationStagesComparatorTest {
29+
30+
@Test
31+
fun `when ordering stages, then prioritizes email`() {
32+
val input = listOf(
33+
aDummyStage(),
34+
anOtherStage(),
35+
aMsisdnStage(),
36+
anEmailStage(),
37+
aRecaptchaStage(),
38+
aTermsStage()
39+
)
40+
41+
val result = input.sortedWith(FtueMissingRegistrationStagesComparator())
42+
43+
result shouldBeEqualTo listOf(
44+
anEmailStage(),
45+
aMsisdnStage(),
46+
aTermsStage(),
47+
aRecaptchaStage(),
48+
anOtherStage(),
49+
aDummyStage()
50+
)
51+
}
52+
}
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
/*
2+
* Copyright (c) 2022 New Vector Ltd
3+
*
4+
* Licensed under the Apache License, Version 2.0 (the "License");
5+
* you may not use this file except in compliance with the License.
6+
* You may obtain a copy of the License at
7+
*
8+
* http://www.apache.org/licenses/LICENSE-2.0
9+
*
10+
* Unless required by applicable law or agreed to in writing, software
11+
* distributed under the License is distributed on an "AS IS" BASIS,
12+
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13+
* See the License for the specific language governing permissions and
14+
* limitations under the License.
15+
*/
16+
17+
package im.vector.app.test.fixtures
18+
19+
import org.matrix.android.sdk.api.auth.registration.Stage
20+
21+
fun aDummyStage() = Stage.Dummy(mandatory = true)
22+
fun anEmailStage() = Stage.Email(mandatory = true)
23+
fun aMsisdnStage() = Stage.Msisdn(mandatory = true)
24+
fun aTermsStage() = Stage.Terms(mandatory = true, policies = emptyMap<String, String>())
25+
fun aRecaptchaStage() = Stage.ReCaptcha(mandatory = true, publicKey = "any-key")
26+
fun anOtherStage() = Stage.Other(mandatory = true, type = "raw-type", params = emptyMap<String, String>())

0 commit comments

Comments
 (0)