diff --git a/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsPage.kt b/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsPage.kt index c911eab6..194d5a41 100644 --- a/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsPage.kt +++ b/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsPage.kt @@ -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) -> Unit, contentPadding: PaddingValues, - modifier: Modifier = Modifier, openUserProfile: (String) -> Unit, + modifier: Modifier = Modifier, + viewModel: CommentsViewModel = injectedViewModel(), ) { - val postDetails by - produceState(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(initialValue = null, key1 = postId) { value = getSeenComments(postId) } - when (postDetails) { + when (val postDetails = viewModel.postDetails) { is Success<*> -> { CommentsPageInternal( details = (postDetails as Success).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, diff --git a/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsViewModel.kt b/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsViewModel.kt new file mode 100644 index 00000000..917f6046 --- /dev/null +++ b/common/src/main/kotlin/dev/msfjarvis/claw/common/comments/CommentsViewModel.kt @@ -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.Loading) + + suspend fun loadPostDetails(postId: String) { + postDetails = + runSuspendCatching { + 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") }, + ) + } +}