knock requests : add permissions check
This commit is contained in:
parent
58365730de
commit
2c9f0dd471
5 changed files with 150 additions and 39 deletions
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -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,
|
||||||
)
|
)
|
||||||
|
|
|
||||||
|
|
@ -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(),
|
|
||||||
)
|
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue