[1.211.*] Pre-release merge (#676)
This commit is contained in:
@@ -6,15 +6,15 @@
|
||||
*/
|
||||
package dev.msfjarvis.claw.common.comments
|
||||
|
||||
import dev.msfjarvis.claw.database.local.PostComments
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
|
||||
internal class CommentNode(
|
||||
internal data class CommentNode(
|
||||
val comment: Comment,
|
||||
private var parent: CommentNode? = null,
|
||||
val children: MutableList<CommentNode> = mutableListOf(),
|
||||
val isUnread: Boolean = false,
|
||||
val indentLevel: Int,
|
||||
val isExpanded: Boolean = true,
|
||||
) {
|
||||
|
||||
fun addChild(child: CommentNode) {
|
||||
@@ -50,6 +50,7 @@ internal class CommentNode(
|
||||
if (children != other.children) return false
|
||||
if (isUnread != other.isUnread) return false
|
||||
if (indentLevel != other.indentLevel) return false
|
||||
if (isExpanded != other.isExpanded) return false
|
||||
|
||||
return true
|
||||
}
|
||||
@@ -59,37 +60,7 @@ internal class CommentNode(
|
||||
result = 31 * result + children.hashCode()
|
||||
result = 31 * result + isUnread.hashCode()
|
||||
result = 31 * result + indentLevel
|
||||
result = 31 * result + isExpanded.hashCode()
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
internal fun createListNode(
|
||||
comments: List<Comment>,
|
||||
commentState: PostComments?,
|
||||
): MutableList<CommentNode> {
|
||||
val commentNodes = mutableListOf<CommentNode>()
|
||||
val isUnread = { id: String -> commentState?.commentIds?.contains(id) == false }
|
||||
|
||||
for (i in comments.indices) {
|
||||
if (comments[i].parentComment == null) {
|
||||
commentNodes.add(
|
||||
CommentNode(
|
||||
comment = comments[i],
|
||||
isUnread = isUnread(comments[i].shortId),
|
||||
indentLevel = 1,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
commentNodes.lastOrNull()?.let { commentNode ->
|
||||
commentNode.addChild(
|
||||
CommentNode(
|
||||
comment = comments[i],
|
||||
isUnread = isUnread(comments[i].shortId),
|
||||
indentLevel = commentNode.indentLevel + 1,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
return commentNodes
|
||||
}
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
/*
|
||||
* Copyright © 2024 Harsh Shandilya.
|
||||
* Use of this source code is governed by an MIT-style
|
||||
* license that can be found in the LICENSE file or at
|
||||
* https://opensource.org/licenses/MIT.
|
||||
*/
|
||||
package dev.msfjarvis.claw.common.comments
|
||||
|
||||
import dev.msfjarvis.claw.database.local.PostComments
|
||||
import dev.msfjarvis.claw.model.Comment
|
||||
import kotlinx.coroutines.flow.MutableStateFlow
|
||||
import kotlinx.coroutines.flow.StateFlow
|
||||
import kotlinx.coroutines.flow.asStateFlow
|
||||
|
||||
internal class CommentsHandler {
|
||||
|
||||
private val _listItems: MutableStateFlow<List<CommentNode>> = MutableStateFlow(emptyList())
|
||||
val listItems: StateFlow<List<CommentNode>> = _listItems.asStateFlow()
|
||||
|
||||
fun createListNode(comments: List<Comment>, commentState: PostComments?) {
|
||||
val commentNodes = mutableListOf<CommentNode>()
|
||||
val isUnread = { id: String -> commentState?.commentIds?.contains(id) == false }
|
||||
|
||||
for (i in comments.indices) {
|
||||
if (comments[i].parentComment == null) {
|
||||
commentNodes.add(
|
||||
CommentNode(
|
||||
comment = comments[i],
|
||||
isUnread = isUnread(comments[i].shortId),
|
||||
indentLevel = 1,
|
||||
)
|
||||
)
|
||||
} else {
|
||||
commentNodes.lastOrNull()?.let { commentNode ->
|
||||
commentNode.addChild(
|
||||
CommentNode(
|
||||
comment = comments[i],
|
||||
isUnread = isUnread(comments[i].shortId),
|
||||
indentLevel = commentNode.indentLevel + 1,
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
_listItems.value = commentNodes
|
||||
}
|
||||
|
||||
fun updateListNode(shortId: String, isExpanded: Boolean) {
|
||||
val listNode = _listItems.value.toMutableList()
|
||||
val index = listNode.indexOfFirst { it.comment.shortId == shortId }
|
||||
|
||||
if (index != -1) {
|
||||
val commentNode = listNode[index].copy(isExpanded = isExpanded)
|
||||
listNode[index] = commentNode
|
||||
|
||||
_listItems.value = listNode.toList()
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,6 +60,7 @@ fun CommentsPage(
|
||||
markSeenComments = markSeenComments,
|
||||
openUserProfile = openUserProfile,
|
||||
contentPadding = contentPadding,
|
||||
commentsHandler = CommentsHandler(),
|
||||
modifier = modifier.fillMaxSize(),
|
||||
)
|
||||
}
|
||||
|
||||
@@ -8,6 +8,12 @@ package dev.msfjarvis.claw.common.comments
|
||||
|
||||
import android.text.format.DateUtils
|
||||
import android.widget.Toast
|
||||
import androidx.compose.animation.AnimatedVisibility
|
||||
import androidx.compose.animation.core.tween
|
||||
import androidx.compose.animation.expandVertically
|
||||
import androidx.compose.animation.fadeIn
|
||||
import androidx.compose.animation.fadeOut
|
||||
import androidx.compose.animation.shrinkVertically
|
||||
import androidx.compose.foundation.background
|
||||
import androidx.compose.foundation.clickable
|
||||
import androidx.compose.foundation.layout.Arrangement
|
||||
@@ -21,6 +27,7 @@ import androidx.compose.foundation.layout.padding
|
||||
import androidx.compose.foundation.layout.systemBars
|
||||
import androidx.compose.foundation.layout.windowInsetsBottomHeight
|
||||
import androidx.compose.foundation.lazy.LazyColumn
|
||||
import androidx.compose.foundation.lazy.items
|
||||
import androidx.compose.material3.HorizontalDivider
|
||||
import androidx.compose.material3.MaterialTheme
|
||||
import androidx.compose.material3.Surface
|
||||
@@ -28,9 +35,6 @@ import androidx.compose.material3.Text
|
||||
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.platform.LocalContext
|
||||
@@ -39,6 +43,7 @@ import androidx.compose.ui.text.buildAnnotatedString
|
||||
import androidx.compose.ui.text.font.FontWeight
|
||||
import androidx.compose.ui.text.style.TextAlign
|
||||
import androidx.compose.ui.unit.dp
|
||||
import androidx.lifecycle.compose.collectAsStateWithLifecycle
|
||||
import dev.msfjarvis.claw.common.posts.PostActions
|
||||
import dev.msfjarvis.claw.common.posts.Submitter
|
||||
import dev.msfjarvis.claw.common.ui.ThemedRichText
|
||||
@@ -48,6 +53,8 @@ import dev.msfjarvis.claw.model.UIPost
|
||||
import java.time.Instant
|
||||
import java.time.temporal.TemporalAccessor
|
||||
|
||||
private const val AnimationDuration = 100
|
||||
|
||||
@Composable
|
||||
internal fun CommentsPageInternal(
|
||||
details: UIPost,
|
||||
@@ -57,10 +64,19 @@ internal fun CommentsPageInternal(
|
||||
markSeenComments: (String, List<Comment>) -> Unit,
|
||||
openUserProfile: (String) -> Unit,
|
||||
contentPadding: PaddingValues,
|
||||
commentsHandler: CommentsHandler,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
|
||||
LaunchedEffect(Unit) { commentsHandler.createListNode(details.comments, commentState) }
|
||||
|
||||
val onToggleExpandedState = { shortId: String, isExpanded: Boolean ->
|
||||
commentsHandler.updateListNode(shortId, isExpanded)
|
||||
}
|
||||
|
||||
val context = LocalContext.current
|
||||
val commentNodes = createListNode(details.comments, commentState)
|
||||
val commentNodes by commentsHandler.listItems.collectAsStateWithLifecycle()
|
||||
|
||||
LaunchedEffect(key1 = commentNodes) {
|
||||
if (details.comments.isNotEmpty() && !commentState?.commentIds.isNullOrEmpty()) {
|
||||
val unreadCount = details.comments.size - (commentState?.commentIds?.size ?: 0)
|
||||
@@ -96,8 +112,8 @@ internal fun CommentsPageInternal(
|
||||
)
|
||||
}
|
||||
|
||||
commentNodes.forEach { node ->
|
||||
item(key = node.comment.shortId) { Node(node, htmlConverter, openUserProfile) }
|
||||
items(items = commentNodes, key = { node -> node.comment.shortId }) { node ->
|
||||
Node(node, htmlConverter, openUserProfile, onToggleExpandedState)
|
||||
}
|
||||
|
||||
item(key = "bottom_spacer") {
|
||||
@@ -127,22 +143,30 @@ private fun Node(
|
||||
node: CommentNode,
|
||||
htmlConverter: HTMLConverter,
|
||||
openUserProfile: (String) -> Unit,
|
||||
onToggleExpandedState: (String, Boolean) -> Unit,
|
||||
modifier: Modifier = Modifier,
|
||||
) {
|
||||
Column(horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
var isChildrenShown by remember { mutableStateOf(true) }
|
||||
|
||||
NodeBox(
|
||||
node = node,
|
||||
isExpanded = isChildrenShown,
|
||||
isExpanded = node.isExpanded,
|
||||
htmlConverter = htmlConverter,
|
||||
openUserProfile,
|
||||
modifier = modifier.clickable(onClick = { isChildrenShown = !isChildrenShown }),
|
||||
modifier =
|
||||
modifier.clickable(
|
||||
onClick = { onToggleExpandedState(node.comment.shortId, !node.isExpanded) }
|
||||
),
|
||||
)
|
||||
|
||||
if (isChildrenShown) {
|
||||
AnimatedVisibility(
|
||||
visible = node.isExpanded,
|
||||
enter = fadeIn(tween(AnimationDuration)) + expandVertically(tween(AnimationDuration)),
|
||||
exit = fadeOut(tween(AnimationDuration)) + shrinkVertically(tween(AnimationDuration)),
|
||||
) {
|
||||
Column(modifier = modifier, horizontalAlignment = Alignment.CenterHorizontally) {
|
||||
node.children.forEach { model -> Node(model, htmlConverter, openUserProfile) }
|
||||
node.children.forEach { model ->
|
||||
Node(model, htmlConverter, openUserProfile, onToggleExpandedState)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,14 +1,14 @@
|
||||
[versions]
|
||||
aboutLibraries = "11.2.3"
|
||||
agp = "8.7.0"
|
||||
android-junit5 = "1.11.0.0"
|
||||
android-junit5 = "1.11.2.0"
|
||||
benchmark = "1.3.2"
|
||||
coil = "2.7.0"
|
||||
coroutines = "1.9.0"
|
||||
dagger = "2.52"
|
||||
glance = "1.0.0"
|
||||
haze = "0.9.0-beta02"
|
||||
junit = "5.11.1"
|
||||
haze = "0.9.0-beta03"
|
||||
junit = "5.11.2"
|
||||
konvert = "3.2.2"
|
||||
kotlin = "2.0.20"
|
||||
kotlinResult = "2.0.0"
|
||||
@@ -121,7 +121,7 @@ android-junit5 = { id = "de.mannodermaus.android-junit5", version.ref = "android
|
||||
android-test = { id = "com.android.test", version.ref = "agp" }
|
||||
anvil = "com.squareup.anvil:2.5.0-beta11"
|
||||
baselineprofile = { id = "androidx.baselineprofile", version.ref = "benchmark" }
|
||||
dependencyAnalysis = "com.autonomousapps.dependency-analysis:2.1.3"
|
||||
dependencyAnalysis = "com.autonomousapps.dependency-analysis:2.1.4"
|
||||
invert = "com.squareup.invert:0.0.1-dev"
|
||||
kotlin-composeCompiler = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
|
||||
kotlin-serialization = { id = "org.jetbrains.kotlin.plugin.serialization", version.ref = "kotlin" }
|
||||
|
||||
Reference in New Issue
Block a user