From dfa9aea007424252badfa60bad860c01fd6d7933 Mon Sep 17 00:00:00 2001 From: Sahil Khan <85223122+sahilsk3333@users.noreply.github.com> Date: Wed, 27 Dec 2023 22:56:12 +0530 Subject: [PATCH 1/3] Add pull to refresh to gallery screen [866] (#934) * Replaced TopAppBar with CenterAlignedTopAppBar, Fix issue #857 App title moves * Feature pull to refresh GalleryScreen issue[#866] * Moved isRefreshing state to compose * Remove unnecessary isLoading state * Apply suggestions from code review * Remove unnecessary imports --------- Co-authored-by: Chris Arriola Co-authored-by: Chris Arriola --- .../compose/gallery/GalleryScreen.kt | 70 ++++++++++++++----- .../apps/sunflower/compose/home/HomeScreen.kt | 1 - .../sunflower/viewmodels/GalleryViewModel.kt | 30 +++++++- gradle/libs.versions.toml | 2 +- 4 files changed, 82 insertions(+), 21 deletions(-) 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" From 5f864ae2c4b81b036aa47f77be44520d795c70a0 Mon Sep 17 00:00:00 2001 From: Hieu Vu Date: Thu, 28 Dec 2023 01:20:32 +0700 Subject: [PATCH 2/3] Add translation for Vietnamese (#733) * Add translation for Vietnamese * Update translate for back --------- Co-authored-by: Chris Arriola --- app/src/main/res/values-vi/strings.xml | 51 ++++++++++++++++++++++++++ 1 file changed, 51 insertions(+) create mode 100644 app/src/main/res/values-vi/strings.xml diff --git a/app/src/main/res/values-vi/strings.xml b/app/src/main/res/values-vi/strings.xml new file mode 100644 index 000000000..04891b63c --- /dev/null +++ b/app/src/main/res/values-vi/strings.xml @@ -0,0 +1,51 @@ + + + + Lọc theo vùng phát triển + Vườn của tôi + Danh sách cây + Cây Hiện Có + Chi tiết cây + Thêm cây + Đã thêm cây vào vườn + Vườn của bạn đang trống + Đã trồng + Lần cuối tưới + Chia sẻ + Xem cây %s tại ứng dụng Android Sunflower + Hình ảnh từ Unsplash + + + Cần tưới + + hàng ngày + mỗi %d ngày + + + + tưới vào ngày mai. + tưới trong %d ngày. + + + + Hình ảnh của cây + Trở lại + Đi đến thư viện + Hình của cây + + + \ No newline at end of file From 9a00783cf8e24358f665b49b5f71fc75adc33b8e Mon Sep 17 00:00:00 2001 From: Chris Arriola Date: Thu, 28 Dec 2023 08:44:57 -0800 Subject: [PATCH 3/3] Update Glide implementation and item key ID. (#941) Change-Id: I3d9182d209ac85dc338f2b7b123b2a788e4453ed --- .../apps/sunflower/compose/gallery/GalleryScreen.kt | 3 +-- .../sunflower/compose/plantdetail/PlantDetailView.kt | 10 +++++----- .../apps/sunflower/compose/utils/SunflowerImage.kt | 10 ++++------ gradle/libs.versions.toml | 2 +- 4 files changed, 11 insertions(+), 14 deletions(-) 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 3df1ffd7f..db8192378 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 @@ -107,14 +107,13 @@ private fun GalleryScreen( .padding(padding) .nestedScroll(pullToRefreshState.nestedScrollConnection) ) { - LazyVerticalGrid( columns = GridCells.Fixed(2), contentPadding = PaddingValues(all = dimensionResource(id = R.dimen.card_side_margin)) ) { items( count = pagingItems.itemCount, - key = pagingItems.itemKey { it } + key = pagingItems.itemKey { it.id } ) { index -> val photo = pagingItems[index] ?: return@items PhotoListItem(photo = photo) { diff --git a/app/src/main/java/com/google/samples/apps/sunflower/compose/plantdetail/PlantDetailView.kt b/app/src/main/java/com/google/samples/apps/sunflower/compose/plantdetail/PlantDetailView.kt index b290f4da5..f74e93cbe 100644 --- a/app/src/main/java/com/google/samples/apps/sunflower/compose/plantdetail/PlantDetailView.kt +++ b/app/src/main/java/com/google/samples/apps/sunflower/compose/plantdetail/PlantDetailView.kt @@ -326,7 +326,7 @@ private fun PlantImage( override fun onLoadFailed( e: GlideException?, model: Any?, - target: Target?, + target: Target, isFirstResource: Boolean ): Boolean { isLoading = false @@ -334,10 +334,10 @@ private fun PlantImage( } override fun onResourceReady( - resource: Drawable?, - model: Any?, + resource: Drawable, + model: Any, target: Target?, - dataSource: DataSource?, + dataSource: DataSource, isFirstResource: Boolean ): Boolean { isLoading = false @@ -596,4 +596,4 @@ private fun PlantDetailContentPreview() { ) } } -} \ No newline at end of file +} diff --git a/app/src/main/java/com/google/samples/apps/sunflower/compose/utils/SunflowerImage.kt b/app/src/main/java/com/google/samples/apps/sunflower/compose/utils/SunflowerImage.kt index a1f57d20a..98881dd5d 100644 --- a/app/src/main/java/com/google/samples/apps/sunflower/compose/utils/SunflowerImage.kt +++ b/app/src/main/java/com/google/samples/apps/sunflower/compose/utils/SunflowerImage.kt @@ -22,12 +22,14 @@ import androidx.compose.foundation.layout.Box import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.size import androidx.compose.material3.CircularProgressIndicator +import androidx.compose.material3.MaterialTheme import androidx.compose.runtime.Composable import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.ColorFilter import androidx.compose.ui.graphics.DefaultAlpha +import androidx.compose.ui.graphics.painter.ColorPainter import androidx.compose.ui.layout.ContentScale import androidx.compose.ui.platform.LocalInspectionMode import androidx.compose.ui.unit.dp @@ -65,10 +67,6 @@ fun SunflowerImage( alpha = alpha, colorFilter = colorFilter, requestBuilderTransform = requestBuilderTransform, - loading = placeholder { - Box(modifier.fillMaxWidth(), contentAlignment = Alignment.Center) { - CircularProgressIndicator(Modifier.size(40.dp)) - } - } + loading = placeholder(ColorPainter(MaterialTheme.colorScheme.secondary)) ) -} \ No newline at end of file +} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml index 5dedaf8c0..4ddb0b355 100644 --- a/gradle/libs.versions.toml +++ b/gradle/libs.versions.toml @@ -27,7 +27,7 @@ constraintLayoutCompose = "1.0.1" coreTesting = "2.2.0" coroutines = "1.6.4" espresso = "3.4.0" -glide = "1.0.0-alpha.3" +glide = "1.0.0-beta01" gradle = "7.2.0" gson = "2.9.0" guava = "31.1-android"