fix: handle user profile navigation correctly

This commit is contained in:
Harsh Shandilya 2024-04-18 01:34:28 +05:30
parent 2b9680d3d8
commit d0bf2a4fb2
7 changed files with 80 additions and 14 deletions

View File

@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
* Fixed a crash when clicking an item on the bottom navigation bar
too quickly
* Removed buggy deeplinks
* Clicking a username now correctly navigates to the right page in-app
## [1.44.0] - 2024-03-19

View File

@ -261,6 +261,11 @@ fun LobstersPostsScreen(
htmlConverter = htmlConverter,
getSeenComments = viewModel::getSeenComments,
markSeenComments = viewModel::markSeenComments,
openUserProfile = {
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, it)
)
},
)
}
composable(
@ -272,7 +277,15 @@ fun LobstersPostsScreen(
"Navigating to ${Destinations.User.route} without necessary 'username' argument"
}
setWebUri("https://lobste.rs/u/$username")
UserProfile(username = username, getProfile = viewModel::getUserProfile)
UserProfile(
username = username,
getProfile = viewModel::getUserProfile,
openUserProfile = {
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, it)
)
},
)
}
composable(route = Destinations.Settings.route) {
SettingsScreen(

View File

@ -67,6 +67,11 @@ fun SearchScreen(
htmlConverter = htmlConverter,
getSeenComments = viewModel::getSeenComments,
markSeenComments = viewModel::markSeenComments,
openUserProfile = { username: String ->
navController.navigate(
Destinations.User.route.replace(Destinations.User.PLACEHOLDER, username)
)
},
)
}
}

View File

@ -29,7 +29,6 @@ import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler
import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.SpanStyle
import androidx.compose.ui.text.buildAnnotatedString
@ -56,9 +55,9 @@ internal fun CommentsHeader(
post: UIPost,
postActions: PostActions,
htmlConverter: HTMLConverter,
openUserProfile: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current
val linkMetadata by
produceState(initialValue = LinkMetadata(post.url, null)) {
runSuspendCatching { postActions.getLinkMetadata(post.url) }
@ -93,8 +92,7 @@ internal fun CommentsHeader(
text = AnnotatedString("Submitted by ${post.submitter}"),
avatarUrl = "https://lobste.rs/avatars/${post.submitter}-100.png",
contentDescription = "User avatar for ${post.submitter}",
modifier =
Modifier.clickable { uriHandler.openUri("https://lobste.rs/u/${post.submitter}") },
modifier = Modifier.clickable { openUserProfile(post.submitter) },
)
}
}
@ -133,9 +131,9 @@ internal fun CommentEntry(
commentNode: CommentNode,
htmlConverter: HTMLConverter,
toggleExpanded: (CommentNode) -> Unit,
openUserProfile: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val uriHandler = LocalUriHandler.current
val comment = commentNode.comment
Box(
modifier =
@ -162,7 +160,7 @@ internal fun CommentEntry(
),
avatarUrl = "https://lobste.rs/avatars/${comment.user}-100.png",
contentDescription = "User avatar for ${comment.user}",
modifier = Modifier.clickable { uriHandler.openUri("https://lobste.rs/u/${comment.user}") },
modifier = Modifier.clickable { openUserProfile(comment.user) },
)
if (commentNode.isExpanded) {
ThemedRichText(

View File

@ -84,9 +84,15 @@ internal fun LazyListScope.nodes(
nodes: List<CommentNode>,
htmlConverter: HTMLConverter,
toggleExpanded: (CommentNode) -> Unit,
openUserProfile: (String) -> Unit,
) {
nodes.forEach { node ->
node(node = node, htmlConverter = htmlConverter, toggleExpanded = toggleExpanded)
node(
node = node,
htmlConverter = htmlConverter,
toggleExpanded = toggleExpanded,
openUserProfile = openUserProfile,
)
}
}
@ -94,16 +100,27 @@ private fun LazyListScope.node(
node: CommentNode,
htmlConverter: HTMLConverter,
toggleExpanded: (CommentNode) -> Unit,
openUserProfile: (String) -> Unit,
) {
// Skip the node if neither the node nor its parent is expanded
if (!node.isExpanded && node.parent?.isExpanded == false) {
return
}
item {
CommentEntry(commentNode = node, htmlConverter = htmlConverter, toggleExpanded = toggleExpanded)
CommentEntry(
commentNode = node,
htmlConverter = htmlConverter,
toggleExpanded = toggleExpanded,
openUserProfile = openUserProfile,
)
HorizontalDivider()
}
if (node.children.isNotEmpty()) {
nodes(node.children, htmlConverter = htmlConverter, toggleExpanded = toggleExpanded)
nodes(
node.children,
htmlConverter = htmlConverter,
toggleExpanded = toggleExpanded,
openUserProfile = openUserProfile,
)
}
}

View File

@ -46,6 +46,7 @@ private fun CommentsPageInternal(
htmlConverter: HTMLConverter,
commentState: PostComments?,
markSeenComments: (String, List<Comment>) -> Unit,
openUserProfile: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val commentNodes = createListNode(details.comments, commentState).toMutableStateList()
@ -54,7 +55,12 @@ private fun CommentsPageInternal(
Surface(color = MaterialTheme.colorScheme.surfaceVariant) {
LazyColumn(modifier = modifier, contentPadding = PaddingValues(bottom = 24.dp)) {
item {
CommentsHeader(post = details, postActions = postActions, htmlConverter = htmlConverter)
CommentsHeader(
post = details,
postActions = postActions,
htmlConverter = htmlConverter,
openUserProfile = openUserProfile,
)
}
if (commentNodes.isNotEmpty()) {
@ -79,6 +85,7 @@ private fun CommentsPageInternal(
commentNodes.add(index, parent)
}
},
openUserProfile = openUserProfile,
)
} else {
item {
@ -104,6 +111,7 @@ fun CommentsPage(
getSeenComments: suspend (String) -> PostComments?,
markSeenComments: (String, List<Comment>) -> Unit,
modifier: Modifier = Modifier,
openUserProfile: (String) -> Unit,
) {
val postDetails by
produceState<NetworkState>(Loading) {
@ -124,6 +132,7 @@ fun CommentsPage(
htmlConverter = htmlConverter,
commentState = commentState,
markSeenComments = markSeenComments,
openUserProfile = openUserProfile,
modifier = modifier.fillMaxSize(),
)
}

View File

@ -24,6 +24,8 @@ import androidx.compose.runtime.produceState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import androidx.compose.ui.draw.clip
import androidx.compose.ui.text.LinkAnnotation
import androidx.compose.ui.text.buildAnnotatedString
import androidx.compose.ui.unit.dp
import com.github.michaelbull.result.coroutines.runSuspendCatching
import com.github.michaelbull.result.fold
@ -42,6 +44,7 @@ import dev.msfjarvis.claw.model.User
fun UserProfile(
username: String,
getProfile: suspend (username: String) -> User,
openUserProfile: (String) -> Unit,
modifier: Modifier = Modifier,
) {
val user by
@ -56,7 +59,11 @@ fun UserProfile(
}
when (user) {
is Success<*> -> {
UserProfileInternal(user = (user as Success<User>).data, modifier = modifier)
UserProfileInternal(
user = (user as Success<User>).data,
openUserProfile = openUserProfile,
modifier = modifier,
)
}
is Error -> {
val error = user as Error
@ -77,7 +84,11 @@ fun UserProfile(
}
@Composable
private fun UserProfileInternal(user: User, modifier: Modifier = Modifier) {
private fun UserProfileInternal(
user: User,
openUserProfile: (String) -> Unit,
modifier: Modifier = Modifier,
) {
Surface(modifier = modifier) {
Column(
horizontalAlignment = Alignment.CenterHorizontally,
@ -93,7 +104,19 @@ private fun UserProfileInternal(user: User, modifier: Modifier = Modifier) {
Text(text = user.username, style = MaterialTheme.typography.displaySmall)
ThemedRichText(text = user.about)
user.invitedBy?.let { invitedBy ->
ThemedRichText(text = "Invited by [${invitedBy}](https://lobste.rs/u/${user.invitedBy})")
Text(
text =
buildAnnotatedString {
append("Invited by ")
pushLink(
LinkAnnotation.Clickable(
tag = "username",
linkInteractionListener = { openUserProfile(invitedBy) },
)
)
append(invitedBy)
}
)
}
}
}