Skip to content

Commit

Permalink
Add a composable implementation of swipe to refresh
Browse files Browse the repository at this point in the history
  • Loading branch information
JorgeMucientes committed Dec 5, 2024
1 parent 83227a1 commit 0eca83c
Show file tree
Hide file tree
Showing 3 changed files with 52 additions and 21 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import androidx.compose.foundation.Image
import androidx.compose.foundation.background
import androidx.compose.foundation.border
import androidx.compose.foundation.layout.Arrangement
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.Spacer
Expand All @@ -18,8 +19,12 @@ import androidx.compose.foundation.lazy.staggeredgrid.LazyVerticalStaggeredGrid
import androidx.compose.foundation.lazy.staggeredgrid.StaggeredGridCells
import androidx.compose.foundation.lazy.staggeredgrid.items
import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material.ExperimentalMaterialApi
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Text
import androidx.compose.material.pullrefresh.PullRefreshIndicator
import androidx.compose.material.pullrefresh.pullRefresh
import androidx.compose.material.pullrefresh.rememberPullRefreshState
import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.livedata.observeAsState
Expand Down Expand Up @@ -58,25 +63,37 @@ import com.woocommerce.android.ui.dashboard.stock.DashboardProductStockCard
import com.woocommerce.android.ui.dashboard.topperformers.DashboardTopPerformersWidgetCard
import com.woocommerce.android.ui.main.MainActivityViewModel

@OptIn(ExperimentalMaterialApi::class)
@Composable
fun DashboardContainer(
mainActivityViewModel: MainActivityViewModel,
dashboardViewModel: DashboardViewModel,
blazeCampaignCreationDispatcher: BlazeCampaignCreationDispatcher,
windowSizeClass: WindowSizeClass
windowSizeClass: WindowSizeClass,
) {
dashboardViewModel.dashboardWidgets.observeAsState().value?.let { widgets ->
DashboardWidgets(
widgetUiModels = widgets,
mainActivityViewModel = mainActivityViewModel,
dashboardViewModel = dashboardViewModel,
blazeCampaignCreationDispatcher = blazeCampaignCreationDispatcher,
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.surface)
.padding(vertical = dimensionResource(id = R.dimen.major_100)),
numberOfColumns = if (windowSizeClass != WindowSizeClass.Compact) 2 else 1
)
dashboardViewModel.dashboardCardsState.observeAsState().value?.let { state ->

val pullRefreshState = rememberPullRefreshState(state.isRefreshing, dashboardViewModel::onPullToRefresh)
Box(Modifier.pullRefresh(pullRefreshState)) {
DashboardWidgets(
widgetUiModels = state.widgets,
mainActivityViewModel = mainActivityViewModel,
dashboardViewModel = dashboardViewModel,
blazeCampaignCreationDispatcher = blazeCampaignCreationDispatcher,
modifier = Modifier
.fillMaxSize()
.background(MaterialTheme.colors.surface)
.padding(vertical = dimensionResource(id = R.dimen.major_100)),
numberOfColumns = if (windowSizeClass != WindowSizeClass.Compact) 2 else 1
)

PullRefreshIndicator(
refreshing = state.isRefreshing,
state = pullRefreshState,
modifier = Modifier.align(Alignment.TopCenter),
contentColor = MaterialTheme.colors.primary,
)
}
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@ import com.woocommerce.android.R
import com.woocommerce.android.analytics.AnalyticsEvent
import com.woocommerce.android.analytics.AnalyticsTracker
import com.woocommerce.android.databinding.FragmentDashboardBinding
import com.woocommerce.android.extensions.WindowSizeClass
import com.woocommerce.android.extensions.getColorCompat
import com.woocommerce.android.extensions.handleNotice
import com.woocommerce.android.extensions.handleResult
Expand Down Expand Up @@ -200,10 +199,10 @@ class DashboardFragment :
dashboardViewModel.jetpackBenefitsBannerState.observe(viewLifecycleOwner) { jetpackBenefitsBanner ->
onVisitorStatsUnavailable(jetpackBenefitsBanner)
}
dashboardViewModel.dashboardWidgets.observe(viewLifecycleOwner) { widgets ->
dashboardViewModel.dashboardCardsState.observe(viewLifecycleOwner) { state ->
// Show banners only if onboarding list is NOT displayed
if (
widgets.none {
state.widgets.none {
(it as? DashboardWidgetUiModel.ConfigurableWidget)?.widget?.type == DashboardWidget.Type.ONBOARDING
}
) {
Expand All @@ -213,9 +212,6 @@ class DashboardFragment :
dashboardViewModel.hasNewWidgets.observe(viewLifecycleOwner) { hasNewWidgets ->
editButtonBadge.isVisible = hasNewWidgets
}
dashboardViewModel.isRefreshingOnBackground.observe(viewLifecycleOwner) { isRefreshing ->
binding.myStoreRefreshLayout.isRefreshing = isRefreshing
}
}

private fun setupResultHandlers() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -105,19 +105,32 @@ class DashboardViewModel @Inject constructor(
feedbackPrefs.userFeedbackIsDueObservable
) { configurableWidgets, hasNewWidgets, userFeedbackIsDue ->
mapWidgetsToUiModels(configurableWidgets, hasNewWidgets, userFeedbackIsDue)
}.asLiveData()
}

val hasNewWidgets = dashboardRepository.hasNewWidgets.asLiveData()

private val refreshingOnBackground = MutableStateFlow(-1)

val isRefreshingOnBackground = refreshingOnBackground.map { it > -1 }.asLiveData()
fun displayRefreshingIndicator() { refreshingOnBackground.value += 1 }
fun displayRefreshingIndicator() {
refreshingOnBackground.value += 1
}

fun hideRefreshingIndicator() {
val value = (refreshingOnBackground.value - 1).coerceAtLeast(-1)
refreshingOnBackground.value = value
}

val dashboardCardsState = combine(
dashboardWidgets,
refreshingOnBackground.map { it > -1 }
) { widgets, isRefreshing ->
DashboardCardsState(
widgets = widgets,
isRefreshing = isRefreshing
)
}.asLiveData()

init {
ConnectionChangeReceiver.getEventBus().register(this)

Expand Down Expand Up @@ -364,4 +377,9 @@ class DashboardViewModel @Inject constructor(
action = action
)
}

data class DashboardCardsState(
val widgets: List<DashboardWidgetUiModel>,
val isRefreshing: Boolean
)
}

0 comments on commit 0eca83c

Please sign in to comment.