diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsMviModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsMviModel.kt index f7699b7d9..a8b040845 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsMviModel.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsMviModel.kt @@ -6,13 +6,14 @@ import com.github.diegoberaldin.raccoonforlemmy.domain.lemmy.data.CommunityModel interface ManageSubscriptionsMviModel : MviModel { sealed interface Intent { + data object Refresh : Intent data object HapticIndication : Intent data class Unsubscribe(val index: Int) : Intent } data class UiState( - val loading: Boolean = false, + val refreshing: Boolean = false, val communities: List = emptyList(), ) diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsScreen.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsScreen.kt index ac82c8e78..df386bab1 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsScreen.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsScreen.kt @@ -2,7 +2,9 @@ package com.github.diegoberaldin.raccoonforlemmy.feature.search.managesubscripti import androidx.compose.foundation.Image import androidx.compose.foundation.background +import androidx.compose.foundation.layout.Arrangement import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding import androidx.compose.foundation.lazy.LazyColumn @@ -10,10 +12,14 @@ import androidx.compose.foundation.lazy.itemsIndexed import androidx.compose.foundation.shape.CircleShape import androidx.compose.material.DismissDirection import androidx.compose.material.DismissValue +import androidx.compose.material.ExperimentalMaterialApi import androidx.compose.material.Icon import androidx.compose.material.icons.Icons import androidx.compose.material.icons.filled.ArrowBack import androidx.compose.material.icons.filled.Unsubscribe +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.MaterialTheme import androidx.compose.material3.Scaffold @@ -24,6 +30,7 @@ import androidx.compose.runtime.Composable import androidx.compose.runtime.collectAsState import androidx.compose.runtime.getValue import androidx.compose.runtime.remember +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter @@ -34,7 +41,6 @@ import com.github.diegoberaldin.raccoonforlemmy.core.appearance.theme.Spacing import com.github.diegoberaldin.raccoonforlemmy.core.architecture.bindToLifecycle import com.github.diegoberaldin.raccoonforlemmy.core.commonui.communitydetail.CommunityDetailScreen import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.CommunityItem -import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.ProgressHud import com.github.diegoberaldin.raccoonforlemmy.core.commonui.components.SwipeableCard import com.github.diegoberaldin.raccoonforlemmy.core.commonui.di.getNavigationCoordinator import com.github.diegoberaldin.raccoonforlemmy.core.utils.onClick @@ -43,7 +49,7 @@ import com.github.diegoberaldin.raccoonforlemmy.resources.MR import dev.icerock.moko.resources.compose.stringResource class ManageSubscriptionsScreen : Screen { - @OptIn(ExperimentalMaterial3Api::class) + @OptIn(ExperimentalMaterial3Api::class, ExperimentalMaterialApi::class) @Composable override fun Content() { val model = rememberScreenModel { getManageSubscriptionsViewModel() } @@ -75,12 +81,21 @@ class ManageSubscriptionsScreen : Screen { ) }, ) { paddingValues -> + val pullRefreshState = rememberPullRefreshState( + uiState.refreshing, + { + model.reduce(ManageSubscriptionsMviModel.Intent.Refresh) + } + ) Box( - modifier = Modifier.padding(paddingValues), + modifier = Modifier + .padding(paddingValues) + .nestedScroll(scrollBehavior.nestedScrollConnection) + .pullRefresh(pullRefreshState), ) { LazyColumn( - modifier = Modifier - .nestedScroll(scrollBehavior.nestedScrollConnection) + modifier = Modifier.fillMaxSize(), + verticalArrangement = Arrangement.spacedBy(Spacing.xxs), ) { itemsIndexed(uiState.communities) { idx, community -> SwipeableCard( @@ -127,9 +142,14 @@ class ManageSubscriptionsScreen : Screen { ) } } - if (uiState.loading) { - ProgressHud() - } + + PullRefreshIndicator( + refreshing = uiState.refreshing, + state = pullRefreshState, + modifier = Modifier.align(Alignment.TopCenter), + backgroundColor = MaterialTheme.colorScheme.background, + contentColor = MaterialTheme.colorScheme.onBackground, + ) } } } diff --git a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsViewModel.kt b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsViewModel.kt index 356ec67b6..3a35e5d88 100644 --- a/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsViewModel.kt +++ b/feature-search/src/commonMain/kotlin/com/github/diegoberaldin/raccoonforlemmy/feature/search/managesubscriptions/ManageSubscriptionsViewModel.kt @@ -29,6 +29,7 @@ class ManageSubscriptionsViewModel( override fun reduce(intent: ManageSubscriptionsMviModel.Intent) { when (intent) { ManageSubscriptionsMviModel.Intent.HapticIndication -> hapticFeedback.vibrate() + ManageSubscriptionsMviModel.Intent.Refresh -> refresh() is ManageSubscriptionsMviModel.Intent.Unsubscribe -> handleUnsubscription( community = uiState.value.communities[intent.index] ) @@ -36,13 +37,16 @@ class ManageSubscriptionsViewModel( } private fun refresh() { - mvi.updateState { it.copy(loading = true) } + if (uiState.value.refreshing) { + return + } + mvi.updateState { it.copy(refreshing = true) } mvi.scope?.launch(Dispatchers.IO) { val auth = identityRepository.authToken.value val items = communityRepository.getSubscribed(auth).sortedBy { it.name } mvi.updateState { it.copy( - loading = false, + refreshing = false, communities = items, ) }