fix(common-ui): swipe actions visibility in comment cards
This commit is contained in:
parent
79afe2e40e
commit
01f63bf8b8
@ -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(
|
||||||
|
@ -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)
|
||||||
|
@ -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)
|
||||||
|
@ -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 {
|
||||||
|
@ -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
|
||||||
|
Loading…
x
Reference in New Issue
Block a user