diff --git a/app/src/main/java/com/google/samples/apps/sunflower/compose/gallery/GalleryScreen.kt b/app/src/main/java/com/google/samples/apps/sunflower/compose/gallery/GalleryScreen.kt index 08c31320b..3df1ffd7f 100644 --- a/app/src/main/java/com/google/samples/apps/sunflower/compose/gallery/GalleryScreen.kt +++ b/app/src/main/java/com/google/samples/apps/sunflower/compose/gallery/GalleryScreen.kt @@ -16,27 +16,34 @@ package com.google.samples.apps.sunflower.compose.gallery +import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.statusBarsPadding import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.LazyVerticalGrid import androidx.compose.material.icons.Icons -import androidx.compose.material.icons.filled.ArrowBack +import androidx.compose.material.icons.automirrored.filled.ArrowBack import androidx.compose.material3.ExperimentalMaterial3Api import androidx.compose.material3.Icon import androidx.compose.material3.IconButton import androidx.compose.material3.Scaffold import androidx.compose.material3.Text import androidx.compose.material3.TopAppBar +import androidx.compose.material3.pulltorefresh.PullToRefreshContainer +import androidx.compose.material3.pulltorefresh.rememberPullToRefreshState import androidx.compose.runtime.Composable +import androidx.compose.runtime.LaunchedEffect +import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier +import androidx.compose.ui.input.nestedscroll.nestedScroll import androidx.compose.ui.res.dimensionResource import androidx.compose.ui.res.stringResource import androidx.compose.ui.tooling.preview.Preview import androidx.compose.ui.tooling.preview.PreviewParameter import androidx.compose.ui.tooling.preview.PreviewParameterProvider import androidx.hilt.navigation.compose.hiltViewModel +import androidx.paging.LoadState import androidx.paging.PagingData import androidx.paging.compose.LazyPagingItems import androidx.paging.compose.collectAsLazyPagingItems @@ -60,35 +67,66 @@ fun GalleryScreen( plantPictures = viewModel.plantPictures, onPhotoClick = onPhotoClick, onUpClick = onUpClick, + onPullToRefresh = viewModel::refreshData, ) } - +@OptIn(ExperimentalMaterial3Api::class) @Composable private fun GalleryScreen( plantPictures: Flow>, onPhotoClick: (UnsplashPhoto) -> Unit = {}, onUpClick: () -> Unit = {}, + onPullToRefresh: () -> Unit, ) { Scaffold( topBar = { GalleryTopBar(onUpClick = onUpClick) }, ) { padding -> - val pagingItems: LazyPagingItems = plantPictures.collectAsLazyPagingItems() - LazyVerticalGrid( - columns = GridCells.Fixed(2), - modifier = Modifier.padding(padding), - contentPadding = PaddingValues(all = dimensionResource(id = R.dimen.card_side_margin)) + + val pullToRefreshState = rememberPullToRefreshState() + + if (pullToRefreshState.isRefreshing) { + onPullToRefresh() + } + + val pagingItems: LazyPagingItems = + plantPictures.collectAsLazyPagingItems() + + LaunchedEffect(pagingItems.loadState) { + when (pagingItems.loadState.refresh) { + is LoadState.Loading -> Unit + is LoadState.Error,is LoadState.NotLoading -> { + pullToRefreshState.endRefresh() + } + } + } + + Box( + modifier = Modifier + .padding(padding) + .nestedScroll(pullToRefreshState.nestedScrollConnection) ) { - items( - count = pagingItems.itemCount, - key = pagingItems.itemKey { it } - ) { index -> - val photo = pagingItems[index] ?: return@items - PhotoListItem(photo = photo) { - onPhotoClick(photo) + + LazyVerticalGrid( + columns = GridCells.Fixed(2), + contentPadding = PaddingValues(all = dimensionResource(id = R.dimen.card_side_margin)) + ) { + items( + count = pagingItems.itemCount, + key = pagingItems.itemKey { it } + ) { index -> + val photo = pagingItems[index] ?: return@items + PhotoListItem(photo = photo) { + onPhotoClick(photo) + } } } + + PullToRefreshContainer( + modifier = Modifier.align(Alignment.TopCenter), + state = pullToRefreshState + ) } } } @@ -107,7 +145,7 @@ private fun GalleryTopBar( navigationIcon = { IconButton(onClick = onUpClick) { Icon( - Icons.Filled.ArrowBack, + Icons.AutoMirrored.Filled.ArrowBack, contentDescription = null ) } @@ -120,7 +158,7 @@ private fun GalleryTopBar( private fun GalleryScreenPreview( @PreviewParameter(GalleryScreenPreviewParamProvider::class) plantPictures: Flow> ) { - GalleryScreen(plantPictures = plantPictures) + GalleryScreen(plantPictures = plantPictures, onPullToRefresh = {}) } private class GalleryScreenPreviewParamProvider : diff --git a/app/src/main/java/com/google/samples/apps/sunflower/compose/home/HomeScreen.kt b/app/src/main/java/com/google/samples/apps/sunflower/compose/home/HomeScreen.kt index 9deaba6a8..7a32e18d5 100644 --- a/app/src/main/java/com/google/samples/apps/sunflower/compose/home/HomeScreen.kt +++ b/app/src/main/java/com/google/samples/apps/sunflower/compose/home/HomeScreen.kt @@ -16,7 +16,6 @@ package com.google.samples.apps.sunflower.compose.home -import android.util.Log import androidx.annotation.DrawableRes import androidx.annotation.StringRes import androidx.compose.foundation.ExperimentalFoundationApi diff --git a/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/GalleryViewModel.kt b/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/GalleryViewModel.kt index c58b8ac32..5dc35ef12 100644 --- a/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/GalleryViewModel.kt +++ b/app/src/main/java/com/google/samples/apps/sunflower/viewmodels/GalleryViewModel.kt @@ -19,19 +19,43 @@ package com.google.samples.apps.sunflower.viewmodels import androidx.lifecycle.SavedStateHandle import androidx.lifecycle.ViewModel import androidx.lifecycle.viewModelScope +import androidx.paging.PagingData import androidx.paging.cachedIn +import com.google.samples.apps.sunflower.data.UnsplashPhoto import com.google.samples.apps.sunflower.data.UnsplashRepository import dagger.hilt.android.lifecycle.HiltViewModel +import kotlinx.coroutines.flow.Flow +import kotlinx.coroutines.flow.MutableStateFlow +import kotlinx.coroutines.flow.filterNotNull +import kotlinx.coroutines.flow.first +import kotlinx.coroutines.launch import javax.inject.Inject @HiltViewModel class GalleryViewModel @Inject constructor( savedStateHandle: SavedStateHandle, - repository: UnsplashRepository + private val repository: UnsplashRepository ) : ViewModel() { private var queryString: String? = savedStateHandle["plantName"] - val plantPictures = - repository.getSearchResultStream(queryString ?: "").cachedIn(viewModelScope) + + private val _plantPictures = MutableStateFlow?>(null) + val plantPictures: Flow> get() = _plantPictures.filterNotNull() + + init { + refreshData() + } + + + fun refreshData() { + + viewModelScope.launch { + try { + _plantPictures.value = repository.getSearchResultStream(queryString ?: "").cachedIn(viewModelScope).first() + } catch (e: Exception) { + e.printStackTrace() + } + } + } } \ No newline at end of file diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index fb9ecac4e..5dedaf8c0 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -39,7 +39,7 @@ ktlint = "0.40.0" ktx = "1.7.0" lifecycle = "2.6.0-alpha04" material = "1.8.0-rc01" -material3 = "1.0.1" +material3 = "1.2.0-alpha11" # @keep minSdk = "23" monitor = "1.6.0"