fix(common-ui): swipe actions visibility in comment cards

This commit is contained in:
Diego Beraldin 2023-09-19 21:46:18 +02:00
parent 79afe2e40e
commit 01f63bf8b8
5 changed files with 167 additions and 174 deletions

View File

@ -47,7 +47,9 @@ fun CommentCard(
fontScale = fontScale, fontScale = fontScale,
), ),
) { ) {
Column { Column(
modifier = Modifier.background(MaterialTheme.colorScheme.surface)
) {
var commentHeight by remember { mutableStateOf(0f) } var commentHeight by remember { mutableStateOf(0f) }
val barWidth = 2.dp val barWidth = 2.dp
val barColor = themeRepository.getCommentBarColor( val barColor = themeRepository.getCommentBarColor(

View File

@ -24,6 +24,9 @@ import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.onGloballyPositioned import androidx.compose.ui.layout.onGloballyPositioned
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.toSize import androidx.compose.ui.unit.toSize
import kotlinx.coroutines.flow.launchIn
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.flow.onEach
@OptIn(ExperimentalMaterialApi::class) @OptIn(ExperimentalMaterialApi::class)
@Composable @Composable
@ -59,23 +62,20 @@ fun SwipeableCard(
false false
}, },
) )
var willDismissDirection: DismissDirection? by remember {
mutableStateOf(null) val threshold = 0.25f
} LaunchedEffect(dismissState) {
val threshold = 0.15f snapshotFlow { dismissState.offset.value }.map {
LaunchedEffect(Unit) { when {
snapshotFlow { dismissState.offset.value }.collect {
willDismissDirection = when {
it > width * threshold -> DismissDirection.StartToEnd it > width * threshold -> DismissDirection.StartToEnd
it < -width * threshold -> DismissDirection.EndToStart it < -width * threshold -> DismissDirection.EndToStart
else -> null else -> null
} }
} }.onEach { willDismissDirection ->
}
LaunchedEffect(willDismissDirection) {
if (willDismissDirection != null) { if (willDismissDirection != null) {
onGestureBegin() onGestureBegin()
} }
}.launchIn(this)
} }
SwipeToDismiss( SwipeToDismiss(
modifier = modifier.onGloballyPositioned { modifier = modifier.onGloballyPositioned {
@ -97,7 +97,10 @@ fun SwipeableCard(
DismissDirection.EndToStart -> Alignment.CenterEnd DismissDirection.EndToStart -> Alignment.CenterEnd
} }
Box( Box(
Modifier.fillMaxSize().background(bgColor).padding(horizontal = 20.dp), Modifier
.fillMaxSize()
.background(bgColor)
.padding(horizontal = 20.dp),
contentAlignment = alignment, contentAlignment = alignment,
) { ) {
swipeContent(direction) swipeContent(direction)

View File

@ -7,9 +7,9 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background import androidx.compose.foundation.background
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.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
@ -223,13 +223,13 @@ class PostDetailScreen(
model.reduce(PostDetailMviModel.Intent.Refresh) model.reduce(PostDetailMviModel.Intent.Refresh)
}) })
Box( Box(
modifier = Modifier modifier = Modifier.padding(padding)
.padding(padding)
.nestedScroll(scrollBehavior.nestedScrollConnection) .nestedScroll(scrollBehavior.nestedScrollConnection)
.nestedScroll(fabNestedScrollConnection) .nestedScroll(fabNestedScrollConnection)
.pullRefresh(pullRefreshState), .pullRefresh(pullRefreshState),
) { ) {
LazyColumn( LazyColumn(
modifier = Modifier.fillMaxSize(),
verticalArrangement = Arrangement.spacedBy(Spacing.xs), verticalArrangement = Arrangement.spacedBy(Spacing.xs),
) { ) {
item { item {
@ -267,16 +267,14 @@ class PostDetailScreen(
) )
}, },
) )
PostCardImage( PostCardImage(imageUrl = statePost.thumbnailUrl.orEmpty(),
imageUrl = statePost.thumbnailUrl.orEmpty(),
onImageClick = { onImageClick = {
navigator?.push( navigator?.push(
ZoomableImageScreen( ZoomableImageScreen(
url = statePost.thumbnailUrl.orEmpty() url = statePost.thumbnailUrl.orEmpty()
), ),
) )
} })
)
PostCardBody( PostCardBody(
text = statePost.text, text = statePost.text,
) )
@ -286,8 +284,7 @@ class PostDetailScreen(
it?.contains("pictrs/image") == false it?.contains("pictrs/image") == false
}.orEmpty(), }.orEmpty(),
) )
PostCardFooter( PostCardFooter(comments = statePost.comments,
comments = statePost.comments,
score = statePost.score, score = statePost.score,
upVoted = statePost.myVote > 0, upVoted = statePost.myVote > 0,
downVoted = statePost.myVote < 0, downVoted = statePost.myVote < 0,
@ -335,20 +332,18 @@ class PostDetailScreen(
) )
bottomSheetNavigator.show( bottomSheetNavigator.show(
CreatePostScreen( CreatePostScreen(
editedPost = post, editedPost = statePost,
) )
) )
} }
else -> model.reduce(PostDetailMviModel.Intent.SharePost) else -> model.reduce(PostDetailMviModel.Intent.SharePost)
} }
} })
)
} }
} }
} }
itemsIndexed(uiState.comments) { idx, comment -> itemsIndexed(uiState.comments) { idx, comment ->
Column {
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled,
@ -378,7 +373,7 @@ class PostDetailScreen(
DismissDirection.EndToStart -> Icons.Default.ArrowCircleUp DismissDirection.EndToStart -> Icons.Default.ArrowCircleUp
} }
val (iconModifier, iconTint) = when { val (iconModifier, iconTint) = when {
direction == DismissDirection.StartToEnd && statePost.myVote < 0 -> { direction == DismissDirection.StartToEnd && comment.myVote < 0 -> {
Modifier.background( Modifier.background(
color = Color.Transparent, color = Color.Transparent,
shape = CircleShape, shape = CircleShape,
@ -392,7 +387,7 @@ class PostDetailScreen(
) to MaterialTheme.colorScheme.tertiary ) to MaterialTheme.colorScheme.tertiary
} }
direction == DismissDirection.EndToStart && statePost.myVote > 0 -> { direction == DismissDirection.EndToStart && comment.myVote > 0 -> {
Modifier.background( Modifier.background(
color = Color.Transparent, color = Color.Transparent,
shape = CircleShape, shape = CircleShape,
@ -414,38 +409,32 @@ class PostDetailScreen(
) )
}, },
content = { content = {
CommentCard( CommentCard(comment = comment, options = buildList {
comment = comment,
options = buildList {
if (comment.creator?.id == uiState.currentUserId) { if (comment.creator?.id == uiState.currentUserId) {
add(stringResource(MR.strings.comment_action_delete)) add(stringResource(MR.strings.comment_action_delete))
} }
}, }, onUpVote = {
onUpVote = {
model.reduce( model.reduce(
PostDetailMviModel.Intent.UpVoteComment( PostDetailMviModel.Intent.UpVoteComment(
index = idx, index = idx,
feedback = true, feedback = true,
), ),
) )
}, }, onDownVote = {
onDownVote = {
model.reduce( model.reduce(
PostDetailMviModel.Intent.DownVoteComment( PostDetailMviModel.Intent.DownVoteComment(
index = idx, index = idx,
feedback = true, feedback = true,
), ),
) )
}, }, onSave = {
onSave = {
model.reduce( model.reduce(
PostDetailMviModel.Intent.SaveComment( PostDetailMviModel.Intent.SaveComment(
index = idx, index = idx,
feedback = true, feedback = true,
), ),
) )
}, }, onReply = {
onReply = {
val screen = CreateCommentScreen( val screen = CreateCommentScreen(
originalPost = statePost, originalPost = statePost,
originalComment = comment, originalComment = comment,
@ -458,8 +447,7 @@ class PostDetailScreen(
NotificationCenterContractKeys.CommentCreated NotificationCenterContractKeys.CommentCreated
) )
bottomSheetNavigator.show(screen) bottomSheetNavigator.show(screen)
}, }, onOptionSelected = { idx ->
onOptionSelected = { idx ->
when (idx) { when (idx) {
1 -> model.reduce( 1 -> model.reduce(
PostDetailMviModel.Intent.DeleteComment( PostDetailMviModel.Intent.DeleteComment(
@ -482,8 +470,7 @@ class PostDetailScreen(
) )
} }
} }
} })
)
}, },
) )
if ((comment.comments if ((comment.comments
@ -507,7 +494,6 @@ class PostDetailScreen(
} }
} }
} }
}
item { item {
if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) { if (!uiState.loading && !uiState.refreshing && uiState.canFetchMore) {
model.reduce(PostDetailMviModel.Intent.LoadNextPage) model.reduce(PostDetailMviModel.Intent.LoadNextPage)

View File

@ -41,9 +41,11 @@ class PostDetailViewModel(
override fun onStarted() { override fun onStarted() {
mvi.onStarted() mvi.onStarted()
val sortType = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType() val sortType = keyStore[KeyStoreKeys.DefaultCommentSortType, 3].toSortType()
val swipeActionsEnabled = keyStore[KeyStoreKeys.EnableSwipeActions, true]
mvi.updateState { mvi.updateState {
it.copy( it.copy(
sortType = sortType, sortType = sortType,
swipeActionsEnabled = swipeActionsEnabled,
) )
} }
mvi.scope?.launch { mvi.scope?.launch {

View File

@ -164,6 +164,13 @@ class PostListScreen : Screen {
SwipeableCard( SwipeableCard(
modifier = Modifier.fillMaxWidth(), modifier = Modifier.fillMaxWidth(),
enabled = uiState.swipeActionsEnabled, enabled = uiState.swipeActionsEnabled,
backgroundColor = {
when (it) {
DismissValue.DismissedToStart -> MaterialTheme.colorScheme.secondary
DismissValue.DismissedToEnd -> MaterialTheme.colorScheme.tertiary
DismissValue.Default -> Color.Transparent
}
},
onGestureBegin = { onGestureBegin = {
model.reduce(PostListMviModel.Intent.HapticIndication) model.reduce(PostListMviModel.Intent.HapticIndication)
}, },
@ -173,13 +180,6 @@ class PostListScreen : Screen {
onDismissToEnd = { onDismissToEnd = {
model.reduce(PostListMviModel.Intent.DownVotePost(idx)) model.reduce(PostListMviModel.Intent.DownVotePost(idx))
}, },
backgroundColor = {
when (it) {
DismissValue.DismissedToStart -> MaterialTheme.colorScheme.secondary
DismissValue.DismissedToEnd -> MaterialTheme.colorScheme.tertiary
else -> Color.Transparent
}
},
swipeContent = { direction -> swipeContent = { direction ->
val icon = when (direction) { val icon = when (direction) {
DismissDirection.StartToEnd -> Icons.Default.ArrowCircleDown DismissDirection.StartToEnd -> Icons.Default.ArrowCircleDown