Add mark all as read feature

This commit is contained in:
Ash 2022-04-08 04:35:28 +08:00
parent f95108fa67
commit aaf032332b
14 changed files with 304 additions and 114 deletions

View File

@ -6,46 +6,68 @@ import kotlinx.coroutines.flow.Flow
import me.ash.reader.data.entity.Article import me.ash.reader.data.entity.Article
import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.data.entity.ImportantCount import me.ash.reader.data.entity.ImportantCount
import java.util.*
@Dao @Dao
interface ArticleDao { interface ArticleDao {
@Query( @Query(
""" """
UPDATE article SET isUnread = 0 UPDATE article SET isUnread = :isUnread
WHERE accountId = :accountId WHERE accountId = :accountId
AND isUnread = 1 AND date < :before
AND date <= :before
""" """
) )
suspend fun markAllAsRead(accountId: Int, before: Long) suspend fun markAllAsRead(
accountId: Int,
isUnread: Boolean,
before: Date,
)
@Query( @Query(
""" """
UPDATE article SET isUnread = 0 UPDATE article SET isUnread = :isUnread
WHERE accountId = :accountId WHERE feedId IN (
AND isUnread = 1 SELECT id FROM feed
AND date <= :before WHERE groupId = :groupId
AND feedId = :feedId )
AND accountId = :accountId
AND date < :before
""" """
) )
suspend fun markAllAsReadByFeedId(accountId: Int, before: Long, feedId: String) suspend fun markAllAsReadByGroupId(
// accountId: Int,
// @Query( groupId: String,
// """ isUnread: Boolean,
// UPDATE article SET isUnread = 0 before: Date,
// WHERE accountId = :accountId )
// AND isUnread = 1
// AND date <= :before @Query(
// AND feedId = :feedId """
// UPDATE article SET isUnread = :isUnread
// SELECT * FROM `group` AS a, feed AS b, article AS c WHERE feedId = :feedId
// WHERE a.accountId = :accountId AND accountId = :accountId
// AND a.id = b.groupId AND date < :before
// AND b.groupId = :groupId """
// AND c.feedId = b.id )
// """ suspend fun markAllAsReadByFeedId(
// ) accountId: Int,
// suspend fun markAllAsReadByGroupId(accountId: Int, before: Long, groupId: String) feedId: String,
isUnread: Boolean,
before: Date,
)
@Query(
"""
UPDATE article SET isUnread = :isUnread
WHERE id = :articleId
AND accountId = :accountId
"""
)
suspend fun markAsReadByArticleId(
accountId: Int,
articleId: String,
isUnread: Boolean,
)
@Query( @Query(
""" """

View File

@ -38,6 +38,14 @@ abstract class AbstractRssRepository constructor(
abstract suspend fun sync(coroutineWorker: CoroutineWorker): ListenableWorker.Result abstract suspend fun sync(coroutineWorker: CoroutineWorker): ListenableWorker.Result
abstract suspend fun markAsRead(
groupId: String?,
feedId: String?,
articleId: String?,
before: Date?,
isUnread: Boolean,
)
fun doSync() { fun doSync() {
workManager.enqueueUniquePeriodicWork( workManager.enqueueUniquePeriodicWork(
SyncWorker.WORK_NAME, SyncWorker.WORK_NAME,

View File

@ -125,6 +125,40 @@ class LocalRssRepository @Inject constructor(
} }
} }
override suspend fun markAsRead(
groupId: String?,
feedId: String?,
articleId: String?,
before: Date?,
isUnread: Boolean,
) {
val accountId = context.currentAccountId
when {
groupId != null -> {
articleDao.markAllAsReadByGroupId(
accountId = accountId,
groupId = groupId,
isUnread = isUnread,
before = before ?: Date(Long.MAX_VALUE)
)
}
feedId != null -> {
articleDao.markAllAsReadByFeedId(
accountId = accountId,
feedId = feedId,
isUnread = isUnread,
before = before ?: Date(Long.MAX_VALUE)
)
}
articleId != null -> {
articleDao.markAsReadByArticleId(accountId, articleId, isUnread)
}
else -> {
articleDao.markAllAsRead(accountId, isUnread, before ?: Date(Long.MAX_VALUE))
}
}
}
data class ArticleNotify( data class ArticleNotify(
val articles: List<Article>, val articles: List<Article>,
val isNotify: Boolean, val isNotify: Boolean,

View File

@ -0,0 +1,48 @@
package me.ash.reader.ui.component
import androidx.compose.animation.*
import androidx.compose.runtime.Composable
import androidx.compose.ui.platform.LocalDensity
import androidx.compose.ui.unit.*
import androidx.compose.ui.window.Popup
import androidx.compose.ui.window.PopupPositionProvider
import androidx.compose.ui.window.PopupProperties
import com.google.accompanist.insets.LocalWindowInsets
@Composable
fun AnimatedPopup(
visible: Boolean = false,
absoluteY: Dp = Dp.Hairline,
absoluteX: Dp = Dp.Hairline,
onDismissRequest: () -> Unit = {},
content: @Composable () -> Unit = {},
) {
val density = LocalDensity.current
val insets = LocalWindowInsets.current
Popup(
properties = PopupProperties(focusable = visible),
onDismissRequest = onDismissRequest,
popupPositionProvider = object : PopupPositionProvider {
override fun calculatePosition(
anchorBounds: IntRect,
windowSize: IntSize,
layoutDirection: LayoutDirection,
popupContentSize: IntSize
): IntOffset {
return IntOffset(
x = with(density) { (absoluteX).roundToPx() },
y = with(density) { (absoluteY).roundToPx() + insets.statusBars.top }
)
}
},
) {
AnimatedVisibility(
visible = visible,
enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(),
) {
content()
}
}
}

View File

@ -3,11 +3,13 @@ package me.ash.reader.ui.component
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.style.BaselineShift
import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.text.style.TextOverflow
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
@ -28,8 +30,11 @@ fun DisplayText(
) )
) { ) {
Text( Text(
modifier = Modifier.height(44.dp),
text = text, text = text,
style = MaterialTheme.typography.displaySmall, style = MaterialTheme.typography.displaySmall.copy(
baselineShift = BaselineShift.Superscript
),
color = MaterialTheme.colorScheme.onSurface, color = MaterialTheme.colorScheme.onSurface,
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,
@ -40,8 +45,11 @@ fun DisplayText(
exit = fadeOut() + shrinkVertically(), exit = fadeOut() + shrinkVertically(),
) { ) {
Text( Text(
modifier = Modifier.height(16.dp),
text = desc, text = desc,
style = MaterialTheme.typography.labelMedium, style = MaterialTheme.typography.labelMedium.copy(
baselineShift = BaselineShift.Superscript
),
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f), color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),
maxLines = 1, maxLines = 1,
overflow = TextOverflow.Ellipsis, overflow = TextOverflow.Ellipsis,

View File

@ -70,28 +70,30 @@ fun Modifier.combinedFeedbackClickable(
isSound: Boolean? = false, isSound: Boolean? = false,
onPressDown: (() -> Unit)? = null, onPressDown: (() -> Unit)? = null,
onPressUp: (() -> Unit)? = null, onPressUp: (() -> Unit)? = null,
onTap: (() -> Unit)? = null,
onLongClick: (() -> Unit)? = null, onLongClick: (() -> Unit)? = null,
onDoubleClick: (() -> Unit)? = null, onDoubleClick: (() -> Unit)? = null,
onClick: (() -> Unit)? = null, onClick: (() -> Unit)? = null,
): Modifier { ): Modifier {
val view = LocalView.current val view = LocalView.current
val interactionSource = remember { MutableInteractionSource() } val interactionSource = remember { MutableInteractionSource() }
return if (onPressDown != null || onPressUp != null) { return if (onPressDown != null || onPressUp != null || onTap != null) {
indication(interactionSource, LocalIndication.current) indication(interactionSource, LocalIndication.current)
.pointerInput(Unit) { .pointerInput(Unit) {
detectTapGestures( detectTapGestures(
onPress = { offset -> onPress = { offset ->
onPressDown?.let { onPressDown?.let {
it()
if (isHaptic == true) view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) if (isHaptic == true) view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
val press = PressInteraction.Press(offset) val press = PressInteraction.Press(offset)
interactionSource.emit(press) interactionSource.emit(press)
tryAwaitRelease() tryAwaitRelease()
onPressUp?.invoke()
interactionSource.emit(PressInteraction.Release(press)) interactionSource.emit(PressInteraction.Release(press))
it()
} }
}, },
onTap = { onTap = {
onPressUp?.let { onTap?.let {
if (isHaptic == true) view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP) if (isHaptic == true) view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
if (isSound == true) view.playSoundEffect(SoundEffectConstants.CLICK) if (isSound == true) view.playSoundEffect(SoundEffectConstants.CLICK)
it() it()

View File

@ -64,7 +64,7 @@ fun FeedItem(
modifier = Modifier modifier = Modifier
.size(20.dp) .size(20.dp)
.clip(CircleShape) .clip(CircleShape)
.background(MaterialTheme.colorScheme.outline), .background(MaterialTheme.colorScheme.outline.copy(alpha = 0.2f))
) {} ) {}
Text( Text(
modifier = Modifier.padding(start = 12.dp, end = 6.dp), modifier = Modifier.padding(start = 12.dp, end = 6.dp),

View File

@ -109,7 +109,6 @@ fun FeedsPage(
title = {}, title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
modifier = Modifier.size(20.dp), modifier = Modifier.size(20.dp),
imageVector = Icons.Outlined.Settings, imageVector = Icons.Outlined.Settings,
contentDescription = stringResource(R.string.settings), contentDescription = stringResource(R.string.settings),
@ -120,7 +119,6 @@ fun FeedsPage(
}, },
actions = { actions = {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
modifier = Modifier.rotate(if (isSyncing) angle else 0f), modifier = Modifier.rotate(if (isSyncing) angle else 0f),
imageVector = Icons.Rounded.Refresh, imageVector = Icons.Rounded.Refresh,
contentDescription = stringResource(R.string.refresh), contentDescription = stringResource(R.string.refresh),
@ -131,7 +129,6 @@ fun FeedsPage(
} }
} }
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Rounded.Add, imageVector = Icons.Rounded.Add,
contentDescription = stringResource(R.string.subscribe), contentDescription = stringResource(R.string.subscribe),
tint = MaterialTheme.colorScheme.onSurface, tint = MaterialTheme.colorScheme.onSurface,

View File

@ -3,8 +3,10 @@ package me.ash.reader.ui.page.home.flow
import androidx.compose.animation.* import androidx.compose.animation.*
import androidx.compose.foundation.ExperimentalFoundationApi import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.gestures.detectTapGestures import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.height
import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.material.icons.Icons import androidx.compose.material.icons.Icons
import androidx.compose.material.icons.rounded.ArrowBack import androidx.compose.material.icons.rounded.ArrowBack
@ -16,7 +18,6 @@ import androidx.compose.material3.Scaffold
import androidx.compose.material3.SmallTopAppBar import androidx.compose.material3.SmallTopAppBar
import androidx.compose.runtime.* import androidx.compose.runtime.*
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.pointer.pointerInput
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalLifecycleOwner import androidx.compose.ui.platform.LocalLifecycleOwner
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
@ -71,28 +72,13 @@ fun FlowPage(
) )
} }
// LaunchedEffect(viewState.listState.isScrollInProgress) {
// Log.i("RLog", "isScrollInProgress: ${viewState.listState.isScrollInProgress}")
// if (viewState.listState.isScrollInProgress) {
// Log.i("RLog", "isScrollInProgress: ${true}")
// markAsRead = false
// }
// }
Scaffold( Scaffold(
modifier = Modifier modifier = Modifier.background(MaterialTheme.colorScheme.surface),
.background(MaterialTheme.colorScheme.surface)
.pointerInput(markAsRead) {
detectTapGestures {
markAsRead = false
}
},
topBar = { topBar = {
SmallTopAppBar( SmallTopAppBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Rounded.ArrowBack, imageVector = Icons.Rounded.ArrowBack,
contentDescription = stringResource(R.string.back), contentDescription = stringResource(R.string.back),
tint = MaterialTheme.colorScheme.onSurface tint = MaterialTheme.colorScheme.onSurface
@ -107,7 +93,6 @@ fun FlowPage(
exit = fadeOut() + shrinkVertically(), exit = fadeOut() + shrinkVertically(),
) { ) {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Rounded.DoneAll, imageVector = Icons.Rounded.DoneAll,
contentDescription = stringResource(R.string.mark_all_as_read), contentDescription = stringResource(R.string.mark_all_as_read),
tint = if (markAsRead) { tint = if (markAsRead) {
@ -123,7 +108,6 @@ fun FlowPage(
} }
} }
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Rounded.Search, imageVector = Icons.Rounded.Search,
contentDescription = stringResource(R.string.search), contentDescription = stringResource(R.string.search),
tint = MaterialTheme.colorScheme.onSurface, tint = MaterialTheme.colorScheme.onSurface,
@ -162,17 +146,30 @@ fun FlowPage(
enter = fadeIn() + expandVertically(), enter = fadeIn() + expandVertically(),
exit = fadeOut() + shrinkVertically(), exit = fadeOut() + shrinkVertically(),
) { ) {
Column { Spacer(modifier = Modifier.height((56 + 24 + 10).dp))
MarkAsReadBar() }
Spacer(modifier = Modifier.height(24.dp)) MarkAsReadBar(
} visible = markAsRead,
absoluteY = if (isSyncing) (4 + 16 + 180).dp else 180.dp,
onDismissRequest = {
markAsRead = false
},
) {
markAsRead = false
flowViewModel.dispatch(
FlowViewAction.MarkAsRead(
groupId = filterState.group?.id,
feedId = filterState.feed?.id,
articleId = null,
markAsReadBefore = it,
)
)
} }
} }
generateArticleList( generateArticleList(
context = context, context = context,
pagingItems = pagingItems, pagingItems = pagingItems,
) { ) {
markAsRead = false
onItemClick(it) onItemClick(it)
} }
item { item {
@ -190,14 +187,7 @@ fun FlowPage(
.height(60.dp) .height(60.dp)
.fillMaxWidth(), .fillMaxWidth(),
filter = filterState.filter, filter = filterState.filter,
filterOnClick = { filterOnClick = { onFilterChange(filterState.copy(filter = it)) },
markAsRead = false
onFilterChange(
filterState.copy(
filter = it
)
)
},
) )
} }
) )

View File

@ -14,6 +14,7 @@ import kotlinx.coroutines.launch
import me.ash.reader.data.entity.ArticleWithFeed import me.ash.reader.data.entity.ArticleWithFeed
import me.ash.reader.data.repository.RssRepository import me.ash.reader.data.repository.RssRepository
import me.ash.reader.ui.page.home.FilterState import me.ash.reader.ui.page.home.FilterState
import java.util.*
import javax.inject.Inject import javax.inject.Inject
@HiltViewModel @HiltViewModel
@ -28,14 +29,11 @@ class FlowViewModel @Inject constructor(
is FlowViewAction.FetchData -> fetchData(action.filterState) is FlowViewAction.FetchData -> fetchData(action.filterState)
is FlowViewAction.ChangeRefreshing -> changeRefreshing(action.isRefreshing) is FlowViewAction.ChangeRefreshing -> changeRefreshing(action.isRefreshing)
is FlowViewAction.ScrollToItem -> scrollToItem(action.index) is FlowViewAction.ScrollToItem -> scrollToItem(action.index)
is FlowViewAction.PeekSyncWork -> peekSyncWork() is FlowViewAction.MarkAsRead -> markAsRead(
} action.groupId,
} action.feedId,
action.articleId,
private fun peekSyncWork() { action.markAsReadBefore,
_viewState.update {
it.copy(
syncWorkInfo = rssRepository.get().peekWork()
) )
} }
} }
@ -76,6 +74,37 @@ class FlowViewModel @Inject constructor(
it.copy(isRefreshing = isRefreshing) it.copy(isRefreshing = isRefreshing)
} }
} }
private fun markAsRead(
groupId: String?,
feedId: String?,
articleId: String?,
markAsReadBefore: MarkAsReadBefore
) {
viewModelScope.launch {
rssRepository.get().markAsRead(
groupId = groupId,
feedId = feedId,
articleId = articleId,
before = when (markAsReadBefore) {
MarkAsReadBefore.All -> null
MarkAsReadBefore.OneDay -> Calendar.getInstance().apply {
time = Date()
add(Calendar.DAY_OF_MONTH, -1)
}.time
MarkAsReadBefore.ThreeDays -> Calendar.getInstance().apply {
time = Date()
add(Calendar.DAY_OF_MONTH, -3)
}.time
MarkAsReadBefore.SevenDays -> Calendar.getInstance().apply {
time = Date()
add(Calendar.DAY_OF_MONTH, -7)
}.time
},
isUnread = false,
)
}
}
} }
data class ArticleViewState( data class ArticleViewState(
@ -99,5 +128,17 @@ sealed class FlowViewAction {
val index: Int val index: Int
) : FlowViewAction() ) : FlowViewAction()
object PeekSyncWork : FlowViewAction() data class MarkAsRead(
val groupId: String?,
val feedId: String?,
val articleId: String?,
val markAsReadBefore: MarkAsReadBefore
) : FlowViewAction()
}
enum class MarkAsReadBefore {
SevenDays,
ThreeDays,
OneDay,
All,
} }

View File

@ -1,5 +1,10 @@
package me.ash.reader.ui.page.home.flow package me.ash.reader.ui.page.home.flow
import android.view.HapticFeedbackConstants
import android.view.SoundEffectConstants
import androidx.compose.animation.core.Animatable
import androidx.compose.animation.core.Spring
import androidx.compose.animation.core.spring
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.layout.* import androidx.compose.foundation.layout.*
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
@ -7,38 +12,68 @@ import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface import androidx.compose.material3.Surface
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.remember
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip import androidx.compose.ui.draw.clip
import androidx.compose.ui.platform.LocalView
import androidx.compose.ui.res.stringResource import androidx.compose.ui.res.stringResource
import androidx.compose.ui.unit.Dp
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import me.ash.reader.R import me.ash.reader.R
import me.ash.reader.ui.component.AnimatedPopup
@Composable @Composable
fun MarkAsReadBar() { fun MarkAsReadBar(
Row( visible: Boolean = false,
modifier = Modifier absoluteY: Dp = Dp.Hairline,
.padding(horizontal = 24.dp) onDismissRequest: () -> Unit = {},
.fillMaxWidth(), onItemClick: (MarkAsReadBefore) -> Unit = {},
verticalAlignment = Alignment.CenterVertically, ) {
val animated = remember { Animatable(absoluteY.value) }
LaunchedEffect(absoluteY) {
animated.animateTo(absoluteY.value, spring(stiffness = Spring.StiffnessMediumLow))
}
AnimatedPopup(
visible = visible,
absoluteY = animated.value.dp,
onDismissRequest = onDismissRequest,
) { ) {
MarkAsReadBarItem( Row(
modifier = Modifier.weight(1f), modifier = Modifier
text = stringResource(R.string.seven_days), .padding(horizontal = 24.dp)
) .fillMaxWidth(),
MarkAsReadBarItem( verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.weight(1f), ) {
text = stringResource(R.string.three_days), MarkAsReadBarItem(
) modifier = Modifier.width(56.dp),
MarkAsReadBarItem( text = stringResource(R.string.seven_days),
modifier = Modifier.weight(1f), ) {
text = stringResource(R.string.one_day), onItemClick(MarkAsReadBefore.SevenDays)
) }
MarkAsReadBarItem( MarkAsReadBarItem(
modifier = Modifier.weight(2.5f), modifier = Modifier.width(56.dp),
text = stringResource(R.string.mark_all_as_read), text = stringResource(R.string.three_days),
isPrimary = true, ) {
) onItemClick(MarkAsReadBefore.ThreeDays)
}
MarkAsReadBarItem(
modifier = Modifier.width(56.dp),
text = stringResource(R.string.one_day),
) {
onItemClick(MarkAsReadBefore.OneDay)
}
MarkAsReadBarItem(
modifier = Modifier.weight(1f),
text = stringResource(R.string.mark_all_as_read),
isPrimary = true,
) {
onItemClick(MarkAsReadBefore.All)
}
}
} }
} }
@ -47,12 +82,19 @@ fun MarkAsReadBarItem(
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
text: String, text: String,
isPrimary: Boolean = false, isPrimary: Boolean = false,
onClick: () -> Unit = {},
) { ) {
val view = LocalView.current
Surface( Surface(
modifier = modifier modifier = modifier
.height(52.dp) .height(56.dp)
.clip(RoundedCornerShape(16.dp)) .clip(RoundedCornerShape(16.dp))
.clickable { }, .clickable {
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
view.playSoundEffect(SoundEffectConstants.CLICK)
onClick()
},
tonalElevation = 2.dp, tonalElevation = 2.dp,
shape = RoundedCornerShape(16.dp), shape = RoundedCornerShape(16.dp),
color = if (isPrimary) { color = if (isPrimary) {
@ -70,7 +112,7 @@ fun MarkAsReadBarItem(
text = text, text = text,
style = MaterialTheme.typography.titleSmall, style = MaterialTheme.typography.titleSmall,
color = if (isPrimary) { color = if (isPrimary) {
MaterialTheme.colorScheme.onPrimaryContainer MaterialTheme.colorScheme.onSurface
} else { } else {
MaterialTheme.colorScheme.secondary MaterialTheme.colorScheme.secondary
}, },

View File

@ -143,7 +143,6 @@ private fun TopBar(
title = {}, title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Rounded.Close, imageVector = Icons.Rounded.Close,
contentDescription = stringResource(R.string.close), contentDescription = stringResource(R.string.close),
tint = MaterialTheme.colorScheme.onSurface tint = MaterialTheme.colorScheme.onSurface
@ -156,7 +155,6 @@ private fun TopBar(
actions = { actions = {
if (isShowActions) { if (isShowActions) {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
modifier = Modifier.size(22.dp), modifier = Modifier.size(22.dp),
imageVector = Icons.Outlined.Headphones, imageVector = Icons.Outlined.Headphones,
contentDescription = stringResource(R.string.mark_all_as_read), contentDescription = stringResource(R.string.mark_all_as_read),
@ -164,7 +162,6 @@ private fun TopBar(
) { ) {
} }
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Outlined.MoreVert, imageVector = Icons.Outlined.MoreVert,
contentDescription = stringResource(R.string.search), contentDescription = stringResource(R.string.search),
tint = MaterialTheme.colorScheme.onSurface, tint = MaterialTheme.colorScheme.onSurface,

View File

@ -79,7 +79,7 @@ class ReadViewModel @Inject constructor(
private fun markUnread(isUnread: Boolean) { private fun markUnread(isUnread: Boolean) {
val articleWithFeed = _viewState.value.articleWithFeed ?: return val articleWithFeed = _viewState.value.articleWithFeed ?: return
viewModelScope.launch(Dispatchers.IO) { viewModelScope.launch {
_viewState.update { _viewState.update {
it.copy( it.copy(
articleWithFeed = articleWithFeed.copy( articleWithFeed = articleWithFeed.copy(
@ -89,10 +89,12 @@ class ReadViewModel @Inject constructor(
) )
) )
} }
rssRepository.get().updateArticleInfo( rssRepository.get().markAsRead(
articleWithFeed.article.copy( groupId = null,
isUnread = isUnread feedId = null,
) articleId = _viewState.value.articleWithFeed!!.article.id,
before = null,
isUnread = isUnread,
) )
} }
} }

View File

@ -33,7 +33,6 @@ fun SettingsPage(
title = {}, title = {},
navigationIcon = { navigationIcon = {
FeedbackIconButton( FeedbackIconButton(
isHaptic = false,
imageVector = Icons.Rounded.ArrowBack, imageVector = Icons.Rounded.ArrowBack,
contentDescription = stringResource(R.string.back), contentDescription = stringResource(R.string.back),
tint = MaterialTheme.colorScheme.onSurface tint = MaterialTheme.colorScheme.onSurface