Update LobstersCard UI (#296)

This commit is contained in:
Sasikanth Miriyampalli 2022-02-20 15:23:26 +05:30 committed by GitHub
parent 93b013515c
commit 0db4e48613
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
5 changed files with 81 additions and 87 deletions

View file

@ -5,18 +5,20 @@ import androidx.compose.foundation.lazy.rememberLazyListState
import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.ExperimentalMaterial3Api
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Scaffold import androidx.compose.material3.Scaffold
import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.SideEffect import androidx.compose.runtime.SideEffect
import androidx.compose.runtime.collectAsState import androidx.compose.runtime.collectAsState
import androidx.compose.runtime.getValue import androidx.compose.runtime.getValue
import androidx.compose.runtime.remember
import androidx.compose.runtime.rememberCoroutineScope import androidx.compose.runtime.rememberCoroutineScope
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.input.nestedscroll.nestedScroll
import androidx.compose.ui.platform.LocalConfiguration import androidx.compose.ui.platform.LocalConfiguration
import androidx.compose.ui.platform.LocalContext import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.res.painterResource import androidx.compose.ui.res.painterResource
import androidx.compose.ui.unit.dp
import androidx.lifecycle.viewmodel.compose.viewModel import androidx.lifecycle.viewmodel.compose.viewModel
import androidx.navigation.compose.NavHost import androidx.navigation.compose.NavHost
import androidx.navigation.compose.composable import androidx.navigation.compose.composable
@ -57,6 +59,7 @@ fun LobstersApp(
val coroutineScope = rememberCoroutineScope() val coroutineScope = rememberCoroutineScope()
val postActions = rememberPostActions(urlLauncher, navController, viewModel) val postActions = rememberPostActions(urlLauncher, navController, viewModel)
val currentDestination by currentNavigationDestination(navController) val currentDestination by currentNavigationDestination(navController)
val scrollBehavior = remember { TopAppBarDefaults.enterAlwaysScrollBehavior() }
val networkPosts = viewModel.pagerFlow.collectAsLazyPagingItems() val networkPosts = viewModel.pagerFlow.collectAsLazyPagingItems()
val savedPosts by viewModel.savedPosts.collectAsState(emptyList()) val savedPosts by viewModel.savedPosts.collectAsState(emptyList())
@ -98,10 +101,12 @@ fun LobstersApp(
} }
Scaffold( Scaffold(
modifier = Modifier.nestedScroll(scrollBehavior.nestedScrollConnection),
topBar = { topBar = {
ClawAppBar( ClawAppBar(
backgroundColor = systemBarsColor,
modifier = Modifier.statusBarsPadding(), modifier = Modifier.statusBarsPadding(),
backgroundColor = systemBarsColor,
scrollBehavior = scrollBehavior,
) )
}, },
bottomBar = { bottomBar = {
@ -115,7 +120,6 @@ fun LobstersApp(
NavHost( NavHost(
navController, navController,
startDestination = Destinations.startDestination.getRoute(), startDestination = Destinations.startDestination.getRoute(),
modifier = Modifier.padding(top = 8.dp),
) { ) {
composable(Destinations.Hottest.getRoute()) { composable(Destinations.Hottest.getRoute()) {
setWebUri("https://lobste.rs/") setWebUri("https://lobste.rs/")

View file

@ -3,6 +3,7 @@ package dev.msfjarvis.claw.android.ui.decorations
import androidx.compose.material3.SmallTopAppBar import androidx.compose.material3.SmallTopAppBar
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.material3.TopAppBarDefaults import androidx.compose.material3.TopAppBarDefaults
import androidx.compose.material3.TopAppBarScrollBehavior
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
@ -13,6 +14,7 @@ import dev.msfjarvis.claw.android.R
@Composable @Composable
fun ClawAppBar( fun ClawAppBar(
backgroundColor: Color, backgroundColor: Color,
scrollBehavior: TopAppBarScrollBehavior? = null,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
SmallTopAppBar( SmallTopAppBar(
@ -24,5 +26,6 @@ fun ClawAppBar(
}, },
modifier = modifier, modifier = modifier,
colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = backgroundColor), colors = TopAppBarDefaults.smallTopAppBarColors(containerColor = backgroundColor),
scrollBehavior = scrollBehavior,
) )
} }

View file

@ -2,6 +2,7 @@ package dev.msfjarvis.claw.android.ui.lists
import androidx.compose.foundation.lazy.LazyColumn import androidx.compose.foundation.lazy.LazyColumn
import androidx.compose.foundation.lazy.LazyListState import androidx.compose.foundation.lazy.LazyListState
import androidx.compose.material.Divider
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.LazyPagingItems
@ -31,6 +32,8 @@ fun NetworkPosts(
isSaved = isSaved, isSaved = isSaved,
postActions = postActions, postActions = postActions,
) )
Divider()
} }
} }
} }

View file

@ -20,7 +20,7 @@ import com.halilibo.richtext.markdown.Markdown
import com.halilibo.richtext.ui.RichTextScope import com.halilibo.richtext.ui.RichTextScope
import com.halilibo.richtext.ui.material.MaterialRichText import com.halilibo.richtext.ui.material.MaterialRichText
import dev.msfjarvis.claw.common.posts.PostDetails 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.common.posts.toDbModel
import dev.msfjarvis.claw.model.Comment import dev.msfjarvis.claw.model.Comment
import dev.msfjarvis.claw.model.LobstersPostDetails import dev.msfjarvis.claw.model.LobstersPostDetails
@ -70,7 +70,7 @@ fun CommentEntry(
bottom = 4.dp bottom = 4.dp
) )
) { ) {
SubmitterName( Submitter(
text = comment.user.username, text = comment.user.username,
avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}", avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}",
contentDescription = "User avatar for ${comment.user.username}", contentDescription = "User avatar for ${comment.user.username}",

View file

@ -5,17 +5,21 @@ import androidx.compose.foundation.ExperimentalFoundationApi
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.clickable import androidx.compose.foundation.clickable
import androidx.compose.foundation.combinedClickable import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.interaction.MutableInteractionSource
import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.Spacer
import androidx.compose.foundation.layout.fillMaxHeight
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.foundation.layout.requiredSize import androidx.compose.foundation.layout.requiredSize
import androidx.compose.foundation.layout.width
import androidx.compose.foundation.shape.CircleShape import androidx.compose.foundation.shape.CircleShape
import androidx.compose.foundation.shape.RoundedCornerShape 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.Icon
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
@ -27,6 +31,7 @@ import androidx.compose.runtime.setValue
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.semantics.Role
import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import com.google.accompanist.flowlayout.FlowRow import com.google.accompanist.flowlayout.FlowRow
@ -46,32 +51,39 @@ fun LobstersCard(
) { ) {
var localSavedState by remember(post, isSaved) { mutableStateOf(isSaved) } var localSavedState by remember(post, isSaved) { mutableStateOf(isSaved) }
Box(modifier = modifier.clickable { postActions.viewPost(post.url, post.commentsUrl) }) { Box(modifier = modifier.clickable { postActions.viewPost(post.url, post.commentsUrl) }) {
Column( Row(
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp).fillMaxWidth(), modifier = Modifier.fillMaxWidth().padding(16.dp),
verticalArrangement = Arrangement.spacedBy(4.dp), horizontalArrangement = Arrangement.spacedBy(8.dp),
verticalAlignment = Alignment.CenterVertically,
) { ) {
PostDetails( PostDetails(
modifier = Modifier.weight(1f),
post = post, post = post,
) )
Row( Column(
modifier = Modifier.fillMaxWidth().padding(bottom = 8.dp), modifier = Modifier.weight(0.15f).fillMaxHeight(),
verticalAlignment = Alignment.CenterVertically, verticalArrangement = Arrangement.spacedBy(8.dp),
horizontalArrangement = Arrangement.End, horizontalAlignment = Alignment.CenterHorizontally,
) { ) {
SaveButton( SaveButton(
isSaved = localSavedState, isSaved = localSavedState,
modifier = modifier =
Modifier.clickable { Modifier.clickable(
role = Role.Button,
indication = rememberRipple(bounded = false, radius = 24.dp),
interactionSource = remember { MutableInteractionSource() },
) {
localSavedState = !localSavedState localSavedState = !localSavedState
postActions.toggleSave(post) postActions.toggleSave(post)
}, },
) )
Spacer( Divider()
modifier = Modifier.width(8.dp),
)
CommentsButton( CommentsButton(
modifier = modifier =
Modifier.combinedClickable( Modifier.combinedClickable(
role = Role.Button,
indication = rememberRipple(bounded = false, radius = 24.dp),
interactionSource = remember { MutableInteractionSource() },
onClick = { postActions.viewComments(post.shortId) }, onClick = { postActions.viewComments(post.shortId) },
onLongClick = { postActions.viewCommentsPage(post.commentsUrl) }, onLongClick = { postActions.viewCommentsPage(post.commentsUrl) },
), ),
@ -82,22 +94,17 @@ fun LobstersCard(
} }
@Composable @Composable
fun PostDetails( fun PostDetails(post: SavedPost, modifier: Modifier = Modifier) {
post: SavedPost, Column(modifier = modifier, verticalArrangement = Arrangement.spacedBy(8.dp)) {
) { PostTitle(title = post.title)
PostTitle( TagRow(tags = post.tags)
title = post.title, Spacer(Modifier.height(4.dp))
modifier = Modifier.padding(bottom = 4.dp), Submitter(
) text = "Submitted by ${post.submitterName}",
TagRow( avatarUrl = "https://lobste.rs/${post.submitterAvatarUrl}",
tags = post.tags, contentDescription = "User avatar for ${post.submitterName}",
modifier = Modifier.padding(bottom = 4.dp), )
) }
SubmitterName(
text = "Submitted by ${post.submitterName}",
avatarUrl = "https://lobste.rs/${post.submitterAvatarUrl}",
contentDescription = "User avatar for ${post.submitterName}",
)
} }
@Composable @Composable
@ -107,13 +114,14 @@ fun PostTitle(
) { ) {
Text( Text(
text = title, text = title,
fontWeight = FontWeight.Bold,
modifier = modifier, modifier = modifier,
style = MaterialTheme.typography.titleMedium,
fontWeight = FontWeight.Bold
) )
} }
@Composable @Composable
fun SubmitterName( fun Submitter(
text: String, text: String,
avatarUrl: String, avatarUrl: String,
contentDescription: String, contentDescription: String,
@ -122,42 +130,18 @@ fun SubmitterName(
Row( Row(
modifier = modifier, modifier = modifier,
verticalAlignment = Alignment.CenterVertically, verticalAlignment = Alignment.CenterVertically,
horizontalArrangement = Arrangement.spacedBy(4.dp),
) { ) {
SubmitterAvatar( NetworkImage(
avatarUrl = avatarUrl, url = avatarUrl,
contentDescription = contentDescription, contentDescription = contentDescription,
modifier = modifier.requiredSize(24.dp).clip(CircleShape),
) )
SubmitterNameText(
text = text, Text(text = text, modifier = modifier, style = MaterialTheme.typography.bodyMedium)
modifier = Modifier.padding(start = 4.dp),
)
} }
} }
@Composable
fun SubmitterAvatar(
avatarUrl: String,
contentDescription: String,
modifier: Modifier = Modifier,
) {
NetworkImage(
url = avatarUrl,
contentDescription = contentDescription,
modifier = modifier.requiredSize(24.dp).clip(CircleShape),
)
}
@Composable
fun SubmitterNameText(
text: String,
modifier: Modifier,
) {
Text(
text = text,
modifier = modifier,
)
}
@Composable @Composable
fun SaveButton( fun SaveButton(
isSaved: Boolean, isSaved: Boolean,
@ -168,7 +152,7 @@ fun SaveButton(
painter = if (saved) heartIcon else heartBorderIcon, painter = if (saved) heartIcon else heartBorderIcon,
tint = MaterialTheme.colorScheme.secondary, tint = MaterialTheme.colorScheme.secondary,
contentDescription = if (saved) "Remove from saved posts" else "Add to saved posts", 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, painter = commentIcon,
tint = MaterialTheme.colorScheme.secondary, tint = MaterialTheme.colorScheme.secondary,
contentDescription = "Open comments", contentDescription = "Open comments",
modifier = modifier, modifier = modifier.padding(12.dp),
) )
} }
@ -190,25 +174,25 @@ fun TagRow(
tags: List<String>, tags: List<String>,
modifier: Modifier = Modifier, modifier: Modifier = Modifier,
) { ) {
Box( FlowRow(
modifier = modifier, modifier = modifier,
) { mainAxisSpacing = 8.dp,
FlowRow( crossAxisSpacing = 8.dp,
mainAxisSpacing = 8.dp, ) { tags.forEach { tag -> TagText(tag) } }
crossAxisSpacing = 8.dp, }
) {
tags.forEach { tag -> @Composable
Text( fun TagText(
text = tag, tag: String,
modifier = modifier: Modifier = Modifier,
Modifier.background( ) {
MaterialTheme.colorScheme.secondary.copy(alpha = 0.75f), Text(
RoundedCornerShape(8.dp) text = tag,
) modifier =
.padding(vertical = 2.dp, horizontal = 6.dp), Modifier.background(MaterialTheme.colorScheme.tertiaryContainer, RoundedCornerShape(50))
color = MaterialTheme.colorScheme.onSecondary, .padding(vertical = 4.dp, horizontal = 12.dp)
) .then(modifier),
} color = MaterialTheme.colorScheme.onTertiaryContainer,
} style = MaterialTheme.typography.labelLarge
} )
} }