From 3408ef635d552a385d48bce03c3fcfa98be3a697 Mon Sep 17 00:00:00 2001 From: "Tran M. Cuong" Date: Sat, 27 Jul 2024 02:01:32 +0700 Subject: [PATCH] Fix disappearance items when fast scrolling (#1035) * Don't use animateItem's fade-in/fade-out in FastScrollLazyColumn * Move to extension function Avoid using animateItemPlacement name since it's shadowed by compose-bom's deprecated one (cherry picked from commit 913ff22132390a59a13c463645ce954c7cbc5c6b) --- .../eu/kanade/presentation/browse/ExtensionsScreen.kt | 7 ++++--- .../main/java/eu/kanade/presentation/browse/FeedScreen.kt | 4 ++-- .../eu/kanade/presentation/browse/MigrationListScreen.kt | 3 ++- .../eu/kanade/presentation/browse/SourceFeedScreen.kt | 3 ++- .../eu/kanade/presentation/browse/SourcesFilterScreen.kt | 7 ++++--- .../components/biometric/BiometricTimesContent.kt | 2 +- .../category/components/genre/SortTagContent.kt | 2 +- .../category/components/sources/SourceCategoryContent.kt | 2 +- .../java/eu/kanade/presentation/history/HistoryScreen.kt | 5 +++-- .../kanade/presentation/manga/components/NamespaceTags.kt | 4 ++-- .../java/eu/kanade/presentation/updates/UpdatesUiItem.kt | 7 ++++--- .../eu/kanade/presentation/util/FastScrollAnimateItem.kt | 8 ++++++++ 12 files changed, 34 insertions(+), 20 deletions(-) create mode 100644 app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt 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 31d7f7e69f87..6d94fef5c35f 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/ExtensionsScreen.kt @@ -48,6 +48,7 @@ import eu.kanade.presentation.browse.components.ExtensionIcon import eu.kanade.presentation.components.WarningBanner import eu.kanade.presentation.manga.components.DotSeparatorNoSpaceText import eu.kanade.presentation.more.settings.screen.browse.ExtensionReposScreen +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.presentation.util.rememberRequestPackageInstallsPermissionState import eu.kanade.tachiyomi.extension.model.Extension import eu.kanade.tachiyomi.extension.model.InstallStep @@ -188,14 +189,14 @@ private fun ExtensionContent( } ExtensionHeader( textRes = header.textRes, - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), action = action, ) } is ExtensionUiModel.Header.Text -> { ExtensionHeader( text = header.text, - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), ) } } @@ -213,7 +214,7 @@ private fun ExtensionContent( }, ) { item -> ExtensionItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), item = item, onClickItem = { when (it) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt index fa95f208a523..e843c17efbd1 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/FeedScreen.kt @@ -92,7 +92,7 @@ fun FeedScreen( refreshing = true onRefresh() }, - enabled = { !state.isLoadingItems }, + enabled = !state.isLoadingItems, ) { ScrollbarLazyColumn( contentPadding = contentPadding + topSmallPaddingValues, @@ -103,7 +103,6 @@ fun FeedScreen( key = { it.feed.id }, ) { item -> GlobalSearchResultItem( - modifier = Modifier.animateItemPlacement(), title = item.title, subtitle = item.subtitle, onLongClick = { @@ -116,6 +115,7 @@ fun FeedScreen( onClickSource(item.source) } }, + modifier = Modifier.animateItem(), ) { FeedItem( item = item, diff --git a/app/src/main/java/eu/kanade/presentation/browse/MigrationListScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/MigrationListScreen.kt index a9d3547c9a8c..51be899e2f92 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/MigrationListScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/MigrationListScreen.kt @@ -28,6 +28,7 @@ import eu.kanade.presentation.browse.components.MigrationItem import eu.kanade.presentation.browse.components.MigrationItemResult import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.components.AppBarActions +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.tachiyomi.ui.browse.migration.advanced.process.MigratingManga import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -95,7 +96,7 @@ fun MigrationListScreen( Row( Modifier .fillMaxWidth() - .animateItemPlacement() + .animateItemFastScroll() .padding(horizontal = 16.dp) .height(IntrinsicSize.Min), horizontalArrangement = Arrangement.SpaceBetween, diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt index 0c156e3528df..758eebfadc04 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourceFeedScreen.kt @@ -15,6 +15,7 @@ import eu.kanade.presentation.browse.components.GlobalSearchLoadingResultItem import eu.kanade.presentation.browse.components.GlobalSearchResultItem import eu.kanade.presentation.components.AppBarTitle import eu.kanade.presentation.components.SearchToolbar +import eu.kanade.presentation.util.animateItemFastScroll import kotlinx.collections.immutable.ImmutableList import tachiyomi.domain.manga.model.Manga import tachiyomi.domain.source.model.FeedSavedSearch @@ -153,7 +154,7 @@ fun SourceFeedList( key = { it.id }, ) { item -> GlobalSearchResultItem( - modifier = Modifier.animateItemPlacement(), + modifier = Modifier.animateItemFastScroll(), title = item.title, subtitle = null, onLongClick = if (item is SourceFeedUI.SourceSavedSearch) { diff --git a/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt b/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt index f77cc20d5a1d..8dff71d532c4 100644 --- a/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/browse/SourcesFilterScreen.kt @@ -11,6 +11,7 @@ import androidx.compose.ui.platform.LocalContext import eu.kanade.presentation.browse.components.BaseSourceItem import eu.kanade.presentation.components.AppBar import eu.kanade.presentation.more.settings.widget.SwitchPreferenceWidget +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.tachiyomi.ui.browse.source.SourcesFilterScreenModel import eu.kanade.tachiyomi.util.system.LocaleHelper import tachiyomi.domain.source.model.Source @@ -79,7 +80,7 @@ private fun SourcesFilterContent( contentType = "source-filter-header", ) { SourcesFilterHeader( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), language = language, enabled = enabled, onClickItem = onClickLanguage, @@ -95,7 +96,7 @@ private fun SourcesFilterContent( sources.none { it.id.toString() in state.disabledSources } } SourcesFilterToggle( - modifier = Modifier.animateItemPlacement(), + modifier = Modifier.animateItem(), isEnabled = toggleEnabled, onClickItem = { onClickSources(!toggleEnabled, sources) @@ -109,7 +110,7 @@ private fun SourcesFilterContent( contentType = { "source-filter-item" }, ) { source -> SourcesFilterItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), source = source, enabled = "${source.id}" !in state.disabledSources, onClickItem = onClickSource, diff --git a/app/src/main/java/eu/kanade/presentation/category/components/biometric/BiometricTimesContent.kt b/app/src/main/java/eu/kanade/presentation/category/components/biometric/BiometricTimesContent.kt index d8465e2953f1..0f8cd9c73213 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/biometric/BiometricTimesContent.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/biometric/BiometricTimesContent.kt @@ -26,7 +26,7 @@ fun BiometricTimesContent( ) { items(timeRanges, key = { it.formattedString }) { timeRange -> BiometricTimesListItem( - modifier = Modifier.animateItemPlacement(), + modifier = Modifier.animateItem(), timeRange = timeRange, onDelete = { onClickDelete(timeRange) }, ) diff --git a/app/src/main/java/eu/kanade/presentation/category/components/genre/SortTagContent.kt b/app/src/main/java/eu/kanade/presentation/category/components/genre/SortTagContent.kt index 4700e18831a0..dcce5e0eac64 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/genre/SortTagContent.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/genre/SortTagContent.kt @@ -27,7 +27,7 @@ fun SortTagContent( ) { itemsIndexed(tags, key = { _, tag -> tag }) { index, tag -> SortTagListItem( - modifier = Modifier.animateItemPlacement(), + modifier = Modifier.animateItem(), tag = tag, canMoveUp = index != 0, canMoveDown = index != tags.lastIndex, diff --git a/app/src/main/java/eu/kanade/presentation/category/components/sources/SourceCategoryContent.kt b/app/src/main/java/eu/kanade/presentation/category/components/sources/SourceCategoryContent.kt index 2f5b26b3eb48..e3925c7aaed4 100644 --- a/app/src/main/java/eu/kanade/presentation/category/components/sources/SourceCategoryContent.kt +++ b/app/src/main/java/eu/kanade/presentation/category/components/sources/SourceCategoryContent.kt @@ -26,7 +26,7 @@ fun SourceCategoryContent( ) { items(categories, key = { it }) { category -> SourceCategoryListItem( - modifier = Modifier.animateItemPlacement(), + modifier = Modifier.animateItem(), category = category, onRename = { onClickRename(category) }, onDelete = { onClickDelete(category) }, diff --git a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt index 66f31f3d785a..2d5d58524da3 100644 --- a/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/history/HistoryScreen.kt @@ -18,6 +18,7 @@ import eu.kanade.presentation.components.SearchToolbar import eu.kanade.presentation.components.relativeDateText import eu.kanade.presentation.history.components.HistoryItem import eu.kanade.presentation.theme.TachiyomiPreviewTheme +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.tachiyomi.ui.history.HistoryScreenModel import kotlinx.collections.immutable.ImmutableList import kotlinx.collections.immutable.persistentListOf @@ -114,14 +115,14 @@ private fun HistoryScreenContent( when (item) { is HistoryUiModel.Header -> { ListGroupHeader( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), text = relativeDateText(item.date), ) } is HistoryUiModel.Item -> { val value = item.item HistoryItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), history = value, onClickCover = { onClickCover(value) }, onClickResume = { onClickResume(value) }, diff --git a/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt b/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt index 6838732edcc6..29a9209f0c18 100644 --- a/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt +++ b/app/src/main/java/eu/kanade/presentation/manga/components/NamespaceTags.kt @@ -7,7 +7,7 @@ import androidx.compose.foundation.layout.FlowRow import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding -import androidx.compose.material3.LocalMinimumInteractiveComponentEnforcement +import androidx.compose.material3.LocalMinimumInteractiveComponentSize import androidx.compose.material3.MaterialTheme import androidx.compose.material3.SuggestionChip import androidx.compose.material3.Surface @@ -141,7 +141,7 @@ fun TagsChip( border: ChipBorder? = SuggestionChipDefaults.suggestionChipBorder(), borderM3: BorderStroke? = SuggestionChipDefaultsM3.suggestionChipBorder(enabled = true), ) { - CompositionLocalProvider(LocalMinimumInteractiveComponentEnforcement provides false) { + CompositionLocalProvider(LocalMinimumInteractiveComponentSize provides 0.dp) { if (onClick != null) { SuggestionChip( modifier = modifier, diff --git a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt index e9baffde7290..235b00ba8601 100644 --- a/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt +++ b/app/src/main/java/eu/kanade/presentation/updates/UpdatesUiItem.kt @@ -37,6 +37,7 @@ import eu.kanade.presentation.manga.components.ChapterDownloadAction import eu.kanade.presentation.manga.components.ChapterDownloadIndicator import eu.kanade.presentation.manga.components.DotSeparatorText import eu.kanade.presentation.manga.components.MangaCover +import eu.kanade.presentation.util.animateItemFastScroll import eu.kanade.presentation.util.relativeTimeSpanString import eu.kanade.tachiyomi.data.download.model.Download import eu.kanade.tachiyomi.ui.updates.UpdatesItem @@ -54,7 +55,7 @@ internal fun LazyListScope.updatesLastUpdatedItem( item(key = "updates-lastUpdated") { Box( modifier = Modifier - .animateItem() + .animateItem(fadeInSpec = null, fadeOutSpec = null) .padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small), ) { Text( @@ -94,14 +95,14 @@ internal fun LazyListScope.updatesUiItems( when (item) { is UpdatesUiModel.Header -> { ListGroupHeader( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), text = relativeDateText(item.date), ) } is UpdatesUiModel.Item -> { val updatesItem = item.item UpdatesUiItem( - modifier = Modifier.animateItem(), + modifier = Modifier.animateItemFastScroll(), update = updatesItem.update, selected = updatesItem.selected, readProgress = updatesItem.update.lastPageRead diff --git a/app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt b/app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt new file mode 100644 index 000000000000..a6c9f70198d6 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/util/FastScrollAnimateItem.kt @@ -0,0 +1,8 @@ +package eu.kanade.presentation.util + +import androidx.compose.foundation.lazy.LazyItemScope +import androidx.compose.ui.Modifier + +// https://issuetracker.google.com/352584409 +context(LazyItemScope) +fun Modifier.animateItemFastScroll() = this.animateItem(fadeInSpec = null, fadeOutSpec = null)