Merge remote-tracking branch 'origin/develop' into feature/fre/start_chat_with_matrix_id

This commit is contained in:
Florian Renaud 2023-04-05 17:43:52 +02:00
commit 4bbc2aa3c2
75 changed files with 1695 additions and 125 deletions

View file

@ -0,0 +1,72 @@
/*
* 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.appnav
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.designsystem.utils.SnackbarMessage
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.libraries.matrix.api.verification.SessionVerificationService
import io.element.android.libraries.matrix.api.verification.VerificationFlowState
import io.element.android.libraries.ui.strings.R
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.coroutines.Job
import kotlinx.coroutines.flow.drop
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
import kotlinx.coroutines.launch
import javax.inject.Inject
import kotlin.coroutines.coroutineContext
class LoggedInEventProcessor @Inject constructor(
private val snackbarDispatcher: SnackbarDispatcher,
roomMembershipObserver: RoomMembershipObserver,
sessionVerificationService: SessionVerificationService,
) {
private var observingJob: Job? = null
private val displayLeftRoomMessage = roomMembershipObserver.updates
.map { !it.isUserInRoom }
private val displayVerificationSuccessfulMessage = sessionVerificationService.verificationFlowState
.map { it == VerificationFlowState.Finished }
fun observeEvents(coroutineScope: CoroutineScope) {
observingJob = coroutineScope.launch {
displayLeftRoomMessage.onEach {
displayMessage(R.string.common_current_user_left_room)
}.launchIn(this)
displayVerificationSuccessfulMessage
.drop(1)
.onEach {
displayMessage(R.string.common_verification_complete)
}.launchIn(this)
}
}
fun stopObserving() {
observingJob?.cancel()
observingJob = null
}
private suspend fun displayMessage(message: Int) {
snackbarDispatcher.post(SnackbarMessage(message))
}
}

View file

@ -47,13 +47,17 @@ import io.element.android.libraries.architecture.bindings
import io.element.android.libraries.architecture.createNode
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.designsystem.theme.components.Text
import io.element.android.libraries.designsystem.utils.SnackbarDispatcher
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.MAIN_SPACE
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.ui.di.MatrixUIBindings
import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.Dispatchers
import kotlinx.parcelize.Parcelize
import kotlin.coroutines.coroutineContext
@ContributesNode(AppScope::class)
class LoggedInFlowNode @AssistedInject constructor(
@ -64,6 +68,8 @@ class LoggedInFlowNode @AssistedInject constructor(
private val createRoomEntryPoint: CreateRoomEntryPoint,
private val appNavigationStateService: AppNavigationStateService,
private val verifySessionEntryPoint: VerifySessionEntryPoint,
private val coroutineScope: CoroutineScope,
snackbarDispatcher: SnackbarDispatcher,
) : BackstackNode<LoggedInFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.RoomList,
@ -88,6 +94,11 @@ class LoggedInFlowNode @AssistedInject constructor(
) : NodeInputs
private val inputs: Inputs = inputs()
private val loggedInFlowProcessor = LoggedInEventProcessor(
snackbarDispatcher,
inputs.matrixClient.roomMembershipObserver(),
inputs.matrixClient.sessionVerificationService(),
)
override fun onBuilt() {
super.onBuilt()
@ -100,6 +111,7 @@ class LoggedInFlowNode @AssistedInject constructor(
appNavigationStateService.onNavigateToSession(inputs.matrixClient.sessionId)
// TODO We do not support Space yet, so directly navigate to main space
appNavigationStateService.onNavigateToSpace(MAIN_SPACE)
loggedInFlowProcessor.observeEvents(coroutineScope)
},
onDestroy = {
val imageLoaderFactory = bindings<MatrixUIBindings>().notLoggedInImageLoaderFactory()
@ -107,6 +119,7 @@ class LoggedInFlowNode @AssistedInject constructor(
plugins<LifecycleCallback>().forEach { it.onFlowReleased(inputs.matrixClient) }
appNavigationStateService.onLeavingSpace()
appNavigationStateService.onLeavingSession()
loggedInFlowProcessor.stopObserving()
}
)
}

View file

@ -18,6 +18,7 @@ package io.element.android.appnav
import android.os.Parcelable
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.ui.Modifier
import com.bumble.appyx.core.composable.Children
import com.bumble.appyx.core.lifecycle.subscribe
@ -38,7 +39,12 @@ import io.element.android.libraries.architecture.animation.rememberDefaultTransi
import io.element.android.libraries.architecture.inputs
import io.element.android.libraries.di.SessionScope
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.api.room.RoomMembershipObserver
import io.element.android.services.appnavstate.api.AppNavigationStateService
import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.flow.filter
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.onEach
import kotlinx.parcelize.Parcelize
import timber.log.Timber
@ -49,6 +55,8 @@ class RoomFlowNode @AssistedInject constructor(
private val messagesEntryPoint: MessagesEntryPoint,
private val roomDetailsEntryPoint: RoomDetailsEntryPoint,
private val appNavigationStateService: AppNavigationStateService,
roomMembershipObserver: RoomMembershipObserver,
coroutineScope: CoroutineScope,
) : BackstackNode<RoomFlowNode.NavTarget>(
backstack = BackStack(
initialElement = NavTarget.Messages,
@ -68,6 +76,7 @@ class RoomFlowNode @AssistedInject constructor(
) : NodeInputs
private val inputs: Inputs = inputs()
private val timeline = inputs.room.timeline()
private val roomFlowPresenter = RoomFlowPresenter(inputs.room)
@ -85,6 +94,13 @@ class RoomFlowNode @AssistedInject constructor(
appNavigationStateService.onLeavingRoom()
}
)
roomMembershipObserver.updates
.filter { update -> update.roomId == inputs.room.roomId && !update.isUserInRoom }
.onEach {
navigateUp()
}
.launchIn(coroutineScope)
}
override fun resolve(navTarget: NavTarget, buildContext: BuildContext): Node {
@ -97,7 +113,7 @@ class RoomFlowNode @AssistedInject constructor(
})
}
NavTarget.RoomDetails -> {
roomDetailsEntryPoint.createNode(this, buildContext)
roomDetailsEntryPoint.createNode(this, buildContext, emptyList())
}
}
}