Library category page performance fixes (#7650)

* Don't compose category page unnecessarily

* Remove unnecessary library pager recompose

Defer and remember the "currentPage" state read since it's only needed when the
pager is composed for the first time.

* Badge opts

* Sync text style with previous impl

Also avoid reallocating by using copy
This commit is contained in:
Ivan Iskandar 2022-07-30 22:47:27 +07:00 committed by GitHub
parent f90e1b935c
commit d49ec41f3a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 68 additions and 63 deletions

View File

@ -1,12 +1,10 @@
package eu.kanade.presentation.components package eu.kanade.presentation.components
import androidx.compose.foundation.background import androidx.compose.foundation.background
import androidx.compose.foundation.layout.Box
import androidx.compose.foundation.layout.Row import androidx.compose.foundation.layout.Row
import androidx.compose.foundation.layout.RowScope import androidx.compose.foundation.layout.RowScope
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.LocalTextStyle
import androidx.compose.material3.MaterialTheme import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
@ -36,18 +34,15 @@ fun Badge(
textColor: Color = MaterialTheme.colorScheme.onSecondary, textColor: Color = MaterialTheme.colorScheme.onSecondary,
shape: Shape = RectangleShape, shape: Shape = RectangleShape,
) { ) {
Box( Text(
text = text,
modifier = Modifier modifier = Modifier
.clip(shape) .clip(shape)
.background(color), .background(color)
) { .padding(horizontal = 3.dp, vertical = 1.dp),
Text( color = textColor,
text = text, fontWeight = FontWeight.Medium,
modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp), maxLines = 1,
style = LocalTextStyle.current.copy( style = MaterialTheme.typography.bodySmall,
color = textColor, )
fontWeight = FontWeight.Medium,
),
)
}
} }

View File

@ -61,8 +61,8 @@ fun LibraryScreen(
LibraryContent( LibraryContent(
state = presenter, state = presenter,
contentPadding = paddingValues, contentPadding = paddingValues,
currentPage = presenter.activeCategory, currentPage = { presenter.activeCategory },
isLibraryEmpty = presenter.loadedManga.isEmpty(), isLibraryEmpty = { presenter.loadedManga.isEmpty() },
showPageTabs = presenter.tabVisibility, showPageTabs = presenter.tabVisibility,
showMangaCount = presenter.mangaCountVisibility, showMangaCount = presenter.mangaCountVisibility,
onChangeCurrentPage = { presenter.activeCategory = it }, onChangeCurrentPage = { presenter.activeCategory = it },

View File

@ -4,12 +4,12 @@ import androidx.compose.foundation.combinedClickable
import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.domain.manga.model.MangaCover import eu.kanade.domain.manga.model.MangaCover
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.ui.library.LibraryItem import eu.kanade.tachiyomi.ui.library.LibraryItem
@ -81,8 +81,9 @@ fun LibraryComfortableGridItem(
Text( Text(
modifier = Modifier.padding(4.dp), modifier = Modifier.padding(4.dp),
text = manga.title, text = manga.title,
fontSize = 12.sp,
maxLines = 2, maxLines = 2,
style = LocalTextStyle.current.copy(fontWeight = FontWeight.SemiBold), style = MaterialTheme.typography.titleSmall,
) )
} }
} }

View File

@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
import androidx.compose.foundation.layout.padding import androidx.compose.foundation.layout.padding
import androidx.compose.foundation.lazy.grid.items import androidx.compose.foundation.lazy.grid.items
import androidx.compose.foundation.shape.RoundedCornerShape import androidx.compose.foundation.shape.RoundedCornerShape
import androidx.compose.material3.LocalTextStyle import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Text import androidx.compose.material3.Text
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.ui.Alignment import androidx.compose.ui.Alignment
@ -17,8 +17,8 @@ import androidx.compose.ui.draw.clip
import androidx.compose.ui.graphics.Brush import androidx.compose.ui.graphics.Brush
import androidx.compose.ui.graphics.Color import androidx.compose.ui.graphics.Color
import androidx.compose.ui.graphics.Shadow import androidx.compose.ui.graphics.Shadow
import androidx.compose.ui.text.font.FontWeight
import androidx.compose.ui.unit.dp import androidx.compose.ui.unit.dp
import androidx.compose.ui.unit.sp
import eu.kanade.tachiyomi.data.database.models.LibraryManga import eu.kanade.tachiyomi.data.database.models.LibraryManga
import eu.kanade.tachiyomi.ui.library.LibraryItem import eu.kanade.tachiyomi.ui.library.LibraryItem
@ -102,10 +102,10 @@ fun LibraryCompactGridItem(
modifier = Modifier modifier = Modifier
.padding(8.dp) .padding(8.dp)
.align(Alignment.BottomStart), .align(Alignment.BottomStart),
color = Color.White,
fontSize = 12.sp,
maxLines = 2, maxLines = 2,
style = LocalTextStyle.current.copy( style = MaterialTheme.typography.titleSmall.copy(
color = Color.White,
fontWeight = FontWeight.SemiBold,
shadow = Shadow( shadow = Shadow(
color = Color.Black, color = Color.Black,
blurRadius = 4f, blurRadius = 4f,

View File

@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding
import androidx.compose.runtime.Composable import androidx.compose.runtime.Composable
import androidx.compose.runtime.LaunchedEffect import androidx.compose.runtime.LaunchedEffect
import androidx.compose.runtime.State import androidx.compose.runtime.State
import androidx.compose.runtime.remember
import androidx.compose.ui.Modifier import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalUriHandler import androidx.compose.ui.platform.LocalUriHandler
import com.google.accompanist.pager.rememberPagerState import com.google.accompanist.pager.rememberPagerState
@ -26,8 +27,8 @@ import eu.kanade.tachiyomi.widget.EmptyView
fun LibraryContent( fun LibraryContent(
state: LibraryState, state: LibraryState,
contentPadding: PaddingValues, contentPadding: PaddingValues,
currentPage: Int, currentPage: () -> Int,
isLibraryEmpty: Boolean, isLibraryEmpty: () -> Boolean,
isDownloadOnly: Boolean, isDownloadOnly: Boolean,
isIncognitoMode: Boolean, isIncognitoMode: Boolean,
showPageTabs: Boolean, showPageTabs: Boolean,
@ -42,12 +43,13 @@ fun LibraryContent(
getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>, getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
getLibraryForPage: @Composable (Int) -> State<List<LibraryItem>>, getLibraryForPage: @Composable (Int) -> State<List<LibraryItem>>,
) { ) {
val categories = state.categories
val pagerState = rememberPagerState(currentPage.coerceAtMost(categories.lastIndex))
Column( Column(
modifier = Modifier.padding(contentPadding), modifier = Modifier.padding(contentPadding),
) { ) {
val categories = state.categories
val coercedCurrentPage = remember { currentPage().coerceAtMost(categories.lastIndex) }
val pagerState = rememberPagerState(coercedCurrentPage)
if (showPageTabs && categories.size > 1) { if (showPageTabs && categories.size > 1) {
LibraryTabs( LibraryTabs(
state = pagerState, state = pagerState,
@ -72,7 +74,7 @@ fun LibraryContent(
SwipeRefresh( SwipeRefresh(
state = rememberSwipeRefreshState(isRefreshing = false), state = rememberSwipeRefreshState(isRefreshing = false),
onRefresh = { onRefresh(categories[currentPage]) }, onRefresh = { onRefresh(categories[currentPage()]) },
indicator = { s, trigger -> indicator = { s, trigger ->
SwipeRefreshIndicator( SwipeRefreshIndicator(
state = s, state = s,
@ -80,7 +82,7 @@ fun LibraryContent(
) )
}, },
) { ) {
if (state.searchQuery.isNullOrEmpty() && isLibraryEmpty) { if (state.searchQuery.isNullOrEmpty() && isLibraryEmpty()) {
val handler = LocalUriHandler.current val handler = LocalUriHandler.current
EmptyScreen( EmptyScreen(
R.string.information_empty_library, R.string.information_empty_library,

View File

@ -36,40 +36,43 @@ fun LibraryGridCover(
data = mangaCover, data = mangaCover,
) )
content() content()
BadgeGroup( if (downloadCount > 0 || unreadCount > 0) {
modifier = Modifier BadgeGroup(
.padding(4.dp) modifier = Modifier
.align(Alignment.TopStart), .padding(4.dp)
) { .align(Alignment.TopStart),
if (downloadCount > 0) { ) {
Badge( if (downloadCount > 0) {
text = "$downloadCount", Badge(
color = MaterialTheme.colorScheme.tertiary, text = "$downloadCount",
textColor = MaterialTheme.colorScheme.onTertiary, color = MaterialTheme.colorScheme.tertiary,
) textColor = MaterialTheme.colorScheme.onTertiary,
} )
if (unreadCount > 0) { }
Badge(text = "$unreadCount") if (unreadCount > 0) {
Badge(text = "$unreadCount")
}
} }
} }
BadgeGroup( if (isLocal || language.isNotEmpty()) {
modifier = Modifier BadgeGroup(
.padding(4.dp) modifier = Modifier
.align(Alignment.TopEnd), .padding(4.dp)
) { .align(Alignment.TopEnd),
if (isLocal) { ) {
Badge( if (isLocal) {
text = stringResource(R.string.local_source_badge), Badge(
color = MaterialTheme.colorScheme.tertiary, text = stringResource(R.string.local_source_badge),
textColor = MaterialTheme.colorScheme.onTertiary, color = MaterialTheme.colorScheme.tertiary,
) textColor = MaterialTheme.colorScheme.onTertiary,
} )
if (isLocal.not() && language.isNotEmpty()) { } else if (language.isNotEmpty()) {
Badge( Badge(
text = language, text = language,
color = MaterialTheme.colorScheme.tertiary, color = MaterialTheme.colorScheme.tertiary,
textColor = MaterialTheme.colorScheme.onTertiary, textColor = MaterialTheme.colorScheme.onTertiary,
) )
}
} }
} }
} }

View File

@ -36,6 +36,10 @@ fun LibraryPager(
state = state, state = state,
verticalAlignment = Alignment.Top, verticalAlignment = Alignment.Top,
) { page -> ) { page ->
if (page !in ((state.currentPage - 1)..(state.currentPage + 1))) {
// To make sure only one offscreen page is being composed
return@HorizontalPager
}
val library by getLibraryForPage(page) val library by getLibraryForPage(page)
val displayMode by getDisplayModeForPage(page) val displayMode by getDisplayModeForPage(page)
val columns by if (displayMode != DisplayModeSetting.LIST) { val columns by if (displayMode != DisplayModeSetting.LIST) {