mirror of https://github.com/readrops/Readrops.git
Restore swipe to mark as read/unread
This commit is contained in:
parent
683ca54acc
commit
c31a0cde20
|
@ -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,14 +36,87 @@ 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
|
||||
) {
|
||||
val swipeState = rememberSwipeToDismissBoxState()
|
||||
|
||||
LaunchedEffect(swipeState.currentValue) {
|
||||
if (swipeState.currentValue == SwipeToDismissBoxValue.EndToStart) {
|
||||
onSetReadState()
|
||||
swipeState.snapTo(SwipeToDismissBoxValue.Settled)
|
||||
}
|
||||
}
|
||||
|
||||
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)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
) {
|
||||
when (size) {
|
||||
TimelineItemSize.COMPACT -> {
|
||||
|
@ -33,6 +128,7 @@ fun TimelineItem(
|
|||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
TimelineItemSize.REGULAR -> {
|
||||
RegularTimelineItem(
|
||||
itemWithFeed = itemWithFeed,
|
||||
|
@ -42,6 +138,7 @@ fun TimelineItem(
|
|||
modifier = modifier
|
||||
)
|
||||
}
|
||||
|
||||
TimelineItemSize.LARGE -> {
|
||||
LargeTimelineItem(
|
||||
itemWithFeed = itemWithFeed,
|
||||
|
@ -53,6 +150,7 @@ fun TimelineItem(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val itemWithFeed = ItemWithFeed(
|
||||
item = com.readrops.db.entities.Item(
|
||||
|
|
|
@ -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()
|
||||
|
|
|
@ -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) {
|
||||
|
|
|
@ -403,9 +403,11 @@ object TimelineTab : Tab {
|
|||
context
|
||||
)
|
||||
},
|
||||
onSetReadState = {
|
||||
screenModel.updateItemReadState(itemWithFeed.item)
|
||||
},
|
||||
size = state.itemSize
|
||||
)
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue