Room join : add presenter tests

This commit is contained in:
ganfra 2024-04-11 21:07:10 +02:00
parent fbb92f0c9a
commit ab8c31541b
10 changed files with 410 additions and 88 deletions

View file

@ -32,8 +32,8 @@ import io.element.android.libraries.matrix.api.MatrixClient
import io.element.android.libraries.matrix.api.core.RoomId
import io.element.android.libraries.matrix.api.room.CurrentUserMembership
import io.element.android.libraries.matrix.api.room.MatrixRoomInfo
import org.jetbrains.annotations.VisibleForTesting
import java.util.Optional
import kotlin.jvm.optionals.getOrNull
class JoinRoomPresenter @AssistedInject constructor(
@Assisted private val roomId: RoomId,
@ -49,8 +49,6 @@ class JoinRoomPresenter @AssistedInject constructor(
@Composable
override fun present(): JoinRoomState {
val roomInfo by matrixClient.getRoomInfoFlow(roomId).collectAsState(initial = Optional.empty())
val joinAuthorisationStatus = joinAuthorisationStatus(roomInfo)
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
val contentState by produceState<AsyncData<ContentState>>(initialValue = AsyncData.Uninitialized, key1 = roomInfo) {
value = when {
roomInfo.isPresent -> {
@ -61,20 +59,25 @@ class JoinRoomPresenter @AssistedInject constructor(
val contentState = roomDescription.get().toContentState()
AsyncData.Success(contentState)
}
else -> AsyncData.Uninitialized
else -> {
AsyncData.Uninitialized
}
}
}
val acceptDeclineInviteState = acceptDeclineInvitePresenter.present()
fun handleEvents(event: JoinRoomEvents) {
when (event) {
JoinRoomEvents.AcceptInvite, JoinRoomEvents.JoinRoom -> {
val inviteData = contentState.toInviteData() ?: return
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.AcceptInvite(contentState.toInviteData())
AcceptDeclineInviteEvents.AcceptInvite(inviteData)
)
}
JoinRoomEvents.DeclineInvite -> {
val inviteData = contentState.toInviteData() ?: return
acceptDeclineInviteState.eventSink(
AcceptDeclineInviteEvents.DeclineInvite(contentState.toInviteData())
AcceptDeclineInviteEvents.DeclineInvite(inviteData)
)
}
}
@ -82,66 +85,69 @@ class JoinRoomPresenter @AssistedInject constructor(
return JoinRoomState(
contentState = contentState,
joinAuthorisationStatus = joinAuthorisationStatus,
acceptDeclineInviteState = acceptDeclineInviteState,
eventSink = ::handleEvents
)
}
}
private fun RoomDescription.toContentState(): ContentState {
return ContentState(
roomId = roomId,
name = name,
description = description,
numberOfMembers = numberOfMembers,
isDirect = false,
roomAvatarUrl = avatarUrl
)
}
private fun MatrixRoomInfo.toContentState(): ContentState {
fun title(): String {
return name ?: canonicalAlias ?: roomId.value
}
fun description(): String? {
val topic = topic
val alias = canonicalAlias
val name = name
return when {
topic != null -> topic
name != null && alias != null -> alias
name == null && alias == null -> null
else -> roomId.value
}
}
return ContentState(
roomId = roomId,
name = title(),
description = description(),
numberOfMembers = activeMembersCount,
isDirect = isDirect,
roomAvatarUrl = avatarUrl
)
}
private fun AsyncData<ContentState>.toInviteData(): InviteData {
return dataOrNull().let {
InviteData(
roomId = roomId,
roomName = it?.name ?: "",
isDirect = it?.isDirect ?: false
)
}
}
@Composable
private fun joinAuthorisationStatus(roomInfo: Optional<MatrixRoomInfo>): JoinAuthorisationStatus {
val userMembership = roomInfo.getOrNull()?.currentUserMembership
return when {
userMembership == CurrentUserMembership.INVITED -> return JoinAuthorisationStatus.IsInvited
@VisibleForTesting
internal fun RoomDescription.toContentState(): ContentState {
return ContentState(
roomId = roomId,
name = name,
description = description,
numberOfMembers = numberOfMembers,
isDirect = false,
roomAvatarUrl = avatarUrl,
joinAuthorisationStatus = when (joinRule) {
RoomDescription.JoinRule.KNOCK -> JoinAuthorisationStatus.CanKnock
RoomDescription.JoinRule.PUBLIC -> JoinAuthorisationStatus.CanJoin
else -> JoinAuthorisationStatus.Unknown
}
)
}
@VisibleForTesting
internal fun MatrixRoomInfo.toContentState(): ContentState {
fun title(): String {
return name ?: canonicalAlias ?: id
}
fun description(): String? {
val topic = topic
val alias = canonicalAlias
val name = name
return when {
topic != null -> topic
name != null && alias != null -> alias
name == null && alias == null -> null
else -> id
}
}
return ContentState(
roomId = RoomId(id),
name = title(),
description = description(),
numberOfMembers = activeMembersCount,
isDirect = isDirect,
roomAvatarUrl = avatarUrl,
joinAuthorisationStatus = when {
currentUserMembership == CurrentUserMembership.INVITED -> JoinAuthorisationStatus.IsInvited
isPublic -> JoinAuthorisationStatus.CanJoin
else -> JoinAuthorisationStatus.Unknown
}
)
}
@VisibleForTesting
internal fun AsyncData<ContentState>.toInviteData(): InviteData? {
return dataOrNull()?.let { contentState ->
InviteData(
roomId = contentState.roomId,
roomName = contentState.name,
isDirect = contentState.isDirect
)
}
}

View file

@ -26,10 +26,11 @@ import io.element.android.libraries.matrix.api.core.RoomId
@Immutable
data class JoinRoomState(
val contentState: AsyncData<ContentState>,
val joinAuthorisationStatus: JoinAuthorisationStatus,
val acceptDeclineInviteState: AcceptDeclineInviteState,
val eventSink: (JoinRoomEvents) -> Unit
)
) {
val joinAuthorisationStatus = contentState.dataOrNull()?.joinAuthorisationStatus ?: JoinAuthorisationStatus.Unknown
}
data class ContentState(
val roomId: RoomId,
@ -38,6 +39,7 @@ data class ContentState(
val numberOfMembers: Long?,
val isDirect: Boolean,
val roomAvatarUrl: String?,
val joinAuthorisationStatus: JoinAuthorisationStatus,
) {
val showMemberCount = numberOfMembers != null

View file

@ -29,34 +29,49 @@ open class JoinRoomStateProvider : PreviewParameterProvider<JoinRoomState> {
contentState = AsyncData.Uninitialized
),
aJoinRoomState(
joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin
contentState = AsyncData.Success(
aContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanJoin)
)
),
aJoinRoomState(
joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock
contentState = AsyncData.Success(
aContentState(joinAuthorisationStatus = JoinAuthorisationStatus.CanKnock)
)
),
aJoinRoomState(
joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited
contentState = AsyncData.Success(
aContentState(joinAuthorisationStatus = JoinAuthorisationStatus.IsInvited)
)
),
)
}
fun aContentState(
roomId: RoomId = RoomId("@exa:matrix.org"),
name: String = "Element x android",
description: String? = "#exa:matrix.org",
numberOfMembers: Long? = null,
isDirect: Boolean = false,
roomAvatarUrl: String? = null,
joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown
) = ContentState(
roomId = roomId,
name = name,
description = description,
numberOfMembers = numberOfMembers,
isDirect = isDirect,
roomAvatarUrl = roomAvatarUrl,
joinAuthorisationStatus = joinAuthorisationStatus
)
fun aJoinRoomState(
contentState: AsyncData<ContentState> = AsyncData.Success(
ContentState(
roomId = RoomId("@exa:matrix.org"),
name = "Element x android",
description = "#exa:matrix.org",
numberOfMembers = null,
isDirect = false,
roomAvatarUrl = null
)
aContentState()
),
joinAuthorisationStatus: JoinAuthorisationStatus = JoinAuthorisationStatus.Unknown,
acceptDeclineInviteState: AcceptDeclineInviteState = anAcceptDeclineInviteState(),
eventSink: (JoinRoomEvents) -> Unit = {}
) = JoinRoomState(
contentState = contentState,
joinAuthorisationStatus = joinAuthorisationStatus,
acceptDeclineInviteState = acceptDeclineInviteState,
eventSink = eventSink
)

View file

@ -109,8 +109,7 @@ private fun JoinRoomFooter(
)
}
}
// TODO handle all cases properly
else -> {
JoinAuthorisationStatus.CanJoin -> {
Button(
text = stringResource(CommonStrings.action_join),
onClick = onJoinRoom,
@ -118,6 +117,18 @@ private fun JoinRoomFooter(
size = ButtonSize.Medium,
)
}
JoinAuthorisationStatus.CanKnock -> {
//TODO knock
/*
Button(
text = stringResource(CommonStrings.action_knock),
onClick = onJoinRoom,
modifier = modifier.fillMaxWidth(),
size = ButtonSize.Medium,
)
*/
}
JoinAuthorisationStatus.Unknown -> Unit
}
}
@ -154,8 +165,8 @@ private fun JoinRoomContent(
Column(
modifier = modifier
.fillMaxWidth()
.padding(all = 16.dp),
.fillMaxWidth()
.padding(all = 16.dp),
horizontalAlignment = Alignment.CenterHorizontally
) {
when (asyncContentState) {
@ -191,9 +202,9 @@ private fun JoinRoomMembersCount(memberCount: Long) {
Spacer(modifier = Modifier.height(8.dp))
Row(
modifier = Modifier
.background(color = ElementTheme.colors.bgSubtleSecondary, shape = CircleShape)
.widthIn(min = 48.dp)
.padding(all = 2.dp),
.background(color = ElementTheme.colors.bgSubtleSecondary, shape = CircleShape)
.widthIn(min = 48.dp)
.padding(all = 2.dp),
verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp)
) {