Skip to content

Commit 150239b

Browse files
bmartyElementBot
andauthored
Merge on boarding module to login module (#4746)
* Move onboarding code to the login module. * Remove OnBoardingEntryPoint, move the flow to LoginFlowNode * Update screenshots --------- Co-authored-by: ElementBot <android@element.io>
1 parent fd4774d commit 150239b

File tree

91 files changed

+287
-512
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

91 files changed

+287
-512
lines changed

appnav/src/main/kotlin/io/element/android/appnav/NotLoggedInFlowNode.kt

Lines changed: 5 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -20,13 +20,10 @@ import com.bumble.appyx.core.node.Node
2020
import com.bumble.appyx.core.plugin.Plugin
2121
import com.bumble.appyx.core.plugin.plugins
2222
import com.bumble.appyx.navmodel.backstack.BackStack
23-
import com.bumble.appyx.navmodel.backstack.operation.push
2423
import dagger.assisted.Assisted
2524
import dagger.assisted.AssistedInject
2625
import io.element.android.anvilannotations.ContributesNode
2726
import io.element.android.features.login.api.LoginEntryPoint
28-
import io.element.android.features.login.api.LoginFlowType
29-
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
3027
import io.element.android.libraries.architecture.BackstackView
3128
import io.element.android.libraries.architecture.BaseFlowNode
3229
import io.element.android.libraries.designsystem.utils.ForceOrientationInMobileDevices
@@ -39,12 +36,11 @@ import kotlinx.parcelize.Parcelize
3936
class NotLoggedInFlowNode @AssistedInject constructor(
4037
@Assisted buildContext: BuildContext,
4138
@Assisted plugins: List<Plugin>,
42-
private val onBoardingEntryPoint: OnBoardingEntryPoint,
4339
private val loginEntryPoint: LoginEntryPoint,
4440
private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory,
4541
) : BaseFlowNode<NotLoggedInFlowNode.NavTarget>(
4642
backstack = BackStack(
47-
initialElement = NavTarget.OnBoarding,
43+
initialElement = NavTarget.Root,
4844
savedStateMap = buildContext.savedStateMap
4945
),
5046
buildContext = buildContext,
@@ -65,42 +61,22 @@ class NotLoggedInFlowNode @AssistedInject constructor(
6561

6662
sealed interface NavTarget : Parcelable {
6763
@Parcelize
68-
data object OnBoarding : NavTarget
69-
70-
@Parcelize
71-
data class LoginFlow(val type: LoginFlowType) : NavTarget
64+
data object Root : NavTarget
7265
}
7366

7467
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
7568
return when (navTarget) {
76-
NavTarget.OnBoarding -> {
77-
val callback = object : OnBoardingEntryPoint.Callback {
78-
override fun onSignUp() {
79-
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_UP))
80-
}
81-
82-
override fun onSignIn() {
83-
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_IN_MANUAL))
84-
}
85-
86-
override fun onSignInWithQrCode() {
87-
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_IN_QR_CODE))
88-
}
89-
69+
NavTarget.Root -> {
70+
val callback = object : LoginEntryPoint.Callback {
9071
override fun onReportProblem() {
9172
plugins<Callback>().forEach { it.onOpenBugReport() }
9273
}
9374
}
94-
onBoardingEntryPoint
75+
loginEntryPoint
9576
.nodeBuilder(this, buildContext)
9677
.callback(callback)
9778
.build()
9879
}
99-
is NavTarget.LoginFlow -> {
100-
loginEntryPoint.nodeBuilder(this, buildContext)
101-
.params(LoginEntryPoint.Params(flowType = navTarget.type))
102-
.build()
103-
}
10480
}
10581
}
10682

features/login/api/src/main/kotlin/io/element/android/features/login/api/LoginEntryPoint.kt

Lines changed: 5 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,20 @@
77

88
package io.element.android.features.login.api
99

10-
import android.os.Parcelable
1110
import com.bumble.appyx.core.modality.BuildContext
1211
import com.bumble.appyx.core.node.Node
12+
import com.bumble.appyx.core.plugin.Plugin
1313
import io.element.android.libraries.architecture.FeatureEntryPoint
14-
import kotlinx.parcelize.Parcelize
1514

1615
interface LoginEntryPoint : FeatureEntryPoint {
17-
data class Params(
18-
val flowType: LoginFlowType
19-
)
16+
interface Callback : Plugin {
17+
fun onReportProblem()
18+
}
2019

2120
fun nodeBuilder(parentNode: Node, buildContext: BuildContext): NodeBuilder
2221

2322
interface NodeBuilder {
24-
fun params(params: Params): NodeBuilder
23+
fun callback(callback: Callback): NodeBuilder
2524
fun build(): Node
2625
}
2726
}
28-
29-
@Parcelize
30-
enum class LoginFlowType : Parcelable {
31-
SIGN_IN_MANUAL,
32-
SIGN_IN_QR_CODE,
33-
SIGN_UP
34-
}

features/login/impl/build.gradle.kts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,9 +29,11 @@ setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP)
2929
dependencies {
3030
implementation(projects.appconfig)
3131
implementation(projects.features.enterprise.api)
32+
implementation(projects.features.rageshake.api)
3233
implementation(projects.libraries.core)
3334
implementation(projects.libraries.androidutils)
3435
implementation(projects.libraries.architecture)
36+
implementation(projects.libraries.featureflag.api)
3537
implementation(projects.libraries.matrix.api)
3638
implementation(projects.libraries.matrix.api)
3739
implementation(projects.libraries.network)
@@ -57,6 +59,7 @@ dependencies {
5759
testImplementation(libs.test.truth)
5860
testImplementation(libs.test.turbine)
5961
testImplementation(projects.features.enterprise.test)
62+
testImplementation(projects.libraries.featureflag.test)
6063
testImplementation(projects.libraries.matrix.test)
6164
testImplementation(projects.libraries.oidc.impl)
6265
testImplementation(projects.libraries.permissions.test)

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPoint.kt

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,8 +22,8 @@ class DefaultLoginEntryPoint @Inject constructor() : LoginEntryPoint {
2222
val plugins = ArrayList<Plugin>()
2323

2424
return object : LoginEntryPoint.NodeBuilder {
25-
override fun params(params: LoginEntryPoint.Params): LoginEntryPoint.NodeBuilder {
26-
plugins += LoginFlowNode.Inputs(flowType = params.flowType)
25+
override fun callback(callback: LoginEntryPoint.Callback): LoginEntryPoint.NodeBuilder {
26+
plugins += callback
2727
return this
2828
}
2929

features/login/impl/src/main/kotlin/io/element/android/features/login/impl/LoginFlowNode.kt

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -18,15 +18,17 @@ import com.bumble.appyx.core.lifecycle.subscribe
1818
import com.bumble.appyx.core.modality.BuildContext
1919
import com.bumble.appyx.core.node.Node
2020
import com.bumble.appyx.core.plugin.Plugin
21+
import com.bumble.appyx.core.plugin.plugins
2122
import com.bumble.appyx.navmodel.backstack.BackStack
2223
import com.bumble.appyx.navmodel.backstack.operation.push
2324
import com.bumble.appyx.navmodel.backstack.operation.singleTop
2425
import dagger.assisted.Assisted
2526
import dagger.assisted.AssistedInject
2627
import io.element.android.anvilannotations.ContributesNode
2728
import io.element.android.compound.theme.ElementTheme
28-
import io.element.android.features.login.api.LoginFlowType
29+
import io.element.android.features.login.api.LoginEntryPoint
2930
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
31+
import io.element.android.features.login.impl.onboarding.OnBoardingNode
3032
import io.element.android.features.login.impl.qrcode.QrCodeLoginFlowNode
3133
import io.element.android.features.login.impl.screens.changeaccountprovider.ChangeAccountProviderNode
3234
import io.element.android.features.login.impl.screens.confirmaccountprovider.ConfirmAccountProviderNode
@@ -35,9 +37,7 @@ import io.element.android.features.login.impl.screens.loginpassword.LoginPasswor
3537
import io.element.android.features.login.impl.screens.searchaccountprovider.SearchAccountProviderNode
3638
import io.element.android.libraries.architecture.BackstackView
3739
import io.element.android.libraries.architecture.BaseFlowNode
38-
import io.element.android.libraries.architecture.NodeInputs
3940
import io.element.android.libraries.architecture.createNode
40-
import io.element.android.libraries.architecture.inputs
4141
import io.element.android.libraries.di.AppScope
4242
import io.element.android.libraries.matrix.api.auth.OidcDetails
4343
import io.element.android.libraries.oidc.api.OidcAction
@@ -57,7 +57,7 @@ class LoginFlowNode @AssistedInject constructor(
5757
private val oidcEntryPoint: OidcEntryPoint,
5858
) : BaseFlowNode<LoginFlowNode.NavTarget>(
5959
backstack = BackStack(
60-
initialElement = NavTarget.Root,
60+
initialElement = NavTarget.OnBoarding,
6161
savedStateMap = buildContext.savedStateMap,
6262
),
6363
buildContext = buildContext,
@@ -66,12 +66,6 @@ class LoginFlowNode @AssistedInject constructor(
6666
private var activity: Activity? = null
6767
private var darkTheme: Boolean = false
6868

69-
data class Inputs(
70-
val flowType: LoginFlowType,
71-
) : NodeInputs
72-
73-
private val inputs: Inputs = inputs()
74-
7569
private var customChromeTabStarted = false
7670

7771
override fun onBuilt() {
@@ -96,10 +90,15 @@ class LoginFlowNode @AssistedInject constructor(
9690

9791
sealed interface NavTarget : Parcelable {
9892
@Parcelize
99-
data object Root : NavTarget
93+
data object OnBoarding : NavTarget
94+
95+
@Parcelize
96+
data object QrCode : NavTarget
10097

10198
@Parcelize
102-
data object ConfirmAccountProvider : NavTarget
99+
data class ConfirmAccountProvider(
100+
val isAccountCreation: Boolean,
101+
) : NavTarget
103102

104103
@Parcelize
105104
data object ChangeAccountProvider : NavTarget
@@ -119,16 +118,36 @@ class LoginFlowNode @AssistedInject constructor(
119118

120119
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
121120
return when (navTarget) {
122-
NavTarget.Root -> {
123-
if (inputs.flowType == LoginFlowType.SIGN_IN_QR_CODE) {
124-
createNode<QrCodeLoginFlowNode>(buildContext)
125-
} else {
126-
resolve(NavTarget.ConfirmAccountProvider, buildContext)
121+
NavTarget.OnBoarding -> {
122+
val callback = object : OnBoardingNode.Callback {
123+
override fun onSignUp() {
124+
backstack.push(
125+
NavTarget.ConfirmAccountProvider(isAccountCreation = true)
126+
)
127+
}
128+
129+
override fun onSignIn() {
130+
backstack.push(
131+
NavTarget.ConfirmAccountProvider(isAccountCreation = false)
132+
)
133+
}
134+
135+
override fun onSignInWithQrCode() {
136+
backstack.push(NavTarget.QrCode)
137+
}
138+
139+
override fun onReportProblem() {
140+
plugins<LoginEntryPoint.Callback>().forEach { it.onReportProblem() }
141+
}
127142
}
143+
createNode<OnBoardingNode>(buildContext, listOf(callback))
144+
}
145+
NavTarget.QrCode -> {
146+
createNode<QrCodeLoginFlowNode>(buildContext)
128147
}
129-
NavTarget.ConfirmAccountProvider -> {
148+
is NavTarget.ConfirmAccountProvider -> {
130149
val inputs = ConfirmAccountProviderNode.Inputs(
131-
isAccountCreation = inputs.flowType == LoginFlowType.SIGN_UP,
150+
isAccountCreation = navTarget.isAccountCreation,
132151
)
133152
val callback = object : ConfirmAccountProviderNode.Callback {
134153
override fun onOidcDetails(oidcDetails: OidcDetails) {
@@ -162,7 +181,10 @@ class LoginFlowNode @AssistedInject constructor(
162181
val callback = object : ChangeAccountProviderNode.Callback {
163182
override fun onDone() {
164183
// Go back to the Account Provider screen
165-
backstack.singleTop(NavTarget.ConfirmAccountProvider)
184+
val confirmAccountProvider = backstack.elements.value.firstOrNull {
185+
it.key.navTarget is NavTarget.ConfirmAccountProvider
186+
}?.key?.navTarget ?: NavTarget.ConfirmAccountProvider(isAccountCreation = false)
187+
backstack.singleTop(confirmAccountProvider)
166188
}
167189

168190
override fun onOtherClick() {
@@ -176,7 +198,10 @@ class LoginFlowNode @AssistedInject constructor(
176198
val callback = object : SearchAccountProviderNode.Callback {
177199
override fun onDone() {
178200
// Go back to the Account Provider screen
179-
backstack.singleTop(NavTarget.ConfirmAccountProvider)
201+
val confirmAccountProvider = backstack.elements.value.firstOrNull {
202+
it.key.navTarget is NavTarget.ConfirmAccountProvider
203+
}?.key?.navTarget ?: NavTarget.ConfirmAccountProvider(isAccountCreation = false)
204+
backstack.singleTop(confirmAccountProvider)
180205
}
181206
}
182207

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8-
package io.element.android.features.onboarding.impl
8+
package io.element.android.features.login.impl.onboarding
99

1010
import androidx.compose.runtime.Composable
1111
import androidx.compose.ui.Modifier
@@ -16,7 +16,6 @@ import com.bumble.appyx.core.plugin.plugins
1616
import dagger.assisted.Assisted
1717
import dagger.assisted.AssistedInject
1818
import io.element.android.anvilannotations.ContributesNode
19-
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
2019
import io.element.android.libraries.di.AppScope
2120

2221
@ContributesNode(AppScope::class)
@@ -28,20 +27,27 @@ class OnBoardingNode @AssistedInject constructor(
2827
buildContext = buildContext,
2928
plugins = plugins
3029
) {
30+
interface Callback : Plugin {
31+
fun onSignUp()
32+
fun onSignIn()
33+
fun onSignInWithQrCode()
34+
fun onReportProblem()
35+
}
36+
3137
private fun onSignIn() {
32-
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignIn() }
38+
plugins<Callback>().forEach { it.onSignIn() }
3339
}
3440

3541
private fun onSignUp() {
36-
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignUp() }
42+
plugins<Callback>().forEach { it.onSignUp() }
3743
}
3844

3945
private fun onSignInWithQrCode() {
40-
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignInWithQrCode() }
46+
plugins<Callback>().forEach { it.onSignInWithQrCode() }
4147
}
4248

4349
private fun onReportProblem() {
44-
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onReportProblem() }
50+
plugins<Callback>().forEach { it.onReportProblem() }
4551
}
4652

4753
@Composable
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8-
package io.element.android.features.onboarding.impl
8+
package io.element.android.features.login.impl.onboarding
99

1010
import androidx.compose.runtime.Composable
1111
import androidx.compose.runtime.getValue
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8-
package io.element.android.features.onboarding.impl
8+
package io.element.android.features.login.impl.onboarding
99

1010
data class OnBoardingState(
1111
val productionApplicationName: String,
Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8-
package io.element.android.features.onboarding.impl
8+
package io.element.android.features.login.impl.onboarding
99

1010
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
1111

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
* Please see LICENSE files in the repository root for full details.
66
*/
77

8-
package io.element.android.features.onboarding.impl
8+
package io.element.android.features.login.impl.onboarding
99

1010
import androidx.compose.foundation.clickable
1111
import androidx.compose.foundation.layout.Box
@@ -26,6 +26,7 @@ import androidx.compose.ui.unit.dp
2626
import androidx.compose.ui.unit.sp
2727
import io.element.android.compound.theme.ElementTheme
2828
import io.element.android.compound.tokens.generated.CompoundIcons
29+
import io.element.android.features.login.impl.R
2930
import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtom
3031
import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtomSize
3132
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule

features/login/impl/src/main/res/values-be/translations.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,12 @@
2929
<string name="screen_login_subtitle">"Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."</string>
3030
<string name="screen_login_title">"Сардэчна запрашаем!"</string>
3131
<string name="screen_login_title_with_homeserver">"Увайсці ў %1$s"</string>
32+
<string name="screen_onboarding_sign_in_manually">"Увайсці ўручную"</string>
33+
<string name="screen_onboarding_sign_in_with_qr_code">"Увайсці з QR-кодам"</string>
34+
<string name="screen_onboarding_sign_up">"Стварыць уліковы запіс"</string>
35+
<string name="screen_onboarding_welcome_message">"Сардэчна запрашаем у самы хуткі %1$s. Перавага ў хуткасці і прастаце."</string>
36+
<string name="screen_onboarding_welcome_subtitle">"Сардэчна запрашаем у %1$s. Зараджаны, для хуткасці і прастаты."</string>
37+
<string name="screen_onboarding_welcome_title">"Будзьце ў сваім element"</string>
3238
<string name="screen_qr_code_login_connecting_subtitle">"Ўсталяванне бяспечнага злучэння"</string>
3339
<string name="screen_qr_code_login_connection_note_secure_state_description">"Не атрымалася ўсталяваць бяспечнае злучэнне з новай прыладай. Існуючыя прылады па-ранейшаму ў бяспецы, і вам не трэба турбавацца пра іх."</string>
3440
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Што зараз?"</string>

features/login/impl/src/main/res/values-bg/translations.xml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,12 @@
1919
<string name="screen_login_subtitle">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string>
2020
<string name="screen_login_title">"Добре дошли отново!"</string>
2121
<string name="screen_login_title_with_homeserver">"Влизане в %1$s"</string>
22+
<string name="screen_onboarding_sign_in_manually">"Влизане ръчно"</string>
23+
<string name="screen_onboarding_sign_in_with_qr_code">"Влизане с QR код"</string>
24+
<string name="screen_onboarding_sign_up">"Създаване на акаунт"</string>
25+
<string name="screen_onboarding_welcome_message">"Добре дошли в най-бързия %1$s досега. Супер зареден за скорост и простота."</string>
26+
<string name="screen_onboarding_welcome_subtitle">"Добре дошли в %1$s. Супер зареден за скорост и простота."</string>
27+
<string name="screen_onboarding_welcome_title">"Бъдете в стихията си"</string>
2228
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Повторен опит"</string>
2329
<string name="screen_server_confirmation_change_server">"Промяна на доставчика на акаунт"</string>
2430
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string>

0 commit comments

Comments
 (0)