From f1aed575a42a58a2fd86769f1e80350edc441072 Mon Sep 17 00:00:00 2001 From: Rikin Marfatia Date: Thu, 8 Aug 2024 15:49:26 -0700 Subject: [PATCH] Post Body Size Toggling (#109) Added the ability to toggle the post body size, defaulting to collapsed and displaying 4 lines. --- .../features/comments/CommentsDomain.kt | 26 ++++++-- .../features/comments/CommentsScreen.kt | 61 ++++++++++++------- 2 files changed, 60 insertions(+), 27 deletions(-) diff --git a/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsDomain.kt b/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsDomain.kt index f9c691f8..ec4086ee 100644 --- a/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsDomain.kt +++ b/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsDomain.kt @@ -42,7 +42,7 @@ sealed interface CommentsState { val author: String, val points: Int, val timeLabel: String, - val body: String?, + val body: BodyState, val loggedIn: Boolean, val upvoted: Boolean, val upvoteUrl: String, @@ -86,14 +86,14 @@ enum class HiddenStatus { Displayed; fun toggle(): HiddenStatus { - return when(this) { + return when (this) { Hidden, HiddenByParent -> Displayed else -> Hidden } } fun toggleChild(): HiddenStatus { - return when(this) { + return when (this) { Hidden, HiddenByParent -> Displayed else -> HiddenByParent } @@ -123,6 +123,11 @@ sealed interface CommentState { ) : CommentState } +data class BodyState( + val text: String?, + val collapsed: Boolean = true +) + sealed interface HeaderState { data object Loading : HeaderState data class Content( @@ -131,7 +136,7 @@ sealed interface HeaderState { val author: String, val points: Int, val timeLabel: String, - val body: String?, + val body: BodyState, val upvoted: Boolean, val upvoteUrl: String, ) : HeaderState @@ -159,6 +164,7 @@ sealed interface CommentsAction { ) : CommentsAction data class ToggleHideComment(val id: Long) : CommentsAction + data class ToggleBody(val collapse: Boolean) : CommentsAction } sealed interface CommentsNavigation { @@ -213,7 +219,7 @@ class CommentsViewModel( .parse(searchResponse.item.createdAt) .toEpochSecond() ), - body = searchResponse.item.text, + body = BodyState(text = searchResponse.item.text), loggedIn = loggedIn, upvoted = postPage.postInfo.upvoted, upvoteUrl = postPage.postInfo.upvoteUrl, @@ -332,6 +338,16 @@ class CommentsViewModel( internalState.compareAndSet(currentState, updatedState) } } + + is CommentsAction.ToggleBody -> { + val currentState = internalState.value + if (currentState is CommentsState.Content) { + val updatedState = currentState.copy( + body = currentState.body.copy(collapsed = action.collapse) + ) + internalState.compareAndSet(currentState, updatedState) + } + } } } diff --git a/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsScreen.kt b/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsScreen.kt index 860e4dca..59ed35eb 100644 --- a/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsScreen.kt +++ b/android/app/src/main/java/com/emergetools/hackernews/features/comments/CommentsScreen.kt @@ -19,7 +19,6 @@ import androidx.compose.foundation.layout.Spacer import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.height -import androidx.compose.foundation.layout.heightIn import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.size import androidx.compose.foundation.layout.width @@ -53,6 +52,7 @@ import androidx.compose.ui.res.painterResource import androidx.compose.ui.text.font.FontWeight import androidx.compose.ui.text.input.ImeAction import androidx.compose.ui.text.input.KeyboardType +import androidx.compose.ui.text.style.TextOverflow import androidx.compose.ui.tooling.preview.PreviewLightDark import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.sp @@ -97,7 +97,8 @@ fun CommentsScreen( } else { navigation(CommentsNavigation.GoToLogin) } - } + }, + onToggleBody = { actions(CommentsAction.ToggleBody(it)) } ) } item { @@ -188,7 +189,7 @@ private fun CommentsScreenPreview() { author = "rikinm", points = 69, timeLabel = "2h ago", - body = "Hello There", + body = BodyState("Hello There"), loggedIn = false, upvoted = false, upvoteUrl = "", @@ -458,6 +459,7 @@ fun ItemHeader( state: HeaderState, modifier: Modifier = Modifier, onLikeTapped: (HeaderState.Content) -> Unit, + onToggleBody: (Boolean) -> Unit ) { Column( modifier = modifier.background(color = MaterialTheme.colorScheme.background), @@ -515,22 +517,35 @@ fun ItemHeader( } } } - if (state.body != null) { - Box( - Modifier - .fillMaxWidth() - .heightIn(min = 40.dp) - .clip(RoundedCornerShape(8.dp)) - .background(color = MaterialTheme.colorScheme.surface) - .padding(8.dp), - contentAlignment = Alignment.CenterStart - ) { - Text( - text = state.body.parseAsHtml(), - color = MaterialTheme.colorScheme.onBackground, - style = MaterialTheme.typography.labelSmall, - ) - } + if (state.body.text != null) { + Column( + Modifier + .fillMaxWidth() + .wrapContentHeight() + .clip(RoundedCornerShape(8.dp)) + .clickable { onToggleBody(!state.body.collapsed) } + .background(color = MaterialTheme.colorScheme.surface) + .padding(8.dp), + verticalArrangement = Arrangement.spacedBy(4.dp) + ) { + Icon( + modifier = Modifier + .graphicsLayer { + rotationZ = if (state.body.collapsed) 180f else 0f + } + .size(12.dp), + painter = painterResource(R.drawable.ic_collapse), + tint = MaterialTheme.colorScheme.onSurface, + contentDescription = "Expand or Collapse" + ) + Text( + text = state.body.text.parseAsHtml(), + color = MaterialTheme.colorScheme.onBackground, + style = MaterialTheme.typography.labelSmall, + overflow = TextOverflow.Ellipsis, + maxLines = if (state.body.collapsed) 4 else Int.MAX_VALUE + ) + } } } @@ -631,14 +646,15 @@ private fun ItemHeaderPreview() { author = "rikinm", points = 69, timeLabel = "2h ago", - body = "Wassup HN. I just built a sick new Hacker News Android client", + body = BodyState("Wassup HN. I just built a sick new Hacker News Android client. Lalalalalala hahahah"), upvoted = false, upvoteUrl = "", ), modifier = Modifier .fillMaxWidth() .wrapContentHeight(), - onLikeTapped = {} + onLikeTapped = {}, + onToggleBody = {} ) } } @@ -658,7 +674,8 @@ private fun ItemHeaderLoadingPreview() { modifier = Modifier .fillMaxWidth() .wrapContentHeight(), - onLikeTapped = {} + onLikeTapped = {}, + onToggleBody = {} ) } }