Ensure a Callback and only one is provided in the Plugin. Also reduce boilerplate code in Nodes.

This commit is contained in:
Benoit Marty 2025-10-30 09:14:41 +01:00 committed by Benoit Marty
parent 2e8785b36b
commit be03c50aaf
76 changed files with 374 additions and 741 deletions

View file

@ -18,7 +18,6 @@ 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
@ -41,6 +40,7 @@ import io.element.android.libraries.androidutils.browser.openUrlInChromeCustomTa
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.callback
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.matrix.api.auth.OidcDetails
@ -70,6 +70,7 @@ class LoginFlowNode(
val loginHint: String?,
) : NodeInputs
private val callback: LoginEntryPoint.Callback = callback()
private var activity: Activity? = null
private var darkTheme: Boolean = false
@ -147,7 +148,7 @@ class LoginFlowNode(
}
override fun navigateToBugReport() {
plugins<LoginEntryPoint.Callback>().forEach { it.navigateToBugReport() }
callback.navigateToBugReport()
}
override fun navigateToOidc(oidcDetails: OidcDetails) {

View file

@ -13,12 +13,12 @@ import androidx.compose.ui.platform.LocalContext
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 dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.util.openLearnMorePage
import io.element.android.libraries.architecture.callback
@ContributesNode(AppScope::class)
@AssistedInject
@ -32,13 +32,7 @@ class ChangeAccountProviderNode(
fun navigateToSearchAccountProvider()
}
private fun onDone() {
plugins<Callback>().forEach { it.onDone() }
}
private fun onOtherClick() {
plugins<Callback>().forEach { it.navigateToSearchAccountProvider() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
@ -49,8 +43,8 @@ class ChangeAccountProviderNode(
modifier = modifier,
onBackClick = ::navigateUp,
onLearnMoreClick = { openLearnMorePage(context) },
onSuccess = ::onDone,
onOtherProviderClick = ::onOtherClick,
onSuccess = callback::onDone,
onOtherProviderClick = callback::navigateToSearchAccountProvider,
)
}
}

View file

@ -13,12 +13,12 @@ import androidx.compose.ui.platform.LocalContext
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 dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.util.openLearnMorePage
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.matrix.api.auth.OidcDetails
@ContributesNode(AppScope::class)
@ -34,17 +34,7 @@ class ChooseAccountProviderNode(
fun navigateToCreateAccount(url: String)
}
private fun onOidcDetails(oidcDetails: OidcDetails) {
plugins<Callback>().forEach { it.navigateToOidc(oidcDetails) }
}
private fun onLoginPasswordNeeded() {
plugins<Callback>().forEach { it.navigateToLoginPassword() }
}
private fun onCreateAccountContinue(url: String) {
plugins<Callback>().forEach { it.navigateToCreateAccount(url) }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
@ -54,10 +44,10 @@ class ChooseAccountProviderNode(
state = state,
modifier = modifier,
onBackClick = ::navigateUp,
onOidcDetails = ::onOidcDetails,
onNeedLoginPassword = ::onLoginPasswordNeeded,
onOidcDetails = callback::navigateToOidc,
onNeedLoginPassword = callback::navigateToLoginPassword,
onLearnMoreClick = { openLearnMorePage(context) },
onCreateAccountContinue = ::onCreateAccountContinue,
onCreateAccountContinue = callback::navigateToCreateAccount,
)
}
}

View file

@ -13,13 +13,13 @@ import androidx.compose.ui.platform.LocalContext
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 dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.util.openLearnMorePage
import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.matrix.api.auth.OidcDetails
@ -48,21 +48,7 @@ class ConfirmAccountProviderNode(
fun navigateToChangeAccountProvider()
}
private fun onOidcDetails(data: OidcDetails) {
plugins<Callback>().forEach { it.navigateToOidc(data) }
}
private fun onLoginPasswordNeeded() {
plugins<Callback>().forEach { it.navigateToLoginPassword() }
}
private fun onCreateAccountContinue(url: String) {
plugins<Callback>().forEach { it.navigateToCreateAccount(url) }
}
private fun onChangeAccountProvider() {
plugins<Callback>().forEach { it.navigateToChangeAccountProvider() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
@ -71,10 +57,10 @@ class ConfirmAccountProviderNode(
ConfirmAccountProviderView(
state = state,
modifier = modifier,
onOidcDetails = ::onOidcDetails,
onNeedLoginPassword = ::onLoginPasswordNeeded,
onCreateAccountContinue = ::onCreateAccountContinue,
onChange = ::onChangeAccountProvider,
onOidcDetails = callback::navigateToOidc,
onNeedLoginPassword = callback::navigateToLoginPassword,
onCreateAccountContinue = callback::navigateToCreateAccount,
onChange = callback::navigateToChangeAccountProvider,
onLearnMoreClick = { openLearnMorePage(context) },
)
}

View file

@ -13,13 +13,13 @@ import androidx.compose.ui.platform.LocalContext
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 dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.util.openLearnMorePage
import io.element.android.libraries.architecture.NodeInputs
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.matrix.api.auth.OidcDetails
@ -48,40 +48,13 @@ class OnBoardingNode(
val loginHint: String?,
) : NodeInputs
private val callback: Callback = callback()
private val params = inputs<Params>()
private val presenter = presenterFactory.create(
params = params,
)
private fun onSignIn(mustChooseAccountProvider: Boolean) {
plugins<Callback>().forEach { it.navigateToSignInFlow(mustChooseAccountProvider) }
}
private fun onSignUp() {
plugins<Callback>().forEach { it.navigateToSignUpFlow() }
}
private fun onSignInWithQrCode() {
plugins<Callback>().forEach { it.navigateToQrCode() }
}
private fun onReportProblem() {
plugins<Callback>().forEach { it.navigateToBugReport() }
}
private fun onOidcDetails(data: OidcDetails) {
plugins<Callback>().forEach { it.navigateToOidc(data) }
}
private fun onLoginPasswordNeeded() {
plugins<Callback>().forEach { it.navigateToLoginPassword() }
}
private fun onCreateAccountContinue(url: String) {
plugins<Callback>().forEach { it.navigateToCreateAccount(url) }
}
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
@ -89,14 +62,14 @@ class OnBoardingNode(
OnBoardingView(
state = state,
modifier = modifier,
onSignIn = ::onSignIn,
onCreateAccount = ::onSignUp,
onSignInWithQrCode = ::onSignInWithQrCode,
onReportProblem = ::onReportProblem,
onOidcDetails = ::onOidcDetails,
onNeedLoginPassword = ::onLoginPasswordNeeded,
onSignIn = callback::navigateToSignInFlow,
onCreateAccount = callback::navigateToSignUpFlow,
onSignInWithQrCode = callback::navigateToQrCode,
onReportProblem = callback::navigateToBugReport,
onOidcDetails = callback::navigateToOidc,
onNeedLoginPassword = callback::navigateToLoginPassword,
onLearnMoreClick = { openLearnMorePage(context) },
onCreateAccountContinue = ::onCreateAccountContinue,
onCreateAccountContinue = callback::navigateToCreateAccount,
onBackClick = ::navigateUp,
)
}

View file

@ -12,11 +12,11 @@ import androidx.compose.ui.Modifier
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 dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.di.QrCodeLoginScope
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.architecture.inputs
@ContributesNode(QrCodeLoginScope::class)
@ -29,17 +29,14 @@ class QrCodeConfirmationNode(
fun onCancel()
}
private val callback: Callback = callback()
private val step = inputs<QrCodeConfirmationStep>()
private fun onCancel() {
plugins<Callback>().forEach { it.onCancel() }
}
@Composable
override fun View(modifier: Modifier) {
QrCodeConfirmationView(
step = step,
onCancel = ::onCancel,
onCancel = callback::onCancel,
)
}
}

View file

@ -12,12 +12,12 @@ import androidx.compose.ui.Modifier
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 dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.di.QrCodeLoginScope
import io.element.android.features.login.impl.qrcode.QrCodeErrorScreenType
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.core.meta.BuildMeta
@ -32,10 +32,7 @@ class QrCodeErrorNode(
fun onRetry()
}
private fun onRetry() {
plugins<Callback>().forEach { it.onRetry() }
}
private val callback: Callback = callback()
private val qrCodeErrorScreenType = inputs<QrCodeErrorScreenType>()
@Composable
@ -44,7 +41,7 @@ class QrCodeErrorNode(
modifier = modifier,
errorScreenType = qrCodeErrorScreenType,
appName = buildMeta.productionApplicationName,
onRetry = ::onRetry,
onRetry = callback::onRetry,
)
}
}

View file

@ -12,11 +12,11 @@ import androidx.compose.ui.Modifier
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 dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.di.QrCodeLoginScope
import io.element.android.libraries.architecture.callback
@ContributesNode(QrCodeLoginScope::class)
@AssistedInject
@ -30,21 +30,15 @@ class QrCodeIntroNode(
fun navigateToQrCodeScan()
}
private fun onCancelClicked() {
plugins<Callback>().forEach { it.cancel() }
}
private fun onContinue() {
plugins<Callback>().forEach { it.navigateToQrCodeScan() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
QrCodeIntroView(
state = state,
onBackClick = ::onCancelClicked,
onContinue = ::onContinue,
onBackClick = callback::cancel,
onContinue = callback::navigateToQrCodeScan,
modifier = modifier
)
}

View file

@ -12,11 +12,11 @@ import androidx.compose.ui.Modifier
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 dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.di.QrCodeLoginScope
import io.element.android.libraries.architecture.callback
import io.element.android.libraries.matrix.api.auth.qrlogin.MatrixQrCodeLoginData
@ContributesNode(QrCodeLoginScope::class)
@ -31,21 +31,15 @@ class QrCodeScanNode(
fun cancel()
}
private fun onQrCodeDataReady(qrCodeLoginData: MatrixQrCodeLoginData) {
plugins<Callback>().forEach { it.handleScannedCode(qrCodeLoginData) }
}
private fun onCancelClicked() {
plugins<Callback>().forEach { it.cancel() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
val state = presenter.present()
QrCodeScanView(
state = state,
onQrCodeDataReady = ::onQrCodeDataReady,
onBackClick = ::onCancelClicked,
onQrCodeDataReady = callback::handleScannedCode,
onBackClick = callback::cancel,
modifier = modifier
)
}

View file

@ -13,12 +13,12 @@ import androidx.compose.ui.platform.LocalContext
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 dev.zacsweers.metro.AppScope
import dev.zacsweers.metro.Assisted
import dev.zacsweers.metro.AssistedInject
import io.element.android.annotations.ContributesNode
import io.element.android.features.login.impl.util.openLearnMorePage
import io.element.android.libraries.architecture.callback
@ContributesNode(AppScope::class)
@AssistedInject
@ -31,9 +31,7 @@ class SearchAccountProviderNode(
fun onDone()
}
private fun onDone() {
plugins<Callback>().forEach { it.onDone() }
}
private val callback: Callback = callback()
@Composable
override fun View(modifier: Modifier) {
@ -44,7 +42,7 @@ class SearchAccountProviderNode(
modifier = modifier,
onBackClick = ::navigateUp,
onLearnMoreClick = { openLearnMorePage(context) },
onSuccess = ::onDone,
onSuccess = callback::onDone,
)
}
}