mirror of https://github.com/Ashinch/ReadYou.git
Optimize the feeds page
This commit is contained in:
parent
5867186751
commit
433ff6e6f2
|
@ -10,12 +10,12 @@ import androidx.work.WorkManager
|
|||
import kotlinx.coroutines.CoroutineDispatcher
|
||||
import kotlinx.coroutines.flow.Flow
|
||||
import kotlinx.coroutines.flow.flowOn
|
||||
import kotlinx.coroutines.flow.mapLatest
|
||||
import me.ash.reader.data.dao.AccountDao
|
||||
import me.ash.reader.data.dao.ArticleDao
|
||||
import me.ash.reader.data.dao.FeedDao
|
||||
import me.ash.reader.data.dao.GroupDao
|
||||
import me.ash.reader.data.entity.*
|
||||
import me.ash.reader.data.model.ImportantCount
|
||||
import me.ash.reader.ui.ext.currentAccountId
|
||||
import java.util.*
|
||||
|
||||
|
@ -99,7 +99,7 @@ abstract class AbstractRssRepository constructor(
|
|||
fun pullImportant(
|
||||
isStarred: Boolean = false,
|
||||
isUnread: Boolean = false,
|
||||
): Flow<List<ImportantCount>> {
|
||||
): Flow<Map<String, Int>> {
|
||||
val accountId = context.currentAccountId
|
||||
Log.i(
|
||||
"RLog",
|
||||
|
@ -111,6 +111,12 @@ abstract class AbstractRssRepository constructor(
|
|||
isUnread -> articleDao
|
||||
.queryImportantCountWhenIsUnread(accountId, isUnread)
|
||||
else -> articleDao.queryImportantCountWhenIsAll(accountId)
|
||||
}.mapLatest {
|
||||
mapOf(
|
||||
*(it.map {
|
||||
it.feedId to it.important
|
||||
}.toTypedArray())
|
||||
)
|
||||
}.flowOn(dispatcherIO)
|
||||
}
|
||||
|
||||
|
|
|
@ -4,6 +4,7 @@ import android.os.Build
|
|||
import android.view.SoundEffectConstants
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.navigationBarsPadding
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.material3.*
|
||||
import androidx.compose.runtime.Composable
|
||||
|
@ -20,7 +21,6 @@ import me.ash.reader.ui.theme.palette.onDark
|
|||
|
||||
@Composable
|
||||
fun FilterBar(
|
||||
modifier: Modifier = Modifier,
|
||||
filter: Filter,
|
||||
filterBarStyle: Int,
|
||||
filterBarFilled: Boolean,
|
||||
|
@ -33,7 +33,8 @@ fun FilterBar(
|
|||
|
||||
NavigationBar(
|
||||
modifier = Modifier
|
||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(filterBarTonalElevation)),
|
||||
.background(MaterialTheme.colorScheme.surfaceColorAtElevation(filterBarTonalElevation))
|
||||
.navigationBarsPadding(),
|
||||
tonalElevation = filterBarTonalElevation,
|
||||
) {
|
||||
Spacer(modifier = Modifier.width(filterBarPadding))
|
||||
|
|
|
@ -31,14 +31,14 @@ fun RYScaffold(
|
|||
color = containerColor
|
||||
)
|
||||
)
|
||||
.statusBarsPadding()
|
||||
.run {
|
||||
if (bottomBar != null || floatingActionButton != null) {
|
||||
navigationBarsPadding()
|
||||
} else {
|
||||
this
|
||||
}
|
||||
},
|
||||
.statusBarsPadding(),
|
||||
// .run {
|
||||
// if (bottomBar != null || floatingActionButton != null) {
|
||||
// navigationBarsPadding()
|
||||
// } else {
|
||||
// this
|
||||
// }
|
||||
// },
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
containerTonalElevation,
|
||||
color = containerColor
|
||||
|
|
|
@ -67,7 +67,7 @@ fun Context.share(content: String) {
|
|||
}, getString(R.string.share)))
|
||||
}
|
||||
|
||||
fun Context.openURL(url: String? = null) {
|
||||
fun Context.openURL(url: String?) {
|
||||
url?.takeIf { it.trim().isNotEmpty() }
|
||||
?.let { startActivity(Intent(Intent.ACTION_VIEW, Uri.parse(it))) }
|
||||
}
|
|
@ -1,53 +1,55 @@
|
|||
package me.ash.reader.ui.page.home.feeds
|
||||
|
||||
import RYExtensibleVisibility
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Badge
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.graphics.RectangleShape
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import me.ash.reader.data.entity.Feed
|
||||
import me.ash.reader.ui.component.FeedIcon
|
||||
import me.ash.reader.ui.page.home.feeds.drawer.feed.FeedOptionViewModel
|
||||
import kotlin.math.ln
|
||||
import me.ash.reader.ui.theme.ShapeBottom32
|
||||
|
||||
@OptIn(
|
||||
androidx.compose.foundation.ExperimentalFoundationApi::class,
|
||||
androidx.compose.material.ExperimentalMaterialApi::class,
|
||||
)
|
||||
@Composable
|
||||
fun FeedItem(
|
||||
feed: Feed,
|
||||
alpha: Float = 1f,
|
||||
badgeAlpha: Float = 1f,
|
||||
isEnded: Boolean = false,
|
||||
isExpanded: () -> Boolean,
|
||||
feedOptionViewModel: FeedOptionViewModel = hiltViewModel(),
|
||||
tonalElevation: Dp,
|
||||
onClick: () -> Unit = {},
|
||||
) {
|
||||
val view = LocalView.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val tonalElevationAlpha by remember {
|
||||
derivedStateOf {
|
||||
(ln(tonalElevation.value + 1.4f) + 2f) / 100f
|
||||
}
|
||||
}
|
||||
|
||||
RYExtensibleVisibility(visible = isExpanded()) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 14.dp)
|
||||
.clip(RoundedCornerShape(32.dp))
|
||||
.padding(horizontal = 16.dp)
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.secondary.copy(alpha = alpha),
|
||||
shape = if (isEnded) ShapeBottom32 else RectangleShape,
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
onClick()
|
||||
|
@ -57,7 +59,8 @@ fun FeedItem(
|
|||
feedOptionViewModel.showDrawer(scope, feed.id)
|
||||
}
|
||||
)
|
||||
.padding(vertical = 14.dp),
|
||||
.padding(horizontal = 14.dp)
|
||||
.padding(top = 14.dp, bottom = if (isEnded) 22.dp else 14.dp),
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier
|
||||
|
@ -80,7 +83,7 @@ fun FeedItem(
|
|||
if ((feed.important ?: 0) != 0) {
|
||||
Badge(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceTint.copy(
|
||||
alpha = tonalElevationAlpha
|
||||
alpha = badgeAlpha
|
||||
),
|
||||
contentColor = MaterialTheme.colorScheme.outline,
|
||||
content = {
|
||||
|
@ -93,4 +96,5 @@ fun FeedItem(
|
|||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -31,6 +31,7 @@ import me.ash.reader.data.preference.*
|
|||
import me.ash.reader.data.repository.SyncWorker.Companion.getIsSyncing
|
||||
import me.ash.reader.ui.component.FilterBar
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.ext.alphaLN
|
||||
import me.ash.reader.ui.ext.collectAsStateValue
|
||||
import me.ash.reader.ui.ext.findActivity
|
||||
import me.ash.reader.ui.ext.getCurrentVersion
|
||||
|
@ -41,9 +42,9 @@ import me.ash.reader.ui.page.home.feeds.drawer.feed.FeedOptionDrawer
|
|||
import me.ash.reader.ui.page.home.feeds.drawer.group.GroupOptionDrawer
|
||||
import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeDialog
|
||||
import me.ash.reader.ui.page.home.feeds.subscribe.SubscribeViewModel
|
||||
import kotlin.math.ln
|
||||
|
||||
@OptIn(
|
||||
com.google.accompanist.pager.ExperimentalPagerApi::class,
|
||||
androidx.compose.foundation.ExperimentalFoundationApi::class
|
||||
)
|
||||
@Composable
|
||||
|
@ -96,6 +97,24 @@ fun FeedsPage(
|
|||
}
|
||||
}
|
||||
|
||||
val feedBadgeAlpha by remember { derivedStateOf { (ln(groupListTonalElevation.value + 1.4f) + 2f) / 100f } }
|
||||
val groupAlpha by remember { derivedStateOf { groupListTonalElevation.value.dp.alphaLN(weight = 1.2f) } }
|
||||
val groupIndicatorAlpha by remember {
|
||||
derivedStateOf {
|
||||
groupListTonalElevation.value.dp.alphaLN(
|
||||
weight = 1.4f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
val groupsVisible = remember(feedsUiState.groupWithFeedList) {
|
||||
mutableStateMapOf(
|
||||
*(feedsUiState.groupWithFeedList.filterIsInstance<GroupFeedsView.Group>().map {
|
||||
it.group.id to groupListExpand.value
|
||||
}.toTypedArray())
|
||||
)
|
||||
}
|
||||
|
||||
LaunchedEffect(Unit) {
|
||||
feedsViewModel.fetchAccount()
|
||||
}
|
||||
|
@ -161,7 +180,7 @@ fun FeedsPage(
|
|||
item {
|
||||
Banner(
|
||||
title = filterUiState.filter.getName(),
|
||||
desc = feedsUiState.importantCount.ifEmpty { stringResource(R.string.loading) },
|
||||
desc = feedsUiState.importantSum.ifEmpty { stringResource(R.string.loading) },
|
||||
icon = filterUiState.filter.iconOutline,
|
||||
action = {
|
||||
Icon(
|
||||
|
@ -189,14 +208,21 @@ fun FeedsPage(
|
|||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
itemsIndexed(feedsUiState.groupWithFeedList) { index, groupWithFeed ->
|
||||
// Crossfade(targetState = groupWithFeed) { groupWithFeed ->
|
||||
Column {
|
||||
when (groupWithFeed) {
|
||||
is GroupFeedsView.Group -> {
|
||||
if (index != 0) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
GroupItem(
|
||||
isExpanded = groupListExpand.value,
|
||||
tonalElevation = groupListTonalElevation.value.dp,
|
||||
isExpanded = { groupsVisible[groupWithFeed.group.id] ?: false },
|
||||
group = groupWithFeed.group,
|
||||
feeds = groupWithFeed.feeds,
|
||||
groupOnClick = {
|
||||
alpha = groupAlpha,
|
||||
indicatorAlpha = groupIndicatorAlpha,
|
||||
onExpanded = {
|
||||
groupsVisible[groupWithFeed.group.id] =
|
||||
!(groupsVisible[groupWithFeed.group.id] ?: false)
|
||||
}
|
||||
) {
|
||||
filterChange(
|
||||
navController = navController,
|
||||
homeViewModel = homeViewModel,
|
||||
|
@ -205,23 +231,27 @@ fun FeedsPage(
|
|||
feed = null,
|
||||
)
|
||||
)
|
||||
},
|
||||
feedOnClick = { feed ->
|
||||
}
|
||||
}
|
||||
is GroupFeedsView.Feed -> {
|
||||
FeedItem(
|
||||
feed = groupWithFeed.feed,
|
||||
alpha = groupAlpha,
|
||||
badgeAlpha = feedBadgeAlpha,
|
||||
isEnded = index != feedsUiState.groupWithFeedList.lastIndex && feedsUiState.groupWithFeedList[index + 1] is GroupFeedsView.Group,
|
||||
isExpanded = { groupsVisible[groupWithFeed.feed.groupId] ?: false },
|
||||
) {
|
||||
filterChange(
|
||||
navController = navController,
|
||||
homeViewModel = homeViewModel,
|
||||
filterState = filterUiState.copy(
|
||||
group = null,
|
||||
feed = feed,
|
||||
feed = groupWithFeed.feed,
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
if (index != feedsUiState.groupWithFeedList.lastIndex) {
|
||||
Spacer(modifier = Modifier.height(8.dp))
|
||||
}
|
||||
}
|
||||
// }
|
||||
}
|
||||
item {
|
||||
Spacer(modifier = Modifier.height(128.dp))
|
||||
|
|
|
@ -2,6 +2,7 @@ package me.ash.reader.ui.page.home.feeds
|
|||
|
||||
import android.util.Log
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.ui.util.fastForEach
|
||||
import androidx.lifecycle.ViewModel
|
||||
import androidx.lifecycle.viewModelScope
|
||||
import dagger.hilt.android.lifecycle.HiltViewModel
|
||||
|
@ -10,7 +11,6 @@ import kotlinx.coroutines.flow.*
|
|||
import kotlinx.coroutines.launch
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.entity.Account
|
||||
import me.ash.reader.data.entity.GroupWithFeed
|
||||
import me.ash.reader.data.module.DispatcherDefault
|
||||
import me.ash.reader.data.module.DispatcherIO
|
||||
import me.ash.reader.data.repository.AccountRepository
|
||||
|
@ -67,42 +67,20 @@ class FeedsViewModel @Inject constructor(
|
|||
combine(
|
||||
rssRepository.get().pullFeeds(),
|
||||
rssRepository.get().pullImportant(isStarred, isUnread),
|
||||
) { groupWithFeedList, importantList ->
|
||||
val groupImportantMap = mutableMapOf<String, Int>()
|
||||
val feedImportantMap = mutableMapOf<String, Int>()
|
||||
importantList.groupBy { it.groupId }.forEach { (i, list) ->
|
||||
var groupImportantSum = 0
|
||||
list.forEach {
|
||||
feedImportantMap[it.feedId] = it.important
|
||||
groupImportantSum += it.important
|
||||
}
|
||||
groupImportantMap[i] = groupImportantSum
|
||||
}
|
||||
val groupsIt = groupWithFeedList.iterator()
|
||||
while (groupsIt.hasNext()) {
|
||||
val groupWithFeed = groupsIt.next()
|
||||
val groupImportant = groupImportantMap[groupWithFeed.group.id]
|
||||
if (groupImportant == null && (isStarred || isUnread)) {
|
||||
groupsIt.remove()
|
||||
} else {
|
||||
groupWithFeed.group.important = groupImportant
|
||||
val feedsIt = groupWithFeed.feeds.iterator()
|
||||
while (feedsIt.hasNext()) {
|
||||
val feed = feedsIt.next()
|
||||
val feedImportant = feedImportantMap[feed.id]
|
||||
if (feedImportant == null && (isStarred || isUnread)) {
|
||||
feedsIt.remove()
|
||||
} else {
|
||||
feed.important = feedImportant
|
||||
}
|
||||
}
|
||||
) { groupWithFeedList, importantMap ->
|
||||
groupWithFeedList.fastForEach {
|
||||
var groupImportant = 0
|
||||
it.feeds.fastForEach {
|
||||
it.important = importantMap[it.id]
|
||||
groupImportant += it.important ?: 0
|
||||
}
|
||||
it.group.important = groupImportant
|
||||
}
|
||||
groupWithFeedList
|
||||
}.onEach { groupWithFeedList ->
|
||||
}.mapLatest { groupWithFeedList ->
|
||||
_feedsUiState.update {
|
||||
it.copy(
|
||||
importantCount = groupWithFeedList.sumOf { it.group.important ?: 0 }.run {
|
||||
importantSum = groupWithFeedList.sumOf { it.group.important ?: 0 }.run {
|
||||
when {
|
||||
isStarred -> stringsRepository.getQuantityString(
|
||||
R.plurals.starred_desc,
|
||||
|
@ -121,8 +99,15 @@ class FeedsViewModel @Inject constructor(
|
|||
)
|
||||
}
|
||||
},
|
||||
groupWithFeedList = groupWithFeedList,
|
||||
feedsVisible = List(groupWithFeedList.size, init = { true })
|
||||
groupWithFeedList = groupWithFeedList.map {
|
||||
mutableListOf<GroupFeedsView>(GroupFeedsView.Group(it.group)).apply {
|
||||
addAll(
|
||||
it.feeds.map {
|
||||
GroupFeedsView.Feed(it)
|
||||
}
|
||||
)
|
||||
}
|
||||
}.flatten(),
|
||||
)
|
||||
}
|
||||
}.catch {
|
||||
|
@ -133,9 +118,13 @@ class FeedsViewModel @Inject constructor(
|
|||
|
||||
data class FeedsUiState(
|
||||
val account: Account? = null,
|
||||
val importantCount: String = "",
|
||||
val groupWithFeedList: List<GroupWithFeed> = emptyList(),
|
||||
val feedsVisible: List<Boolean> = emptyList(),
|
||||
val importantSum: String = "",
|
||||
val groupWithFeedList: List<GroupFeedsView> = emptyList(),
|
||||
val listState: LazyListState = LazyListState(),
|
||||
val groupsVisible: Boolean = true,
|
||||
)
|
||||
|
||||
sealed class GroupFeedsView {
|
||||
class Group(val group: me.ash.reader.data.entity.Group) : GroupFeedsView()
|
||||
class Feed(val feed: me.ash.reader.data.entity.Feed) : GroupFeedsView()
|
||||
}
|
|
@ -1,58 +1,56 @@
|
|||
package me.ash.reader.ui.page.home.feeds
|
||||
|
||||
import RYExtensibleVisibility
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ExpandLess
|
||||
import androidx.compose.material.icons.rounded.ExpandMore
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.hilt.navigation.compose.hiltViewModel
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.entity.Feed
|
||||
import me.ash.reader.data.entity.Group
|
||||
import me.ash.reader.ui.ext.alphaLN
|
||||
import me.ash.reader.ui.page.home.feeds.drawer.group.GroupOptionViewModel
|
||||
import me.ash.reader.ui.theme.Shape32
|
||||
import me.ash.reader.ui.theme.ShapeTop32
|
||||
|
||||
@OptIn(androidx.compose.foundation.ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
fun GroupItem(
|
||||
modifier: Modifier = Modifier,
|
||||
tonalElevation: Dp,
|
||||
group: Group,
|
||||
feeds: List<Feed>,
|
||||
isExpanded: Boolean = true,
|
||||
alpha: Float = 1f,
|
||||
indicatorAlpha: Float = 1f,
|
||||
isExpanded: () -> Boolean,
|
||||
groupOptionViewModel: GroupOptionViewModel = hiltViewModel(),
|
||||
onExpanded: () -> Unit = {},
|
||||
groupOnClick: () -> Unit = {},
|
||||
feedOnClick: (feed: Feed) -> Unit = {},
|
||||
) {
|
||||
val view = LocalView.current
|
||||
val scope = rememberCoroutineScope()
|
||||
var expanded by remember { mutableStateOf(isExpanded) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.fillMaxWidth()
|
||||
.padding(horizontal = 16.dp)
|
||||
.clip(RoundedCornerShape(32.dp))
|
||||
.clip(if (isExpanded()) ShapeTop32 else Shape32)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.secondary.copy(alpha = tonalElevation.alphaLN(weight = 1.2f))
|
||||
MaterialTheme.colorScheme.secondary.copy(alpha = alpha)
|
||||
)
|
||||
.combinedClickable(
|
||||
onClick = {
|
||||
|
@ -66,7 +64,7 @@ fun GroupItem(
|
|||
.padding(top = 22.dp)
|
||||
) {
|
||||
Row(
|
||||
modifier = modifier.fillMaxWidth(),
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
|
@ -86,38 +84,21 @@ fun GroupItem(
|
|||
.size(24.dp)
|
||||
.clip(CircleShape)
|
||||
.background(
|
||||
MaterialTheme.colorScheme.surfaceTint.copy(
|
||||
alpha = tonalElevation.alphaLN(weight = 1.4f)
|
||||
)
|
||||
MaterialTheme.colorScheme.surfaceTint.copy(alpha = indicatorAlpha)
|
||||
)
|
||||
.clickable {
|
||||
expanded = !expanded
|
||||
onExpanded()
|
||||
},
|
||||
horizontalArrangement = Arrangement.Center,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
Icon(
|
||||
imageVector = if (expanded) Icons.Rounded.ExpandLess else Icons.Rounded.ExpandMore,
|
||||
contentDescription = stringResource(if (expanded) R.string.expand_less else R.string.expand_more),
|
||||
imageVector = if (isExpanded()) Icons.Rounded.ExpandLess else Icons.Rounded.ExpandMore,
|
||||
contentDescription = stringResource(if (isExpanded()) R.string.expand_less else R.string.expand_more),
|
||||
tint = MaterialTheme.colorScheme.onSecondaryContainer,
|
||||
)
|
||||
}
|
||||
}
|
||||
Spacer(modifier = Modifier.height(22.dp))
|
||||
RYExtensibleVisibility(visible = expanded) {
|
||||
Column {
|
||||
feeds.forEach { feed ->
|
||||
FeedItem(
|
||||
feed = feed,
|
||||
tonalElevation = tonalElevation,
|
||||
) {
|
||||
feedOnClick(feed)
|
||||
}
|
||||
}
|
||||
if (feeds.isNotEmpty()) {
|
||||
Spacer(modifier = Modifier.height(16.dp))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,5 +1,6 @@
|
|||
package me.ash.reader.ui.page.home.feeds.drawer.feed
|
||||
|
||||
import android.view.HapticFeedbackConstants
|
||||
import androidx.activity.compose.BackHandler
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.material.ExperimentalMaterialApi
|
||||
|
@ -13,6 +14,7 @@ import androidx.compose.runtime.rememberCoroutineScope
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalView
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -23,6 +25,7 @@ import me.ash.reader.ui.component.FeedIcon
|
|||
import me.ash.reader.ui.component.base.BottomDrawer
|
||||
import me.ash.reader.ui.component.base.TextFieldDialog
|
||||
import me.ash.reader.ui.ext.collectAsStateValue
|
||||
import me.ash.reader.ui.ext.openURL
|
||||
import me.ash.reader.ui.ext.roundClick
|
||||
import me.ash.reader.ui.ext.showToast
|
||||
import me.ash.reader.ui.page.home.feeds.subscribe.ResultView
|
||||
|
@ -34,6 +37,7 @@ fun FeedOptionDrawer(
|
|||
content: @Composable () -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val view = LocalView.current
|
||||
val scope = rememberCoroutineScope()
|
||||
val feedOptionUiState = feedOptionViewModel.feedOptionUiState.collectAsStateValue()
|
||||
val feed = feedOptionUiState.feed
|
||||
|
@ -77,7 +81,8 @@ fun FeedOptionDrawer(
|
|||
ResultView(
|
||||
link = feed?.url ?: stringResource(R.string.unknown),
|
||||
groups = feedOptionUiState.groups,
|
||||
selectedAllowNotificationPreset = feedOptionUiState.feed?.isNotification ?: false,
|
||||
selectedAllowNotificationPreset = feedOptionUiState.feed?.isNotification
|
||||
?: false,
|
||||
selectedParseFullContentPreset = feedOptionUiState.feed?.isFullContent ?: false,
|
||||
isMoveToGroup = true,
|
||||
showUnsubscribe = true,
|
||||
|
@ -101,6 +106,10 @@ fun FeedOptionDrawer(
|
|||
feedOptionViewModel.showNewGroupDialog()
|
||||
},
|
||||
onFeedUrlClick = {
|
||||
context.openURL(feed?.url)
|
||||
},
|
||||
onFeedUrlLongClick = {
|
||||
view.performHapticFeedback(HapticFeedbackConstants.KEYBOARD_TAP)
|
||||
feedOptionViewModel.showFeedUrlDialog()
|
||||
}
|
||||
)
|
||||
|
|
|
@ -1,15 +1,11 @@
|
|||
package me.ash.reader.ui.page.home.feeds.subscribe
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.*
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyRow
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.foundation.rememberScrollState
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.text.selection.SelectionContainer
|
||||
import androidx.compose.foundation.verticalScroll
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.outlined.Add
|
||||
import androidx.compose.material.icons.outlined.Article
|
||||
|
@ -32,7 +28,6 @@ import me.ash.reader.R
|
|||
import me.ash.reader.data.entity.Group
|
||||
import me.ash.reader.ui.component.base.RYSelectionChip
|
||||
import me.ash.reader.ui.component.base.Subtitle
|
||||
import me.ash.reader.ui.ext.roundClick
|
||||
import me.ash.reader.ui.theme.palette.alwaysLight
|
||||
|
||||
@Composable
|
||||
|
@ -51,7 +46,8 @@ fun ResultView(
|
|||
unsubscribeOnClick: () -> Unit = {},
|
||||
onGroupClick: (groupId: String) -> Unit = {},
|
||||
onAddNewGroup: () -> Unit = {},
|
||||
onFeedUrlClick: () -> Unit = {}
|
||||
onFeedUrlClick: () -> Unit = {},
|
||||
onFeedUrlLongClick: () -> Unit = {},
|
||||
) {
|
||||
LaunchedEffect(Unit) {
|
||||
if (groups.isNotEmpty() && selectedGroupId.isEmpty()) onGroupClick(groups.first().id)
|
||||
|
@ -60,7 +56,11 @@ fun ResultView(
|
|||
Column(
|
||||
modifier = modifier.verticalScroll(rememberScrollState())
|
||||
) {
|
||||
EditableUrl(text = link, onFeedUrlClick)
|
||||
EditableUrl(
|
||||
text = link,
|
||||
onClick = onFeedUrlClick,
|
||||
onLongClick = onFeedUrlLongClick,
|
||||
)
|
||||
Spacer(modifier = Modifier.height(26.dp))
|
||||
|
||||
Preset(
|
||||
|
@ -85,20 +85,24 @@ fun ResultView(
|
|||
}
|
||||
}
|
||||
|
||||
@OptIn(ExperimentalFoundationApi::class)
|
||||
@Composable
|
||||
private fun EditableUrl(
|
||||
text: String,
|
||||
onClick: () -> Unit
|
||||
onClick: () -> Unit,
|
||||
onLongClick: () -> Unit,
|
||||
) {
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.Center
|
||||
) {
|
||||
SelectionContainer {
|
||||
Text(
|
||||
modifier = Modifier.roundClick {
|
||||
onClick()
|
||||
},
|
||||
modifier = Modifier
|
||||
.clip(MaterialTheme.shapes.small)
|
||||
.combinedClickable(
|
||||
onClick = onClick,
|
||||
onLongClick = onLongClick,
|
||||
),
|
||||
text = text,
|
||||
color = MaterialTheme.colorScheme.outline.copy(alpha = 0.7f),
|
||||
style = MaterialTheme.typography.bodyMedium,
|
||||
|
@ -106,7 +110,6 @@ private fun EditableUrl(
|
|||
overflow = TextOverflow.Ellipsis,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
|
|
@ -13,7 +13,6 @@ import androidx.compose.ui.Modifier
|
|||
import androidx.compose.ui.draw.alpha
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.layout.ContentScale
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.text.style.TextOverflow
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
@ -25,14 +24,13 @@ import me.ash.reader.data.preference.*
|
|||
import me.ash.reader.ui.component.FeedIcon
|
||||
import me.ash.reader.ui.component.base.RYAsyncImage
|
||||
import me.ash.reader.ui.component.base.SIZE_1000
|
||||
import me.ash.reader.ui.theme.SHAPE_20
|
||||
import me.ash.reader.ui.theme.Shape20
|
||||
|
||||
@Composable
|
||||
fun ArticleItem(
|
||||
articleWithFeed: ArticleWithFeed,
|
||||
onClick: (ArticleWithFeed) -> Unit = {},
|
||||
) {
|
||||
val context = LocalContext.current
|
||||
val articleListFeedIcon = LocalFlowArticleListFeedIcon.current
|
||||
val articleListFeedName = LocalFlowArticleListFeedName.current
|
||||
val articleListImage = LocalFlowArticleListImage.current
|
||||
|
@ -42,12 +40,12 @@ fun ArticleItem(
|
|||
Column(
|
||||
modifier = Modifier
|
||||
.padding(horizontal = 12.dp)
|
||||
.clip(SHAPE_20)
|
||||
.clip(Shape20)
|
||||
.clickable { onClick(articleWithFeed) }
|
||||
.padding(horizontal = 12.dp, vertical = 12.dp)
|
||||
.alpha(if (articleWithFeed.article.isStarred || articleWithFeed.article.isUnread) 1f else 0.5f),
|
||||
) {
|
||||
// Upper
|
||||
// Top
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
horizontalArrangement = Arrangement.SpaceBetween,
|
||||
|
@ -99,7 +97,7 @@ fun ArticleItem(
|
|||
}
|
||||
}
|
||||
|
||||
// Lower
|
||||
// Bottom
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth(),
|
||||
) {
|
||||
|
@ -142,7 +140,7 @@ fun ArticleItem(
|
|||
modifier = Modifier
|
||||
.padding(start = 10.dp)
|
||||
.size(80.dp)
|
||||
.clip(SHAPE_20),
|
||||
.clip(Shape20),
|
||||
data = articleWithFeed.article.img,
|
||||
scale = Scale.FILL,
|
||||
precision = Precision.INEXACT,
|
||||
|
|
|
@ -0,0 +1,143 @@
|
|||
package me.ash.reader.ui.page.settings.color.feeds
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.Refresh
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.entity.Feed
|
||||
import me.ash.reader.data.entity.Group
|
||||
import me.ash.reader.data.model.Filter
|
||||
import me.ash.reader.data.preference.FeedsGroupListExpandPreference
|
||||
import me.ash.reader.data.preference.FeedsGroupListTonalElevationPreference
|
||||
import me.ash.reader.data.preference.FeedsTopBarTonalElevationPreference
|
||||
import me.ash.reader.ui.component.FilterBar
|
||||
import me.ash.reader.ui.component.base.FeedbackIconButton
|
||||
import me.ash.reader.ui.ext.alphaLN
|
||||
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
||||
import me.ash.reader.ui.page.home.feeds.FeedItem
|
||||
import me.ash.reader.ui.page.home.feeds.GroupItem
|
||||
import me.ash.reader.ui.theme.palette.onDark
|
||||
import kotlin.math.ln
|
||||
|
||||
@Composable
|
||||
fun FeedsPagePreview(
|
||||
topBarTonalElevation: FeedsTopBarTonalElevationPreference,
|
||||
groupListExpand: FeedsGroupListExpandPreference,
|
||||
groupListTonalElevation: FeedsGroupListTonalElevationPreference,
|
||||
filterBarStyle: Int,
|
||||
filterBarFilled: Boolean,
|
||||
filterBarPadding: Dp,
|
||||
filterBarTonalElevation: Dp,
|
||||
) {
|
||||
var filter by remember { mutableStateOf(Filter.Unread) }
|
||||
val feedBadgeAlpha by remember { derivedStateOf { (ln(groupListTonalElevation.value + 1.4f) + 2f) / 100f } }
|
||||
val groupAlpha by remember { derivedStateOf { groupListTonalElevation.value.dp.alphaLN(weight = 1.2f) } }
|
||||
val groupIndicatorAlpha by remember {
|
||||
derivedStateOf {
|
||||
groupListTonalElevation.value.dp.alphaLN(
|
||||
weight = 1.4f
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
groupListTonalElevation.value.dp
|
||||
) onDark MaterialTheme.colorScheme.surface,
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
title = {},
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
topBarTonalElevation.value.dp
|
||||
),
|
||||
),
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
)
|
||||
},
|
||||
actions = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.Refresh,
|
||||
contentDescription = stringResource(R.string.refresh),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.Add,
|
||||
contentDescription = stringResource(R.string.subscribe),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
)
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
GroupItem(
|
||||
isExpanded = { groupListExpand.value },
|
||||
group = generateGroupPreview(),
|
||||
alpha = groupAlpha,
|
||||
indicatorAlpha = groupIndicatorAlpha,
|
||||
)
|
||||
FeedItem(
|
||||
feed = generateFeedPreview(),
|
||||
alpha = groupAlpha,
|
||||
badgeAlpha = feedBadgeAlpha,
|
||||
isEnded = true,
|
||||
isExpanded = { true },
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
FilterBar(
|
||||
filter = filter,
|
||||
filterBarStyle = filterBarStyle,
|
||||
filterBarFilled = filterBarFilled,
|
||||
filterBarPadding = filterBarPadding,
|
||||
filterBarTonalElevation = filterBarTonalElevation,
|
||||
) {
|
||||
filter = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun generateFeedPreview(): Feed =
|
||||
Feed(
|
||||
id = "",
|
||||
name = stringResource(R.string.preview_feed_name),
|
||||
icon = "",
|
||||
accountId = 0,
|
||||
groupId = "",
|
||||
url = "",
|
||||
).apply {
|
||||
important = 100
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun generateGroupPreview(): Group =
|
||||
Group(
|
||||
id = "",
|
||||
name = stringResource(R.string.defaults),
|
||||
accountId = 0,
|
||||
)
|
|
@ -1,38 +1,25 @@
|
|||
package me.ash.reader.ui.page.settings.color.feeds
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.Add
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.Refresh
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.entity.Feed
|
||||
import me.ash.reader.data.entity.Group
|
||||
import me.ash.reader.data.model.Filter
|
||||
import me.ash.reader.data.preference.*
|
||||
import me.ash.reader.ui.component.FilterBar
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
||||
import me.ash.reader.ui.page.home.feeds.GroupItem
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onDark
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
|
||||
@Composable
|
||||
|
@ -270,88 +257,3 @@ fun FeedsPageStylePage(
|
|||
groupListTonalElevationDialogVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FeedsPagePreview(
|
||||
topBarTonalElevation: FeedsTopBarTonalElevationPreference,
|
||||
groupListExpand: FeedsGroupListExpandPreference,
|
||||
groupListTonalElevation: FeedsGroupListTonalElevationPreference,
|
||||
filterBarStyle: Int,
|
||||
filterBarFilled: Boolean,
|
||||
filterBarPadding: Dp,
|
||||
filterBarTonalElevation: Dp,
|
||||
) {
|
||||
var filter by remember { mutableStateOf(Filter.Unread) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
groupListTonalElevation.value.dp
|
||||
) onDark MaterialTheme.colorScheme.surface,
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
title = {},
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
topBarTonalElevation.value.dp
|
||||
),
|
||||
),
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {}
|
||||
},
|
||||
actions = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.Refresh,
|
||||
contentDescription = stringResource(R.string.refresh),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
) {}
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.Add,
|
||||
contentDescription = stringResource(R.string.subscribe),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
) {}
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
GroupItem(
|
||||
isExpanded = groupListExpand.value,
|
||||
tonalElevation = groupListTonalElevation.value.dp,
|
||||
group = Group(
|
||||
id = "",
|
||||
name = stringResource(R.string.defaults),
|
||||
accountId = 0,
|
||||
),
|
||||
feeds = listOf(
|
||||
Feed(
|
||||
id = "",
|
||||
name = stringResource(R.string.preview_feed_name),
|
||||
icon = "",
|
||||
accountId = 0,
|
||||
groupId = "",
|
||||
url = "",
|
||||
).apply {
|
||||
important = 100
|
||||
}
|
||||
),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
FilterBar(
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
filter = filter,
|
||||
filterBarStyle = filterBarStyle,
|
||||
filterBarFilled = filterBarFilled,
|
||||
filterBarPadding = filterBarPadding,
|
||||
filterBarTonalElevation = filterBarTonalElevation,
|
||||
) {
|
||||
filter = it
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,124 @@
|
|||
package me.ash.reader.ui.page.settings.color.flow
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.DoneAll
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.entity.Article
|
||||
import me.ash.reader.data.entity.ArticleWithFeed
|
||||
import me.ash.reader.data.entity.Feed
|
||||
import me.ash.reader.data.model.Filter
|
||||
import me.ash.reader.data.preference.FlowArticleListTonalElevationPreference
|
||||
import me.ash.reader.data.preference.FlowTopBarTonalElevationPreference
|
||||
import me.ash.reader.ui.component.FilterBar
|
||||
import me.ash.reader.ui.component.base.FeedbackIconButton
|
||||
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
||||
import me.ash.reader.ui.page.home.flow.ArticleItem
|
||||
import me.ash.reader.ui.theme.palette.onDark
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun FlowPagePreview(
|
||||
topBarTonalElevation: FlowTopBarTonalElevationPreference,
|
||||
articleListTonalElevation: FlowArticleListTonalElevationPreference,
|
||||
filterBarStyle: Int,
|
||||
filterBarFilled: Boolean,
|
||||
filterBarPadding: Dp,
|
||||
filterBarTonalElevation: Dp,
|
||||
) {
|
||||
var filter by remember { mutableStateOf(Filter.Unread) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
articleListTonalElevation.value.dp
|
||||
) onDark MaterialTheme.colorScheme.surface,
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
title = {},
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
topBarTonalElevation.value.dp
|
||||
),
|
||||
),
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {}
|
||||
},
|
||||
actions = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.DoneAll,
|
||||
contentDescription = stringResource(R.string.mark_all_as_read),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
) {}
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.Search,
|
||||
contentDescription = stringResource(R.string.search),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
) {}
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
ArticleItem(
|
||||
articleWithFeed = generateArticleWithFeedPreview(),
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
FilterBar(
|
||||
filter = filter,
|
||||
filterBarStyle = filterBarStyle,
|
||||
filterBarFilled = filterBarFilled,
|
||||
filterBarPadding = filterBarPadding,
|
||||
filterBarTonalElevation = filterBarTonalElevation,
|
||||
) {
|
||||
filter = it
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Stable
|
||||
@Composable
|
||||
fun generateArticleWithFeedPreview(): ArticleWithFeed =
|
||||
ArticleWithFeed(
|
||||
Article(
|
||||
id = "",
|
||||
title = stringResource(R.string.preview_article_title),
|
||||
shortDescription = stringResource(R.string.preview_article_desc),
|
||||
rawDescription = stringResource(R.string.preview_article_desc),
|
||||
link = "",
|
||||
feedId = "",
|
||||
accountId = 0,
|
||||
date = Date(1654053729L),
|
||||
isStarred = true,
|
||||
img = "https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1yZWxhdGVkfDJ8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60"
|
||||
),
|
||||
feed = Feed(
|
||||
id = "",
|
||||
name = stringResource(R.string.preview_feed_name),
|
||||
icon = "",
|
||||
accountId = 0,
|
||||
groupId = "",
|
||||
url = "",
|
||||
),
|
||||
)
|
|
@ -1,6 +1,5 @@
|
|||
package me.ash.reader.ui.page.settings.color.flow
|
||||
|
||||
import androidx.compose.animation.animateContentSize
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.*
|
||||
|
@ -8,34 +7,20 @@ import androidx.compose.foundation.lazy.LazyColumn
|
|||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.icons.Icons
|
||||
import androidx.compose.material.icons.rounded.ArrowBack
|
||||
import androidx.compose.material.icons.rounded.DoneAll
|
||||
import androidx.compose.material.icons.rounded.Search
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.*
|
||||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.res.stringResource
|
||||
import androidx.compose.ui.unit.Dp
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.navigation.NavHostController
|
||||
import me.ash.reader.R
|
||||
import me.ash.reader.data.entity.Article
|
||||
import me.ash.reader.data.entity.ArticleWithFeed
|
||||
import me.ash.reader.data.entity.Feed
|
||||
import me.ash.reader.data.model.Filter
|
||||
import me.ash.reader.data.preference.*
|
||||
import me.ash.reader.ui.component.FilterBar
|
||||
import me.ash.reader.ui.component.base.*
|
||||
import me.ash.reader.ui.ext.surfaceColorAtElevation
|
||||
import me.ash.reader.ui.page.home.flow.ArticleItem
|
||||
import me.ash.reader.ui.page.settings.SettingItem
|
||||
import me.ash.reader.ui.theme.palette.onDark
|
||||
import me.ash.reader.ui.theme.palette.onLight
|
||||
import java.util.*
|
||||
|
||||
@Composable
|
||||
fun FlowPageStylePage(
|
||||
|
@ -332,90 +317,3 @@ fun FlowPageStylePage(
|
|||
articleListTonalElevationDialogVisible = false
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun FlowPagePreview(
|
||||
topBarTonalElevation: FlowTopBarTonalElevationPreference,
|
||||
articleListTonalElevation: FlowArticleListTonalElevationPreference,
|
||||
filterBarStyle: Int,
|
||||
filterBarFilled: Boolean,
|
||||
filterBarPadding: Dp,
|
||||
filterBarTonalElevation: Dp,
|
||||
) {
|
||||
var filter by remember { mutableStateOf(Filter.Unread) }
|
||||
|
||||
Column(
|
||||
modifier = Modifier
|
||||
.animateContentSize()
|
||||
.background(
|
||||
color = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
articleListTonalElevation.value.dp
|
||||
) onDark MaterialTheme.colorScheme.surface,
|
||||
shape = RoundedCornerShape(24.dp)
|
||||
)
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
title = {},
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(
|
||||
containerColor = MaterialTheme.colorScheme.surfaceColorAtElevation(
|
||||
topBarTonalElevation.value.dp
|
||||
),
|
||||
),
|
||||
navigationIcon = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.ArrowBack,
|
||||
contentDescription = stringResource(R.string.back),
|
||||
tint = MaterialTheme.colorScheme.onSurface
|
||||
) {}
|
||||
},
|
||||
actions = {
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.DoneAll,
|
||||
contentDescription = stringResource(R.string.mark_all_as_read),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
) {}
|
||||
FeedbackIconButton(
|
||||
imageVector = Icons.Rounded.Search,
|
||||
contentDescription = stringResource(R.string.search),
|
||||
tint = MaterialTheme.colorScheme.onSurface,
|
||||
) {}
|
||||
}
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
ArticleItem(
|
||||
articleWithFeed = ArticleWithFeed(
|
||||
Article(
|
||||
id = "",
|
||||
title = stringResource(R.string.preview_article_title),
|
||||
shortDescription = stringResource(R.string.preview_article_desc),
|
||||
rawDescription = stringResource(R.string.preview_article_desc),
|
||||
link = "",
|
||||
feedId = "",
|
||||
accountId = 0,
|
||||
date = Date(),
|
||||
isStarred = true,
|
||||
img = "https://images.unsplash.com/photo-1544716278-ca5e3f4abd8c?ixlib=rb-1.2.1&ixid=MnwxMjA3fDB8MHxwaG90by1yZWxhdGVkfDJ8fHxlbnwwfHx8fA%3D%3D&auto=format&fit=crop&w=800&q=60"
|
||||
),
|
||||
feed = Feed(
|
||||
id = "",
|
||||
name = stringResource(R.string.preview_feed_name),
|
||||
icon = "",
|
||||
accountId = 0,
|
||||
groupId = "",
|
||||
url = "",
|
||||
),
|
||||
)
|
||||
)
|
||||
Spacer(modifier = Modifier.height(12.dp))
|
||||
FilterBar(
|
||||
modifier = Modifier.padding(horizontal = 12.dp),
|
||||
filter = filter,
|
||||
filterBarStyle = filterBarStyle,
|
||||
filterBarFilled = filterBarFilled,
|
||||
filterBarPadding = filterBarPadding,
|
||||
filterBarTonalElevation = filterBarTonalElevation,
|
||||
) {
|
||||
filter = it
|
||||
}
|
||||
}
|
||||
}
|
|
@ -2,6 +2,7 @@ package me.ash.reader.ui.theme
|
|||
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material3.Shapes
|
||||
import androidx.compose.runtime.Stable
|
||||
import androidx.compose.ui.unit.dp
|
||||
|
||||
val Shapes = Shapes(
|
||||
|
@ -12,4 +13,14 @@ val Shapes = Shapes(
|
|||
extraLarge = RoundedCornerShape(28.0.dp)
|
||||
)
|
||||
|
||||
val SHAPE_20 = RoundedCornerShape(20.0.dp)
|
||||
@Stable
|
||||
val Shape20 = RoundedCornerShape(20.0.dp)
|
||||
|
||||
@Stable
|
||||
val Shape32 = RoundedCornerShape(32.0.dp)
|
||||
|
||||
@Stable
|
||||
val ShapeTop32 = RoundedCornerShape(32.0.dp, 32.0.dp, 0.0.dp, 0.0.dp)
|
||||
|
||||
@Stable
|
||||
val ShapeBottom32 = RoundedCornerShape(0.0.dp, 0.0.dp, 32.0.dp, 32.0.dp)
|
||||
|
|
Loading…
Reference in New Issue