[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.integration.NodeHost
|
||||||
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
|
import com.bumble.appyx.core.integrationpoint.NodeComponentActivity
|
||||||
import io.element.android.libraries.architecture.bindings
|
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.designsystem.theme.ElementTheme
|
||||||
import io.element.android.libraries.di.DaggerComponentOwner
|
|
||||||
import io.element.android.x.di.AppBindings
|
import io.element.android.x.di.AppBindings
|
||||||
import io.element.android.x.node.RootFlowNode
|
import io.element.android.x.node.RootFlowNode
|
||||||
|
|
||||||
|
|
@ -45,13 +45,7 @@ class MainActivity : NodeComponentActivity() {
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxSize(),
|
||||||
) {
|
) {
|
||||||
NodeHost(integrationPoint = appyxIntegrationPoint) {
|
NodeHost(integrationPoint = appyxIntegrationPoint) {
|
||||||
RootFlowNode(
|
createNode<RootFlowNode>(it)
|
||||||
buildContext = it,
|
|
||||||
appComponentOwner = applicationContext as DaggerComponentOwner,
|
|
||||||
authenticationService = appBindings.authenticationService(),
|
|
||||||
presenter = appBindings.rootPresenter(),
|
|
||||||
matrixClientsHolder = appBindings.matrixClientsHolder()
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -29,38 +29,69 @@ import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.node.ParentNode
|
import com.bumble.appyx.core.node.ParentNode
|
||||||
import com.bumble.appyx.core.node.node
|
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.BackStack
|
||||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
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.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.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.bindings
|
import io.element.android.libraries.architecture.bindings
|
||||||
import io.element.android.libraries.architecture.createNode
|
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.designsystem.theme.components.Text
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
import io.element.android.libraries.di.DaggerComponentOwner
|
import io.element.android.libraries.di.DaggerComponentOwner
|
||||||
import io.element.android.libraries.matrix.MatrixClient
|
import io.element.android.libraries.matrix.MatrixClient
|
||||||
import io.element.android.libraries.matrix.core.RoomId
|
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.libraries.matrix.ui.di.MatrixUIBindings
|
||||||
import io.element.android.x.di.SessionComponent
|
import io.element.android.x.di.SessionComponent
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@ContributesNode(AppScope::class)
|
||||||
class LoggedInFlowNode(
|
class LoggedInFlowNode(
|
||||||
buildContext: BuildContext,
|
buildContext: BuildContext,
|
||||||
val sessionId: SessionId,
|
plugins: List<Plugin>,
|
||||||
private val matrixClient: MatrixClient,
|
private val backstack: BackStack<NavTarget>,
|
||||||
private val onOpenBugReport: () -> Unit,
|
private val roomListEntryPoint: RoomListEntryPoint,
|
||||||
private val backstack: BackStack<NavTarget> = BackStack(
|
|
||||||
initialElement = NavTarget.RoomList,
|
|
||||||
savedStateMap = buildContext.savedStateMap,
|
|
||||||
),
|
|
||||||
) : ParentNode<LoggedInFlowNode.NavTarget>(
|
) : ParentNode<LoggedInFlowNode.NavTarget>(
|
||||||
navModel = backstack,
|
navModel = backstack,
|
||||||
buildContext = buildContext
|
buildContext = buildContext,
|
||||||
|
plugins = plugins
|
||||||
), DaggerComponentOwner {
|
), 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 {
|
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() {
|
override fun onBuilt() {
|
||||||
|
|
@ -69,7 +100,7 @@ class LoggedInFlowNode(
|
||||||
onCreate = {
|
onCreate = {
|
||||||
val imageLoaderFactory = bindings<MatrixUIBindings>().loggedInImageLoaderFactory()
|
val imageLoaderFactory = bindings<MatrixUIBindings>().loggedInImageLoaderFactory()
|
||||||
Coil.setImageLoader(imageLoaderFactory)
|
Coil.setImageLoader(imageLoaderFactory)
|
||||||
matrixClient.startSync()
|
inputs.matrixClient.startSync()
|
||||||
},
|
},
|
||||||
onDestroy = {
|
onDestroy = {
|
||||||
val imageLoaderFactory = bindings<MatrixUIBindings>().notLoggedInImageLoaderFactory()
|
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 {
|
sealed interface NavTarget : Parcelable {
|
||||||
@Parcelize
|
@Parcelize
|
||||||
object RoomList : NavTarget
|
object RoomList : NavTarget
|
||||||
|
|
@ -102,10 +123,19 @@ class LoggedInFlowNode(
|
||||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||||
return when (navTarget) {
|
return when (navTarget) {
|
||||||
NavTarget.RoomList -> {
|
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 -> {
|
is NavTarget.Room -> {
|
||||||
val room = matrixClient.getRoom(roomId = navTarget.roomId)
|
val room = inputs.matrixClient.getRoom(roomId = navTarget.roomId)
|
||||||
if (room == null) {
|
if (room == null) {
|
||||||
// TODO CREATE UNKNOWN ROOM NODE
|
// TODO CREATE UNKNOWN ROOM NODE
|
||||||
node(buildContext) {
|
node(buildContext) {
|
||||||
|
|
@ -114,11 +144,17 @@ class LoggedInFlowNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
RoomFlowNode(buildContext, room)
|
val inputsProvider = nodeInputsProvider(RoomFlowNode.Inputs(room))
|
||||||
|
createNode<RoomFlowNode>(buildContext, plugins = listOf(inputsProvider))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
NavTarget.Settings -> {
|
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.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.node.ParentNode
|
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.BackStack
|
||||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||||
import io.element.android.features.login.LoginFlowNode
|
import dagger.assisted.Assisted
|
||||||
import io.element.android.features.onboarding.OnBoardingScreen
|
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.architecture.animation.rememberDefaultTransitionHandler
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class NotLoggedInFlowNode(
|
@ContributesNode(AppScope::class)
|
||||||
|
class NotLoggedInFlowNode private constructor(
|
||||||
buildContext: BuildContext,
|
buildContext: BuildContext,
|
||||||
private val backstack: BackStack<NavTarget> = BackStack(
|
plugins: List<Plugin>,
|
||||||
initialElement = NavTarget.OnBoarding,
|
private val onBoardingEntryPoint: OnBoardingEntryPoint,
|
||||||
savedStateMap = buildContext.savedStateMap,
|
private val loginEntryPoint: LoginEntryPoint,
|
||||||
),
|
private val backstack: BackStack<NavTarget>,
|
||||||
) : ParentNode<NotLoggedInFlowNode.NavTarget>(
|
) : ParentNode<NotLoggedInFlowNode.NavTarget>(
|
||||||
navModel = backstack,
|
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 {
|
init {
|
||||||
lifecycle.subscribe(
|
lifecycle.subscribe(
|
||||||
|
|
@ -61,12 +81,21 @@ class NotLoggedInFlowNode(
|
||||||
|
|
||||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||||
return when (navTarget) {
|
return when (navTarget) {
|
||||||
NavTarget.OnBoarding -> node(buildContext) {
|
NavTarget.OnBoarding -> {
|
||||||
OnBoardingScreen(
|
val callback = object : OnBoardingEntryPoint.Callback {
|
||||||
onSignIn = { backstack.push(NavTarget.LoginFlow) }
|
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.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.node.ParentNode
|
import com.bumble.appyx.core.node.ParentNode
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
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.features.messages.MessagesNode
|
||||||
|
import io.element.android.libraries.architecture.NodeInputs
|
||||||
import io.element.android.libraries.architecture.bindings
|
import io.element.android.libraries.architecture.bindings
|
||||||
import io.element.android.libraries.architecture.createNode
|
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.DaggerComponentOwner
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.room.MatrixRoom
|
import io.element.android.libraries.matrix.room.MatrixRoom
|
||||||
import io.element.android.x.di.RoomComponent
|
import io.element.android.x.di.RoomComponent
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
|
@ContributesNode(SessionScope::class)
|
||||||
class RoomFlowNode(
|
class RoomFlowNode(
|
||||||
buildContext: BuildContext,
|
buildContext: BuildContext,
|
||||||
private val room: MatrixRoom,
|
plugins: List<Plugin>,
|
||||||
private val backstack: BackStack<NavTarget> = BackStack(
|
private val backstack: BackStack<NavTarget>,
|
||||||
initialElement = NavTarget.Messages,
|
|
||||||
savedStateMap = buildContext.savedStateMap,
|
|
||||||
),
|
|
||||||
) : ParentNode<RoomFlowNode.NavTarget>(
|
) : ParentNode<RoomFlowNode.NavTarget>(
|
||||||
navModel = backstack,
|
navModel = backstack,
|
||||||
buildContext = buildContext
|
buildContext = buildContext,
|
||||||
|
plugins = plugins,
|
||||||
), DaggerComponentOwner {
|
), 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 {
|
override val daggerComponent: Any by lazy {
|
||||||
parent!!.bindings<RoomComponent.ParentBindings>().roomComponentBuilder().room(room).build()
|
parent!!.bindings<RoomComponent.ParentBindings>().roomComponentBuilder().room(inputs.room).build()
|
||||||
}
|
}
|
||||||
|
|
||||||
init {
|
init {
|
||||||
|
|
|
||||||
|
|
@ -16,6 +16,7 @@
|
||||||
|
|
||||||
package io.element.android.x.node
|
package io.element.android.x.node
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.fillMaxSize
|
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.Node
|
||||||
import com.bumble.appyx.core.node.ParentNode
|
import com.bumble.appyx.core.node.ParentNode
|
||||||
import com.bumble.appyx.core.node.node
|
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.BackStack
|
||||||
import com.bumble.appyx.navmodel.backstack.operation.newRoot
|
import com.bumble.appyx.navmodel.backstack.operation.newRoot
|
||||||
import com.bumble.appyx.navmodel.backstack.operation.pop
|
import com.bumble.appyx.navmodel.backstack.operation.pop
|
||||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
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.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.createNode
|
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.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.di.DaggerComponentOwner
|
||||||
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
||||||
import io.element.android.libraries.matrix.core.SessionId
|
import io.element.android.libraries.matrix.core.SessionId
|
||||||
|
|
@ -48,7 +56,8 @@ import kotlinx.coroutines.flow.onEach
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
import timber.log.Timber
|
import timber.log.Timber
|
||||||
|
|
||||||
class RootFlowNode(
|
@ContributesNode(AppScope::class)
|
||||||
|
class RootFlowNode private constructor(
|
||||||
private val buildContext: BuildContext,
|
private val buildContext: BuildContext,
|
||||||
private val backstack: BackStack<NavTarget> = BackStack(
|
private val backstack: BackStack<NavTarget> = BackStack(
|
||||||
initialElement = NavTarget.SplashScreen,
|
initialElement = NavTarget.SplashScreen,
|
||||||
|
|
@ -57,7 +66,8 @@ class RootFlowNode(
|
||||||
private val appComponentOwner: DaggerComponentOwner,
|
private val appComponentOwner: DaggerComponentOwner,
|
||||||
private val authenticationService: MatrixAuthenticationService,
|
private val authenticationService: MatrixAuthenticationService,
|
||||||
private val matrixClientsHolder: MatrixClientsHolder,
|
private val matrixClientsHolder: MatrixClientsHolder,
|
||||||
private val presenter: RootPresenter
|
private val presenter: RootPresenter,
|
||||||
|
private val bugReportEntryPoint: BugReportEntryPoint,
|
||||||
) :
|
) :
|
||||||
ParentNode<RootFlowNode.NavTarget>(
|
ParentNode<RootFlowNode.NavTarget>(
|
||||||
navModel = backstack,
|
navModel = backstack,
|
||||||
|
|
@ -66,6 +76,28 @@ class RootFlowNode(
|
||||||
|
|
||||||
DaggerComponentOwner by appComponentOwner {
|
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() {
|
override fun onBuilt() {
|
||||||
super.onBuilt()
|
super.onBuilt()
|
||||||
observeLoggedInState()
|
observeLoggedInState()
|
||||||
|
|
@ -140,12 +172,6 @@ class RootFlowNode(
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private val bugReportNodeCallback = object : BugReportNode.Callback {
|
|
||||||
override fun onBugReportSent() {
|
|
||||||
backstack.pop()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
sealed interface NavTarget : Parcelable {
|
sealed interface NavTarget : Parcelable {
|
||||||
@Parcelize
|
@Parcelize
|
||||||
object SplashScreen : NavTarget
|
object SplashScreen : NavTarget
|
||||||
|
|
@ -167,16 +193,24 @@ class RootFlowNode(
|
||||||
Timber.w("Couldn't find any session, go through SplashScreen")
|
Timber.w("Couldn't find any session, go through SplashScreen")
|
||||||
backstack.newRoot(NavTarget.SplashScreen)
|
backstack.newRoot(NavTarget.SplashScreen)
|
||||||
}
|
}
|
||||||
LoggedInFlowNode(
|
val inputsProvider = nodeInputsProvider(LoggedInFlowNode.Inputs(matrixClient))
|
||||||
buildContext = buildContext,
|
val callback = object : LoggedInFlowNode.Callback {
|
||||||
sessionId = navTarget.sessionId,
|
override fun onOpenBugReport() {
|
||||||
matrixClient = matrixClient,
|
backstack.push(NavTarget.BugReport)
|
||||||
onOpenBugReport = this::onOpenBugReport
|
}
|
||||||
)
|
}
|
||||||
|
createNode<LoggedInFlowNode>(buildContext, plugins = listOf(inputsProvider, callback))
|
||||||
}
|
}
|
||||||
NavTarget.NotLoggedInFlow -> NotLoggedInFlowNode(buildContext)
|
NavTarget.NotLoggedInFlow -> createNode<NotLoggedInFlowNode>(buildContext)
|
||||||
NavTarget.SplashScreen -> splashNode(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))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,21 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.login.api
|
||||||
|
|
||||||
|
import io.element.android.libraries.architecture.EntryPoint
|
||||||
|
|
||||||
|
interface LoginEntryPoint : EntryPoint
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.login.implementation
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.features.login.api.LoginEntryPoint
|
||||||
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultLoginEntryPoint @Inject constructor() : LoginEntryPoint {
|
||||||
|
override fun node(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node {
|
||||||
|
return parentNode.createNode<LoginFlowNode>(buildContext, plugins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login
|
package io.element.android.features.login.implementation
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
|
|
@ -23,30 +23,39 @@ import com.bumble.appyx.core.composable.Children
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.node.ParentNode
|
import com.bumble.appyx.core.node.ParentNode
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
import com.bumble.appyx.navmodel.backstack.BackStack
|
import com.bumble.appyx.navmodel.backstack.BackStack
|
||||||
import com.bumble.appyx.navmodel.backstack.operation.push
|
import com.bumble.appyx.navmodel.backstack.operation.push
|
||||||
import io.element.android.features.login.changeserver.ChangeServerNode
|
import dagger.assisted.Assisted
|
||||||
import io.element.android.features.login.root.LoginRootNode
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.features.login.implementation.changeserver.ChangeServerNode
|
||||||
|
import io.element.android.features.login.implementation.root.LoginRootNode
|
||||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@ContributesNode(AppScope::class)
|
||||||
class LoginFlowNode(
|
class LoginFlowNode(
|
||||||
buildContext: BuildContext,
|
buildContext: BuildContext,
|
||||||
private val backstack: BackStack<NavTarget> = BackStack(
|
plugins: List<Plugin>,
|
||||||
initialElement = NavTarget.Root,
|
private val backstack: BackStack<NavTarget>,
|
||||||
savedStateMap = buildContext.savedStateMap,
|
|
||||||
),
|
|
||||||
) : ParentNode<LoginFlowNode.NavTarget>(
|
) : ParentNode<LoginFlowNode.NavTarget>(
|
||||||
navModel = backstack,
|
navModel = backstack,
|
||||||
buildContext = buildContext
|
buildContext = buildContext,
|
||||||
|
plugins = plugins,
|
||||||
) {
|
) {
|
||||||
|
|
||||||
private val loginRootCallback = object : LoginRootNode.Callback {
|
@AssistedInject
|
||||||
override fun onChangeHomeServer() {
|
constructor(@Assisted buildContext: BuildContext, @Assisted plugins: List<Plugin>) : this(
|
||||||
backstack.push(NavTarget.ChangeServer)
|
buildContext = buildContext,
|
||||||
}
|
plugins = plugins,
|
||||||
}
|
backstack = BackStack(
|
||||||
|
initialElement = NavTarget.Root,
|
||||||
|
savedStateMap = buildContext.savedStateMap,
|
||||||
|
),
|
||||||
|
)
|
||||||
|
|
||||||
sealed interface NavTarget : Parcelable {
|
sealed interface NavTarget : Parcelable {
|
||||||
@Parcelize
|
@Parcelize
|
||||||
|
|
@ -58,7 +67,14 @@ class LoginFlowNode(
|
||||||
|
|
||||||
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
|
||||||
return when (navTarget) {
|
return when (navTarget) {
|
||||||
NavTarget.Root -> createNode<LoginRootNode>(buildContext, plugins = listOf(loginRootCallback))
|
NavTarget.Root -> {
|
||||||
|
val callback = object : LoginRootNode.Callback {
|
||||||
|
override fun onChangeHomeServer() {
|
||||||
|
backstack.push(NavTarget.ChangeServer)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
createNode<LoginRootNode>(buildContext, plugins = listOf(callback))
|
||||||
|
}
|
||||||
NavTarget.ChangeServer -> createNode<ChangeServerNode>(buildContext)
|
NavTarget.ChangeServer -> createNode<ChangeServerNode>(buildContext)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.implementation.changeserver
|
||||||
|
|
||||||
sealed interface ChangeServerEvents {
|
sealed interface ChangeServerEvents {
|
||||||
data class SetServer(val server: String) : ChangeServerEvents
|
data class SetServer(val server: String) : ChangeServerEvents
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.implementation.changeserver
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.implementation.changeserver
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.implementation.changeserver
|
||||||
|
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.implementation.changeserver
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.changeserver
|
package io.element.android.features.login.implementation.changeserver
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
|
@ -46,7 +46,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.features.login.R
|
import io.element.android.features.login.R
|
||||||
import io.element.android.features.login.error.changeServerError
|
import io.element.android.features.login.implementation.error.changeServerError
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
|
|
@ -14,11 +14,11 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.error
|
package io.element.android.features.login.implementation.error
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.res.stringResource
|
import androidx.compose.ui.res.stringResource
|
||||||
import io.element.android.features.login.root.LoginFormState
|
import io.element.android.features.login.implementation.root.LoginFormState
|
||||||
import io.element.android.libraries.core.uri.isValidUrl
|
import io.element.android.libraries.core.uri.isValidUrl
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.implementation.root
|
||||||
|
|
||||||
sealed interface LoginRootEvents {
|
sealed interface LoginRootEvents {
|
||||||
object RefreshHomeServer : LoginRootEvents
|
object RefreshHomeServer : LoginRootEvents
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.implementation.root
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.implementation.root
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.MutableState
|
import androidx.compose.runtime.MutableState
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.implementation.root
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
|
|
@ -48,7 +48,7 @@ import androidx.compose.ui.text.style.TextAlign
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import io.element.android.features.login.error.loginError
|
import io.element.android.features.login.implementation.error.loginError
|
||||||
import io.element.android.libraries.designsystem.components.form.textFieldState
|
import io.element.android.libraries.designsystem.components.form.textFieldState
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.implementation.root
|
||||||
|
|
||||||
import android.os.Parcelable
|
import android.os.Parcelable
|
||||||
import io.element.android.libraries.matrix.core.SessionId
|
import io.element.android.libraries.matrix.core.SessionId
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.login.root
|
package io.element.android.features.login.implementation.root
|
||||||
|
|
||||||
fun aLoginRootState() = LoginRootState(
|
fun aLoginRootState() = LoginRootState(
|
||||||
homeserver = "",
|
homeserver = "",
|
||||||
|
|
@ -22,6 +22,8 @@ import app.cash.molecule.RecompositionClock
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.login.implementation.changeserver.ChangeServerEvents
|
||||||
|
import io.element.android.features.login.implementation.changeserver.ChangeServerPresenter
|
||||||
import io.element.android.libraries.architecture.Async
|
import io.element.android.libraries.architecture.Async
|
||||||
import io.element.android.libraries.matrixtest.A_HOMESERVER
|
import io.element.android.libraries.matrixtest.A_HOMESERVER
|
||||||
import io.element.android.libraries.matrixtest.auth.FakeAuthenticationService
|
import io.element.android.libraries.matrixtest.auth.FakeAuthenticationService
|
||||||
|
|
|
||||||
|
|
@ -22,6 +22,10 @@ import app.cash.molecule.RecompositionClock
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
|
import io.element.android.features.login.implementation.root.LoggedInState
|
||||||
|
import io.element.android.features.login.implementation.root.LoginFormState
|
||||||
|
import io.element.android.features.login.implementation.root.LoginRootEvents
|
||||||
|
import io.element.android.features.login.implementation.root.LoginRootPresenter
|
||||||
import io.element.android.libraries.matrix.core.SessionId
|
import io.element.android.libraries.matrix.core.SessionId
|
||||||
import io.element.android.libraries.matrixtest.A_HOMESERVER
|
import io.element.android.libraries.matrixtest.A_HOMESERVER
|
||||||
import io.element.android.libraries.matrixtest.A_HOMESERVER_2
|
import io.element.android.libraries.matrixtest.A_HOMESERVER_2
|
||||||
|
|
|
||||||
|
|
@ -19,15 +19,23 @@
|
||||||
plugins {
|
plugins {
|
||||||
id("io.element.android-compose-library")
|
id("io.element.android-compose-library")
|
||||||
alias(libs.plugins.ksp)
|
alias(libs.plugins.ksp)
|
||||||
|
alias(libs.plugins.anvil)
|
||||||
}
|
}
|
||||||
|
|
||||||
android {
|
android {
|
||||||
namespace = "io.element.android.features.onboarding"
|
namespace = "io.element.android.features.onboarding"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
anvil {
|
||||||
|
generateDaggerFactories.set(true)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(projects.libraries.core)
|
implementation(projects.libraries.core)
|
||||||
implementation(projects.libraries.elementresources)
|
implementation(projects.libraries.elementresources)
|
||||||
|
implementation(projects.anvilannotations)
|
||||||
|
anvil(projects.anvilcodegen)
|
||||||
implementation(projects.libraries.uiStrings)
|
implementation(projects.libraries.uiStrings)
|
||||||
implementation(projects.libraries.designsystem)
|
implementation(projects.libraries.designsystem)
|
||||||
implementation(projects.libraries.architecture)
|
implementation(projects.libraries.architecture)
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,27 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.onboarding.api
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import io.element.android.libraries.architecture.EntryPoint
|
||||||
|
|
||||||
|
interface OnBoardingEntryPoint : EntryPoint {
|
||||||
|
interface Callback : Plugin {
|
||||||
|
fun onSignUp()
|
||||||
|
fun onSignIn()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.onboarding.implementation
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.features.onboarding.api.OnBoardingEntryPoint
|
||||||
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultOnBoardingEntryPoint @Inject constructor() : OnBoardingEntryPoint {
|
||||||
|
override fun node(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node {
|
||||||
|
return parentNode.createNode<OnBoardingNode>(buildContext, plugins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,56 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.onboarding.implementation
|
||||||
|
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
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 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)
|
||||||
|
class OnBoardingNode @AssistedInject constructor(
|
||||||
|
@Assisted buildContext: BuildContext,
|
||||||
|
@Assisted plugins: List<Plugin>,
|
||||||
|
) : Node(
|
||||||
|
buildContext = buildContext,
|
||||||
|
plugins = plugins
|
||||||
|
) {
|
||||||
|
|
||||||
|
private fun onSignIn() {
|
||||||
|
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignIn() }
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun onSignUp() {
|
||||||
|
plugins<OnBoardingEntryPoint.Callback>().forEach { it.onSignUp() }
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
override fun View(modifier: Modifier) {
|
||||||
|
OnBoardingScreen(
|
||||||
|
modifier = modifier,
|
||||||
|
onSignIn = this::onSignIn,
|
||||||
|
onSignUp = this::onSignUp
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.onboarding
|
package io.element.android.features.onboarding.implementation
|
||||||
|
|
||||||
import androidx.compose.foundation.Image
|
import androidx.compose.foundation.Image
|
||||||
import androidx.compose.foundation.layout.Box
|
import androidx.compose.foundation.layout.Box
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.onboarding
|
package io.element.android.features.onboarding.implementation
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
import androidx.annotation.StringRes
|
import androidx.annotation.StringRes
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,9 +14,10 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.onboarding
|
package io.element.android.features.onboarding.implementation
|
||||||
|
|
||||||
import androidx.annotation.DrawableRes
|
import androidx.annotation.DrawableRes
|
||||||
|
import io.element.android.features.onboarding.R
|
||||||
import io.element.android.libraries.ui.strings.R as StringR
|
import io.element.android.libraries.ui.strings.R as StringR
|
||||||
|
|
||||||
class SplashCarouselDataFactory {
|
class SplashCarouselDataFactory {
|
||||||
|
|
@ -23,27 +23,46 @@ import com.bumble.appyx.core.composable.Children
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.node.ParentNode
|
import com.bumble.appyx.core.node.ParentNode
|
||||||
|
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.BackStack
|
||||||
|
import dagger.assisted.Assisted
|
||||||
|
import dagger.assisted.AssistedInject
|
||||||
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
import io.element.android.features.preferences.root.PreferencesRootNode
|
import io.element.android.features.preferences.root.PreferencesRootNode
|
||||||
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
import io.element.android.libraries.architecture.animation.rememberDefaultTransitionHandler
|
||||||
import io.element.android.libraries.architecture.createNode
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.SessionScope
|
||||||
import kotlinx.parcelize.Parcelize
|
import kotlinx.parcelize.Parcelize
|
||||||
|
|
||||||
|
@ContributesNode(SessionScope::class)
|
||||||
class PreferencesFlowNode(
|
class PreferencesFlowNode(
|
||||||
buildContext: BuildContext,
|
buildContext: BuildContext,
|
||||||
private val onOpenBugReport: () -> Unit,
|
plugins: List<Plugin>,
|
||||||
private val backstack: BackStack<NavTarget> = BackStack(
|
private val backstack: BackStack<NavTarget>,
|
||||||
initialElement = NavTarget.Root,
|
|
||||||
savedStateMap = buildContext.savedStateMap,
|
|
||||||
),
|
|
||||||
) : ParentNode<PreferencesFlowNode.NavTarget>(
|
) : ParentNode<PreferencesFlowNode.NavTarget>(
|
||||||
navModel = backstack,
|
navModel = backstack,
|
||||||
buildContext = buildContext
|
buildContext = buildContext,
|
||||||
|
plugins = plugins
|
||||||
) {
|
) {
|
||||||
|
|
||||||
|
@AssistedInject
|
||||||
|
constructor(@Assisted buildContext: BuildContext, @Assisted plugins: List<Plugin>) : this(
|
||||||
|
buildContext = buildContext,
|
||||||
|
plugins = plugins,
|
||||||
|
backstack = BackStack(
|
||||||
|
initialElement = NavTarget.Root,
|
||||||
|
savedStateMap = buildContext.savedStateMap,
|
||||||
|
)
|
||||||
|
)
|
||||||
|
|
||||||
|
interface Callback : Plugin {
|
||||||
|
fun onOpenBugReport()
|
||||||
|
}
|
||||||
|
|
||||||
private val preferencesRootNodeCallback = object : PreferencesRootNode.Callback {
|
private val preferencesRootNodeCallback = object : PreferencesRootNode.Callback {
|
||||||
override fun onOpenBugReport() {
|
override fun onOpenBugReport() {
|
||||||
onOpenBugReport.invoke()
|
plugins<Callback>().forEach { it.onOpenBugReport() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.rageshake.bugreport
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import io.element.android.libraries.architecture.EntryPoint
|
||||||
|
|
||||||
|
interface BugReportEntryPoint : EntryPoint {
|
||||||
|
interface Callback : Plugin {
|
||||||
|
fun onBugReportSent()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -34,10 +34,6 @@ class BugReportNode @AssistedInject constructor(
|
||||||
private val presenter: BugReportPresenter,
|
private val presenter: BugReportPresenter,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
interface Callback : Plugin {
|
|
||||||
fun onBugReportSent()
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
override fun View(modifier: Modifier) {
|
override fun View(modifier: Modifier) {
|
||||||
val state = presenter.present()
|
val state = presenter.present()
|
||||||
|
|
@ -49,6 +45,6 @@ class BugReportNode @AssistedInject constructor(
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onDone() {
|
private fun onDone() {
|
||||||
plugins<Callback>().forEach { it.onBugReportSent() }
|
plugins<BugReportEntryPoint.Callback>().forEach { it.onBugReportSent() }
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,32 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.rageshake.bugreport
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultBugReportEntryPoint @Inject constructor() : BugReportEntryPoint {
|
||||||
|
override fun node(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node {
|
||||||
|
return parentNode.createNode<BugReportNode>(buildContext, plugins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,28 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.roomlist.api
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import io.element.android.libraries.architecture.EntryPoint
|
||||||
|
import io.element.android.libraries.matrix.core.RoomId
|
||||||
|
|
||||||
|
interface RoomListEntryPoint : EntryPoint {
|
||||||
|
interface Callback : Plugin {
|
||||||
|
fun onRoomClicked(roomId: RoomId)
|
||||||
|
fun onSettingsClicked()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,33 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import com.squareup.anvil.annotations.ContributesBinding
|
||||||
|
import io.element.android.features.roomlist.api.RoomListEntryPoint
|
||||||
|
import io.element.android.libraries.architecture.createNode
|
||||||
|
import io.element.android.libraries.di.AppScope
|
||||||
|
import javax.inject.Inject
|
||||||
|
|
||||||
|
@ContributesBinding(AppScope::class)
|
||||||
|
class DefaultRoomListEntryPoint @Inject constructor() : RoomListEntryPoint {
|
||||||
|
override fun node(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin>): Node {
|
||||||
|
return parentNode.createNode<RoomListNode>(buildContext, plugins)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.model
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
sealed interface RoomListEvents {
|
sealed interface RoomListEvents {
|
||||||
data class UpdateFilter(val newFilter: String) : RoomListEvents
|
data class UpdateFilter(val newFilter: String) : RoomListEvents
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
|
|
@ -25,6 +25,7 @@ import com.bumble.appyx.core.plugin.plugins
|
||||||
import dagger.assisted.Assisted
|
import dagger.assisted.Assisted
|
||||||
import dagger.assisted.AssistedInject
|
import dagger.assisted.AssistedInject
|
||||||
import io.element.android.anvilannotations.ContributesNode
|
import io.element.android.anvilannotations.ContributesNode
|
||||||
|
import io.element.android.features.roomlist.api.RoomListEntryPoint
|
||||||
import io.element.android.libraries.di.SessionScope
|
import io.element.android.libraries.di.SessionScope
|
||||||
import io.element.android.libraries.matrix.core.RoomId
|
import io.element.android.libraries.matrix.core.RoomId
|
||||||
|
|
||||||
|
|
@ -35,17 +36,12 @@ class RoomListNode @AssistedInject constructor(
|
||||||
private val presenter: RoomListPresenter,
|
private val presenter: RoomListPresenter,
|
||||||
) : Node(buildContext, plugins = plugins) {
|
) : Node(buildContext, plugins = plugins) {
|
||||||
|
|
||||||
interface Callback : Plugin {
|
|
||||||
fun onRoomClicked(roomId: RoomId)
|
|
||||||
fun onSettingsClicked()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun onRoomClicked(roomId: RoomId) {
|
private fun onRoomClicked(roomId: RoomId) {
|
||||||
plugins<Callback>().forEach { it.onRoomClicked(roomId) }
|
plugins<RoomListEntryPoint.Callback>().forEach { it.onRoomClicked(roomId) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun onOpenSettings() {
|
private fun onOpenSettings() {
|
||||||
plugins<Callback>().forEach { it.onSettingsClicked() }
|
plugins<RoomListEntryPoint.Callback>().forEach { it.onSettingsClicked() }
|
||||||
}
|
}
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.LaunchedEffect
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
|
@ -25,10 +25,6 @@ import androidx.compose.runtime.mutableStateOf
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.runtime.saveable.rememberSaveable
|
import androidx.compose.runtime.saveable.rememberSaveable
|
||||||
import androidx.compose.runtime.setValue
|
import androidx.compose.runtime.setValue
|
||||||
import io.element.android.features.roomlist.model.RoomListEvents
|
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummary
|
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummaryPlaceholders
|
|
||||||
import io.element.android.features.roomlist.model.RoomListState
|
|
||||||
import io.element.android.libraries.architecture.Presenter
|
import io.element.android.libraries.architecture.Presenter
|
||||||
import io.element.android.libraries.core.coroutine.parallelMap
|
import io.element.android.libraries.core.coroutine.parallelMap
|
||||||
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.model
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.model
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.model
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.model
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.runtime.Immutable
|
import androidx.compose.runtime.Immutable
|
||||||
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
import io.element.android.libraries.matrix.ui.model.MatrixUser
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.model
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist
|
package io.element.android.features.roomlist.impl
|
||||||
|
|
||||||
import androidx.compose.foundation.layout.Column
|
import androidx.compose.foundation.layout.Column
|
||||||
import androidx.compose.foundation.layout.padding
|
import androidx.compose.foundation.layout.padding
|
||||||
|
|
@ -34,12 +34,8 @@ import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||||
import androidx.compose.ui.tooling.preview.Preview
|
import androidx.compose.ui.tooling.preview.Preview
|
||||||
import androidx.compose.ui.tooling.preview.PreviewParameter
|
import androidx.compose.ui.tooling.preview.PreviewParameter
|
||||||
import androidx.compose.ui.unit.Velocity
|
import androidx.compose.ui.unit.Velocity
|
||||||
import io.element.android.features.roomlist.components.RoomListTopBar
|
import io.element.android.features.roomlist.impl.components.RoomListTopBar
|
||||||
import io.element.android.features.roomlist.components.RoomSummaryRow
|
import io.element.android.features.roomlist.impl.components.RoomSummaryRow
|
||||||
import io.element.android.features.roomlist.model.RoomListEvents
|
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummary
|
|
||||||
import io.element.android.features.roomlist.model.RoomListState
|
|
||||||
import io.element.android.features.roomlist.model.RoomListStateProvider
|
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
import io.element.android.libraries.designsystem.theme.components.Scaffold
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -16,7 +16,7 @@
|
||||||
|
|
||||||
@file:OptIn(ExperimentalMaterial3Api::class)
|
@file:OptIn(ExperimentalMaterial3Api::class)
|
||||||
|
|
||||||
package io.element.android.features.roomlist.components
|
package io.element.android.features.roomlist.impl.components
|
||||||
|
|
||||||
import androidx.activity.compose.BackHandler
|
import androidx.activity.compose.BackHandler
|
||||||
import androidx.compose.foundation.layout.fillMaxWidth
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
/*
|
/*
|
||||||
* Copyright (c) 2022 New Vector Ltd
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
*
|
*
|
||||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
* you may not use this file except in compliance with the License.
|
* you may not use this file except in compliance with the License.
|
||||||
|
|
@ -14,7 +14,7 @@
|
||||||
* limitations under the License.
|
* limitations under the License.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
package io.element.android.features.roomlist.components
|
package io.element.android.features.roomlist.impl.components
|
||||||
|
|
||||||
import androidx.compose.foundation.background
|
import androidx.compose.foundation.background
|
||||||
import androidx.compose.foundation.clickable
|
import androidx.compose.foundation.clickable
|
||||||
|
|
@ -53,8 +53,8 @@ import androidx.compose.ui.unit.LayoutDirection
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import androidx.compose.ui.unit.sp
|
import androidx.compose.ui.unit.sp
|
||||||
import com.google.accompanist.placeholder.material.placeholder
|
import com.google.accompanist.placeholder.material.placeholder
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummary
|
import io.element.android.features.roomlist.impl.RoomListRoomSummary
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummaryProvider
|
import io.element.android.features.roomlist.impl.RoomListRoomSummaryProvider
|
||||||
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
import io.element.android.libraries.designsystem.components.avatar.Avatar
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
import io.element.android.libraries.designsystem.preview.ElementPreviewDark
|
||||||
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
import io.element.android.libraries.designsystem.preview.ElementPreviewLight
|
||||||
|
|
@ -22,8 +22,9 @@ import app.cash.molecule.RecompositionClock
|
||||||
import app.cash.molecule.moleculeFlow
|
import app.cash.molecule.moleculeFlow
|
||||||
import app.cash.turbine.test
|
import app.cash.turbine.test
|
||||||
import com.google.common.truth.Truth.assertThat
|
import com.google.common.truth.Truth.assertThat
|
||||||
import io.element.android.features.roomlist.model.RoomListEvents
|
import io.element.android.features.roomlist.impl.RoomListPresenter
|
||||||
import io.element.android.features.roomlist.model.RoomListRoomSummary
|
import io.element.android.features.roomlist.impl.RoomListEvents
|
||||||
|
import io.element.android.features.roomlist.impl.RoomListRoomSummary
|
||||||
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
import io.element.android.libraries.dateformatter.LastMessageFormatter
|
||||||
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
import io.element.android.libraries.designsystem.components.avatar.AvatarData
|
||||||
import io.element.android.libraries.matrix.core.SessionId
|
import io.element.android.libraries.matrix.core.SessionId
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,25 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.architecture
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
|
||||||
|
interface EntryPoint {
|
||||||
|
fun node(parentNode: Node, buildContext: BuildContext, plugins: List<Plugin> = emptyList()): Node
|
||||||
|
}
|
||||||
|
|
@ -16,14 +16,24 @@
|
||||||
|
|
||||||
package io.element.android.libraries.architecture
|
package io.element.android.libraries.architecture
|
||||||
|
|
||||||
|
import android.content.Context
|
||||||
import com.bumble.appyx.core.modality.BuildContext
|
import com.bumble.appyx.core.modality.BuildContext
|
||||||
import com.bumble.appyx.core.node.Node
|
import com.bumble.appyx.core.node.Node
|
||||||
import com.bumble.appyx.core.plugin.Plugin
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
|
||||||
inline fun <reified NODE : Node> Node.createNode(context: BuildContext, plugins: List<Plugin> = emptyList()): NODE {
|
inline fun <reified NODE : Node> Node.createNode(context: BuildContext, plugins: List<Plugin> = emptyList()): NODE {
|
||||||
val nodeClass = NODE::class.java
|
|
||||||
val bindings: NodeFactoriesBindings = bindings()
|
val bindings: NodeFactoriesBindings = bindings()
|
||||||
val nodeFactoryMap = bindings.nodeFactories()
|
return bindings.createNode(context, plugins)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified NODE : Node> Context.createNode(context: BuildContext, plugins: List<Plugin> = emptyList()): NODE {
|
||||||
|
val bindings: NodeFactoriesBindings = bindings()
|
||||||
|
return bindings.createNode(context, plugins)
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified NODE : Node> NodeFactoriesBindings.createNode(context: BuildContext, plugins: List<Plugin> = emptyList()): NODE {
|
||||||
|
val nodeClass = NODE::class.java
|
||||||
|
val nodeFactoryMap = nodeFactories()
|
||||||
val nodeFactory = nodeFactoryMap[nodeClass] ?: error("Cannot find NodeFactory for ${nodeClass.name}.")
|
val nodeFactory = nodeFactoryMap[nodeClass] ?: error("Cannot find NodeFactory for ${nodeClass.name}.")
|
||||||
|
|
||||||
@Suppress("UNCHECKED_CAST")
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,36 @@
|
||||||
|
/*
|
||||||
|
* Copyright (c) 2023 New Vector Ltd
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package io.element.android.libraries.architecture
|
||||||
|
|
||||||
|
import com.bumble.appyx.core.node.Node
|
||||||
|
import com.bumble.appyx.core.plugin.Plugin
|
||||||
|
import com.bumble.appyx.core.plugin.plugins
|
||||||
|
import kotlin.properties.ReadOnlyProperty
|
||||||
|
|
||||||
|
interface NodeInputs
|
||||||
|
|
||||||
|
interface NodeInputsProvider<I : NodeInputs> : Plugin {
|
||||||
|
fun inputs(): I
|
||||||
|
}
|
||||||
|
|
||||||
|
inline fun <reified I : NodeInputs> nodeInputsProvider(inputs: I) = object : NodeInputsProvider<I> {
|
||||||
|
override fun inputs() = inputs
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <I : NodeInputs> nodeInputs() = ReadOnlyProperty<Node, I> { thisRef, _ ->
|
||||||
|
thisRef.plugins<NodeInputsProvider<I>>().first().inputs()
|
||||||
|
}
|
||||||
|
|
@ -57,7 +57,7 @@ fun ElementTheme(
|
||||||
) {
|
) {
|
||||||
val systemUiController = rememberSystemUiController()
|
val systemUiController = rememberSystemUiController()
|
||||||
val useDarkIcons = !darkTheme
|
val useDarkIcons = !darkTheme
|
||||||
val currentColor = remember { if (darkTheme) darkColors else lightColors }
|
val currentColor = remember(darkTheme) { if (darkTheme) darkColors else lightColors }
|
||||||
val colorScheme = when {
|
val colorScheme = when {
|
||||||
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
dynamicColor && Build.VERSION.SDK_INT >= Build.VERSION_CODES.S -> {
|
||||||
val context = LocalContext.current
|
val context = LocalContext.current
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ package io.element.android.samples.minimal
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.remember
|
import androidx.compose.runtime.remember
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import io.element.android.features.login.root.LoginRootPresenter
|
import io.element.android.features.login.implementation.root.LoginRootPresenter
|
||||||
import io.element.android.features.login.root.LoginRootScreen
|
import io.element.android.features.login.implementation.root.LoginRootScreen
|
||||||
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
import io.element.android.libraries.matrix.auth.MatrixAuthenticationService
|
||||||
|
|
||||||
class LoginScreen(private val authenticationService: MatrixAuthenticationService) {
|
class LoginScreen(private val authenticationService: MatrixAuthenticationService) {
|
||||||
|
|
|
||||||
|
|
@ -19,8 +19,8 @@ package io.element.android.samples.minimal
|
||||||
import androidx.compose.runtime.Composable
|
import androidx.compose.runtime.Composable
|
||||||
import androidx.compose.runtime.DisposableEffect
|
import androidx.compose.runtime.DisposableEffect
|
||||||
import androidx.compose.ui.Modifier
|
import androidx.compose.ui.Modifier
|
||||||
import io.element.android.features.roomlist.RoomListPresenter
|
import io.element.android.features.roomlist.impl.RoomListPresenter
|
||||||
import io.element.android.features.roomlist.RoomListView
|
import io.element.android.features.roomlist.impl.RoomListView
|
||||||
import io.element.android.libraries.dateformatter.impl.DateFormatters
|
import io.element.android.libraries.dateformatter.impl.DateFormatters
|
||||||
import io.element.android.libraries.dateformatter.impl.DefaultLastMessageFormatter
|
import io.element.android.libraries.dateformatter.impl.DefaultLastMessageFormatter
|
||||||
import io.element.android.libraries.dateformatter.impl.LocalDateTimeProvider
|
import io.element.android.libraries.dateformatter.impl.LocalDateTimeProvider
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue