knock requests : add permissions check

This commit is contained in:
ganfra 2024-11-27 11:40:47 +01:00
parent 1978c9dbdb
commit 20ed6bb0d2
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 {
data class Accept(val knockRequest: KnockRequest) : KnockRequestsListEvents
data class Decline(val knockRequest: KnockRequest) : KnockRequestsListEvents
data class DeclineAndBan(val knockRequest: KnockRequest) : KnockRequestsListEvents
data object AcceptAll : KnockRequestsListEvents
data object DismissCurrentAction : KnockRequestsListEvents
}

View file

@ -8,35 +8,77 @@
package io.element.android.features.knockrequests.impl.list
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.remember
import io.element.android.libraries.architecture.AsyncAction
import io.element.android.libraries.architecture.AsyncData
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 javax.inject.Inject
class KnockRequestsListPresenter @Inject constructor() : Presenter<KnockRequestsListState> {
class KnockRequestsListPresenter @Inject constructor(
private val room: MatrixRoom,
) : Presenter<KnockRequestsListState> {
@Composable
override fun present(): KnockRequestsListState {
val actions = remember {
mutableStateOf<KnockRequestsCurrentAction>(KnockRequestsCurrentAction.None)
}
val currentAction = remember { 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) {
when (event) {
KnockRequestsListEvents.AcceptAll -> Unit
is KnockRequestsListEvents.Accept -> Unit
is KnockRequestsListEvents.Decline -> Unit
KnockRequestsListEvents.DismissCurrentAction -> {
actions.value = KnockRequestsCurrentAction.None
KnockRequestsListEvents.AcceptAll -> {
currentAction.value = KnockRequestsCurrentAction.AcceptAll(AsyncAction.Uninitialized)
}
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(
knockRequests = AsyncData.Success(persistentListOf()),
currentAction = actions.value,
currentAction = currentAction.value,
canAccept = canAccept,
canDecline = canDecline,
canBan = canBan,
eventSink = ::handleEvents
)
}

View file

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

View file

@ -52,7 +52,40 @@ open class KnockRequestsListStateProvider : PreviewParameterProvider<KnockReques
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(
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 = {},
) = KnockRequestsListState(
knockRequests = knockRequests,
currentAction = actions,
currentAction = currentAction,
canAccept = canAccept,
canDecline = canDecline,
canBan = canBan,
eventSink = eventSink,
)

View file

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