all: flesh out comments UI and move to common

This commit is contained in:
Harsh Shandilya 2021-10-04 17:34:04 +05:30
parent 84fd9a2c61
commit d56b887a21
No known key found for this signature in database
GPG key ID: 366D7BBAD1031E80
6 changed files with 147 additions and 44 deletions

View file

@ -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) },
)
}
}

View file

@ -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,
) {}

View file

@ -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,
) )
} }
} }

View file

@ -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()
}

View file

@ -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))
}
}
}

View file

@ -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) }
}