diff --git a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt index b31fa94a..e5b8b5f9 100644 --- a/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt +++ b/android/src/main/kotlin/dev/msfjarvis/claw/android/ui/LobstersApp.kt @@ -165,6 +165,7 @@ fun LobstersApp( postId = postId, getDetails = viewModel::getPostComments, modifier = Modifier.navigationBarsPadding(), + postActions = postActions ) } } diff --git a/common/src/androidMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt b/common/src/androidMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt index 71f1f399..e93e6314 100644 --- a/common/src/androidMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt +++ b/common/src/androidMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt @@ -10,3 +10,5 @@ actual val heartIcon @Composable get() = painterResource(R.drawable.ic_favorite_24dp) actual val heartBorderIcon @Composable get() = painterResource(R.drawable.ic_favorite_border_24dp) +actual val webIcon + @Composable get() = painterResource(R.drawable.ic_web_24dp) diff --git a/common/src/androidMain/res/drawable/ic_web_24dp.xml b/common/src/androidMain/res/drawable/ic_web_24dp.xml new file mode 100644 index 00000000..d9911a76 --- /dev/null +++ b/common/src/androidMain/res/drawable/ic_web_24dp.xml @@ -0,0 +1,9 @@ + + + diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt index 68958ff8..34d3dae5 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/CommentEntry.kt @@ -1,26 +1,35 @@ package dev.msfjarvis.claw.common.comments +import androidx.compose.foundation.background +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.Row +import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.height import androidx.compose.foundation.layout.padding -import androidx.compose.foundation.layout.wrapContentHeight +import androidx.compose.foundation.shape.RoundedCornerShape +import androidx.compose.material.Icon import androidx.compose.material.LocalContentColor import androidx.compose.material.LocalTextStyle import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Surface +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.CompositionLocalProvider import androidx.compose.ui.Modifier +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.unit.dp 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.PostActions +import dev.msfjarvis.claw.common.posts.PostTitle import dev.msfjarvis.claw.common.posts.Submitter -import dev.msfjarvis.claw.common.posts.toDbModel -import dev.msfjarvis.claw.common.ui.Divider +import dev.msfjarvis.claw.common.posts.TagRow +import dev.msfjarvis.claw.common.res.webIcon import dev.msfjarvis.claw.model.Comment import dev.msfjarvis.claw.model.LobstersPostDetails @@ -38,17 +47,65 @@ fun ThemedRichText( @Composable fun CommentsHeader( postDetails: LobstersPostDetails, + postActions: PostActions, ) { val htmlConverter = LocalHTMLConverter.current - Surface { + + Surface(color = MaterialTheme.colorScheme.background) { Column( - modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp).fillMaxWidth(), - verticalArrangement = Arrangement.spacedBy(4.dp), + modifier = Modifier.padding(16.dp).fillMaxWidth(), + verticalArrangement = Arrangement.spacedBy(8.dp), ) { - PostDetails( - post = postDetails.toDbModel(), + PostTitle(title = postDetails.title) + TagRow(tags = postDetails.tags) + Spacer(Modifier.height(4.dp)) + + if (postDetails.url.isNotBlank()) { + PostLink( + link = postDetails.url, + modifier = + Modifier.clickable { postActions.viewPost(postDetails.url, postDetails.commentsUrl) } + ) + Spacer(Modifier.height(4.dp)) + } + + if (postDetails.description.isNotBlank()) { + ThemedRichText { Markdown(htmlConverter.convertHTMLToMarkdown(postDetails.description)) } + Spacer(Modifier.height(4.dp)) + } + Submitter( + text = "Submitted by ${postDetails.submitter.username}", + avatarUrl = "https://lobste.rs/${postDetails.submitter.avatarUrl}", + contentDescription = "User avatar for ${postDetails.submitter.username}", + ) + } + } +} + +@Composable +fun PostLink( + link: String, + modifier: Modifier = Modifier, +) { + Box( + modifier.background( + color = MaterialTheme.colorScheme.secondary, + shape = RoundedCornerShape(8.dp) + ) + ) { + Row(modifier = Modifier.padding(16.dp), horizontalArrangement = Arrangement.spacedBy(16.dp)) { + Icon( + painter = webIcon, + contentDescription = null, + tint = MaterialTheme.colorScheme.onSecondary + ) + Text( + text = link, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + color = MaterialTheme.colorScheme.onSecondary, + style = MaterialTheme.typography.labelLarge, ) - ThemedRichText { Markdown(htmlConverter.convertHTMLToMarkdown(postDetails.description)) } } } } @@ -58,17 +115,13 @@ fun CommentEntry( comment: Comment, ) { val htmlConverter = LocalHTMLConverter.current - Divider() - Row(modifier = Modifier.wrapContentHeight()) { - Column( - modifier = - Modifier.padding( - start = (comment.indentLevel * 12).dp, - end = 8.dp, - top = 4.dp, - bottom = 4.dp - ) - ) { + Box( + modifier = + Modifier.fillMaxWidth() + .background(MaterialTheme.colorScheme.background) + .padding(start = (comment.indentLevel * 16).dp, end = 16.dp, top = 16.dp, bottom = 16.dp), + ) { + Column(verticalArrangement = Arrangement.spacedBy(8.dp)) { Submitter( text = comment.user.username, avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}", diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt index 9b834745..03498ab1 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/comments/Comments.kt @@ -1,36 +1,66 @@ package dev.msfjarvis.claw.common.comments import androidx.compose.foundation.layout.Box -import androidx.compose.foundation.layout.Spacer +import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize -import androidx.compose.foundation.layout.height +import androidx.compose.foundation.layout.fillMaxWidth +import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn -import androidx.compose.foundation.lazy.items +import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.material.CircularProgressIndicator +import androidx.compose.material.Surface import androidx.compose.material3.MaterialTheme +import androidx.compose.material3.Text import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.produceState import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.text.font.FontWeight +import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp import dev.msfjarvis.claw.common.NetworkState +import dev.msfjarvis.claw.common.posts.PostActions import dev.msfjarvis.claw.common.ui.Divider import dev.msfjarvis.claw.model.LobstersPostDetails @Composable private fun CommentsPageInternal( details: LobstersPostDetails, + postActions: PostActions, modifier: Modifier = Modifier, ) { - LazyColumn(modifier) { - item { CommentsHeader(postDetails = details) } + Surface(color = MaterialTheme.colorScheme.surfaceVariant) { + LazyColumn(modifier = modifier, contentPadding = PaddingValues(bottom = 24.dp)) { + item { CommentsHeader(postDetails = details, postActions = postActions) } - item { Spacer(modifier = Modifier.height(8.dp)) } + if (details.commentCount > 0) { + item { + Text( + text = "Comments", + style = MaterialTheme.typography.labelLarge, + modifier = Modifier.padding(horizontal = 16.dp, vertical = 12.dp) + ) + } - items(details.comments) { item -> CommentEntry(item) } - - item { Divider() } + itemsIndexed(details.comments) { index, item -> + if (index != 0) { + Divider() + } + CommentEntry(item) + } + } else { + item { + Text( + text = "No Comments", + style = MaterialTheme.typography.bodyLarge, + modifier = Modifier.fillMaxWidth().padding(16.dp), + fontWeight = FontWeight.Bold, + textAlign = TextAlign.Center + ) + } + } + } } } @@ -39,6 +69,7 @@ private fun CommentsPageInternal( fun CommentsPage( postId: String, getDetails: suspend (String) -> LobstersPostDetails, + postActions: PostActions, modifier: Modifier = Modifier, ) { val postDetails by @@ -50,7 +81,8 @@ fun CommentsPage( is NetworkState.Success<*> -> { CommentsPageInternal( (postDetails as NetworkState.Success).data, - modifier, + postActions, + modifier.fillMaxSize(), ) } is NetworkState.Error -> TODO("Handle no network scenario") diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersCard.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersCard.kt index b9e7eb06..92174ba6 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersCard.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/posts/LobstersCard.kt @@ -140,7 +140,7 @@ fun Submitter( Row( modifier = modifier, verticalAlignment = Alignment.CenterVertically, - horizontalArrangement = Arrangement.spacedBy(4.dp), + horizontalArrangement = Arrangement.spacedBy(8.dp), ) { NetworkImage( url = avatarUrl, diff --git a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt index 39ad8f95..6bdb7e25 100644 --- a/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt +++ b/common/src/commonMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt @@ -9,3 +9,5 @@ expect val heartIcon: Painter @Composable get expect val heartBorderIcon: Painter @Composable get +expect val webIcon: Painter + @Composable get diff --git a/common/src/desktopMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt b/common/src/desktopMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt index 8a1f79fc..c7e1519e 100644 --- a/common/src/desktopMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt +++ b/common/src/desktopMain/kotlin/dev/msfjarvis/claw/common/res/drawable.kt @@ -9,3 +9,5 @@ actual val heartIcon @Composable get() = painterResource("favorite_black_24dp.svg") actual val heartBorderIcon @Composable get() = painterResource("favorite_border_black_24dp.svg") +actual val webIcon + @Composable get() = painterResource("web_black_24dp.svg") diff --git a/common/src/desktopMain/resources/web_black_24dp.svg b/common/src/desktopMain/resources/web_black_24dp.svg new file mode 100644 index 00000000..ff472dea --- /dev/null +++ b/common/src/desktopMain/resources/web_black_24dp.svg @@ -0,0 +1,5 @@ + + + +