mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 21:07:04 +05:30
Update LobstersCard
UI (#296)
This commit is contained in:
parent
93b013515c
commit
0db4e48613
5 changed files with 81 additions and 87 deletions
|
@ -5,18 +5,20 @@ import androidx.compose.foundation.lazy.rememberLazyListState
|
|||
import androidx.compose.material3.ExperimentalMaterial3Api
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Scaffold
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.runtime.LaunchedEffect
|
||||
import androidx.compose.runtime.SideEffect
|
||||
import androidx.compose.runtime.collectAsState
|
||||
import androidx.compose.runtime.getValue
|
||||
import androidx.compose.runtime.remember
|
||||
import androidx.compose.runtime.rememberCoroutineScope
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
||||
import androidx.compose.ui.platform.LocalConfiguration
|
||||
import androidx.compose.ui.platform.LocalContext
|
||||
import androidx.compose.ui.platform.LocalUriHandler
|
||||
import androidx.compose.ui.res.painterResource
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.viewmodel.compose.viewModel
|
||||
import androidx.navigation.compose.NavHost
|
||||
import androidx.navigation.compose.composable
|
||||
|
@ -57,6 +59,7 @@ fun LobstersApp(
|
|||
val coroutineScope = rememberCoroutineScope()
|
||||
val postActions = rememberPostActions(urlLauncher, navController, viewModel)
|
||||
val currentDestination by currentNavigationDestination(navController)
|
||||
val scrollBehavior = remember { TopAppBarDefaults.enterAlwaysScrollBehavior() }
|
||||
|
||||
val networkPosts = viewModel.pagerFlow.collectAsLazyPagingItems()
|
||||
val savedPosts by viewModel.savedPosts.collectAsState(emptyList())
|
||||
|
@ -98,10 +101,12 @@ fun LobstersApp(
|
|||
}
|
||||
|
||||
Scaffold(
|
||||
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
|
||||
topBar = {
|
||||
ClawAppBar(
|
||||
backgroundColor = systemBarsColor,
|
||||
modifier = Modifier.statusBarsPadding(),
|
||||
backgroundColor = systemBarsColor,
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
},
|
||||
bottomBar = {
|
||||
|
@ -115,7 +120,6 @@ fun LobstersApp(
|
|||
NavHost(
|
||||
navController,
|
||||
startDestination = Destinations.startDestination.getRoute(),
|
||||
modifier = Modifier.padding(top = 8.dp),
|
||||
) {
|
||||
composable(Destinations.Hottest.getRoute()) {
|
||||
setWebUri("https://lobste.rs/")
|
||||
|
|
|
@ -3,6 +3,7 @@ package dev.msfjarvis.claw.android.ui.decorations
|
|||
import androidx.compose.material3.SmallTopAppBar
|
||||
import androidx.compose.material3.Text
|
||||
import androidx.compose.material3.TopAppBarDefaults
|
||||
import androidx.compose.material3.TopAppBarScrollBehavior
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.graphics.Color
|
||||
|
@ -13,6 +14,7 @@ import dev.msfjarvis.claw.android.R
|
|||
@Composable
|
||||
fun ClawAppBar(
|
||||
backgroundColor: Color,
|
||||
scrollBehavior: TopAppBarScrollBehavior? = null,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
SmallTopAppBar(
|
||||
|
@ -24,5 +26,6 @@ fun ClawAppBar(
|
|||
},
|
||||
modifier = modifier,
|
||||
colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = backgroundColor),
|
||||
scrollBehavior = scrollBehavior,
|
||||
)
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package dev.msfjarvis.claw.android.ui.lists
|
|||
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.LazyListState
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.runtime.Composable
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.paging.compose.LazyPagingItems
|
||||
|
@ -31,6 +32,8 @@ fun NetworkPosts(
|
|||
isSaved = isSaved,
|
||||
postActions = postActions,
|
||||
)
|
||||
|
||||
Divider()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -20,7 +20,7 @@ import com.halilibo.richtext.markdown.Markdown
|
|||
import com.halilibo.richtext.ui.RichTextScope
|
||||
import com.halilibo.richtext.ui.material.MaterialRichText
|
||||
import dev.msfjarvis.claw.common.posts.PostDetails
|
||||
import dev.msfjarvis.claw.common.posts.SubmitterName
|
||||
import dev.msfjarvis.claw.common.posts.Submitter
|
||||
import dev.msfjarvis.claw.common.posts.toDbModel
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||
|
@ -70,7 +70,7 @@ fun CommentEntry(
|
|||
bottom = 4.dp
|
||||
)
|
||||
) {
|
||||
SubmitterName(
|
||||
Submitter(
|
||||
text = comment.user.username,
|
||||
avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}",
|
||||
contentDescription = "User avatar for ${comment.user.username}",
|
||||
|
|
|
@ -5,17 +5,21 @@ import androidx.compose.foundation.ExperimentalFoundationApi
|
|||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.combinedClickable
|
||||
import androidx.compose.foundation.interaction.MutableInteractionSource
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
import androidx.compose.foundation.layout.Box
|
||||
import androidx.compose.foundation.layout.Column
|
||||
import androidx.compose.foundation.layout.Row
|
||||
import androidx.compose.foundation.layout.Spacer
|
||||
import androidx.compose.foundation.layout.fillMaxHeight
|
||||
import androidx.compose.foundation.layout.fillMaxWidth
|
||||
import androidx.compose.foundation.layout.height
|
||||
import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.requiredSize
|
||||
import androidx.compose.foundation.layout.width
|
||||
import androidx.compose.foundation.shape.CircleShape
|
||||
import androidx.compose.foundation.shape.RoundedCornerShape
|
||||
import androidx.compose.material.Divider
|
||||
import androidx.compose.material.ripple.rememberRipple
|
||||
import androidx.compose.material3.Icon
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Text
|
||||
|
@ -27,6 +31,7 @@ import androidx.compose.runtime.setValue
|
|||
import androidx.compose.ui.Alignment
|
||||
import androidx.compose.ui.Modifier
|
||||
import androidx.compose.ui.draw.clip
|
||||
import androidx.compose.ui.semantics.Role
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.unit.dp
|
||||
import com.google.accompanist.flowlayout.FlowRow
|
||||
|
@ -46,32 +51,39 @@ fun LobstersCard(
|
|||
) {
|
||||
var localSavedState by remember(post, isSaved) { mutableStateOf(isSaved) }
|
||||
Box(modifier = modifier.clickable { postActions.viewPost(post.url, post.commentsUrl) }) {
|
||||
Column(
|
||||
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp).fillMaxWidth(),
|
||||
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(16.dp),
|
||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
PostDetails(
|
||||
modifier = Modifier.weight(1f),
|
||||
post = post,
|
||||
)
|
||||
Row(
|
||||
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp),
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
horizontalArrangement = Arrangement.End,
|
||||
Column(
|
||||
modifier = Modifier.weight(0.15f).fillMaxHeight(),
|
||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||
horizontalAlignment = Alignment.CenterHorizontally,
|
||||
) {
|
||||
SaveButton(
|
||||
isSaved = localSavedState,
|
||||
modifier =
|
||||
Modifier.clickable {
|
||||
Modifier.clickable(
|
||||
role = Role.Button,
|
||||
indication = rememberRipple(bounded = false, radius = 24.dp),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
) {
|
||||
localSavedState = !localSavedState
|
||||
postActions.toggleSave(post)
|
||||
},
|
||||
)
|
||||
Spacer(
|
||||
modifier = Modifier.width(8.dp),
|
||||
)
|
||||
Divider()
|
||||
CommentsButton(
|
||||
modifier =
|
||||
Modifier.combinedClickable(
|
||||
role = Role.Button,
|
||||
indication = rememberRipple(bounded = false, radius = 24.dp),
|
||||
interactionSource = remember { MutableInteractionSource() },
|
||||
onClick = { postActions.viewComments(post.shortId) },
|
||||
onLongClick = { postActions.viewCommentsPage(post.commentsUrl) },
|
||||
),
|
||||
|
@ -82,23 +94,18 @@ fun LobstersCard(
|
|||
}
|
||||
|
||||
@Composable
|
||||
fun PostDetails(
|
||||
post: SavedPost,
|
||||
) {
|
||||
PostTitle(
|
||||
title = post.title,
|
||||
modifier = Modifier.padding(bottom = 4.dp),
|
||||
)
|
||||
TagRow(
|
||||
tags = post.tags,
|
||||
modifier = Modifier.padding(bottom = 4.dp),
|
||||
)
|
||||
SubmitterName(
|
||||
fun PostDetails(post: SavedPost, modifier: Modifier = Modifier) {
|
||||
Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp)) {
|
||||
PostTitle(title = post.title)
|
||||
TagRow(tags = post.tags)
|
||||
Spacer(Modifier.height(4.dp))
|
||||
Submitter(
|
||||
text = "Submitted by ${post.submitterName}",
|
||||
avatarUrl = "https://lobste.rs/${post.submitterAvatarUrl}",
|
||||
contentDescription = "User avatar for ${post.submitterName}",
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun PostTitle(
|
||||
|
@ -107,13 +114,14 @@ fun PostTitle(
|
|||
) {
|
||||
Text(
|
||||
text = title,
|
||||
fontWeight = FontWeight.Bold,
|
||||
modifier = modifier,
|
||||
style = MaterialTheme.typography.titleMedium,
|
||||
fontWeight = FontWeight.Bold
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SubmitterName(
|
||||
fun Submitter(
|
||||
text: String,
|
||||
avatarUrl: String,
|
||||
contentDescription: String,
|
||||
|
@ -122,40 +130,16 @@ fun SubmitterName(
|
|||
Row(
|
||||
modifier = modifier,
|
||||
verticalAlignment = Alignment.CenterVertically,
|
||||
) {
|
||||
SubmitterAvatar(
|
||||
avatarUrl = avatarUrl,
|
||||
contentDescription = contentDescription,
|
||||
)
|
||||
SubmitterNameText(
|
||||
text = text,
|
||||
modifier = Modifier.padding(start = 4.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SubmitterAvatar(
|
||||
avatarUrl: String,
|
||||
contentDescription: String,
|
||||
modifier: Modifier = Modifier,
|
||||
horizontalArrangement = Arrangement.spacedBy(4.dp),
|
||||
) {
|
||||
NetworkImage(
|
||||
url = avatarUrl,
|
||||
contentDescription = contentDescription,
|
||||
modifier = modifier.requiredSize(24.dp).clip(CircleShape),
|
||||
)
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun SubmitterNameText(
|
||||
text: String,
|
||||
modifier: Modifier,
|
||||
) {
|
||||
Text(
|
||||
text = text,
|
||||
modifier = modifier,
|
||||
)
|
||||
Text(text = text, modifier = modifier, style = MaterialTheme.typography.bodyMedium)
|
||||
}
|
||||
}
|
||||
|
||||
@Composable
|
||||
|
@ -168,7 +152,7 @@ fun SaveButton(
|
|||
painter = if (saved) heartIcon else heartBorderIcon,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
contentDescription = if (saved) "Remove from saved posts" else "Add to saved posts",
|
||||
modifier = modifier,
|
||||
modifier = modifier.padding(12.dp),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
@ -181,7 +165,7 @@ fun CommentsButton(
|
|||
painter = commentIcon,
|
||||
tint = MaterialTheme.colorScheme.secondary,
|
||||
contentDescription = "Open comments",
|
||||
modifier = modifier,
|
||||
modifier = modifier.padding(12.dp),
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -189,26 +173,26 @@ fun CommentsButton(
|
|||
fun TagRow(
|
||||
tags: List<String>,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Box(
|
||||
modifier = modifier,
|
||||
) {
|
||||
FlowRow(
|
||||
modifier = modifier,
|
||||
mainAxisSpacing = 8.dp,
|
||||
crossAxisSpacing = 8.dp,
|
||||
) { tags.forEach { tag -> TagText(tag) } }
|
||||
}
|
||||
|
||||
@Composable
|
||||
fun TagText(
|
||||
tag: String,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
tags.forEach { tag ->
|
||||
Text(
|
||||
text = tag,
|
||||
modifier =
|
||||
Modifier.background(
|
||||
MaterialTheme.colorScheme.secondary.copy(alpha = 0.75f),
|
||||
RoundedCornerShape(8.dp)
|
||||
Modifier.background(MaterialTheme.colorScheme.tertiaryContainer, RoundedCornerShape(50))
|
||||
.padding(vertical = 4.dp, horizontal = 12.dp)
|
||||
.then(modifier),
|
||||
color = MaterialTheme.colorScheme.onTertiaryContainer,
|
||||
style = MaterialTheme.typography.labelLarge
|
||||
)
|
||||
.padding(vertical = 2.dp, horizontal = 6.dp),
|
||||
color = MaterialTheme.colorScheme.onSecondary,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue