Restore swipe to mark as read/unread

This commit is contained in:
Shinokuni 2024-09-01 22:35:59 +02:00
parent 683ca54acc
commit c31a0cde20
4 changed files with 161 additions and 33 deletions

View File

@ -1,9 +1,31 @@
package com.readrops.app.timelime
import androidx.compose.animation.animateColorAsState
import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.CardDefaults
import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.Icon
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.SwipeToDismissBox
import androidx.compose.material3.SwipeToDismissBoxValue
import androidx.compose.material3.minimumInteractiveComponentSize
import androidx.compose.material3.rememberSwipeToDismissBoxState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import com.readrops.app.R
import com.readrops.app.util.DefaultPreview
import com.readrops.app.util.theme.ReadropsTheme
import com.readrops.app.util.theme.spacing
import com.readrops.db.entities.Folder
import com.readrops.db.pojo.ItemWithFeed
import java.time.LocalDateTime
@ -14,42 +36,118 @@ enum class TimelineItemSize {
LARGE
}
const val readAlpha = 0.6f
@OptIn(ExperimentalMaterial3Api::class)
@Composable
fun TimelineItem(
itemWithFeed: ItemWithFeed,
onClick: () -> Unit,
onFavorite: () -> Unit,
onShare: () -> Unit,
onSetReadState: () -> Unit,
modifier: Modifier = Modifier,
size: TimelineItemSize = TimelineItemSize.LARGE,
size: TimelineItemSize = TimelineItemSize.LARGE
) {
when (size) {
TimelineItemSize.COMPACT -> {
CompactTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare,
modifier = modifier
)
val swipeState = rememberSwipeToDismissBoxState()
LaunchedEffect(swipeState.currentValue) {
if (swipeState.currentValue == SwipeToDismissBoxValue.EndToStart) {
onSetReadState()
swipeState.snapTo(SwipeToDismissBoxValue.Settled)
}
TimelineItemSize.REGULAR -> {
RegularTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare,
modifier = modifier
}
SwipeToDismissBox(
state = swipeState,
enableDismissFromStartToEnd = false,
backgroundContent = {
val color by animateColorAsState(
targetValue = when (swipeState.targetValue) {
SwipeToDismissBoxValue.EndToStart -> MaterialTheme.colorScheme.primary
else -> Color.Transparent
},
label = "Swipe to dismiss background color"
)
val iconColor by animateColorAsState(
targetValue = when (swipeState.targetValue) {
SwipeToDismissBoxValue.EndToStart -> MaterialTheme.colorScheme.onPrimary
else -> Color.Transparent
},
label = "Swipe to dismiss icon color"
)
Box(
modifier = Modifier.padding(
horizontal = if (size == TimelineItemSize.COMPACT) {
0.dp
} else {
MaterialTheme.spacing.shortSpacing
}
)
) {
Box(
contentAlignment = Alignment.CenterEnd,
modifier = Modifier
.fillMaxSize()
.then(
if (size == TimelineItemSize.COMPACT) {
Modifier
} else {
Modifier.clip(CardDefaults.shape)
}
)
.background(color)
) {
Icon(
painter = painterResource(
id = if (itemWithFeed.item.isRead) {
R.drawable.ic_remove_done
} else {
R.drawable.ic_done_all
}
),
contentDescription = null,
tint = iconColor,
modifier = Modifier
.minimumInteractiveComponentSize()
.padding(end = MaterialTheme.spacing.mediumSpacing)
)
}
}
}
TimelineItemSize.LARGE -> {
LargeTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare,
modifier = modifier
)
) {
when (size) {
TimelineItemSize.COMPACT -> {
CompactTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare,
modifier = modifier
)
}
TimelineItemSize.REGULAR -> {
RegularTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare,
modifier = modifier
)
}
TimelineItemSize.LARGE -> {
LargeTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare,
modifier = modifier
)
}
}
}
}

View File

@ -3,6 +3,7 @@ package com.readrops.app.timelime
import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.aspectRatio
import androidx.compose.foundation.layout.fillMaxWidth
@ -24,6 +25,8 @@ import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.alpha
import androidx.compose.ui.draw.drawBehind
import androidx.compose.ui.geometry.CornerRadius
import androidx.compose.ui.graphics.Color
import androidx.compose.ui.layout.ContentScale
import androidx.compose.ui.platform.LocalContext
@ -94,11 +97,18 @@ fun CompactTimelineItem(
onShare: () -> Unit,
modifier: Modifier = Modifier
) {
val containerColor = MaterialTheme.colorScheme.background
Surface(
color = MaterialTheme.colorScheme.surfaceVariant,
modifier = modifier
.fillMaxWidth()
.alpha(if (itemWithFeed.item.isRead) 0.6f else 1f)
.drawBehind {
// if some alpha is applied to the card, the swipe to dismiss background appears behind it
// so we draw a rect with the current screen background color behind the card but in front of the dismiss background
drawRect(containerColor)
}
.alpha(if (itemWithFeed.item.isRead) readAlpha else 1f)
.clickable { onClick() }
) {
Column(
@ -147,7 +157,8 @@ fun LargeTimelineItem(
itemWithFeed = itemWithFeed,
onClick = onClick,
onFavorite = onFavorite,
onShare = onShare
onShare = onShare,
modifier = modifier
)
} else {
TimelineItemContainer(
@ -222,13 +233,24 @@ fun TimelineItemContainer(
isRead: Boolean,
onClick: () -> Unit,
modifier: Modifier = Modifier,
padding: PaddingValues = PaddingValues(horizontal = MaterialTheme.spacing.shortSpacing),
content: @Composable () -> Unit
) {
val containerColor = MaterialTheme.colorScheme.background
Card(
modifier = modifier
.padding(horizontal = MaterialTheme.spacing.shortSpacing)
.padding(padding)
.fillMaxWidth()
.alpha(if (isRead) 0.6f else 1f)
.drawBehind {
// if some alpha is applied to the card, the swipe to dismiss background appears behind it
// so we draw a rect with the current screen background color behind the card but in front of the dismiss background
drawRoundRect(
color = containerColor,
cornerRadius = CornerRadius(12.dp.toPx())
)
}
.alpha(if (isRead) readAlpha else 1f)
.clickable { onClick() }
) {
content()

View File

@ -297,15 +297,21 @@ class TimelineScreenModel(
fun setItemRead(item: Item) {
item.isRead = true
updateItemReadState(item)
}
private fun updateItemReadState(item: Item) {
screenModelScope.launch(dispatcher) {
repository?.setItemReadState(item)
}
}
fun updateItemReadState(item: Item) {
screenModelScope.launch(dispatcher) {
with(item) {
isRead = !isRead
repository?.setItemReadState(this)
}
}
}
fun updateStarState(item: Item) {
screenModelScope.launch(dispatcher) {
with(item) {

View File

@ -403,9 +403,11 @@ object TimelineTab : Tab {
context
)
},
onSetReadState = {
screenModel.updateItemReadState(itemWithFeed.item)
},
size = state.itemSize
)
}
}
}