knock requests : add permissions check

This commit is contained in:
ganfra 2024-11-27 11:40:47 +01:00
parent 58365730de
commit 2c9f0dd471
5 changed files with 150 additions and 39 deletions

View file

@ -12,6 +12,7 @@ import io.element.android.features.knockrequests.impl.KnockRequest
sealed interface KnockRequestsListEvents { sealed interface KnockRequestsListEvents {
data class Accept(val knockRequest: KnockRequest) : KnockRequestsListEvents data class Accept(val knockRequest: KnockRequest) : KnockRequestsListEvents
data class Decline(val knockRequest: KnockRequest) : KnockRequestsListEvents data class Decline(val knockRequest: KnockRequest) : KnockRequestsListEvents
data class DeclineAndBan(val knockRequest: KnockRequest) : KnockRequestsListEvents
data object AcceptAll : KnockRequestsListEvents data object AcceptAll : KnockRequestsListEvents
data object DismissCurrentAction : KnockRequestsListEvents data object DismissCurrentAction : KnockRequestsListEvents
} }

View file

@ -8,35 +8,77 @@
package io.element.android.features.knockrequests.impl.list package io.element.android.features.knockrequests.impl.list
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember import androidx.compose.runtime.remember
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
import io.element.android.libraries.architecture.Presenter import io.element.android.libraries.architecture.Presenter
import io.element.android.libraries.matrix.api.room.MatrixRoom
import io.element.android.libraries.matrix.ui.room.canBanAsState
import io.element.android.libraries.matrix.ui.room.canInviteAsState
import io.element.android.libraries.matrix.ui.room.canKickAsState
import kotlinx.collections.immutable.persistentListOf import kotlinx.collections.immutable.persistentListOf
import javax.inject.Inject import javax.inject.Inject
class KnockRequestsListPresenter @Inject constructor() : Presenter<KnockRequestsListState> { class KnockRequestsListPresenter @Inject constructor(
private val room: MatrixRoom,
) : Presenter<KnockRequestsListState> {
@Composable @Composable
override fun present(): KnockRequestsListState { override fun present(): KnockRequestsListState {
val actions = remember { val currentAction = remember { mutableStateOf<KnockRequestsCurrentAction>(KnockRequestsCurrentAction.None) }
mutableStateOf<KnockRequestsCurrentAction>(KnockRequestsCurrentAction.None) val syncUpdateFlow = room.syncUpdateFlow.collectAsState()
} val canBan by room.canBanAsState(syncUpdateFlow.value)
val canDecline by room.canKickAsState(syncUpdateFlow.value)
val canAccept by room.canInviteAsState(syncUpdateFlow.value)
fun handleEvents(event: KnockRequestsListEvents) { fun handleEvents(event: KnockRequestsListEvents) {
when (event) { when (event) {
KnockRequestsListEvents.AcceptAll -> Unit KnockRequestsListEvents.AcceptAll -> {
is KnockRequestsListEvents.Accept -> Unit currentAction.value = KnockRequestsCurrentAction.AcceptAll(AsyncAction.Uninitialized)
is KnockRequestsListEvents.Decline -> Unit
KnockRequestsListEvents.DismissCurrentAction -> {
actions.value = KnockRequestsCurrentAction.None
} }
is KnockRequestsListEvents.Accept -> {
currentAction.value = KnockRequestsCurrentAction.Accept(event.knockRequest, AsyncAction.Uninitialized)
}
is KnockRequestsListEvents.Decline -> {
currentAction.value = KnockRequestsCurrentAction.Decline(event.knockRequest, AsyncAction.Uninitialized)
}
is KnockRequestsListEvents.DeclineAndBan -> {
currentAction.value = KnockRequestsCurrentAction.DeclineAndBan(event.knockRequest, AsyncAction.Uninitialized)
}
KnockRequestsListEvents.DismissCurrentAction -> {
currentAction.value = KnockRequestsCurrentAction.None
}
}
}
LaunchedEffect(currentAction) {
when (val action = currentAction.value) {
is KnockRequestsCurrentAction.Accept -> {
// Accept the knock request
}
is KnockRequestsCurrentAction.Decline -> {
// Decline the knock request
}
is KnockRequestsCurrentAction.DeclineAndBan -> {
// Decline and ban the user
}
is KnockRequestsCurrentAction.AcceptAll -> {
// Accept all knock requests
}
KnockRequestsCurrentAction.None -> Unit
} }
} }
return KnockRequestsListState( return KnockRequestsListState(
knockRequests = AsyncData.Success(persistentListOf()), knockRequests = AsyncData.Success(persistentListOf()),
currentAction = actions.value, currentAction = currentAction.value,
canAccept = canAccept,
canDecline = canDecline,
canBan = canBan,
eventSink = ::handleEvents eventSink = ::handleEvents
) )
} }

View file

@ -15,6 +15,9 @@ import kotlinx.collections.immutable.ImmutableList
data class KnockRequestsListState( data class KnockRequestsListState(
val knockRequests: AsyncData<ImmutableList<KnockRequest>>, val knockRequests: AsyncData<ImmutableList<KnockRequest>>,
val currentAction: KnockRequestsCurrentAction, val currentAction: KnockRequestsCurrentAction,
val canAccept: Boolean,
val canDecline: Boolean,
val canBan: Boolean,
val eventSink: (KnockRequestsListEvents) -> Unit, val eventSink: (KnockRequestsListEvents) -> Unit,
) { ) {
val canAcceptAll = knockRequests is AsyncData.Success && knockRequests.data.size > 1 val canAcceptAll = knockRequests is AsyncData.Success && knockRequests.data.size > 1
@ -22,7 +25,8 @@ data class KnockRequestsListState(
sealed interface KnockRequestsCurrentAction { sealed interface KnockRequestsCurrentAction {
data object None : KnockRequestsCurrentAction data object None : KnockRequestsCurrentAction
data class Accept(val async: AsyncAction<Unit>) : KnockRequestsCurrentAction data class Accept(val knockRequest: KnockRequest, val async: AsyncAction<Unit>) : KnockRequestsCurrentAction
data class Decline(val async: AsyncAction<Unit>) : KnockRequestsCurrentAction data class Decline(val knockRequest: KnockRequest, val async: AsyncAction<Unit>) : KnockRequestsCurrentAction
data class DeclineAndBan(val knockRequest: KnockRequest, val async: AsyncAction<Unit>) : KnockRequestsCurrentAction
data class AcceptAll(val async: AsyncAction<Unit>) : KnockRequestsCurrentAction data class AcceptAll(val async: AsyncAction<Unit>) : KnockRequestsCurrentAction
} }

View file

@ -52,7 +52,40 @@ open class KnockRequestsListStateProvider : PreviewParameterProvider<KnockReques
aKnockRequest() aKnockRequest()
) )
), ),
actions = KnockRequestsCurrentAction.AcceptAll(AsyncAction.Loading), currentAction = KnockRequestsCurrentAction.AcceptAll(AsyncAction.Loading),
),
aKnockRequestsListState(
knockRequests = AsyncData.Success(
persistentListOf(
aKnockRequest()
)
),
canAccept = false,
),
aKnockRequestsListState(
knockRequests = AsyncData.Success(
persistentListOf(
aKnockRequest()
)
),
canDecline = false,
),
aKnockRequestsListState(
knockRequests = AsyncData.Success(
persistentListOf(
aKnockRequest()
)
),
canAccept = false,
canDecline = false,
),
aKnockRequestsListState(
knockRequests = AsyncData.Success(
persistentListOf(
aKnockRequest()
)
),
canBan = false,
), ),
) )
} }
@ -71,10 +104,16 @@ fun aKnockRequest(
fun aKnockRequestsListState( fun aKnockRequestsListState(
knockRequests: AsyncData<ImmutableList<KnockRequest>> = AsyncData.Success(persistentListOf()), knockRequests: AsyncData<ImmutableList<KnockRequest>> = AsyncData.Success(persistentListOf()),
actions: KnockRequestsCurrentAction = KnockRequestsCurrentAction.None, currentAction: KnockRequestsCurrentAction = KnockRequestsCurrentAction.None,
canAccept: Boolean = true,
canDecline: Boolean = true,
canBan: Boolean = true,
eventSink: (KnockRequestsListEvents) -> Unit = {}, eventSink: (KnockRequestsListEvents) -> Unit = {},
) = KnockRequestsListState( ) = KnockRequestsListState(
knockRequests = knockRequests, knockRequests = knockRequests,
currentAction = actions, currentAction = currentAction,
canAccept = canAccept,
canDecline = canDecline,
canBan = canBan,
eventSink = eventSink, eventSink = eventSink,
) )

View file

@ -101,6 +101,9 @@ private fun KnockRequestsListContent(state: KnockRequestsListState, modifier: Mo
} else { } else {
KnockRequestsList( KnockRequestsList(
knockRequests = knockRequests, knockRequests = knockRequests,
canAccept = state.canAccept,
canDecline = state.canDecline,
canBan = state.canBan,
onAcceptClick = ::onAcceptClick, onAcceptClick = ::onAcceptClick,
onDeclineClick = ::onDeclineClick, onDeclineClick = ::onDeclineClick,
) )
@ -154,6 +157,13 @@ private fun KnockRequestsActionsView(
onErrorDismiss = onDismiss, onErrorDismiss = onDismiss,
) )
} }
is KnockRequestsCurrentAction.DeclineAndBan -> {
AsyncActionView(
async = actions.async,
onSuccess = {},
onErrorDismiss = onDismiss,
)
}
KnockRequestsCurrentAction.None -> Unit KnockRequestsCurrentAction.None -> Unit
} }
} }
@ -162,6 +172,9 @@ private fun KnockRequestsActionsView(
@Composable @Composable
private fun KnockRequestsList( private fun KnockRequestsList(
knockRequests: ImmutableList<KnockRequest>, knockRequests: ImmutableList<KnockRequest>,
canAccept: Boolean,
canDecline: Boolean,
canBan: Boolean,
onAcceptClick: (KnockRequest) -> Unit, onAcceptClick: (KnockRequest) -> Unit,
onDeclineClick: (KnockRequest) -> Unit, onDeclineClick: (KnockRequest) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -171,6 +184,9 @@ private fun KnockRequestsList(
KnockRequestItem( KnockRequestItem(
knockRequest = knockRequest, knockRequest = knockRequest,
onAcceptClick = onAcceptClick, onAcceptClick = onAcceptClick,
canBan = canBan,
canDecline = canDecline,
canAccept = canAccept,
onDeclineClick = onDeclineClick, onDeclineClick = onDeclineClick,
) )
if (index != knockRequests.size - 1) { if (index != knockRequests.size - 1) {
@ -183,6 +199,9 @@ private fun KnockRequestsList(
@Composable @Composable
private fun KnockRequestItem( private fun KnockRequestItem(
knockRequest: KnockRequest, knockRequest: KnockRequest,
canAccept: Boolean,
canDecline: Boolean,
canBan: Boolean,
onAcceptClick: (KnockRequest) -> Unit, onAcceptClick: (KnockRequest) -> Unit,
onDeclineClick: (KnockRequest) -> Unit, onDeclineClick: (KnockRequest) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
@ -194,7 +213,7 @@ private fun KnockRequestItem(
) { ) {
Avatar(knockRequest.getAvatarData(AvatarSize.KnockRequestItem)) Avatar(knockRequest.getAvatarData(AvatarSize.KnockRequestItem))
Spacer(modifier = Modifier.width(16.dp)) Spacer(modifier = Modifier.width(16.dp))
Column(modifier = Modifier) { Column {
// Name // Name
Text( Text(
modifier = Modifier.clipToBounds(), modifier = Modifier.clipToBounds(),
@ -222,37 +241,43 @@ private fun KnockRequestItem(
style = ElementTheme.typography.fontBodyMdRegular, style = ElementTheme.typography.fontBodyMdRegular,
) )
} }
// Actions
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp)) { Row(Modifier.fillMaxWidth(), horizontalArrangement = Arrangement.spacedBy(16.dp)) {
OutlinedButton( if (canDecline) {
text = stringResource(CommonStrings.action_decline), OutlinedButton(
onClick = { text = stringResource(CommonStrings.action_decline),
onDeclineClick(knockRequest) onClick = {
}, onDeclineClick(knockRequest)
size = ButtonSize.MediumLowPadding, },
modifier = Modifier.weight(1f), size = ButtonSize.MediumLowPadding,
) modifier = Modifier.weight(1f),
Button( )
text = stringResource(CommonStrings.action_accept), }
if (canAccept) {
Button(
text = stringResource(CommonStrings.action_accept),
onClick = {
onAcceptClick(knockRequest)
},
size = ButtonSize.MediumLowPadding,
modifier = Modifier.weight(1f),
)
}
}
if (canBan) {
Spacer(modifier = Modifier.height(12.dp))
TextButton(
text = stringResource(CommonStrings.screen_knock_requests_list_decline_and_ban_action_title),
onClick = { onClick = {
onAcceptClick(knockRequest) onAcceptClick(knockRequest)
}, },
size = ButtonSize.MediumLowPadding, destructive = true,
modifier = Modifier.weight(1f), size = ButtonSize.Small,
modifier = Modifier.fillMaxWidth(),
) )
} }
Spacer(modifier = Modifier.height(12.dp))
TextButton(
text = stringResource(CommonStrings.screen_knock_requests_list_decline_and_ban_action_title),
onClick = {
onAcceptClick(knockRequest)
},
destructive = true,
size = ButtonSize.Small,
modifier = Modifier.fillMaxWidth(),
)
} }
} }
} }