Skip to content

Merge on boarding module to login module #4746

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
May 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -20,13 +20,10 @@ import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.push
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.login.api.LoginEntryPoint
import io.element.android.features.login.api.LoginFlowType
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.designsystem.utils.ForceOrientationInMobileDevices
Expand All @@ -39,12 +36,11 @@ import kotlinx.parcelize.Parcelize
class NotLoggedInFlowNode @AssistedInject constructor(
@Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>,
private val onBoardingEntryPoint: OnBoardingEntryPoint,
private val loginEntryPoint: LoginEntryPoint,
private val notLoggedInImageLoaderFactory: NotLoggedInImageLoaderFactory,
) : BaseFlowNode<NotLoggedInFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.OnBoarding,
initialElement = NavTarget.Root,
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This node could be simplified more, since there is no need for a backstack anymore, but it can stay like this.

savedStateMap = buildContext.savedStateMap
),
buildContext = buildContext,
Expand All @@ -65,42 +61,22 @@ class NotLoggedInFlowNode @AssistedInject constructor(

sealed interface NavTarget : Parcelable {
@Parcelize
data object OnBoarding : NavTarget

@Parcelize
data class LoginFlow(val type: LoginFlowType) : NavTarget
data object Root : NavTarget
}

override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) {
NavTarget.OnBoarding -> {
val callback = object : OnBoardingEntryPoint.Callback {
override fun onSignUp() {
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_UP))
}

override fun onSignIn() {
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_IN_MANUAL))
}

override fun onSignInWithQrCode() {
backstack.push(NavTarget.LoginFlow(type = LoginFlowType.SIGN_IN_QR_CODE))
}

NavTarget.Root -> {
val callback = object : LoginEntryPoint.Callback {
override fun onReportProblem() {
plugins<Callback>().forEach { it.onOpenBugReport() }
}
}
onBoardingEntryPoint
loginEntryPoint
.nodeBuilder(this, buildContext)
.callback(callback)
.build()
}
is NavTarget.LoginFlow -> {
loginEntryPoint.nodeBuilder(this, buildContext)
.params(LoginEntryPoint.Params(flowType = navTarget.type))
.build()
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,28 +7,20 @@

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

import android.os.Parcelable
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import io.element.android.libraries.architecture.FeatureEntryPoint
import kotlinx.parcelize.Parcelize

interface LoginEntryPoint : FeatureEntryPoint {
data class Params(
val flowType: LoginFlowType
)
interface Callback : Plugin {
fun onReportProblem()
}

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

interface NodeBuilder {
fun params(params: Params): NodeBuilder
fun callback(callback: Callback): NodeBuilder
fun build(): Node
}
}

@Parcelize
enum class LoginFlowType : Parcelable {
SIGN_IN_MANUAL,
SIGN_IN_QR_CODE,
SIGN_UP
}
3 changes: 3 additions & 0 deletions features/login/impl/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -29,9 +29,11 @@ setupAnvil(componentMergingStrategy = ComponentMergingStrategy.KSP)
dependencies {
implementation(projects.appconfig)
implementation(projects.features.enterprise.api)
implementation(projects.features.rageshake.api)
implementation(projects.libraries.core)
implementation(projects.libraries.androidutils)
implementation(projects.libraries.architecture)
implementation(projects.libraries.featureflag.api)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.matrix.api)
implementation(projects.libraries.network)
Expand All @@ -57,6 +59,7 @@ dependencies {
testImplementation(libs.test.truth)
testImplementation(libs.test.turbine)
testImplementation(projects.features.enterprise.test)
testImplementation(projects.libraries.featureflag.test)
testImplementation(projects.libraries.matrix.test)
testImplementation(projects.libraries.oidc.impl)
testImplementation(projects.libraries.permissions.test)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -22,8 +22,8 @@
val plugins = ArrayList<Plugin>()

return object : LoginEntryPoint.NodeBuilder {
override fun params(params: LoginEntryPoint.Params): LoginEntryPoint.NodeBuilder {
plugins += LoginFlowNode.Inputs(flowType = params.flowType)
override fun callback(callback: LoginEntryPoint.Callback): LoginEntryPoint.NodeBuilder {
plugins += callback

Check warning on line 26 in features/login/impl/src/main/kotlin/io/element/android/features/login/impl/DefaultLoginEntryPoint.kt

View check run for this annotation

Codecov / codecov/patch

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

Added line #L26 was not covered by tests
return this
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,15 +18,17 @@ import com.bumble.appyx.core.lifecycle.subscribe
import com.bumble.appyx.core.modality.BuildContext
import com.bumble.appyx.core.node.Node
import com.bumble.appyx.core.plugin.Plugin
import com.bumble.appyx.core.plugin.plugins
import com.bumble.appyx.navmodel.backstack.BackStack
import com.bumble.appyx.navmodel.backstack.operation.push
import com.bumble.appyx.navmodel.backstack.operation.singleTop
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.compound.theme.ElementTheme
import io.element.android.features.login.api.LoginFlowType
import io.element.android.features.login.api.LoginEntryPoint
import io.element.android.features.login.impl.accountprovider.AccountProviderDataSource
import io.element.android.features.login.impl.onboarding.OnBoardingNode
import io.element.android.features.login.impl.qrcode.QrCodeLoginFlowNode
import io.element.android.features.login.impl.screens.changeaccountprovider.ChangeAccountProviderNode
import io.element.android.features.login.impl.screens.confirmaccountprovider.ConfirmAccountProviderNode
Expand All @@ -35,9 +37,7 @@ import io.element.android.features.login.impl.screens.loginpassword.LoginPasswor
import io.element.android.features.login.impl.screens.searchaccountprovider.SearchAccountProviderNode
import io.element.android.libraries.architecture.BackstackView
import io.element.android.libraries.architecture.BaseFlowNode
import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.auth.OidcDetails
import io.element.android.libraries.oidc.api.OidcAction
Expand All @@ -57,7 +57,7 @@ class LoginFlowNode @AssistedInject constructor(
private val oidcEntryPoint: OidcEntryPoint,
) : BaseFlowNode<LoginFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.Root,
initialElement = NavTarget.OnBoarding,
savedStateMap = buildContext.savedStateMap,
),
buildContext = buildContext,
Expand All @@ -66,12 +66,6 @@ class LoginFlowNode @AssistedInject constructor(
private var activity: Activity? = null
private var darkTheme: Boolean = false

data class Inputs(
val flowType: LoginFlowType,
) : NodeInputs

private val inputs: Inputs = inputs()

private var customChromeTabStarted = false

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

sealed interface NavTarget : Parcelable {
@Parcelize
data object Root : NavTarget
data object OnBoarding : NavTarget

@Parcelize
data object QrCode : NavTarget

@Parcelize
data object ConfirmAccountProvider : NavTarget
data class ConfirmAccountProvider(
val isAccountCreation: Boolean,
) : NavTarget

@Parcelize
data object ChangeAccountProvider : NavTarget
Expand All @@ -119,16 +118,36 @@ class LoginFlowNode @AssistedInject constructor(

override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
return when (navTarget) {
NavTarget.Root -> {
if (inputs.flowType == LoginFlowType.SIGN_IN_QR_CODE) {
createNode<QrCodeLoginFlowNode>(buildContext)
} else {
resolve(NavTarget.ConfirmAccountProvider, buildContext)
NavTarget.OnBoarding -> {
val callback = object : OnBoardingNode.Callback {
override fun onSignUp() {
backstack.push(
NavTarget.ConfirmAccountProvider(isAccountCreation = true)
)
}

override fun onSignIn() {
backstack.push(
NavTarget.ConfirmAccountProvider(isAccountCreation = false)
)
}

override fun onSignInWithQrCode() {
backstack.push(NavTarget.QrCode)
}

override fun onReportProblem() {
plugins<LoginEntryPoint.Callback>().forEach { it.onReportProblem() }
}
}
createNode<OnBoardingNode>(buildContext, listOf(callback))
}
NavTarget.QrCode -> {
createNode<QrCodeLoginFlowNode>(buildContext)
}
NavTarget.ConfirmAccountProvider -> {
is NavTarget.ConfirmAccountProvider -> {
val inputs = ConfirmAccountProviderNode.Inputs(
isAccountCreation = inputs.flowType == LoginFlowType.SIGN_UP,
isAccountCreation = navTarget.isAccountCreation,
)
val callback = object : ConfirmAccountProviderNode.Callback {
override fun onOidcDetails(oidcDetails: OidcDetails) {
Expand Down Expand Up @@ -162,7 +181,10 @@ class LoginFlowNode @AssistedInject constructor(
val callback = object : ChangeAccountProviderNode.Callback {
override fun onDone() {
// Go back to the Account Provider screen
backstack.singleTop(NavTarget.ConfirmAccountProvider)
val confirmAccountProvider = backstack.elements.value.firstOrNull {
it.key.navTarget is NavTarget.ConfirmAccountProvider
}?.key?.navTarget ?: NavTarget.ConfirmAccountProvider(isAccountCreation = false)
backstack.singleTop(confirmAccountProvider)
}

override fun onOtherClick() {
Expand All @@ -176,7 +198,10 @@ class LoginFlowNode @AssistedInject constructor(
val callback = object : SearchAccountProviderNode.Callback {
override fun onDone() {
// Go back to the Account Provider screen
backstack.singleTop(NavTarget.ConfirmAccountProvider)
val confirmAccountProvider = backstack.elements.value.firstOrNull {
it.key.navTarget is NavTarget.ConfirmAccountProvider
}?.key?.navTarget ?: NavTarget.ConfirmAccountProvider(isAccountCreation = false)
backstack.singleTop(confirmAccountProvider)
Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

There is maybe a better way to do this, but it works...

}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.onboarding.impl
package io.element.android.features.login.impl.onboarding

import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
Expand All @@ -16,7 +16,6 @@ import com.bumble.appyx.core.plugin.plugins
import dagger.assisted.Assisted
import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
import io.element.android.libraries.di.AppScope

@ContributesNode(AppScope::class)
Expand All @@ -28,20 +27,27 @@ class OnBoardingNode @AssistedInject constructor(
buildContext = buildContext,
plugins = plugins
) {
interface Callback : Plugin {
fun onSignUp()
fun onSignIn()
fun onSignInWithQrCode()
fun onReportProblem()
}

private fun onSignIn() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignIn() }
plugins<Callback>().forEach { it.onSignIn() }
}

private fun onSignUp() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignUp() }
plugins<Callback>().forEach { it.onSignUp() }
}

private fun onSignInWithQrCode() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignInWithQrCode() }
plugins<Callback>().forEach { it.onSignInWithQrCode() }
}

private fun onReportProblem() {
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onReportProblem() }
plugins<Callback>().forEach { it.onReportProblem() }
}

@Composable
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.onboarding.impl
package io.element.android.features.login.impl.onboarding

import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.onboarding.impl
package io.element.android.features.login.impl.onboarding

data class OnBoardingState(
val productionApplicationName: String,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.onboarding.impl
package io.element.android.features.login.impl.onboarding

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
* Please see LICENSE files in the repository root for full details.
*/

package io.element.android.features.onboarding.impl
package io.element.android.features.login.impl.onboarding

import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Box
Expand All @@ -26,6 +26,7 @@ import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.login.impl.R
import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtom
import io.element.android.libraries.designsystem.atomic.atoms.ElementLogoAtomSize
import io.element.android.libraries.designsystem.atomic.molecules.ButtonColumnMolecule
Expand Down
6 changes: 6 additions & 0 deletions features/login/impl/src/main/res/values-be/translations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,12 @@
<string name="screen_login_subtitle">"Matrix - гэта адкрытая сетка для бяспечнай, дэцэнтралізаванай сувязі."</string>
<string name="screen_login_title">"Сардэчна запрашаем!"</string>
<string name="screen_login_title_with_homeserver">"Увайсці ў %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Увайсці ўручную"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Увайсці з QR-кодам"</string>
<string name="screen_onboarding_sign_up">"Стварыць уліковы запіс"</string>
<string name="screen_onboarding_welcome_message">"Сардэчна запрашаем у самы хуткі %1$s. Перавага ў хуткасці і прастаце."</string>
<string name="screen_onboarding_welcome_subtitle">"Сардэчна запрашаем у %1$s. Зараджаны, для хуткасці і прастаты."</string>
<string name="screen_onboarding_welcome_title">"Будзьце ў сваім element"</string>
<string name="screen_qr_code_login_connecting_subtitle">"Ўсталяванне бяспечнага злучэння"</string>
<string name="screen_qr_code_login_connection_note_secure_state_description">"Не атрымалася ўсталяваць бяспечнае злучэнне з новай прыладай. Існуючыя прылады па-ранейшаму ў бяспецы, і вам не трэба турбавацца пра іх."</string>
<string name="screen_qr_code_login_connection_note_secure_state_list_header">"Што зараз?"</string>
Expand Down
6 changes: 6 additions & 0 deletions features/login/impl/src/main/res/values-bg/translations.xml
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,12 @@
<string name="screen_login_subtitle">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string>
<string name="screen_login_title">"Добре дошли отново!"</string>
<string name="screen_login_title_with_homeserver">"Влизане в %1$s"</string>
<string name="screen_onboarding_sign_in_manually">"Влизане ръчно"</string>
<string name="screen_onboarding_sign_in_with_qr_code">"Влизане с QR код"</string>
<string name="screen_onboarding_sign_up">"Създаване на акаунт"</string>
<string name="screen_onboarding_welcome_message">"Добре дошли в най-бързия %1$s досега. Супер зареден за скорост и простота."</string>
<string name="screen_onboarding_welcome_subtitle">"Добре дошли в %1$s. Супер зареден за скорост и простота."</string>
<string name="screen_onboarding_welcome_title">"Бъдете в стихията си"</string>
<string name="screen_qr_code_login_invalid_scan_state_retry_button">"Повторен опит"</string>
<string name="screen_server_confirmation_change_server">"Промяна на доставчика на акаунт"</string>
<string name="screen_server_confirmation_message_login_matrix_dot_org">"Matrix е отворена мрежа за сигурна, децентрализирана комуникация."</string>
Expand Down
Loading
Loading