refactor: hoist state out of comments page

This commit is contained in:
Harsh Shandilya 2025-05-26 19:14:11 +05:30
parent 0d3c08c10a
commit bcac86d187
2 changed files with 68 additions and 14 deletions

View file

@ -10,13 +10,12 @@ import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.PaddingValues
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.getValue
import androidx.compose.runtime.produceState
import androidx.compose.ui.Alignment
import androidx.compose.ui.Modifier
import com.github.michaelbull.result.coroutines.runSuspendCatching
import com.github.michaelbull.result.fold
import dev.msfjarvis.claw.common.NetworkState
import com.deliveryhero.whetstone.compose.injectedViewModel
import dev.msfjarvis.claw.common.NetworkState.Error
import dev.msfjarvis.claw.common.NetworkState.Loading
import dev.msfjarvis.claw.common.NetworkState.Success
@ -35,23 +34,17 @@ fun CommentsPage(
getSeenComments: suspend (String) -> PostComments?,
markSeenComments: (String, List<Comment>) -> Unit,
contentPadding: PaddingValues,
modifier: Modifier = Modifier,
openUserProfile: (String) -> Unit,
modifier: Modifier = Modifier,
viewModel: CommentsViewModel = injectedViewModel(),
) {
val postDetails by
produceState<NetworkState>(Loading, key1 = postId) {
runSuspendCatching { postActions.getComments(postId) }
.fold(
success = { details -> value = Success(details) },
failure = { value = Error(error = it, description = "Failed to load comments") },
)
}
LaunchedEffect(postId) { viewModel.loadPostDetails(postId) }
val commentState by
produceState<PostComments?>(initialValue = null, key1 = postId) {
value = getSeenComments(postId)
}
when (postDetails) {
when (val postDetails = viewModel.postDetails) {
is Success<*> -> {
CommentsPageInternal(
details = (postDetails as Success<UIPost>).data,
@ -64,7 +57,7 @@ fun CommentsPage(
)
}
is Error -> {
val error = postDetails as Error
val error = postDetails
Box(modifier = Modifier.fillMaxSize()) {
NetworkError(
label = error.description,

View file

@ -0,0 +1,61 @@
/*
* Copyright © 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 android.app.Application
import android.content.Context
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.setValue
import androidx.lifecycle.AndroidViewModel
import com.deliveryhero.whetstone.app.ApplicationScope
import com.deliveryhero.whetstone.viewmodel.ContributesViewModel
import com.github.michaelbull.result.coroutines.runSuspendCatching
import com.github.michaelbull.result.fold
import com.slack.eithernet.ApiResult.Failure
import com.slack.eithernet.ApiResult.Success
import com.squareup.anvil.annotations.optional.ForScope
import dev.msfjarvis.claw.api.LobstersApi
import dev.msfjarvis.claw.api.toError
import dev.msfjarvis.claw.common.NetworkState
import dev.msfjarvis.claw.core.injection.IODispatcher
import dev.msfjarvis.claw.model.UIPost
import dev.msfjarvis.claw.model.toUIPost
import java.io.IOException
import javax.inject.Inject
import kotlinx.coroutines.CoroutineDispatcher
import kotlinx.coroutines.withContext
@ContributesViewModel
class CommentsViewModel
@Inject
constructor(
private val api: LobstersApi,
@IODispatcher private val ioDispatcher: CoroutineDispatcher,
@ForScope(ApplicationScope::class) context: Context,
) : AndroidViewModel(context as Application) {
var postDetails by mutableStateOf<NetworkState>(NetworkState.Loading)
suspend fun loadPostDetails(postId: String) {
postDetails =
runSuspendCatching<UIPost> {
withContext(ioDispatcher) {
when (val result = api.getPostDetails(postId)) {
is Success -> result.value.toUIPost()
is Failure.NetworkFailure -> throw result.error
is Failure.UnknownFailure -> throw result.error
is Failure.HttpFailure -> throw result.toError()
is Failure.ApiFailure -> throw IOException("API returned an invalid response")
}
}
}
.fold(
success = { details -> NetworkState.Success(details) },
failure = { NetworkState.Error(error = it, description = "Failed to load comments") },
)
}
}