knock requests : cleaning up

This commit is contained in:
ganfra 2024-12-04 14:15:17 +01:00
parent affd0570dc
commit 63c4ac81b8
9 changed files with 57 additions and 32 deletions

View file

@ -5,8 +5,6 @@
* Please see LICENSE in the repository root for full details. * Please see LICENSE in the repository root for full details.
*/ */
import extension.setupAnvil
plugins { plugins {
id("io.element.android-library") id("io.element.android-library")
} }
@ -19,4 +17,3 @@ dependencies {
implementation(projects.libraries.architecture) implementation(projects.libraries.architecture)
implementation(projects.libraries.matrix.api) implementation(projects.libraries.matrix.api)
} }

View file

@ -10,7 +10,6 @@ package io.element.android.features.knockrequests.impl
import io.element.android.libraries.designsystem.components.avatar.AvatarData import io.element.android.libraries.designsystem.components.avatar.AvatarData
import io.element.android.libraries.designsystem.components.avatar.AvatarSize import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.matrix.api.core.UserId import io.element.android.libraries.matrix.api.core.UserId
import io.element.android.libraries.matrix.api.user.MatrixUser
data class KnockRequest( data class KnockRequest(
val userId: UserId, val userId: UserId,
@ -30,6 +29,3 @@ fun KnockRequest.getAvatarData(size: AvatarSize) = AvatarData(
fun KnockRequest.getBestName(): String { fun KnockRequest.getBestName(): String {
return displayName?.takeIf { it.isNotEmpty() } ?: userId.value return displayName?.takeIf { it.isNotEmpty() } ?: userId.value
} }

View file

@ -15,7 +15,6 @@ import com.bumble.appyx.core.plugin.Plugin
import dagger.assisted.Assisted import dagger.assisted.Assisted
import dagger.assisted.AssistedInject import dagger.assisted.AssistedInject
import io.element.android.anvilannotations.ContributesNode import io.element.android.anvilannotations.ContributesNode
import io.element.android.libraries.di.AppScope
import io.element.android.libraries.di.RoomScope import io.element.android.libraries.di.RoomScope
@ContributesNode(RoomScope::class) @ContributesNode(RoomScope::class)
@ -24,7 +23,6 @@ class KnockRequestsListNode @AssistedInject constructor(
@Assisted plugins: List<Plugin>, @Assisted plugins: List<Plugin>,
private val presenter: KnockRequestsListPresenter, private val presenter: KnockRequestsListPresenter,
) : Node(buildContext, plugins = plugins) { ) : Node(buildContext, plugins = plugins) {
@Composable @Composable
override fun View(modifier: Modifier) { override fun View(modifier: Modifier) {
val state = presenter.present() val state = presenter.present()

View file

@ -26,7 +26,6 @@ import javax.inject.Inject
class KnockRequestsListPresenter @Inject constructor( class KnockRequestsListPresenter @Inject constructor(
private val room: MatrixRoom, private val room: MatrixRoom,
) : Presenter<KnockRequestsListState> { ) : Presenter<KnockRequestsListState> {
@Composable @Composable
override fun present(): KnockRequestsListState { override fun present(): KnockRequestsListState {
val currentAction = remember { mutableStateOf<KnockRequestsCurrentAction>(KnockRequestsCurrentAction.None) } val currentAction = remember { mutableStateOf<KnockRequestsCurrentAction>(KnockRequestsCurrentAction.None) }
@ -56,7 +55,7 @@ class KnockRequestsListPresenter @Inject constructor(
} }
LaunchedEffect(currentAction) { LaunchedEffect(currentAction) {
when (val action = currentAction.value) { when (currentAction.value) {
is KnockRequestsCurrentAction.Accept -> { is KnockRequestsCurrentAction.Accept -> {
// Accept the knock request // Accept the knock request
} }

View file

@ -13,6 +13,7 @@ import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.consumeWindowInsets import androidx.compose.foundation.layout.consumeWindowInsets
@ -28,7 +29,9 @@ import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableIntStateOf
import androidx.compose.runtime.mutableStateOf import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.saveable.rememberSaveable import androidx.compose.runtime.saveable.rememberSaveable
import androidx.compose.runtime.setValue import androidx.compose.runtime.setValue
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -36,6 +39,7 @@ import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.draw.clipToBounds
import androidx.compose.ui.draw.shadow import androidx.compose.ui.draw.shadow
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onSizeChanged
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameter
@ -43,6 +47,7 @@ import androidx.compose.ui.unit.dp
import io.element.android.compound.theme.ElementTheme import io.element.android.compound.theme.ElementTheme
import io.element.android.compound.tokens.generated.CompoundIcons import io.element.android.compound.tokens.generated.CompoundIcons
import io.element.android.features.knockrequests.impl.KnockRequest import io.element.android.features.knockrequests.impl.KnockRequest
import io.element.android.features.knockrequests.impl.R
import io.element.android.features.knockrequests.impl.getAvatarData import io.element.android.features.knockrequests.impl.getAvatarData
import io.element.android.features.knockrequests.impl.getBestName import io.element.android.features.knockrequests.impl.getBestName
import io.element.android.libraries.architecture.AsyncData import io.element.android.libraries.architecture.AsyncData
@ -54,6 +59,7 @@ import io.element.android.libraries.designsystem.components.avatar.AvatarSize
import io.element.android.libraries.designsystem.components.button.BackButton import io.element.android.libraries.designsystem.components.button.BackButton
import io.element.android.libraries.designsystem.preview.ElementPreview import io.element.android.libraries.designsystem.preview.ElementPreview
import io.element.android.libraries.designsystem.preview.PreviewsDayNight import io.element.android.libraries.designsystem.preview.PreviewsDayNight
import io.element.android.libraries.designsystem.text.toDp
import io.element.android.libraries.designsystem.theme.aliasScreenTitle import io.element.android.libraries.designsystem.theme.aliasScreenTitle
import io.element.android.libraries.designsystem.theme.components.Button import io.element.android.libraries.designsystem.theme.components.Button
import io.element.android.libraries.designsystem.theme.components.ButtonSize import io.element.android.libraries.designsystem.theme.components.ButtonSize
@ -90,8 +96,10 @@ fun KnockRequestsListView(
} }
@Composable @Composable
private fun KnockRequestsListContent(state: KnockRequestsListState, modifier: Modifier) { private fun KnockRequestsListContent(
state: KnockRequestsListState,
modifier: Modifier = Modifier,
) {
fun onAcceptClick(knockRequest: KnockRequest) { fun onAcceptClick(knockRequest: KnockRequest) {
state.eventSink(KnockRequestsListEvents.Accept(knockRequest)) state.eventSink(KnockRequestsListEvents.Accept(knockRequest))
} }
@ -100,6 +108,8 @@ private fun KnockRequestsListContent(state: KnockRequestsListState, modifier: Mo
state.eventSink(KnockRequestsListEvents.Decline(knockRequest)) state.eventSink(KnockRequestsListEvents.Decline(knockRequest))
} }
var bottomPaddingInPixels by remember { mutableIntStateOf(0) }
Box(modifier.fillMaxSize()) { Box(modifier.fillMaxSize()) {
when (state.knockRequests) { when (state.knockRequests) {
is AsyncData.Success -> { is AsyncData.Success -> {
@ -114,6 +124,7 @@ private fun KnockRequestsListContent(state: KnockRequestsListState, modifier: Mo
canBan = state.canBan, canBan = state.canBan,
onAcceptClick = ::onAcceptClick, onAcceptClick = ::onAcceptClick,
onDeclineClick = ::onDeclineClick, onDeclineClick = ::onDeclineClick,
contentPadding = PaddingValues(bottom = bottomPaddingInPixels.toDp()),
) )
} }
} }
@ -130,6 +141,9 @@ private fun KnockRequestsListContent(state: KnockRequestsListState, modifier: Mo
onClick = { onClick = {
state.eventSink(KnockRequestsListEvents.AcceptAll) state.eventSink(KnockRequestsListEvents.AcceptAll)
}, },
onHeightChange = { height ->
bottomPaddingInPixels = height
},
modifier = Modifier.align(Alignment.BottomCenter), modifier = Modifier.align(Alignment.BottomCenter),
) )
} }
@ -186,8 +200,12 @@ private fun KnockRequestsList(
onAcceptClick: (KnockRequest) -> Unit, onAcceptClick: (KnockRequest) -> Unit,
onDeclineClick: (KnockRequest) -> Unit, onDeclineClick: (KnockRequest) -> Unit,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
contentPadding: PaddingValues = PaddingValues(0.dp),
) { ) {
LazyColumn(modifier = modifier) { LazyColumn(
modifier = modifier.fillMaxSize(),
contentPadding = contentPadding,
) {
itemsIndexed(knockRequests) { index, knockRequest -> itemsIndexed(knockRequests) { index, knockRequest ->
KnockRequestItem( KnockRequestItem(
knockRequest = knockRequest, knockRequest = knockRequest,
@ -316,7 +334,7 @@ private fun KnockRequestItem(
if (canBan) { if (canBan) {
Spacer(modifier = Modifier.height(12.dp)) Spacer(modifier = Modifier.height(12.dp))
TextButton( TextButton(
text = stringResource(CommonStrings.screen_knock_requests_list_decline_and_ban_action_title), text = stringResource(R.string.screen_knock_requests_list_decline_and_ban_action_title),
onClick = { onClick = {
onAcceptClick(knockRequest) onAcceptClick(knockRequest)
}, },
@ -325,22 +343,25 @@ private fun KnockRequestItem(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
) )
} }
} }
} }
} }
@Composable @Composable
private fun KnockRequestsAcceptAll(onClick: () -> Unit, modifier: Modifier) { private fun KnockRequestsAcceptAll(
onClick: () -> Unit,
onHeightChange: (Int) -> Unit,
modifier: Modifier = Modifier
) {
Box( Box(
modifier = modifier modifier = modifier
.shadow(elevation = 24.dp, spotColor = Color.Transparent) .shadow(elevation = 24.dp, spotColor = Color.Transparent)
.background(color = ElementTheme.colors.bgCanvasDefault) .background(color = ElementTheme.colors.bgCanvasDefault)
.padding(vertical = 12.dp, horizontal = 16.dp) .padding(vertical = 12.dp, horizontal = 16.dp)
) .onSizeChanged { onHeightChange(it.height) }
{ ) {
OutlinedButton( OutlinedButton(
text = ("Accept all"), text = stringResource(R.string.screen_knock_requests_list_accept_all_button_title),
onClick = onClick, onClick = onClick,
size = ButtonSize.Medium, size = ButtonSize.Medium,
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
@ -360,8 +381,8 @@ private fun KnockRequestsEmptyList(
contentAlignment = Alignment.Center, contentAlignment = Alignment.Center,
) { ) {
IconTitleSubtitleMolecule( IconTitleSubtitleMolecule(
title = "No pending request to join", title = stringResource(R.string.screen_knock_requests_list_empty_state_title),
subTitle = "When somebody will ask to join the room, youll be able to see their request here.", subTitle = stringResource(R.string.screen_knock_requests_list_empty_state_description),
iconStyle = BigIcon.Style.Default(CompoundIcons.Pin()), iconStyle = BigIcon.Style.Default(CompoundIcons.Pin()),
) )
} }
@ -373,7 +394,7 @@ private fun KnockRequestsListTopBar(onBackClick: () -> Unit) {
TopAppBar( TopAppBar(
title = { title = {
Text( Text(
text = "Requests to join", text = stringResource(R.string.screen_knock_requests_list_title),
style = ElementTheme.typography.aliasScreenTitle, style = ElementTheme.typography.aliasScreenTitle,
) )
}, },

View file

@ -0,0 +1,17 @@
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<string name="screen_knock_requests_list_accept_all_alert_confirm_button_title">"Yes, accept all"</string>
<string name="screen_knock_requests_list_accept_all_alert_description">"Are you sure you want to accept all requests to join?"</string>
<string name="screen_knock_requests_list_accept_all_alert_title">"Accept all requests"</string>
<string name="screen_knock_requests_list_accept_all_button_title">"Accept all"</string>
<string name="screen_knock_requests_list_ban_alert_confirm_button_title">"Yes, decline and ban"</string>
<string name="screen_knock_requests_list_ban_alert_description">"Are you sure you want to decline and ban %1$s? This user wont be able to request access to join this room again."</string>
<string name="screen_knock_requests_list_ban_alert_title">"Decline and ban from accessing"</string>
<string name="screen_knock_requests_list_decline_alert_confirm_button_title">"Yes, decline"</string>
<string name="screen_knock_requests_list_decline_alert_description">"Are you sure you want to decline %1$s request to join this room?"</string>
<string name="screen_knock_requests_list_decline_alert_title">"Decline access"</string>
<string name="screen_knock_requests_list_decline_and_ban_action_title">"Decline and ban"</string>
<string name="screen_knock_requests_list_empty_state_description">"When somebody will ask to join the room, youll be able to see their request here."</string>
<string name="screen_knock_requests_list_empty_state_title">"No pending request to join"</string>
<string name="screen_knock_requests_list_title">"Requests to join"</string>
</resources>

View file

@ -169,10 +169,6 @@ class RoomDetailsPresenter @Inject constructor(
) )
} }
private fun getCanBan(membersState: MatrixRoomMembersState): Any {
TODO("Not yet implemented")
}
@Composable @Composable
private fun roomMemberDetailsPresenter(dmMemberState: RoomMember?) = remember(dmMemberState) { private fun roomMemberDetailsPresenter(dmMemberState: RoomMember?) = remember(dmMemberState) {
dmMemberState?.let { roomMember -> dmMemberState?.let { roomMember ->

View file

@ -296,11 +296,6 @@ Reason: %1$s."</string>
<string name="invite_friends_text">"Hey, talk to me on %1$s: %2$s"</string> <string name="invite_friends_text">"Hey, talk to me on %1$s: %2$s"</string>
<string name="login_initial_device_name_android">"%1$s Android"</string> <string name="login_initial_device_name_android">"%1$s Android"</string>
<string name="preference_rageshake">"Rageshake to report bug"</string> <string name="preference_rageshake">"Rageshake to report bug"</string>
<string name="screen_knock_requests_list_accept_all_button_title">"Accept all"</string>
<string name="screen_knock_requests_list_decline_and_ban_action_title">"Decline and ban"</string>
<string name="screen_knock_requests_list_empty_state_description">"When somebody will ask to join the room, youll be able to see their request here."</string>
<string name="screen_knock_requests_list_empty_state_title">"No pending request to join"</string>
<string name="screen_knock_requests_list_title">"Requests to join"</string>
<string name="screen_media_picker_error_failed_selection">"Failed selecting media, please try again."</string> <string name="screen_media_picker_error_failed_selection">"Failed selecting media, please try again."</string>
<string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string> <string name="screen_media_upload_preview_error_failed_processing">"Failed processing media to upload, please try again."</string>
<string name="screen_media_upload_preview_error_failed_sending">"Failed uploading media, please try again."</string> <string name="screen_media_upload_preview_error_failed_sending">"Failed uploading media, please try again."</string>

View file

@ -286,6 +286,12 @@
"screen_join_room_.*", "screen_join_room_.*",
"screen\\.join_room\\..*" "screen\\.join_room\\..*"
] ]
},
{
"name" : ":features:knockrequests:impl",
"includeRegex" : [
"screen\\.knock_requests_list\\..*"
]
} }
] ]
} }