mirror of
				https://github.com/mihonapp/mihon.git
				synced 2025-11-04 08:08:55 +01:00 
			
		
		
		
	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:
		@@ -1,12 +1,10 @@
 | 
			
		||||
package eu.kanade.presentation.components
 | 
			
		||||
 | 
			
		||||
import androidx.compose.foundation.background
 | 
			
		||||
import androidx.compose.foundation.layout.Box
 | 
			
		||||
import androidx.compose.foundation.layout.Row
 | 
			
		||||
import androidx.compose.foundation.layout.RowScope
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.shape.RoundedCornerShape
 | 
			
		||||
import androidx.compose.material3.LocalTextStyle
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
@@ -36,18 +34,15 @@ fun Badge(
 | 
			
		||||
    textColor: Color = MaterialTheme.colorScheme.onSecondary,
 | 
			
		||||
    shape: Shape = RectangleShape,
 | 
			
		||||
) {
 | 
			
		||||
    Box(
 | 
			
		||||
    Text(
 | 
			
		||||
        text = text,
 | 
			
		||||
        modifier = Modifier
 | 
			
		||||
            .clip(shape)
 | 
			
		||||
            .background(color),
 | 
			
		||||
    ) {
 | 
			
		||||
        Text(
 | 
			
		||||
            text = text,
 | 
			
		||||
            modifier = Modifier.padding(horizontal = 4.dp, vertical = 2.dp),
 | 
			
		||||
            style = LocalTextStyle.current.copy(
 | 
			
		||||
                color = textColor,
 | 
			
		||||
                fontWeight = FontWeight.Medium,
 | 
			
		||||
            ),
 | 
			
		||||
        )
 | 
			
		||||
    }
 | 
			
		||||
            .background(color)
 | 
			
		||||
            .padding(horizontal = 3.dp, vertical = 1.dp),
 | 
			
		||||
        color = textColor,
 | 
			
		||||
        fontWeight = FontWeight.Medium,
 | 
			
		||||
        maxLines = 1,
 | 
			
		||||
        style = MaterialTheme.typography.bodySmall,
 | 
			
		||||
    )
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -61,8 +61,8 @@ fun LibraryScreen(
 | 
			
		||||
                LibraryContent(
 | 
			
		||||
                    state = presenter,
 | 
			
		||||
                    contentPadding = paddingValues,
 | 
			
		||||
                    currentPage = presenter.activeCategory,
 | 
			
		||||
                    isLibraryEmpty = presenter.loadedManga.isEmpty(),
 | 
			
		||||
                    currentPage = { presenter.activeCategory },
 | 
			
		||||
                    isLibraryEmpty = { presenter.loadedManga.isEmpty() },
 | 
			
		||||
                    showPageTabs = presenter.tabVisibility,
 | 
			
		||||
                    showMangaCount = presenter.mangaCountVisibility,
 | 
			
		||||
                    onChangeCurrentPage = { presenter.activeCategory = it },
 | 
			
		||||
 
 | 
			
		||||
@@ -4,12 +4,12 @@ import androidx.compose.foundation.combinedClickable
 | 
			
		||||
import androidx.compose.foundation.layout.Column
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
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.runtime.Composable
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.text.font.FontWeight
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.compose.ui.unit.sp
 | 
			
		||||
import eu.kanade.domain.manga.model.MangaCover
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
 | 
			
		||||
@@ -81,8 +81,9 @@ fun LibraryComfortableGridItem(
 | 
			
		||||
            Text(
 | 
			
		||||
                modifier = Modifier.padding(4.dp),
 | 
			
		||||
                text = manga.title,
 | 
			
		||||
                fontSize = 12.sp,
 | 
			
		||||
                maxLines = 2,
 | 
			
		||||
                style = LocalTextStyle.current.copy(fontWeight = FontWeight.SemiBold),
 | 
			
		||||
                style = MaterialTheme.typography.titleSmall,
 | 
			
		||||
            )
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -8,7 +8,7 @@ import androidx.compose.foundation.layout.fillMaxWidth
 | 
			
		||||
import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.foundation.lazy.grid.items
 | 
			
		||||
import androidx.compose.foundation.shape.RoundedCornerShape
 | 
			
		||||
import androidx.compose.material3.LocalTextStyle
 | 
			
		||||
import androidx.compose.material3.MaterialTheme
 | 
			
		||||
import androidx.compose.material3.Text
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
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.Color
 | 
			
		||||
import androidx.compose.ui.graphics.Shadow
 | 
			
		||||
import androidx.compose.ui.text.font.FontWeight
 | 
			
		||||
import androidx.compose.ui.unit.dp
 | 
			
		||||
import androidx.compose.ui.unit.sp
 | 
			
		||||
import eu.kanade.tachiyomi.data.database.models.LibraryManga
 | 
			
		||||
import eu.kanade.tachiyomi.ui.library.LibraryItem
 | 
			
		||||
 | 
			
		||||
@@ -102,10 +102,10 @@ fun LibraryCompactGridItem(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .padding(8.dp)
 | 
			
		||||
                .align(Alignment.BottomStart),
 | 
			
		||||
            color = Color.White,
 | 
			
		||||
            fontSize = 12.sp,
 | 
			
		||||
            maxLines = 2,
 | 
			
		||||
            style = LocalTextStyle.current.copy(
 | 
			
		||||
                color = Color.White,
 | 
			
		||||
                fontWeight = FontWeight.SemiBold,
 | 
			
		||||
            style = MaterialTheme.typography.titleSmall.copy(
 | 
			
		||||
                shadow = Shadow(
 | 
			
		||||
                    color = Color.Black,
 | 
			
		||||
                    blurRadius = 4f,
 | 
			
		||||
 
 | 
			
		||||
@@ -6,6 +6,7 @@ import androidx.compose.foundation.layout.padding
 | 
			
		||||
import androidx.compose.runtime.Composable
 | 
			
		||||
import androidx.compose.runtime.LaunchedEffect
 | 
			
		||||
import androidx.compose.runtime.State
 | 
			
		||||
import androidx.compose.runtime.remember
 | 
			
		||||
import androidx.compose.ui.Modifier
 | 
			
		||||
import androidx.compose.ui.platform.LocalUriHandler
 | 
			
		||||
import com.google.accompanist.pager.rememberPagerState
 | 
			
		||||
@@ -26,8 +27,8 @@ import eu.kanade.tachiyomi.widget.EmptyView
 | 
			
		||||
fun LibraryContent(
 | 
			
		||||
    state: LibraryState,
 | 
			
		||||
    contentPadding: PaddingValues,
 | 
			
		||||
    currentPage: Int,
 | 
			
		||||
    isLibraryEmpty: Boolean,
 | 
			
		||||
    currentPage: () -> Int,
 | 
			
		||||
    isLibraryEmpty: () -> Boolean,
 | 
			
		||||
    isDownloadOnly: Boolean,
 | 
			
		||||
    isIncognitoMode: Boolean,
 | 
			
		||||
    showPageTabs: Boolean,
 | 
			
		||||
@@ -42,12 +43,13 @@ fun LibraryContent(
 | 
			
		||||
    getColumnsForOrientation: (Boolean) -> PreferenceMutableState<Int>,
 | 
			
		||||
    getLibraryForPage: @Composable (Int) -> State<List<LibraryItem>>,
 | 
			
		||||
) {
 | 
			
		||||
    val categories = state.categories
 | 
			
		||||
    val pagerState = rememberPagerState(currentPage.coerceAtMost(categories.lastIndex))
 | 
			
		||||
 | 
			
		||||
    Column(
 | 
			
		||||
        modifier = Modifier.padding(contentPadding),
 | 
			
		||||
    ) {
 | 
			
		||||
        val categories = state.categories
 | 
			
		||||
        val coercedCurrentPage = remember { currentPage().coerceAtMost(categories.lastIndex) }
 | 
			
		||||
        val pagerState = rememberPagerState(coercedCurrentPage)
 | 
			
		||||
 | 
			
		||||
        if (showPageTabs && categories.size > 1) {
 | 
			
		||||
            LibraryTabs(
 | 
			
		||||
                state = pagerState,
 | 
			
		||||
@@ -72,7 +74,7 @@ fun LibraryContent(
 | 
			
		||||
 | 
			
		||||
        SwipeRefresh(
 | 
			
		||||
            state = rememberSwipeRefreshState(isRefreshing = false),
 | 
			
		||||
            onRefresh = { onRefresh(categories[currentPage]) },
 | 
			
		||||
            onRefresh = { onRefresh(categories[currentPage()]) },
 | 
			
		||||
            indicator = { s, trigger ->
 | 
			
		||||
                SwipeRefreshIndicator(
 | 
			
		||||
                    state = s,
 | 
			
		||||
@@ -80,7 +82,7 @@ fun LibraryContent(
 | 
			
		||||
                )
 | 
			
		||||
            },
 | 
			
		||||
        ) {
 | 
			
		||||
            if (state.searchQuery.isNullOrEmpty() && isLibraryEmpty) {
 | 
			
		||||
            if (state.searchQuery.isNullOrEmpty() && isLibraryEmpty()) {
 | 
			
		||||
                val handler = LocalUriHandler.current
 | 
			
		||||
                EmptyScreen(
 | 
			
		||||
                    R.string.information_empty_library,
 | 
			
		||||
 
 | 
			
		||||
@@ -36,40 +36,43 @@ fun LibraryGridCover(
 | 
			
		||||
            data = mangaCover,
 | 
			
		||||
        )
 | 
			
		||||
        content()
 | 
			
		||||
        BadgeGroup(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .padding(4.dp)
 | 
			
		||||
                .align(Alignment.TopStart),
 | 
			
		||||
        ) {
 | 
			
		||||
            if (downloadCount > 0) {
 | 
			
		||||
                Badge(
 | 
			
		||||
                    text = "$downloadCount",
 | 
			
		||||
                    color = MaterialTheme.colorScheme.tertiary,
 | 
			
		||||
                    textColor = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            if (unreadCount > 0) {
 | 
			
		||||
                Badge(text = "$unreadCount")
 | 
			
		||||
        if (downloadCount > 0 || unreadCount > 0) {
 | 
			
		||||
            BadgeGroup(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(4.dp)
 | 
			
		||||
                    .align(Alignment.TopStart),
 | 
			
		||||
            ) {
 | 
			
		||||
                if (downloadCount > 0) {
 | 
			
		||||
                    Badge(
 | 
			
		||||
                        text = "$downloadCount",
 | 
			
		||||
                        color = MaterialTheme.colorScheme.tertiary,
 | 
			
		||||
                        textColor = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
                if (unreadCount > 0) {
 | 
			
		||||
                    Badge(text = "$unreadCount")
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        BadgeGroup(
 | 
			
		||||
            modifier = Modifier
 | 
			
		||||
                .padding(4.dp)
 | 
			
		||||
                .align(Alignment.TopEnd),
 | 
			
		||||
        ) {
 | 
			
		||||
            if (isLocal) {
 | 
			
		||||
                Badge(
 | 
			
		||||
                    text = stringResource(R.string.local_source_badge),
 | 
			
		||||
                    color = MaterialTheme.colorScheme.tertiary,
 | 
			
		||||
                    textColor = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
                )
 | 
			
		||||
            }
 | 
			
		||||
            if (isLocal.not() && language.isNotEmpty()) {
 | 
			
		||||
                Badge(
 | 
			
		||||
                    text = language,
 | 
			
		||||
                    color = MaterialTheme.colorScheme.tertiary,
 | 
			
		||||
                    textColor = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
                )
 | 
			
		||||
        if (isLocal || language.isNotEmpty()) {
 | 
			
		||||
            BadgeGroup(
 | 
			
		||||
                modifier = Modifier
 | 
			
		||||
                    .padding(4.dp)
 | 
			
		||||
                    .align(Alignment.TopEnd),
 | 
			
		||||
            ) {
 | 
			
		||||
                if (isLocal) {
 | 
			
		||||
                    Badge(
 | 
			
		||||
                        text = stringResource(R.string.local_source_badge),
 | 
			
		||||
                        color = MaterialTheme.colorScheme.tertiary,
 | 
			
		||||
                        textColor = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
                    )
 | 
			
		||||
                } else if (language.isNotEmpty()) {
 | 
			
		||||
                    Badge(
 | 
			
		||||
                        text = language,
 | 
			
		||||
                        color = MaterialTheme.colorScheme.tertiary,
 | 
			
		||||
                        textColor = MaterialTheme.colorScheme.onTertiary,
 | 
			
		||||
                    )
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 
 | 
			
		||||
@@ -36,6 +36,10 @@ fun LibraryPager(
 | 
			
		||||
        state = state,
 | 
			
		||||
        verticalAlignment = Alignment.Top,
 | 
			
		||||
    ) { 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 displayMode by getDisplayModeForPage(page)
 | 
			
		||||
        val columns by if (displayMode != DisplayModeSetting.LIST) {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user