-
Notifications
You must be signed in to change notification settings - Fork 169
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Move time ago and score to a flowrow layout #1615
Changes from 3 commits
733df97
0bf14fa
5dadc16
c1c8343
68778f9
be8ab81
4f27431
aaae70b
0baed31
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -258,8 +258,7 @@ fun CommentOrPostNodeHeader( | |
voteDisplayMode: LocalUserVoteDisplayMode, | ||
) { | ||
FlowRow( | ||
horizontalArrangement = Arrangement.SpaceBetween, | ||
verticalArrangement = Arrangement.Center, | ||
horizontalArrangement = Arrangement.spacedBy(SMALLER_PADDING, Alignment.Start), | ||
modifier = | ||
Modifier | ||
.fillMaxWidth() | ||
|
@@ -273,36 +272,40 @@ fun CommentOrPostNodeHeader( | |
bottom = MEDIUM_PADDING, | ||
), | ||
) { | ||
Row( | ||
horizontalArrangement = Arrangement.spacedBy(SMALL_PADDING), | ||
verticalAlignment = Alignment.CenterVertically, | ||
) { | ||
if (deleted) { | ||
Icon( | ||
imageVector = Icons.Outlined.Delete, | ||
contentDescription = stringResource(R.string.commentOrPostHeader_deleted), | ||
tint = MaterialTheme.colorScheme.error, | ||
) | ||
DotSpacer(style = MaterialTheme.typography.bodyMedium) | ||
} | ||
|
||
PersonProfileLink( | ||
person = creator, | ||
onClick = { onPersonClick(creator.id) }, | ||
showTags = true, | ||
isPostCreator = isPostCreator, | ||
isDistinguished = isDistinguished, | ||
isCommunityBanned = isCommunityBanned, | ||
showAvatar = showAvatar, | ||
val centerMod = Modifier.align(Alignment.CenterVertically) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This centerMod is necessary on FlowRows unfortunately. I wish it could do some cross-axis alignment, but it doesn't seem to work. |
||
if (deleted) { | ||
Icon( | ||
imageVector = Icons.Outlined.Delete, | ||
contentDescription = stringResource(R.string.commentOrPostHeader_deleted), | ||
tint = MaterialTheme.colorScheme.error, | ||
modifier = centerMod, | ||
) | ||
DotSpacer(modifier = centerMod) | ||
} | ||
ScoreAndTime( | ||
|
||
PersonProfileLink( | ||
person = creator, | ||
onClick = { onPersonClick(creator.id) }, | ||
showTags = true, | ||
isPostCreator = isPostCreator, | ||
isDistinguished = isDistinguished, | ||
isCommunityBanned = isCommunityBanned, | ||
showAvatar = showAvatar, | ||
modifier = centerMod, | ||
) | ||
DotSpacer(modifier = centerMod) | ||
ScoreCombined( | ||
instantScores = instantScores, | ||
published = published, | ||
updated = updated, | ||
isExpanded = isExpanded, | ||
collapsedCommentsCount = collapsedCommentsCount, | ||
voteDisplayMode = voteDisplayMode, | ||
modifier = centerMod, | ||
) | ||
DotSpacer(modifier = centerMod) | ||
TimeAgo( | ||
published = published, | ||
updated = updated, | ||
modifier = centerMod, | ||
) | ||
} | ||
} | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I split the card and list into different files, and this is now the generic one. |
Large diffs are not rendered by default.
Large diffs are not rendered by default.
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,310 @@ | ||
package com.jerboa.ui.components.post | ||
|
||
import androidx.compose.foundation.clickable | ||
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.ExperimentalLayoutApi | ||
import androidx.compose.foundation.layout.FlowRow | ||
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.material3.MaterialTheme | ||
import androidx.compose.material3.Text | ||
import androidx.compose.runtime.Composable | ||
import androidx.compose.ui.Alignment | ||
import androidx.compose.ui.Modifier | ||
import androidx.compose.ui.draw.alpha | ||
import androidx.compose.ui.platform.testTag | ||
import androidx.compose.ui.res.stringResource | ||
import androidx.compose.ui.text.TextStyle | ||
import androidx.compose.ui.text.font.FontFamily | ||
import androidx.compose.ui.text.font.FontStyle | ||
import androidx.compose.ui.tooling.preview.Preview | ||
import androidx.compose.ui.unit.Dp | ||
import androidx.compose.ui.unit.dp | ||
import com.jerboa.JerboaAppState | ||
import com.jerboa.R | ||
import com.jerboa.datatypes.sampleInstantScores | ||
import com.jerboa.datatypes.samplePostView | ||
import com.jerboa.db.entity.Account | ||
import com.jerboa.db.entity.AnonAccount | ||
import com.jerboa.feat.BlurNSFW | ||
import com.jerboa.feat.InstantScores | ||
import com.jerboa.feat.VoteType | ||
import com.jerboa.feat.default | ||
import com.jerboa.feat.needBlur | ||
import com.jerboa.hostNameCleaned | ||
import com.jerboa.isSameInstance | ||
import com.jerboa.nsfwCheck | ||
import com.jerboa.rememberJerboaAppState | ||
import com.jerboa.ui.components.common.DotSpacer | ||
import com.jerboa.ui.components.common.NsfwBadge | ||
import com.jerboa.ui.components.common.TimeAgo | ||
import com.jerboa.ui.components.common.VoteGeneric | ||
import com.jerboa.ui.components.common.scoreColor | ||
import com.jerboa.ui.components.community.CommunityLink | ||
import com.jerboa.ui.components.person.PersonProfileLink | ||
import com.jerboa.ui.theme.MEDIUM_PADDING | ||
import com.jerboa.ui.theme.SMALLER_PADDING | ||
import com.jerboa.ui.theme.SMALL_PADDING | ||
import it.vercruysse.lemmyapi.datatypes.LocalUserVoteDisplayMode | ||
import it.vercruysse.lemmyapi.datatypes.PostView | ||
|
||
@OptIn(ExperimentalLayoutApi::class) | ||
@Composable | ||
fun PostListingList( | ||
postView: PostView, | ||
instantScores: InstantScores, | ||
onUpvoteClick: () -> Unit, | ||
onDownvoteClick: () -> Unit, | ||
onPostClick: (postView: PostView) -> Unit, | ||
showCommunityName: Boolean = true, | ||
account: Account, | ||
showVotingArrowsInListView: Boolean, | ||
useCustomTabs: Boolean, | ||
usePrivateTabs: Boolean, | ||
blurNSFW: BlurNSFW, | ||
appState: JerboaAppState, | ||
showIfRead: Boolean, | ||
enableDownVotes: Boolean, | ||
voteDisplayMode: LocalUserVoteDisplayMode, | ||
) { | ||
Column( | ||
modifier = | ||
Modifier | ||
.padding( | ||
horizontal = MEDIUM_PADDING, | ||
vertical = MEDIUM_PADDING, | ||
).testTag("jerboa:post"), | ||
) { | ||
Row( | ||
modifier = Modifier.fillMaxWidth(), | ||
horizontalArrangement = | ||
Arrangement.spacedBy( | ||
SMALL_PADDING, | ||
), | ||
) { | ||
if (showVotingArrowsInListView) { | ||
PostVotingTile( | ||
instantScores = instantScores, | ||
onUpvoteClick = onUpvoteClick, | ||
onDownvoteClick = onDownvoteClick, | ||
account = account, | ||
enableDownVotes = enableDownVotes, | ||
voteDisplayMode = voteDisplayMode, | ||
) | ||
} | ||
Column( | ||
modifier = | ||
Modifier | ||
.weight(1f) | ||
.clickable { onPostClick(postView) }, | ||
verticalArrangement = Arrangement.spacedBy(SMALL_PADDING), | ||
) { | ||
PostName(post = postView.post, read = postView.read, showIfRead = showIfRead) | ||
FlowRow( | ||
horizontalArrangement = Arrangement.spacedBy(SMALLER_PADDING, Alignment.Start), | ||
) { | ||
// You must use a center align modifier for each of these | ||
val centerMod = Modifier.align(Alignment.CenterVertically) | ||
if (showCommunityName) { | ||
CommunityLink( | ||
community = postView.community, | ||
onClick = {}, | ||
clickable = false, | ||
showDefaultIcon = false, | ||
showAvatar = false, | ||
blurNSFW = blurNSFW, | ||
modifier = centerMod, | ||
) | ||
DotSpacer(modifier = centerMod) | ||
} | ||
PersonProfileLink( | ||
person = postView.creator, | ||
onClick = {}, | ||
clickable = false, | ||
color = MaterialTheme.colorScheme.outline, | ||
showAvatar = false, | ||
modifier = centerMod, | ||
) | ||
DotSpacer(modifier = centerMod) | ||
postView.post.url?.also { postUrl -> | ||
if (!isSameInstance(postUrl, account.instance)) { | ||
val hostName = hostNameCleaned(postUrl) | ||
hostName?.also { | ||
Text( | ||
text = it, | ||
color = MaterialTheme.colorScheme.outline, | ||
style = MaterialTheme.typography.labelMedium, | ||
fontFamily = FontFamily.Monospace, | ||
modifier = centerMod, | ||
) | ||
DotSpacer(modifier = centerMod) | ||
} | ||
} | ||
} | ||
TimeAgo( | ||
published = postView.post.published, | ||
updated = postView.post.updated, | ||
modifier = centerMod, | ||
) | ||
} | ||
Row( | ||
horizontalArrangement = Arrangement.spacedBy(SMALLER_PADDING), | ||
verticalAlignment = Alignment.CenterVertically, | ||
) { | ||
if (!showVotingArrowsInListView) { | ||
Text( | ||
text = instantScores.score.toString(), | ||
style = MaterialTheme.typography.bodyMedium, | ||
color = scoreColor(myVote = instantScores.myVote), | ||
) | ||
DotSpacer() | ||
} | ||
Text( | ||
text = | ||
stringResource( | ||
R.string.post_listing_comments_count, | ||
postView.counts.comments, | ||
), | ||
style = MaterialTheme.typography.labelMedium, | ||
color = MaterialTheme.colorScheme.outline, | ||
) | ||
CommentNewCount( | ||
comments = postView.counts.comments, | ||
unreadCount = postView.unread_comments, | ||
style = MaterialTheme.typography.labelMedium, | ||
) | ||
NsfwBadge(nsfwCheck(postView)) | ||
} | ||
} | ||
ThumbnailTile( | ||
post = postView.post, | ||
useCustomTabs = useCustomTabs, | ||
usePrivateTabs = usePrivateTabs, | ||
blurEnabled = blurNSFW.needBlur(postView), | ||
appState = appState, | ||
) | ||
} | ||
} | ||
} | ||
|
||
@Preview | ||
@Composable | ||
fun PostListingListPreview() { | ||
PostListingList( | ||
postView = samplePostView, | ||
instantScores = sampleInstantScores, | ||
onUpvoteClick = {}, | ||
onDownvoteClick = {}, | ||
onPostClick = {}, | ||
account = AnonAccount, | ||
showVotingArrowsInListView = true, | ||
useCustomTabs = false, | ||
usePrivateTabs = false, | ||
blurNSFW = BlurNSFW.NSFW, | ||
appState = rememberJerboaAppState(), | ||
showIfRead = true, | ||
enableDownVotes = false, | ||
voteDisplayMode = LocalUserVoteDisplayMode.default(), | ||
) | ||
} | ||
|
||
@Preview | ||
@Composable | ||
fun PostListingListWithThumbPreview() { | ||
PostListingList( | ||
postView = samplePostView, | ||
instantScores = sampleInstantScores, | ||
onUpvoteClick = {}, | ||
onDownvoteClick = {}, | ||
onPostClick = {}, | ||
account = AnonAccount, | ||
showVotingArrowsInListView = true, | ||
useCustomTabs = false, | ||
usePrivateTabs = false, | ||
blurNSFW = BlurNSFW.NSFW, | ||
appState = rememberJerboaAppState(), | ||
showIfRead = true, | ||
enableDownVotes = false, | ||
voteDisplayMode = LocalUserVoteDisplayMode.default(), | ||
) | ||
} | ||
|
||
@Composable | ||
fun CommentNewCount( | ||
comments: Long, | ||
unreadCount: Long, | ||
style: TextStyle = MaterialTheme.typography.labelSmall.copy(fontStyle = FontStyle.Italic), | ||
spacing: Dp = 0.dp, | ||
) { | ||
val unread = | ||
if (unreadCount == 0L || comments == unreadCount) { | ||
null | ||
} else { | ||
unreadCount | ||
} | ||
if (unread != null) { | ||
Spacer(Modifier.padding(horizontal = spacing)) | ||
|
||
Text( | ||
text = stringResource(R.string.post_listing_new, unread), | ||
style = style, | ||
color = MaterialTheme.colorScheme.outline, | ||
) | ||
} | ||
} | ||
|
||
@Composable | ||
fun PostVotingTile( | ||
instantScores: InstantScores, | ||
onUpvoteClick: () -> Unit, | ||
onDownvoteClick: () -> Unit, | ||
account: Account, | ||
enableDownVotes: Boolean, | ||
voteDisplayMode: LocalUserVoteDisplayMode, | ||
) { | ||
Column( | ||
horizontalAlignment = Alignment.CenterHorizontally, | ||
verticalArrangement = Arrangement.spacedBy(SMALL_PADDING), | ||
modifier = | ||
Modifier | ||
.fillMaxHeight() | ||
.padding(end = MEDIUM_PADDING), | ||
) { | ||
VoteGeneric( | ||
myVote = instantScores.myVote, | ||
type = VoteType.Upvote, | ||
onVoteClick = onUpvoteClick, | ||
account = account, | ||
) | ||
|
||
val scoreOrPctStr = instantScores.scoreOrPctStr(voteDisplayMode) | ||
|
||
Text( | ||
text = scoreOrPctStr ?: "", | ||
style = MaterialTheme.typography.bodyMedium, | ||
color = scoreColor(myVote = instantScores.myVote), | ||
// Hide the vote number if its | ||
modifier = Modifier.alpha(if (scoreOrPctStr != null) 1f else 0f), | ||
) | ||
|
||
if (enableDownVotes) { | ||
// invisible Text below aligns width of PostVotingTiles | ||
Text( | ||
text = "00000", | ||
modifier = Modifier.height(0.dp), | ||
style = MaterialTheme.typography.bodyMedium, | ||
) | ||
VoteGeneric( | ||
myVote = instantScores.myVote, | ||
type = VoteType.Downvote, | ||
onVoteClick = onDownvoteClick, | ||
account = account, | ||
) | ||
} | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -4,6 +4,7 @@ import androidx.compose.foundation.clickable | |
import androidx.compose.foundation.layout.Arrangement | ||
import androidx.compose.foundation.layout.Box | ||
import androidx.compose.foundation.layout.Column | ||
import androidx.compose.foundation.layout.ExperimentalLayoutApi | ||
import androidx.compose.foundation.layout.padding | ||
import androidx.compose.material3.HorizontalDivider | ||
import androidx.compose.runtime.Composable | ||
|
@@ -16,10 +17,9 @@ import com.jerboa.db.entity.AnonAccount | |
import com.jerboa.feat.BlurNSFW | ||
import com.jerboa.feat.InstantScores | ||
import com.jerboa.feat.default | ||
import com.jerboa.feat.needBlur | ||
import com.jerboa.rememberJerboaAppState | ||
import com.jerboa.ui.components.post.PostBody | ||
import com.jerboa.ui.components.post.PostHeaderLine | ||
import com.jerboa.ui.components.post.PostCommunityAndCreatorBlock | ||
import com.jerboa.ui.theme.MEDIUM_PADDING | ||
import com.jerboa.ui.theme.SMALL_PADDING | ||
import it.vercruysse.lemmyapi.datatypes.Community | ||
|
@@ -30,6 +30,7 @@ import it.vercruysse.lemmyapi.datatypes.PostView | |
import it.vercruysse.lemmyapi.datatypes.ResolvePostReport | ||
import it.vercruysse.lemmyapi.dto.SubscribedType | ||
|
||
@OptIn(ExperimentalLayoutApi::class) | ||
@Composable | ||
fun PostReportItem( | ||
appState: JerboaAppState, | ||
|
@@ -86,42 +87,43 @@ fun PostReportItem( | |
modifier = Modifier | ||
.clickable { onPostClick(postView) }, | ||
) { | ||
PostHeaderLine( | ||
post = postView.post, | ||
creator = postView.creator, | ||
community = postView.community, | ||
creatorBannedFromCommunity = postView.creator_banned_from_community, | ||
instantScores = InstantScores( | ||
myVote = postView.my_vote, | ||
score = postView.counts.score, | ||
upvotes = postView.counts.upvotes, | ||
downvotes = postView.counts.downvotes, | ||
), | ||
PostCommunityAndCreatorBlock( | ||
postView = postView, | ||
onCommunityClick = onCommunityClick, | ||
onPersonClick = onPersonClick, | ||
showCommunityName = true, | ||
showAvatar = showAvatar, | ||
blurNSFW = blurNSFW, | ||
voteDisplayMode = voteDisplayMode, | ||
fullBody = false, | ||
) | ||
} | ||
|
||
// Title + metadata | ||
PostBody( | ||
post = postView.post, | ||
read = postView.read, | ||
postView = postView, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. These were all "optimizations" There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Any field that changes in postView will cause it recompose instead only if the relevant field changed There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Erps, my bad, I'll go through and fix some of these. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Actually I'm not sure if its worth it. A lot of these use like 5+ fields from IE, is there any field on PostView that changes frequently enough to justify separating these out? I don't think there is, as instantScores is the main one, but that's separated. |
||
fullBody = false, | ||
viewSource = false, | ||
expandedImage = false, | ||
account = account, | ||
useCustomTabs = false, | ||
usePrivateTabs = false, | ||
blurEnabled = blurNSFW.needBlur(postView), | ||
showPostLinkPreview = true, | ||
appState = appState, | ||
clickBody = { onPostClick(postView) }, | ||
showIfRead = true, | ||
instantScores = InstantScores( | ||
myVote = postView.my_vote, | ||
score = postView.counts.score, | ||
upvotes = postView.counts.upvotes, | ||
downvotes = postView.counts.downvotes, | ||
), | ||
voteDisplayMode = voteDisplayMode, | ||
community = postView.community, | ||
onCommunityClick = onCommunityClick, | ||
onPersonClick = onPersonClick, | ||
blurNSFW = blurNSFW, | ||
showAvatar = showAvatar, | ||
showCommunityName = true, | ||
) | ||
|
||
ReportCreatorBlock(postReportView.creator, onPersonClick, showAvatar) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moved this as its only used here.