Let RoomMemberDetailsPresenter use UserProfilePresenter to reduce code duplication.
This commit is contained in:
parent
9b9fef1aa8
commit
9b82c6df1c
18 changed files with 153 additions and 368 deletions
|
|
@ -9,7 +9,7 @@ package io.element.android.features.roomdetails.impl
|
|||
|
||||
import androidx.compose.runtime.Immutable
|
||||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
||||
import io.element.android.features.userprofile.shared.UserProfileState
|
||||
import io.element.android.features.userprofile.api.UserProfileState
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.room.RoomMember
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ import androidx.compose.ui.tooling.preview.PreviewParameterProvider
|
|||
import io.element.android.features.leaveroom.api.LeaveRoomState
|
||||
import io.element.android.features.leaveroom.api.aLeaveRoomState
|
||||
import io.element.android.features.roomdetails.impl.members.aRoomMember
|
||||
import io.element.android.features.userprofile.shared.UserProfileState
|
||||
import io.element.android.features.userprofile.api.UserProfileState
|
||||
import io.element.android.features.userprofile.shared.aUserProfileState
|
||||
import io.element.android.libraries.matrix.api.core.RoomAlias
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
|
|
|
|||
|
|
@ -10,10 +10,9 @@ package io.element.android.features.roomdetails.impl.di
|
|||
import com.squareup.anvil.annotations.ContributesTo
|
||||
import dagger.Module
|
||||
import dagger.Provides
|
||||
import io.element.android.features.createroom.api.StartDMAction
|
||||
import io.element.android.features.roomdetails.impl.members.details.RoomMemberDetailsPresenter
|
||||
import io.element.android.features.userprofile.api.UserProfileStatePresenterFactory
|
||||
import io.element.android.libraries.di.RoomScope
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
|
||||
|
|
@ -22,13 +21,12 @@ import io.element.android.libraries.matrix.api.room.MatrixRoom
|
|||
object RoomMemberModule {
|
||||
@Provides
|
||||
fun provideRoomMemberDetailsPresenterFactory(
|
||||
matrixClient: MatrixClient,
|
||||
room: MatrixRoom,
|
||||
startDMAction: StartDMAction,
|
||||
userProfileStatePresenterFactory: UserProfileStatePresenterFactory,
|
||||
): RoomMemberDetailsPresenter.Factory {
|
||||
return object : RoomMemberDetailsPresenter.Factory {
|
||||
override fun create(roomMemberId: UserId): RoomMemberDetailsPresenter {
|
||||
return RoomMemberDetailsPresenter(roomMemberId, matrixClient, room, startDMAction)
|
||||
return RoomMemberDetailsPresenter(roomMemberId, room, userProfileStatePresenterFactory)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -9,153 +9,60 @@ package io.element.android.features.roomdetails.impl.members.details
|
|||
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.MutableState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.mutableStateOf
|
||||
import androidx.compose.runtime.produceState
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.runtime.setValue
|
||||
import dagger.assisted.Assisted
|
||||
import dagger.assisted.AssistedInject
|
||||
import io.element.android.features.createroom.api.StartDMAction
|
||||
import io.element.android.features.userprofile.shared.UserProfileEvents
|
||||
import io.element.android.features.userprofile.shared.UserProfilePresenterHelper
|
||||
import io.element.android.features.userprofile.shared.UserProfileState
|
||||
import io.element.android.features.userprofile.shared.UserProfileState.ConfirmationDialog
|
||||
import io.element.android.libraries.architecture.AsyncAction
|
||||
import io.element.android.libraries.architecture.AsyncData
|
||||
import io.element.android.features.userprofile.api.UserProfileState
|
||||
import io.element.android.features.userprofile.api.UserProfileStatePresenterFactory
|
||||
import io.element.android.libraries.architecture.Presenter
|
||||
import io.element.android.libraries.core.bool.orFalse
|
||||
import io.element.android.libraries.matrix.api.MatrixClient
|
||||
import io.element.android.libraries.matrix.api.core.RoomId
|
||||
import io.element.android.libraries.matrix.api.core.UserId
|
||||
import io.element.android.libraries.matrix.api.room.MatrixRoom
|
||||
import io.element.android.libraries.matrix.api.user.MatrixUser
|
||||
import io.element.android.libraries.matrix.ui.room.getRoomMemberAsState
|
||||
import kotlinx.coroutines.flow.distinctUntilChanged
|
||||
import kotlinx.coroutines.flow.launchIn
|
||||
import kotlinx.coroutines.flow.map
|
||||
import kotlinx.coroutines.flow.onEach
|
||||
import kotlinx.coroutines.launch
|
||||
|
||||
/**
|
||||
* Presenter for room member details screen.
|
||||
* Rely on UserProfileStatePresenter, but override some fields with room member info when available.
|
||||
*/
|
||||
class RoomMemberDetailsPresenter @AssistedInject constructor(
|
||||
@Assisted private val roomMemberId: UserId,
|
||||
private val client: MatrixClient,
|
||||
private val room: MatrixRoom,
|
||||
private val startDMAction: StartDMAction,
|
||||
userProfileStatePresenterFactory: UserProfileStatePresenterFactory,
|
||||
) : Presenter<UserProfileState> {
|
||||
interface Factory {
|
||||
fun create(roomMemberId: UserId): RoomMemberDetailsPresenter
|
||||
}
|
||||
|
||||
private val userProfilePresenterHelper = UserProfilePresenterHelper(
|
||||
userId = roomMemberId,
|
||||
client = client,
|
||||
)
|
||||
private val userProfilePresenter = userProfileStatePresenterFactory.create(roomMemberId)
|
||||
|
||||
@Composable
|
||||
override fun present(): UserProfileState {
|
||||
val coroutineScope = rememberCoroutineScope()
|
||||
var confirmationDialog by remember { mutableStateOf<ConfirmationDialog?>(null) }
|
||||
val roomMember by room.getRoomMemberAsState(roomMemberId)
|
||||
var userProfile by remember { mutableStateOf<MatrixUser?>(null) }
|
||||
val startDmActionState: MutableState<AsyncAction<RoomId>> = remember { mutableStateOf(AsyncAction.Uninitialized) }
|
||||
val isBlocked: MutableState<AsyncData<Boolean>> = remember { mutableStateOf(AsyncData.Uninitialized) }
|
||||
val isCurrentUser = remember { client.isMe(roomMemberId) }
|
||||
val dmRoomId by userProfilePresenterHelper.getDmRoomId()
|
||||
val canCall by userProfilePresenterHelper.getCanCall(dmRoomId)
|
||||
LaunchedEffect(Unit) {
|
||||
client.ignoredUsersFlow
|
||||
.map { ignoredUsers -> roomMemberId in ignoredUsers }
|
||||
.distinctUntilChanged()
|
||||
.onEach { isBlocked.value = AsyncData.Success(it) }
|
||||
.launchIn(this)
|
||||
}
|
||||
LaunchedEffect(Unit) {
|
||||
// Update room member info when opening this screen
|
||||
// We don't need to assign the result as it will be automatically propagated by `room.getRoomMemberAsState`
|
||||
room.getUpdatedMember(roomMemberId)
|
||||
.onFailure {
|
||||
// Not a member of the room, try to get the user profile
|
||||
userProfile = client.getProfile(roomMemberId).getOrNull()
|
||||
}
|
||||
}
|
||||
|
||||
fun handleEvents(event: UserProfileEvents) {
|
||||
when (event) {
|
||||
is UserProfileEvents.BlockUser -> {
|
||||
if (event.needsConfirmation) {
|
||||
confirmationDialog = ConfirmationDialog.Block
|
||||
} else {
|
||||
confirmationDialog = null
|
||||
userProfilePresenterHelper.blockUser(coroutineScope, isBlocked)
|
||||
}
|
||||
}
|
||||
is UserProfileEvents.UnblockUser -> {
|
||||
if (event.needsConfirmation) {
|
||||
confirmationDialog = ConfirmationDialog.Unblock
|
||||
} else {
|
||||
confirmationDialog = null
|
||||
userProfilePresenterHelper.unblockUser(coroutineScope, isBlocked)
|
||||
}
|
||||
}
|
||||
UserProfileEvents.ClearConfirmationDialog -> confirmationDialog = null
|
||||
UserProfileEvents.ClearBlockUserError -> {
|
||||
isBlocked.value = AsyncData.Success(isBlocked.value.dataOrNull().orFalse())
|
||||
}
|
||||
UserProfileEvents.StartDM -> {
|
||||
coroutineScope.launch {
|
||||
startDMAction.execute(roomMemberId, startDmActionState)
|
||||
}
|
||||
}
|
||||
UserProfileEvents.ClearStartDMState -> {
|
||||
startDmActionState.value = AsyncAction.Uninitialized
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val userName: String? by produceState(
|
||||
initialValue = roomMember?.displayName ?: userProfile?.displayName,
|
||||
val roomUserName: String? by produceState(
|
||||
initialValue = roomMember?.displayName,
|
||||
key1 = roomMember,
|
||||
key2 = userProfile,
|
||||
) {
|
||||
value = room.userDisplayName(roomMemberId)
|
||||
.fold(
|
||||
onSuccess = { it },
|
||||
onFailure = {
|
||||
// Fallback to user profile
|
||||
userProfile?.displayName
|
||||
}
|
||||
)
|
||||
value = room.userDisplayName(roomMemberId).getOrNull() ?: roomMember?.displayName
|
||||
}
|
||||
|
||||
val userAvatar: String? by produceState(
|
||||
initialValue = roomMember?.avatarUrl ?: userProfile?.avatarUrl,
|
||||
val roomUserAvatar: String? by produceState(
|
||||
initialValue = roomMember?.avatarUrl,
|
||||
key1 = roomMember,
|
||||
key2 = userProfile,
|
||||
) {
|
||||
value = room.userAvatarUrl(roomMemberId)
|
||||
.fold(
|
||||
onSuccess = { it },
|
||||
onFailure = {
|
||||
// Fallback to user profile
|
||||
userProfile?.avatarUrl
|
||||
}
|
||||
)
|
||||
value = room.userAvatarUrl(roomMemberId).getOrNull() ?: roomMember?.avatarUrl
|
||||
}
|
||||
|
||||
return UserProfileState(
|
||||
userId = roomMemberId,
|
||||
userName = userName,
|
||||
avatarUrl = userAvatar,
|
||||
isBlocked = isBlocked.value,
|
||||
startDmActionState = startDmActionState.value,
|
||||
displayConfirmationDialog = confirmationDialog,
|
||||
isCurrentUser = isCurrentUser,
|
||||
dmRoomId = dmRoomId,
|
||||
canCall = canCall,
|
||||
eventSink = ::handleEvents
|
||||
val userProfileState = userProfilePresenter.present()
|
||||
|
||||
return userProfileState.copy(
|
||||
userName = roomUserName ?: userProfileState.userName,
|
||||
avatarUrl = roomUserAvatar ?: userProfileState.avatarUrl,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue