mirror of
https://github.com/msfjarvis/compose-lobsters
synced 2025-08-14 19:57:04 +05:30
all: flesh out comments UI and move to common
This commit is contained in:
parent
84fd9a2c61
commit
d56b887a21
6 changed files with 147 additions and 44 deletions
|
@ -1,22 +0,0 @@
|
||||||
package dev.msfjarvis.claw.android.comments
|
|
||||||
|
|
||||||
import android.text.Html
|
|
||||||
import androidx.compose.foundation.layout.Row
|
|
||||||
import androidx.compose.foundation.layout.padding
|
|
||||||
import androidx.compose.material.Text
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import androidx.compose.ui.Modifier
|
|
||||||
import androidx.compose.ui.text.buildAnnotatedString
|
|
||||||
import androidx.compose.ui.unit.dp
|
|
||||||
import dev.msfjarvis.claw.model.Comment
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CommentEntry(
|
|
||||||
comment: Comment,
|
|
||||||
) {
|
|
||||||
Row(modifier = Modifier.padding(start = (10 * (comment.indentLevel.toFloat() - 1)).dp)) {
|
|
||||||
Text(
|
|
||||||
text = buildAnnotatedString { @Suppress("DEPRECATION") Html.fromHtml(comment.comment) },
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,19 +0,0 @@
|
||||||
package dev.msfjarvis.claw.android.comments
|
|
||||||
|
|
||||||
import androidx.compose.foundation.lazy.LazyColumn
|
|
||||||
import androidx.compose.foundation.lazy.items
|
|
||||||
import androidx.compose.runtime.Composable
|
|
||||||
import dev.msfjarvis.claw.model.LobstersPostDetails
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
private fun CommentsPageInternal(
|
|
||||||
details: LobstersPostDetails,
|
|
||||||
) {
|
|
||||||
LazyColumn { items(details.comments) { CommentEntry(it) } }
|
|
||||||
}
|
|
||||||
|
|
||||||
@Composable
|
|
||||||
fun CommentsPage(
|
|
||||||
postId: String,
|
|
||||||
getDetails: suspend (String) -> LobstersPostDetails,
|
|
||||||
) {}
|
|
|
@ -1,5 +1,6 @@
|
||||||
package dev.msfjarvis.claw.android.ui
|
package dev.msfjarvis.claw.android.ui
|
||||||
|
|
||||||
|
import android.text.Html
|
||||||
import androidx.compose.animation.ExperimentalAnimationApi
|
import androidx.compose.animation.ExperimentalAnimationApi
|
||||||
import androidx.compose.foundation.isSystemInDarkTheme
|
import androidx.compose.foundation.isSystemInDarkTheme
|
||||||
import androidx.compose.foundation.lazy.rememberLazyListState
|
import androidx.compose.foundation.lazy.rememberLazyListState
|
||||||
|
@ -28,8 +29,8 @@ import com.google.accompanist.insets.ProvideWindowInsets
|
||||||
import com.google.accompanist.insets.navigationBarsPadding
|
import com.google.accompanist.insets.navigationBarsPadding
|
||||||
import com.google.accompanist.insets.statusBarsPadding
|
import com.google.accompanist.insets.statusBarsPadding
|
||||||
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
import com.google.accompanist.systemuicontroller.rememberSystemUiController
|
||||||
import dev.msfjarvis.claw.android.comments.CommentsPage
|
|
||||||
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
import dev.msfjarvis.claw.android.viewmodel.ClawViewModel
|
||||||
|
import dev.msfjarvis.claw.common.comments.CommentsPage
|
||||||
import dev.msfjarvis.claw.common.theme.LobstersTheme
|
import dev.msfjarvis.claw.common.theme.LobstersTheme
|
||||||
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
import dev.msfjarvis.claw.common.urllauncher.UrlLauncher
|
||||||
|
|
||||||
|
@ -78,12 +79,12 @@ fun LobstersApp(
|
||||||
topBar = { ClawAppBar(modifier = Modifier.statusBarsPadding()) },
|
topBar = { ClawAppBar(modifier = Modifier.statusBarsPadding()) },
|
||||||
floatingActionButton = {
|
floatingActionButton = {
|
||||||
ClawFab(
|
ClawFab(
|
||||||
isFabVisible = isFabVisible,
|
isFabVisible = isFabVisible && navController.currentDestination?.route == "hottest",
|
||||||
listState = listState,
|
listState = listState,
|
||||||
modifier = Modifier.navigationBarsPadding(),
|
modifier = Modifier.navigationBarsPadding(),
|
||||||
)
|
)
|
||||||
},
|
},
|
||||||
) {
|
) { paddingValues ->
|
||||||
NavHost(navController, startDestination = "hottest") {
|
NavHost(navController, startDestination = "hottest") {
|
||||||
composable("hottest") {
|
composable("hottest") {
|
||||||
HottestPosts(
|
HottestPosts(
|
||||||
|
@ -101,6 +102,8 @@ fun LobstersApp(
|
||||||
CommentsPage(
|
CommentsPage(
|
||||||
postId = requireNotNull(backStackEntry.arguments?.getString("postId")),
|
postId = requireNotNull(backStackEntry.arguments?.getString("postId")),
|
||||||
getDetails = viewModel::getPostComments,
|
getDetails = viewModel::getPostComments,
|
||||||
|
parseHtml = { source -> Html.fromHtml(source).toString().trim() },
|
||||||
|
paddingValues = paddingValues,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -0,0 +1,7 @@
|
||||||
|
package dev.msfjarvis.lobsters.ui.comments
|
||||||
|
|
||||||
|
sealed class NetworkState {
|
||||||
|
class Success<T>(val data: T) : NetworkState()
|
||||||
|
class Error(val message: String) : NetworkState()
|
||||||
|
object Loading : NetworkState()
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
package dev.msfjarvis.claw.common.comments
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Arrangement
|
||||||
|
import androidx.compose.foundation.layout.Column
|
||||||
|
import androidx.compose.foundation.layout.Row
|
||||||
|
import androidx.compose.foundation.layout.fillMaxWidth
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.material.Divider
|
||||||
|
import androidx.compose.material.Surface
|
||||||
|
import androidx.compose.material.Text
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import dev.msfjarvis.claw.common.posts.PostDetails
|
||||||
|
import dev.msfjarvis.claw.common.posts.SubmitterName
|
||||||
|
import dev.msfjarvis.claw.common.posts.toDbModel
|
||||||
|
import dev.msfjarvis.claw.model.Comment
|
||||||
|
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CommentsHeader(
|
||||||
|
postDetails: LobstersPostDetails,
|
||||||
|
) {
|
||||||
|
Surface {
|
||||||
|
Column(
|
||||||
|
modifier = Modifier.padding(horizontal = 16.dp, vertical = 4.dp).fillMaxWidth(),
|
||||||
|
verticalArrangement = Arrangement.spacedBy(4.dp),
|
||||||
|
) {
|
||||||
|
PostDetails(
|
||||||
|
post = postDetails.toDbModel(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
fun CommentEntry(
|
||||||
|
comment: Comment,
|
||||||
|
parseHtml: (String) -> String,
|
||||||
|
) {
|
||||||
|
val indentLevel = comment.indentLevel.toInt() - 1
|
||||||
|
val startPadding = ((10 * indentLevel) + 16).dp
|
||||||
|
|
||||||
|
Divider(color = Color.Gray.copy(0.4f))
|
||||||
|
|
||||||
|
Row(modifier = Modifier.padding(start = startPadding, end = 8.dp, top = 4.dp, bottom = 4.dp)) {
|
||||||
|
val text = parseHtml(comment.comment)
|
||||||
|
Column {
|
||||||
|
SubmitterName(
|
||||||
|
text = "Submitted by ${comment.user.username}",
|
||||||
|
avatarUrl = "https://lobste.rs/${comment.user.avatarUrl}",
|
||||||
|
contentDescription = "Submitted by ${comment.user.username}",
|
||||||
|
)
|
||||||
|
Text(text = text, modifier = Modifier.padding(top = 8.dp))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
package dev.msfjarvis.claw.common.comments
|
||||||
|
|
||||||
|
import androidx.compose.foundation.layout.Box
|
||||||
|
import androidx.compose.foundation.layout.PaddingValues
|
||||||
|
import androidx.compose.foundation.layout.Spacer
|
||||||
|
import androidx.compose.foundation.layout.fillMaxSize
|
||||||
|
import androidx.compose.foundation.layout.height
|
||||||
|
import androidx.compose.foundation.layout.padding
|
||||||
|
import androidx.compose.foundation.lazy.LazyColumn
|
||||||
|
import androidx.compose.foundation.lazy.items
|
||||||
|
import androidx.compose.material.CircularProgressIndicator
|
||||||
|
import androidx.compose.material.Divider
|
||||||
|
import androidx.compose.material.MaterialTheme
|
||||||
|
import androidx.compose.runtime.Composable
|
||||||
|
import androidx.compose.runtime.LaunchedEffect
|
||||||
|
import androidx.compose.runtime.getValue
|
||||||
|
import androidx.compose.runtime.mutableStateOf
|
||||||
|
import androidx.compose.runtime.remember
|
||||||
|
import androidx.compose.runtime.setValue
|
||||||
|
import androidx.compose.ui.Alignment
|
||||||
|
import androidx.compose.ui.Modifier
|
||||||
|
import androidx.compose.ui.graphics.Color
|
||||||
|
import androidx.compose.ui.unit.Dp
|
||||||
|
import androidx.compose.ui.unit.dp
|
||||||
|
import dev.msfjarvis.claw.model.LobstersPostDetails
|
||||||
|
import dev.msfjarvis.lobsters.ui.comments.NetworkState
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun CommentsPageInternal(
|
||||||
|
details: LobstersPostDetails,
|
||||||
|
parseHtml: (String) -> String,
|
||||||
|
bottomPadding: Dp,
|
||||||
|
) {
|
||||||
|
LazyColumn(Modifier.padding(bottom = bottomPadding)) {
|
||||||
|
item { CommentsHeader(postDetails = details) }
|
||||||
|
|
||||||
|
item { Spacer(modifier = Modifier.height(8.dp)) }
|
||||||
|
|
||||||
|
items(details.comments) { item -> CommentEntry(item, parseHtml) }
|
||||||
|
|
||||||
|
item { Divider(color = Color.Gray.copy(0.4f)) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Suppress("UNCHECKED_CAST")
|
||||||
|
@Composable
|
||||||
|
fun CommentsPage(
|
||||||
|
postId: String,
|
||||||
|
getDetails: suspend (String) -> LobstersPostDetails,
|
||||||
|
parseHtml: (String) -> String,
|
||||||
|
paddingValues: PaddingValues,
|
||||||
|
) {
|
||||||
|
var postDetails: NetworkState by remember { mutableStateOf(NetworkState.Loading) }
|
||||||
|
|
||||||
|
LaunchedEffect(postId) { postDetails = NetworkState.Success(getDetails(postId)) }
|
||||||
|
|
||||||
|
when (postDetails) {
|
||||||
|
is NetworkState.Success<*> -> {
|
||||||
|
CommentsPageInternal(
|
||||||
|
(postDetails as NetworkState.Success<LobstersPostDetails>).data,
|
||||||
|
parseHtml,
|
||||||
|
paddingValues.calculateBottomPadding(),
|
||||||
|
)
|
||||||
|
}
|
||||||
|
is NetworkState.Error -> TODO("Handle no network scenario")
|
||||||
|
NetworkState.Loading -> ProgressBar(paddingValues.calculateBottomPadding())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@Composable
|
||||||
|
private fun ProgressBar(bottomPadding: Dp) {
|
||||||
|
Box(
|
||||||
|
modifier = Modifier.padding(bottom = bottomPadding).fillMaxSize(),
|
||||||
|
contentAlignment = Alignment.Center
|
||||||
|
) { CircularProgressIndicator(color = MaterialTheme.colors.secondary) }
|
||||||
|
}
|
Loading…
Add table
Add a link
Reference in a new issue