Create RoomComponent and manage in RoomFlowNode

This commit is contained in:
ganfra 2023-01-13 12:29:36 +01:00
parent c3ec363e77
commit 2869f492d9
7 changed files with 111 additions and 27 deletions

View file

@ -0,0 +1,43 @@
/*
* Copyright (c) 2022 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.x.di
import com.squareup.anvil.annotations.ContributesTo
import com.squareup.anvil.annotations.MergeSubcomponent
import dagger.BindsInstance
import dagger.Subcomponent
import io.element.android.x.architecture.NodeFactoriesBindings
import io.element.android.x.matrix.room.MatrixRoom
@SingleIn(RoomScope::class)
@MergeSubcomponent(RoomScope::class)
interface RoomComponent : NodeFactoriesBindings {
fun matrixRoom(): MatrixRoom
@Subcomponent.Builder
interface Builder {
@BindsInstance
fun room(room: MatrixRoom): Builder
fun build(): RoomComponent
}
@ContributesTo(SessionScope::class)
interface ParentBindings {
fun roomComponentBuilder(): Builder
}
}

View file

@ -26,7 +26,7 @@ import io.element.android.x.matrix.MatrixClient
@SingleIn(SessionScope::class) @SingleIn(SessionScope::class)
@MergeSubcomponent(SessionScope::class) @MergeSubcomponent(SessionScope::class)
interface SessionComponent: NodeFactoriesBindings { interface SessionComponent: NodeFactoriesBindings, RoomComponent.ParentBindings {
fun matrixClient(): MatrixClient fun matrixClient(): MatrixClient

View file

@ -1,7 +1,11 @@
package io.element.android.x.node package io.element.android.x.node
import android.os.Parcelable import android.os.Parcelable
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import coil.Coil import coil.Coil
import com.bumble.appyx.core.composable.Children import com.bumble.appyx.core.composable.Children
@ -9,6 +13,7 @@ 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.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.x.architecture.bindings import io.element.android.x.architecture.bindings
@ -83,7 +88,17 @@ class LoggedInFlowNode(
createNode<RoomListNode>(buildContext, plugins = listOf(roomListCallback)) createNode<RoomListNode>(buildContext, plugins = listOf(roomListCallback))
} }
is NavTarget.Room -> { is NavTarget.Room -> {
RoomFlowNode(buildContext, navTarget.roomId) val room = matrixClient.getRoom(roomId = navTarget.roomId)
if (room == null) {
// TODO CREATE UNKNOWN ROOM NODE
node(buildContext) {
Box(modifier = it.fillMaxSize(), contentAlignment = Alignment.Center) {
Text(text = "Unknown room with id = ${navTarget.roomId}")
}
}
} else {
RoomFlowNode(buildContext, room)
}
} }
NavTarget.Settings -> { NavTarget.Settings -> {
PreferencesFlowNode(buildContext, onOpenBugReport) PreferencesFlowNode(buildContext, onOpenBugReport)

View file

@ -9,15 +9,18 @@ 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.navmodel.backstack.BackStack import com.bumble.appyx.navmodel.backstack.BackStack
import io.element.android.x.architecture.bindings
import io.element.android.x.architecture.createNode import io.element.android.x.architecture.createNode
import io.element.android.x.core.di.DaggerComponentOwner
import io.element.android.x.di.RoomComponent
import io.element.android.x.features.messages.MessagesNode import io.element.android.x.features.messages.MessagesNode
import io.element.android.x.matrix.core.RoomId import io.element.android.x.matrix.room.MatrixRoom
import kotlinx.parcelize.Parcelize import kotlinx.parcelize.Parcelize
import timber.log.Timber import timber.log.Timber
class RoomFlowNode( class RoomFlowNode(
buildContext: BuildContext, buildContext: BuildContext,
private val roomId: RoomId, private val room: MatrixRoom,
private val backstack: BackStack<NavTarget> = BackStack( private val backstack: BackStack<NavTarget> = BackStack(
initialElement = NavTarget.Messages, initialElement = NavTarget.Messages,
savedStateMap = buildContext.savedStateMap, savedStateMap = buildContext.savedStateMap,
@ -25,9 +28,11 @@ class RoomFlowNode(
) : ParentNode<RoomFlowNode.NavTarget>( ) : ParentNode<RoomFlowNode.NavTarget>(
navModel = backstack, navModel = backstack,
buildContext = buildContext buildContext = buildContext
) { ), DaggerComponentOwner {
override val daggerComponent: Any by lazy {
parent!!.bindings<RoomComponent.ParentBindings>().roomComponentBuilder().room(room).build()
}
init { init {
lifecycle.subscribe( lifecycle.subscribe(

View file

@ -1,10 +1,8 @@
package io.element.android.x.features.messages package io.element.android.x.features.messages
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
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
@ -12,29 +10,24 @@ import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.x.anvilannotations.ContributesNode import io.element.android.x.anvilannotations.ContributesNode
import io.element.android.x.di.SessionScope import io.element.android.x.architecture.presenterConnector
import io.element.android.x.di.RoomScope
@ContributesNode(SessionScope::class) @ContributesNode(RoomScope::class)
class MessagesNode @AssistedInject constructor( class MessagesNode @AssistedInject constructor(
@Assisted buildContext: BuildContext, @Assisted buildContext: BuildContext,
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
//presenter: MessagesPresenter, presenter: MessagesPresenter,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
private val connector = presenterConnector(presenter)
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
/*
val state by connector.stateFlow.collectAsState() val state by connector.stateFlow.collectAsState()
MessagesView( MessagesView(
state = state, state = state,
onBackPressed = this::navigateUp, onBackPressed = this::navigateUp,
) )
*/
Box(
modifier = modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(text = "MESSAGES NODE")
}
} }
} }

View file

@ -1,8 +1,16 @@
package io.element.android.x.features.messages package io.element.android.x.features.messages
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.runtime.saveable.rememberSaveable
import io.element.android.x.architecture.Presenter import io.element.android.x.architecture.Presenter
import io.element.android.x.designsystem.components.avatar.AvatarData
import io.element.android.x.designsystem.components.avatar.AvatarSize
import io.element.android.x.features.messages.actionlist.ActionListPresenter import io.element.android.x.features.messages.actionlist.ActionListPresenter
import io.element.android.x.features.messages.actionlist.TimelineItemAction import io.element.android.x.features.messages.actionlist.TimelineItemAction
import io.element.android.x.features.messages.model.MessagesTimelineItemState import io.element.android.x.features.messages.model.MessagesTimelineItemState
@ -12,8 +20,8 @@ import io.element.android.x.features.messages.textcomposer.MessageComposerPresen
import io.element.android.x.features.messages.textcomposer.MessageComposerState import io.element.android.x.features.messages.textcomposer.MessageComposerState
import io.element.android.x.features.messages.timeline.TimelinePresenter import io.element.android.x.features.messages.timeline.TimelinePresenter
import io.element.android.x.matrix.MatrixClient import io.element.android.x.matrix.MatrixClient
import io.element.android.x.matrix.core.RoomId
import io.element.android.x.matrix.room.MatrixRoom import io.element.android.x.matrix.room.MatrixRoom
import io.element.android.x.matrix.ui.MatrixItemHelper
import io.element.android.x.textcomposer.MessageComposerMode import io.element.android.x.textcomposer.MessageComposerMode
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -21,14 +29,15 @@ import timber.log.Timber
import javax.inject.Inject import javax.inject.Inject
class MessagesPresenter @Inject constructor( class MessagesPresenter @Inject constructor(
private val client: MatrixClient, private val matrixClient: MatrixClient,
private val roomId: RoomId,
private val room: MatrixRoom, private val room: MatrixRoom,
private val composerPresenter: MessageComposerPresenter, private val composerPresenter: MessageComposerPresenter,
private val timelinePresenter: TimelinePresenter, private val timelinePresenter: TimelinePresenter,
private val actionListPresenter: ActionListPresenter, private val actionListPresenter: ActionListPresenter,
) : Presenter<MessagesState> { ) : Presenter<MessagesState> {
private val matrixItemHelper = MatrixItemHelper(matrixClient)
@Composable @Composable
override fun present(): MessagesState { override fun present(): MessagesState {
val localCoroutineScope = rememberCoroutineScope() val localCoroutineScope = rememberCoroutineScope()
@ -36,13 +45,31 @@ class MessagesPresenter @Inject constructor(
val timelineState = timelinePresenter.present() val timelineState = timelinePresenter.present()
val actionListState = actionListPresenter.present() val actionListState = actionListPresenter.present()
val syncUpdateFlow = room.syncUpdateFlow().collectAsState(0L)
val roomName: MutableState<String?> = rememberSaveable {
mutableStateOf(null)
}
val roomAvatar: MutableState<AvatarData?> = remember {
mutableStateOf(null)
}
LaunchedEffect(syncUpdateFlow) {
roomAvatar.value =
matrixItemHelper.loadAvatarData(
room = room,
size = AvatarSize.SMALL
)
roomName.value = room.name
}
fun handleEvents(event: MessagesEvents) { fun handleEvents(event: MessagesEvents) {
when (event) { when (event) {
is MessagesEvents.HandleAction -> localCoroutineScope.handleTimelineAction(event.action, event.messageEvent, composerState) is MessagesEvents.HandleAction -> localCoroutineScope.handleTimelineAction(event.action, event.messageEvent, composerState)
} }
} }
return MessagesState( return MessagesState(
roomId = roomId, roomId = room.roomId,
roomName = roomName.value,
roomAvatar = roomAvatar.value,
composerState = composerState, composerState = composerState,
timelineState = timelineState, timelineState = timelineState,
actionListState = actionListState, actionListState = actionListState,

View file

@ -17,6 +17,7 @@
package io.element.android.x.matrix package io.element.android.x.matrix
import io.element.android.x.core.coroutine.CoroutineDispatchers import io.element.android.x.core.coroutine.CoroutineDispatchers
import io.element.android.x.matrix.core.RoomId
import io.element.android.x.matrix.core.SessionId import io.element.android.x.matrix.core.SessionId
import io.element.android.x.matrix.core.UserId import io.element.android.x.matrix.core.UserId
import io.element.android.x.matrix.media.MediaResolver import io.element.android.x.matrix.media.MediaResolver
@ -108,8 +109,8 @@ class MatrixClient internal constructor(
slidingSyncObserverToken = slidingSync.sync() slidingSyncObserverToken = slidingSync.sync()
} }
fun getRoom(roomId: String): MatrixRoom? { fun getRoom(roomId: RoomId): MatrixRoom? {
val slidingSyncRoom = slidingSync.getRoom(roomId) ?: return null val slidingSyncRoom = slidingSync.getRoom(roomId.value) ?: return null
val room = slidingSyncRoom.fullRoom() ?: return null val room = slidingSyncRoom.fullRoom() ?: return null
return MatrixRoom( return MatrixRoom(
slidingSyncUpdateFlow = slidingSyncObserverProxy.updateSummaryFlow, slidingSyncUpdateFlow = slidingSyncObserverProxy.updateSummaryFlow,