From 2c4ddca38eef8ea3bc7aad290223ebe0e93dbca2 Mon Sep 17 00:00:00 2001 From: stevenyomi <95685115+stevenyomi@users.noreply.github.com> Date: Thu, 8 Dec 2022 11:40:57 +0800 Subject: [PATCH] Migrate Accompanist SwipeRefresh to Compose PullRefresh (#8106) --- app/build.gradle.kts | 2 +- .../presentation/browse/ExtensionsScreen.kt | 4 +- .../components/CommonMangaItem.kt | 2 +- .../presentation/components/PullRefresh.kt | 50 +++++++++++++++++++ .../presentation/components/SwipeRefresh.kt | 44 ---------------- .../library/components/LibraryContent.kt | 6 +-- .../kanade/presentation/manga/MangaScreen.kt | 6 +-- .../presentation/updates/UpdatesScreen.kt | 6 +-- gradle/compose.versions.toml | 5 +- 9 files changed, 66 insertions(+), 59 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt delete mode 100644 app/src/main/java/eu/kanade/presentation/components/SwipeRefresh.kt diff --git a/app/build.gradle.kts b/app/build.gradle.kts index 60cd6b7425..fbe8a5c562 100644 --- a/app/build.gradle.kts +++ b/app/build.gradle.kts @@ -179,7 +179,6 @@ dependencies { implementation(compose.ui.tooling) implementation(compose.ui.util) implementation(compose.accompanist.webview) - implementation(compose.accompanist.swiperefresh) implementation(compose.accompanist.flowlayout) implementation(compose.accompanist.permissions) implementation(compose.accompanist.themeadapter) @@ -325,6 +324,7 @@ tasks { "-opt-in=androidx.compose.foundation.layout.ExperimentalLayoutApi", "-opt-in=androidx.compose.material.ExperimentalMaterialApi", "-opt-in=androidx.compose.material3.ExperimentalMaterial3Api", + "-opt-in=androidx.compose.material.ExperimentalMaterialApi", "-opt-in=androidx.compose.ui.ExperimentalComposeUiApi", "-opt-in=androidx.compose.foundation.ExperimentalFoundationApi", "-opt-in=androidx.compose.animation.ExperimentalAnimationApi", diff --git a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt index af06f42f6f..527608aa05 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -40,7 +40,7 @@ import eu.kanade.presentation.browse.components.ExtensionIcon import eu.kanade.presentation.components.EmptyScreen import eu.kanade.presentation.components.FastScrollLazyColumn import eu.kanade.presentation.components.LoadingScreen -import eu.kanade.presentation.components.SwipeRefresh +import eu.kanade.presentation.components.PullRefresh import eu.kanade.presentation.manga.components.DotSeparatorNoSpaceText import eu.kanade.presentation.theme.header import eu.kanade.presentation.util.padding @@ -68,7 +68,7 @@ fun ExtensionScreen( onClickUpdateAll: () -> Unit, onRefresh: () -> Unit, ) { - SwipeRefresh( + PullRefresh( refreshing = state.isRefreshing, onRefresh = onRefresh, enabled = !state.isLoading, diff --git a/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt b/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt index ff6645547d..399a2bf25f 100644 --- a/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt +++ b/app/src/main/java/eu/kanade/presentation/components/CommonMangaItem.kt @@ -309,7 +309,7 @@ private fun Modifier.selectedOutline( } return this then modifierElementOf( - params = isSelected.hashCode() + color.hashCode(), + key = isSelected.hashCode() + color.hashCode(), create = { SelectedOutlineNode(isSelected, color) }, update = { it.selected = isSelected diff --git a/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt b/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt new file mode 100644 index 0000000000..5869174c3f --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt @@ -0,0 +1,50 @@ +package eu.kanade.presentation.components + +import androidx.compose.foundation.layout.Box +import androidx.compose.foundation.layout.PaddingValues +import androidx.compose.foundation.layout.padding +import androidx.compose.material.pullrefresh.PullRefreshIndicator +import androidx.compose.material.pullrefresh.pullRefresh +import androidx.compose.material.pullrefresh.rememberPullRefreshState +import androidx.compose.material3.MaterialTheme +import androidx.compose.runtime.Composable +import androidx.compose.ui.Alignment +import androidx.compose.ui.Modifier +import androidx.compose.ui.draw.clipToBounds +import androidx.compose.ui.unit.dp + +/** + * Code reference: [Accompanist SwipeRefresh](https://github.com/google/accompanist/blob/677bc4ca0ee74677a8ba73793d04d85fe4ab55fb/swiperefresh/src/main/java/com/google/accompanist/swiperefresh/SwipeRefresh.kt#L265-L283) + */ +@Composable +fun PullRefresh( + refreshing: Boolean, + onRefresh: () -> Unit, + enabled: Boolean, + indicatorPadding: PaddingValues = PaddingValues(0.dp), + content: @Composable () -> Unit, +) { + val state = rememberPullRefreshState( + refreshing = refreshing, + onRefresh = onRefresh, + ) + + Box(Modifier.pullRefresh(state, enabled)) { + content() + + Box( + Modifier + .padding(indicatorPadding) + .matchParentSize() + .clipToBounds(), + ) { + PullRefreshIndicator( + refreshing = refreshing, + state = state, + modifier = Modifier.align(Alignment.TopCenter), + backgroundColor = MaterialTheme.colorScheme.primary, + contentColor = MaterialTheme.colorScheme.onPrimary, + ) + } + } +} diff --git a/app/src/main/java/eu/kanade/presentation/components/SwipeRefresh.kt b/app/src/main/java/eu/kanade/presentation/components/SwipeRefresh.kt deleted file mode 100644 index 623dc2411e..0000000000 --- a/app/src/main/java/eu/kanade/presentation/components/SwipeRefresh.kt +++ /dev/null @@ -1,44 +0,0 @@ -package eu.kanade.presentation.components - -import androidx.compose.foundation.layout.PaddingValues -import androidx.compose.material3.MaterialTheme -import androidx.compose.runtime.Composable -import androidx.compose.ui.unit.Dp -import androidx.compose.ui.unit.dp -import com.google.accompanist.swiperefresh.SwipeRefreshState -import com.google.accompanist.swiperefresh.rememberSwipeRefreshState -import com.google.accompanist.swiperefresh.SwipeRefreshIndicator as AccompanistSwipeRefreshIndicator - -@Composable -fun SwipeRefreshIndicator( - state: SwipeRefreshState, - refreshTriggerDistance: Dp, - refreshingOffset: Dp = 16.dp, -) { - AccompanistSwipeRefreshIndicator( - state = state, - refreshTriggerDistance = refreshTriggerDistance, - backgroundColor = MaterialTheme.colorScheme.primary, - contentColor = MaterialTheme.colorScheme.onPrimary, - refreshingOffset = refreshingOffset, - ) -} - -@Composable -fun SwipeRefresh( - refreshing: Boolean, - onRefresh: () -> Unit, - enabled: Boolean, - indicatorPadding: PaddingValues = PaddingValues(0.dp), - content: @Composable () -> Unit, -) { - com.google.accompanist.swiperefresh.SwipeRefresh( - state = rememberSwipeRefreshState(refreshing), - onRefresh = onRefresh, - swipeEnabled = enabled, - indicatorPadding = indicatorPadding, - indicator = { s, trigger -> SwipeRefreshIndicator(s, trigger) }, - ) { - content() - } -} diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt index 1038286d2a..62d7b68575 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryContent.kt @@ -18,7 +18,7 @@ import eu.kanade.core.prefs.PreferenceMutableState import eu.kanade.domain.category.model.Category import eu.kanade.domain.library.model.LibraryDisplayMode import eu.kanade.domain.library.model.LibraryManga -import eu.kanade.presentation.components.SwipeRefresh +import eu.kanade.presentation.components.PullRefresh import eu.kanade.presentation.components.rememberPagerState import eu.kanade.tachiyomi.ui.library.LibraryItem import kotlinx.coroutines.delay @@ -79,11 +79,11 @@ fun LibraryContent( } } - SwipeRefresh( + PullRefresh( refreshing = isRefreshing, onRefresh = { val started = onRefresh(categories[currentPage()]) - if (!started) return@SwipeRefresh + if (!started) return@PullRefresh scope.launch { // Fake refresh status but hide it after a second as it's a long running task isRefreshing = true diff --git a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt index cb3e9af1e2..0bc451deae 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/MangaScreen.kt @@ -51,8 +51,8 @@ import eu.kanade.presentation.components.ChapterDownloadAction import eu.kanade.presentation.components.ExtendedFloatingActionButton import eu.kanade.presentation.components.LazyColumn import eu.kanade.presentation.components.MangaBottomActionMenu +import eu.kanade.presentation.components.PullRefresh import eu.kanade.presentation.components.Scaffold -import eu.kanade.presentation.components.SwipeRefresh import eu.kanade.presentation.components.TwoPanelBox import eu.kanade.presentation.components.VerticalFastScroller import eu.kanade.presentation.manga.components.ChapterHeader @@ -287,7 +287,7 @@ private fun MangaScreenSmallImpl( ) { contentPadding -> val topPadding = contentPadding.calculateTopPadding() - SwipeRefresh( + PullRefresh( refreshing = state.isRefreshingData, onRefresh = onRefresh, enabled = chapters.fastAll { !it.selected }, @@ -421,7 +421,7 @@ fun MangaScreenLargeImpl( val insetPadding = WindowInsets.systemBars.only(WindowInsetsSides.Horizontal).asPaddingValues() var topBarHeight by remember { mutableStateOf(0) } - SwipeRefresh( + PullRefresh( refreshing = state.isRefreshingData, onRefresh = onRefresh, enabled = chapters.fastAll { !it.selected }, diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt index f6aa59c003..8d9c6e09ff 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesScreen.kt @@ -29,8 +29,8 @@ import eu.kanade.presentation.components.EmptyScreen import eu.kanade.presentation.components.FastScrollLazyColumn import eu.kanade.presentation.components.LoadingScreen import eu.kanade.presentation.components.MangaBottomActionMenu +import eu.kanade.presentation.components.PullRefresh import eu.kanade.presentation.components.Scaffold -import eu.kanade.presentation.components.SwipeRefresh import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.updates.UpdatesItem @@ -96,11 +96,11 @@ fun UpdateScreen( val scope = rememberCoroutineScope() var isRefreshing by remember { mutableStateOf(false) } - SwipeRefresh( + PullRefresh( refreshing = isRefreshing, onRefresh = { val started = onUpdateLibrary() - if (!started) return@SwipeRefresh + if (!started) return@PullRefresh scope.launch { // Fake refresh status but hide it after a second as it's a long running task isRefreshing = true diff --git a/gradle/compose.versions.toml b/gradle/compose.versions.toml index 942962fc8f..f5b1c697b9 100644 --- a/gradle/compose.versions.toml +++ b/gradle/compose.versions.toml @@ -16,10 +16,11 @@ material3-core = { module = "androidx.compose.material3:material3" } material-icons = { module = "androidx.compose.material:material-icons-extended" } # Here until M3's swipeable became public https://issuetracker.google.com/issues/234640556 -material-core = { module = "androidx.compose.material:material" } +# Using alpha version for PullRefresh fix +# TODO: use default version after next Compose BOM is released +material-core = { module = "androidx.compose.material:material", version = "1.4.0-alpha03" } accompanist-webview = { module = "com.google.accompanist:accompanist-webview", version.ref = "accompanist" } -accompanist-swiperefresh = { module = "com.google.accompanist:accompanist-swiperefresh", version.ref = "accompanist" } accompanist-flowlayout = { module = "com.google.accompanist:accompanist-flowlayout", version.ref = "accompanist" } accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanist" } accompanist-themeadapter = { module = "com.google.accompanist:accompanist-themeadapter-material3", version.ref = "accompanist" } \ No newline at end of file