[Architecture] Introduce EntryPoint and use createNode for ParentNode too
This commit is contained in:
parent
1ec629c304
commit
da92113e43
54 changed files with 674 additions and 164 deletions
|
|
@ -26,8 +26,8 @@ import androidx.core.view.WindowCompat
|
|||
import com.bumble.appyx.core.integration.NodeHost
|
||||
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.designsystem.theme.ElementTheme
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.x.di.AppBindings
|
||||
import io.element.android.x.node.RootFlowNode
|
||||
|
||||
|
|
@ -45,13 +45,7 @@ class MainActivity : NodeComponentActivity() {
|
|||
modifier = Modifier.fillMaxSize(),
|
||||
) {
|
||||
NodeHost(integrationPoint = appyxIntegrationPoint) {
|
||||
RootFlowNode(
|
||||
buildContext = it,
|
||||
appComponentOwner = applicationContext as DaggerComponentOwner,
|
||||
authenticationService = appBindings.authenticationService(),
|
||||
presenter = appBindings.rootPresenter(),
|
||||
matrixClientsHolder = appBindings.matrixClientsHolder()
|
||||
)
|
||||
createNode<RootFlowNode>(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,38 +29,69 @@ import com.bumble.appyx.core.modality.BuildContext
|
|||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.node.ParentNode
|
||||
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.preferences.PreferencesFlowNode
|
||||
import io.element.android.features.roomlist.RoomListNode
|
||||
import io.element.android.features.roomlist.api.RoomListEntryPoint
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.architecture.nodeInputs
|
||||
import io.element.android.libraries.architecture.nodeInputsProvider
|
||||
import io.element.android.libraries.designsystem.theme.components.Text
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.matrix.MatrixClient
|
||||
import io.element.android.libraries.matrix.core.RoomId
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
import io.element.android.libraries.matrix.ui.di.MatrixUIBindings
|
||||
import io.element.android.x.di.SessionComponent
|
||||
import kotlinx.parcelize.Parcelize
|
||||
|
||||
@ContributesNode(AppScope::class)
|
||||
class LoggedInFlowNode(
|
||||
buildContext: BuildContext,
|
||||
val sessionId: SessionId,
|
||||
private val matrixClient: MatrixClient,
|
||||
private val onOpenBugReport: () -> Unit,
|
||||
private val backstack: BackStack<NavTarget> = BackStack(
|
||||
initialElement = NavTarget.RoomList,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
plugins: List<Plugin>,
|
||||
private val backstack: BackStack<NavTarget>,
|
||||
private val roomListEntryPoint: RoomListEntryPoint,
|
||||
) : ParentNode<LoggedInFlowNode.NavTarget>(
|
||||
navModel = backstack,
|
||||
buildContext = buildContext
|
||||
buildContext = buildContext,
|
||||
plugins = plugins
|
||||
), DaggerComponentOwner {
|
||||
|
||||
@AssistedInject
|
||||
constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
roomListEntryPoint: RoomListEntryPoint,
|
||||
) : this(
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
roomListEntryPoint = roomListEntryPoint,
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.RoomList,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
)
|
||||
)
|
||||
|
||||
interface Callback : Plugin {
|
||||
fun onOpenBugReport()
|
||||
}
|
||||
|
||||
data class Inputs(
|
||||
val matrixClient: MatrixClient
|
||||
) : NodeInputs
|
||||
|
||||
private val inputs: Inputs by nodeInputs()
|
||||
|
||||
override val daggerComponent: Any by lazy {
|
||||
parent!!.bindings<SessionComponent.ParentBindings>().sessionComponentBuilder().client(matrixClient).build()
|
||||
parent!!.bindings<SessionComponent.ParentBindings>().sessionComponentBuilder().client(inputs.matrixClient).build()
|
||||
}
|
||||
|
||||
override fun onBuilt() {
|
||||
|
|
@ -69,7 +100,7 @@ class LoggedInFlowNode(
|
|||
onCreate = {
|
||||
val imageLoaderFactory = bindings<MatrixUIBindings>().loggedInImageLoaderFactory()
|
||||
Coil.setImageLoader(imageLoaderFactory)
|
||||
matrixClient.startSync()
|
||||
inputs.matrixClient.startSync()
|
||||
},
|
||||
onDestroy = {
|
||||
val imageLoaderFactory = bindings<MatrixUIBindings>().notLoggedInImageLoaderFactory()
|
||||
|
|
@ -78,16 +109,6 @@ class LoggedInFlowNode(
|
|||
)
|
||||
}
|
||||
|
||||
private val roomListCallback = object : RoomListNode.Callback {
|
||||
override fun onRoomClicked(roomId: RoomId) {
|
||||
backstack.push(NavTarget.Room(roomId))
|
||||
}
|
||||
|
||||
override fun onSettingsClicked() {
|
||||
backstack.push(NavTarget.Settings)
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface NavTarget : Parcelable {
|
||||
@Parcelize
|
||||
object RoomList : NavTarget
|
||||
|
|
@ -102,10 +123,19 @@ class LoggedInFlowNode(
|
|||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.RoomList -> {
|
||||
createNode<RoomListNode>(buildContext, plugins = listOf(roomListCallback))
|
||||
val callback = object : RoomListEntryPoint.Callback {
|
||||
override fun onRoomClicked(roomId: RoomId) {
|
||||
backstack.push(NavTarget.Room(roomId))
|
||||
}
|
||||
|
||||
override fun onSettingsClicked() {
|
||||
backstack.push(NavTarget.Settings)
|
||||
}
|
||||
}
|
||||
roomListEntryPoint.node(this, buildContext, plugins = listOf(callback))
|
||||
}
|
||||
is NavTarget.Room -> {
|
||||
val room = matrixClient.getRoom(roomId = navTarget.roomId)
|
||||
val room = inputs.matrixClient.getRoom(roomId = navTarget.roomId)
|
||||
if (room == null) {
|
||||
// TODO CREATE UNKNOWN ROOM NODE
|
||||
node(buildContext) {
|
||||
|
|
@ -114,11 +144,17 @@ class LoggedInFlowNode(
|
|||
}
|
||||
}
|
||||
} else {
|
||||
RoomFlowNode(buildContext, room)
|
||||
val inputsProvider = nodeInputsProvider(RoomFlowNode.Inputs(room))
|
||||
createNode<RoomFlowNode>(buildContext, plugins = listOf(inputsProvider))
|
||||
}
|
||||
}
|
||||
NavTarget.Settings -> {
|
||||
PreferencesFlowNode(buildContext, onOpenBugReport)
|
||||
val callback = object : PreferencesFlowNode.Callback {
|
||||
override fun onOpenBugReport() {
|
||||
plugins<Callback>().forEach { it.onOpenBugReport() }
|
||||
}
|
||||
}
|
||||
createNode<PreferencesFlowNode>(buildContext, plugins = listOf(callback))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,25 +24,45 @@ 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.node.ParentNode
|
||||
import com.bumble.appyx.core.node.node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import io.element.android.features.login.LoginFlowNode
|
||||
import io.element.android.features.onboarding.OnBoardingScreen
|
||||
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.onboarding.api.OnBoardingEntryPoint
|
||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
class NotLoggedInFlowNode(
|
||||
@ContributesNode(AppScope::class)
|
||||
class NotLoggedInFlowNode private constructor(
|
||||
buildContext: BuildContext,
|
||||
private val backstack: BackStack<NavTarget> = BackStack(
|
||||
initialElement = NavTarget.OnBoarding,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
plugins: List<Plugin>,
|
||||
private val onBoardingEntryPoint: OnBoardingEntryPoint,
|
||||
private val loginEntryPoint: LoginEntryPoint,
|
||||
private val backstack: BackStack<NavTarget>,
|
||||
) : ParentNode<NotLoggedInFlowNode.NavTarget>(
|
||||
navModel = backstack,
|
||||
buildContext = buildContext
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
) {
|
||||
@AssistedInject
|
||||
constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
onBoardingEntryPoint: OnBoardingEntryPoint,
|
||||
loginEntryPoint: LoginEntryPoint,
|
||||
)
|
||||
: this(
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
onBoardingEntryPoint = onBoardingEntryPoint,
|
||||
loginEntryPoint = loginEntryPoint,
|
||||
backstack = BackStack(initialElement = NavTarget.OnBoarding, savedStateMap = buildContext.savedStateMap),
|
||||
)
|
||||
|
||||
init {
|
||||
lifecycle.subscribe(
|
||||
|
|
@ -61,12 +81,21 @@ class NotLoggedInFlowNode(
|
|||
|
||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||
return when (navTarget) {
|
||||
NavTarget.OnBoarding -> node(buildContext) {
|
||||
OnBoardingScreen(
|
||||
onSignIn = { backstack.push(NavTarget.LoginFlow) }
|
||||
)
|
||||
NavTarget.OnBoarding -> {
|
||||
val callback = object : OnBoardingEntryPoint.Callback {
|
||||
override fun onSignUp() {
|
||||
//NOOP
|
||||
}
|
||||
|
||||
override fun onSignIn() {
|
||||
backstack.push(NavTarget.LoginFlow)
|
||||
}
|
||||
}
|
||||
onBoardingEntryPoint.node(this, buildContext, plugins = listOf(callback))
|
||||
}
|
||||
NavTarget.LoginFlow -> {
|
||||
loginEntryPoint.node(this, buildContext)
|
||||
}
|
||||
NavTarget.LoginFlow -> LoginFlowNode(buildContext)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -24,30 +24,52 @@ 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.node.ParentNode
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.features.messages.MessagesNode
|
||||
import io.element.android.libraries.architecture.NodeInputs
|
||||
import io.element.android.libraries.architecture.bindings
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.architecture.nodeInputs
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.di.SessionScope
|
||||
import io.element.android.libraries.matrix.room.MatrixRoom
|
||||
import io.element.android.x.di.RoomComponent
|
||||
import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
@ContributesNode(SessionScope::class)
|
||||
class RoomFlowNode(
|
||||
buildContext: BuildContext,
|
||||
private val room: MatrixRoom,
|
||||
private val backstack: BackStack<NavTarget> = BackStack(
|
||||
initialElement = NavTarget.Messages,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
plugins: List<Plugin>,
|
||||
private val backstack: BackStack<NavTarget>,
|
||||
) : ParentNode<RoomFlowNode.NavTarget>(
|
||||
navModel = backstack,
|
||||
buildContext = buildContext
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
), DaggerComponentOwner {
|
||||
|
||||
data class Inputs(
|
||||
val room: MatrixRoom,
|
||||
) : NodeInputs
|
||||
|
||||
@AssistedInject
|
||||
constructor(@Assisted buildContext: BuildContext, @Assisted plugins: List<Plugin>) : this(
|
||||
buildContext = buildContext,
|
||||
plugins = plugins,
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.Messages,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
)
|
||||
|
||||
private val inputs: Inputs by nodeInputs()
|
||||
|
||||
override val daggerComponent: Any by lazy {
|
||||
parent!!.bindings<RoomComponent.ParentBindings>().roomComponentBuilder().room(room).build()
|
||||
parent!!.bindings<RoomComponent.ParentBindings>().roomComponentBuilder().room(inputs.room).build()
|
||||
}
|
||||
|
||||
init {
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@
|
|||
|
||||
package io.element.android.x.node
|
||||
|
||||
import android.content.Context
|
||||
import android.os.Parcelable
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.fillMaxSize
|
||||
|
|
@ -28,14 +29,21 @@ import com.bumble.appyx.core.modality.BuildContext
|
|||
import com.bumble.appyx.core.node.Node
|
||||
import com.bumble.appyx.core.node.ParentNode
|
||||
import com.bumble.appyx.core.node.node
|
||||
import com.bumble.appyx.core.plugin.Plugin
|
||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||
import com.bumble.appyx.navmodel.backstack.operation.newRoot
|
||||
import com.bumble.appyx.navmodel.backstack.operation.pop
|
||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||
import io.element.android.features.rageshake.bugreport.BugReportNode
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.anvilannotations.ContributesNode
|
||||
import io.element.android.features.rageshake.bugreport.BugReportEntryPoint
|
||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||
import io.element.android.libraries.architecture.createNode
|
||||
import io.element.android.libraries.architecture.nodeInputsProvider
|
||||
import io.element.android.libraries.designsystem.theme.components.CircularProgressIndicator
|
||||
import io.element.android.libraries.di.AppScope
|
||||
import io.element.android.libraries.di.ApplicationContext
|
||||
import io.element.android.libraries.di.DaggerComponentOwner
|
||||
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
||||
import io.element.android.libraries.matrix.core.SessionId
|
||||
|
|
@ -48,7 +56,8 @@ import kotlinx.coroutines.flow.onEach
|
|||
import kotlinx.parcelize.Parcelize
|
||||
import timber.log.Timber
|
||||
|
||||
class RootFlowNode(
|
||||
@ContributesNode(AppScope::class)
|
||||
class RootFlowNode private constructor(
|
||||
private val buildContext: BuildContext,
|
||||
private val backstack: BackStack<NavTarget> = BackStack(
|
||||
initialElement = NavTarget.SplashScreen,
|
||||
|
|
@ -57,7 +66,8 @@ class RootFlowNode(
|
|||
private val appComponentOwner: DaggerComponentOwner,
|
||||
private val authenticationService: MatrixAuthenticationService,
|
||||
private val matrixClientsHolder: MatrixClientsHolder,
|
||||
private val presenter: RootPresenter
|
||||
private val presenter: RootPresenter,
|
||||
private val bugReportEntryPoint: BugReportEntryPoint,
|
||||
) :
|
||||
ParentNode<RootFlowNode.NavTarget>(
|
||||
navModel = backstack,
|
||||
|
|
@ -66,6 +76,28 @@ class RootFlowNode(
|
|||
|
||||
DaggerComponentOwner by appComponentOwner {
|
||||
|
||||
@AssistedInject
|
||||
constructor(
|
||||
@Assisted buildContext: BuildContext,
|
||||
@Assisted plugins: List<Plugin>,
|
||||
@ApplicationContext context: Context,
|
||||
authenticationService: MatrixAuthenticationService,
|
||||
matrixClientsHolder: MatrixClientsHolder,
|
||||
presenter: RootPresenter,
|
||||
bugReportEntryPoint: BugReportEntryPoint,
|
||||
) : this(
|
||||
buildContext = buildContext,
|
||||
backstack = BackStack(
|
||||
initialElement = NavTarget.SplashScreen,
|
||||
savedStateMap = buildContext.savedStateMap,
|
||||
),
|
||||
appComponentOwner = context.applicationContext as DaggerComponentOwner,
|
||||
authenticationService = authenticationService,
|
||||
matrixClientsHolder = matrixClientsHolder,
|
||||
presenter = presenter,
|
||||
bugReportEntryPoint = bugReportEntryPoint,
|
||||
)
|
||||
|
||||
override fun onBuilt() {
|
||||
super.onBuilt()
|
||||
observeLoggedInState()
|
||||
|
|
@ -140,12 +172,6 @@ class RootFlowNode(
|
|||
}
|
||||
}
|
||||
|
||||
private val bugReportNodeCallback = object : BugReportNode.Callback {
|
||||
override fun onBugReportSent() {
|
||||
backstack.pop()
|
||||
}
|
||||
}
|
||||
|
||||
sealed interface NavTarget : Parcelable {
|
||||
@Parcelize
|
||||
object SplashScreen : NavTarget
|
||||
|
|
@ -167,16 +193,24 @@ class RootFlowNode(
|
|||
Timber.w("Couldn't find any session, go through SplashScreen")
|
||||
backstack.newRoot(NavTarget.SplashScreen)
|
||||
}
|
||||
LoggedInFlowNode(
|
||||
buildContext = buildContext,
|
||||
sessionId = navTarget.sessionId,
|
||||
matrixClient = matrixClient,
|
||||
onOpenBugReport = this::onOpenBugReport
|
||||
)
|
||||
val inputsProvider = nodeInputsProvider(LoggedInFlowNode.Inputs(matrixClient))
|
||||
val callback = object : LoggedInFlowNode.Callback {
|
||||
override fun onOpenBugReport() {
|
||||
backstack.push(NavTarget.BugReport)
|
||||
}
|
||||
}
|
||||
createNode<LoggedInFlowNode>(buildContext, plugins = listOf(inputsProvider, callback))
|
||||
}
|
||||
NavTarget.NotLoggedInFlow -> NotLoggedInFlowNode(buildContext)
|
||||
NavTarget.NotLoggedInFlow -> createNode<NotLoggedInFlowNode>(buildContext)
|
||||
NavTarget.SplashScreen -> splashNode(buildContext)
|
||||
NavTarget.BugReport -> createNode<BugReportNode>(buildContext, plugins = listOf(bugReportNodeCallback))
|
||||
NavTarget.BugReport -> {
|
||||
val callback = object : BugReportEntryPoint.Callback {
|
||||
override fun onBugReportSent() {
|
||||
backstack.pop()
|
||||
}
|
||||
}
|
||||
bugReportEntryPoint.node(this, buildContext, plugins = listOf(callback))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue