From 376bbeb724ca6cb7de53213c478d1750d99c8d2a Mon Sep 17 00:00:00 2001 From: arkon Date: Sat, 17 Dec 2022 12:06:02 -0500 Subject: [PATCH] Move library page EmptyScreens into list/grids It does look awkward due to the lack of filled height within those list/grids though. Fixes #8720 Fixes #8721 --- .../presentation/components/EmptyScreen.kt | 100 +++++++----------- .../components/LibraryComfortableGrid.kt | 77 ++++++++------ .../library/components/LibraryCompactGrid.kt | 77 ++++++++------ .../library/components/LibraryList.kt | 71 +++++++------ .../library/components/LibraryPager.kt | 11 +- .../settings/screen/SettingsSearchScreen.kt | 74 ++++++------- 6 files changed, 206 insertions(+), 204 deletions(-) diff --git a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt index 44885c1dcf..9e9711841e 100644 --- a/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/components/EmptyScreen.kt @@ -22,12 +22,9 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.graphics.vector.ImageVector -import androidx.compose.ui.layout.Layout -import androidx.compose.ui.layout.layoutId import androidx.compose.ui.res.stringResource import androidx.compose.ui.text.style.TextAlign import androidx.compose.ui.unit.dp -import androidx.compose.ui.util.fastFirstOrNull import eu.kanade.presentation.theme.TachiyomiTheme import eu.kanade.presentation.util.ThemePreviews import eu.kanade.presentation.util.secondaryItemAlpha @@ -54,68 +51,45 @@ fun EmptyScreen( actions: List? = null, ) { val face = remember { getRandomErrorFace() } - Layout( - content = { - Column( - modifier = Modifier - .layoutId("face") - .padding(horizontal = 24.dp), - horizontalAlignment = Alignment.CenterHorizontally, - ) { - Text( - text = face, - modifier = Modifier.secondaryItemAlpha(), - style = MaterialTheme.typography.displayMedium, - ) + Column( + modifier = modifier + .fillMaxSize() + .padding(horizontal = 24.dp), + horizontalAlignment = Alignment.CenterHorizontally, + verticalArrangement = Arrangement.Center, + ) { + Text( + text = face, + modifier = Modifier.secondaryItemAlpha(), + style = MaterialTheme.typography.displayMedium, + ) - Text( - text = message, - modifier = Modifier.paddingFromBaseline(top = 24.dp).secondaryItemAlpha(), - style = MaterialTheme.typography.bodyMedium, - textAlign = TextAlign.Center, - ) - } - if (!actions.isNullOrEmpty()) { - Row( - modifier = Modifier - .layoutId("actions") - .padding( - top = 24.dp, - start = horizontalPadding, - end = horizontalPadding, - ), - horizontalArrangement = Arrangement.spacedBy(space = 8.dp), - ) { - actions.forEach { - ActionButton( - modifier = Modifier.weight(1f), - title = stringResource(it.stringResId), - icon = it.icon, - onClick = it.onClick, - ) - } + Text( + text = message, + modifier = Modifier.paddingFromBaseline(top = 24.dp).secondaryItemAlpha(), + style = MaterialTheme.typography.bodyMedium, + textAlign = TextAlign.Center, + ) + + if (!actions.isNullOrEmpty()) { + Row( + modifier = Modifier + .padding( + top = 24.dp, + start = 24.dp, + end = 24.dp, + ), + horizontalArrangement = Arrangement.spacedBy(space = 8.dp), + ) { + actions.forEach { + ActionButton( + modifier = Modifier.weight(1f), + title = stringResource(it.stringResId), + icon = it.icon, + onClick = it.onClick, + ) } } - }, - modifier = modifier.fillMaxSize(), - ) { measurables, constraints -> - val looseConstraints = constraints.copy(minWidth = 0, minHeight = 0) - val facePlaceable = measurables.fastFirstOrNull { it.layoutId == "face" }!! - .measure(looseConstraints) - val actionsPlaceable = measurables.fastFirstOrNull { it.layoutId == "actions" } - ?.measure(looseConstraints) - - layout(constraints.maxWidth, constraints.maxHeight) { - val faceY = (constraints.maxHeight - facePlaceable.height) / 2 - facePlaceable.placeRelative( - x = (constraints.maxWidth - facePlaceable.width) / 2, - y = faceY, - ) - - actionsPlaceable?.placeRelative( - x = (constraints.maxWidth - actionsPlaceable.width) / 2, - y = faceY + facePlaceable.height, - ) } } } @@ -187,8 +161,6 @@ data class EmptyScreenAction( val onClick: () -> Unit, ) -private val horizontalPadding = 24.dp - private val ERROR_FACES = listOf( "(・o・;)", "Σ(ಠ_ಠ)", diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt index ee39501461..05aa6a88e9 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryComfortableGrid.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.library.components import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.items import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -22,6 +23,7 @@ fun LibraryComfortableGrid( onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, + hasActiveFilters: Boolean, ) { LazyLibraryGrid( modifier = Modifier.fillMaxSize(), @@ -30,39 +32,48 @@ fun LibraryComfortableGrid( ) { globalSearchItem(searchQuery, onGlobalSearchClicked) - items( - items = items, - contentType = { "library_comfortable_grid_item" }, - ) { libraryItem -> - val manga = libraryItem.libraryManga.manga - MangaComfortableGridItem( - isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id }, - title = manga.title, - coverData = MangaCover( - mangaId = manga.id, - sourceId = manga.source, - isMangaFavorite = manga.favorite, - url = manga.thumbnailUrl, - lastModified = manga.coverLastModified, - ), - coverBadgeStart = { - DownloadsBadge(count = libraryItem.downloadCount.toInt()) - UnreadBadge(count = libraryItem.unreadCount.toInt()) - }, - coverBadgeEnd = { - LanguageBadge( - isLocal = libraryItem.isLocal, - sourceLanguage = libraryItem.sourceLanguage, - ) - }, - onLongClick = { onLongClick(libraryItem.libraryManga) }, - onClick = { onClick(libraryItem.libraryManga) }, - onClickContinueReading = if (onClickContinueReading != null) { - { onClickContinueReading(libraryItem.libraryManga) } - } else { - null - }, - ) + if (items.isEmpty()) { + item( + span = { GridItemSpan(maxLineSpan) }, + contentType = "library_comfortable_grid_empty", + ) { + LibraryPagerEmptyScreen(searchQuery, hasActiveFilters, contentPadding) + } + } else { + items( + items = items, + contentType = { "library_comfortable_grid_item" }, + ) { libraryItem -> + val manga = libraryItem.libraryManga.manga + MangaComfortableGridItem( + isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id }, + title = manga.title, + coverData = MangaCover( + mangaId = manga.id, + sourceId = manga.source, + isMangaFavorite = manga.favorite, + url = manga.thumbnailUrl, + lastModified = manga.coverLastModified, + ), + coverBadgeStart = { + DownloadsBadge(count = libraryItem.downloadCount.toInt()) + UnreadBadge(count = libraryItem.unreadCount.toInt()) + }, + coverBadgeEnd = { + LanguageBadge( + isLocal = libraryItem.isLocal, + sourceLanguage = libraryItem.sourceLanguage, + ) + }, + onLongClick = { onLongClick(libraryItem.libraryManga) }, + onClick = { onClick(libraryItem.libraryManga) }, + onClickContinueReading = if (onClickContinueReading != null) { + { onClickContinueReading(libraryItem.libraryManga) } + } else { + null + }, + ) + } } } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt index de3309325b..c36958bbe5 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryCompactGrid.kt @@ -2,6 +2,7 @@ package eu.kanade.presentation.library.components import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.items import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier @@ -23,6 +24,7 @@ fun LibraryCompactGrid( onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, + hasActiveFilters: Boolean, ) { LazyLibraryGrid( modifier = Modifier.fillMaxSize(), @@ -31,39 +33,48 @@ fun LibraryCompactGrid( ) { globalSearchItem(searchQuery, onGlobalSearchClicked) - items( - items = items, - contentType = { "library_compact_grid_item" }, - ) { libraryItem -> - val manga = libraryItem.libraryManga.manga - MangaCompactGridItem( - isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id }, - title = manga.title.takeIf { showTitle }, - coverData = MangaCover( - mangaId = manga.id, - sourceId = manga.source, - isMangaFavorite = manga.favorite, - url = manga.thumbnailUrl, - lastModified = manga.coverLastModified, - ), - coverBadgeStart = { - DownloadsBadge(count = libraryItem.downloadCount.toInt()) - UnreadBadge(count = libraryItem.unreadCount.toInt()) - }, - coverBadgeEnd = { - LanguageBadge( - isLocal = libraryItem.isLocal, - sourceLanguage = libraryItem.sourceLanguage, - ) - }, - onLongClick = { onLongClick(libraryItem.libraryManga) }, - onClick = { onClick(libraryItem.libraryManga) }, - onClickContinueReading = if (onClickContinueReading != null) { - { onClickContinueReading(libraryItem.libraryManga) } - } else { - null - }, - ) + if (items.isEmpty()) { + item( + span = { GridItemSpan(maxLineSpan) }, + contentType = "library_compact_grid_empty", + ) { + LibraryPagerEmptyScreen(searchQuery, hasActiveFilters, contentPadding) + } + } else { + items( + items = items, + contentType = { "library_compact_grid_item" }, + ) { libraryItem -> + val manga = libraryItem.libraryManga.manga + MangaCompactGridItem( + isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id }, + title = manga.title.takeIf { showTitle }, + coverData = MangaCover( + mangaId = manga.id, + sourceId = manga.source, + isMangaFavorite = manga.favorite, + url = manga.thumbnailUrl, + lastModified = manga.coverLastModified, + ), + coverBadgeStart = { + DownloadsBadge(count = libraryItem.downloadCount.toInt()) + UnreadBadge(count = libraryItem.unreadCount.toInt()) + }, + coverBadgeEnd = { + LanguageBadge( + isLocal = libraryItem.isLocal, + sourceLanguage = libraryItem.sourceLanguage, + ) + }, + onLongClick = { onLongClick(libraryItem.libraryManga) }, + onClick = { onClick(libraryItem.libraryManga) }, + onClickContinueReading = if (onClickContinueReading != null) { + { onClickContinueReading(libraryItem.libraryManga) } + } else { + null + }, + ) + } } } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt index be8015020f..6e7aab9e80 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryList.kt @@ -30,6 +30,7 @@ fun LibraryList( onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, + hasActiveFilters: Boolean, ) { FastScrollLazyColumn( modifier = Modifier.fillMaxSize(), @@ -49,37 +50,45 @@ fun LibraryList( } } - items( - items = items, - contentType = { "library_list_item" }, - ) { libraryItem -> - val manga = libraryItem.libraryManga.manga - MangaListItem( - isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id }, - title = manga.title, - coverData = MangaCover( - mangaId = manga.id, - sourceId = manga.source, - isMangaFavorite = manga.favorite, - url = manga.thumbnailUrl, - lastModified = manga.coverLastModified, - ), - badge = { - DownloadsBadge(count = libraryItem.downloadCount.toInt()) - UnreadBadge(count = libraryItem.unreadCount.toInt()) - LanguageBadge( - isLocal = libraryItem.isLocal, - sourceLanguage = libraryItem.sourceLanguage, - ) - }, - onLongClick = { onLongClick(libraryItem.libraryManga) }, - onClick = { onClick(libraryItem.libraryManga) }, - onClickContinueReading = if (onClickContinueReading != null) { - { onClickContinueReading(libraryItem.libraryManga) } - } else { - null - }, - ) + if (items.isEmpty()) { + item( + contentType = "library_list_empty", + ) { + LibraryPagerEmptyScreen(searchQuery, hasActiveFilters, contentPadding) + } + } else { + items( + items = items, + contentType = { "library_list_item" }, + ) { libraryItem -> + val manga = libraryItem.libraryManga.manga + MangaListItem( + isSelected = selection.fastAny { it.id == libraryItem.libraryManga.id }, + title = manga.title, + coverData = MangaCover( + mangaId = manga.id, + sourceId = manga.source, + isMangaFavorite = manga.favorite, + url = manga.thumbnailUrl, + lastModified = manga.coverLastModified, + ), + badge = { + DownloadsBadge(count = libraryItem.downloadCount.toInt()) + UnreadBadge(count = libraryItem.unreadCount.toInt()) + LanguageBadge( + isLocal = libraryItem.isLocal, + sourceLanguage = libraryItem.sourceLanguage, + ) + }, + onLongClick = { onLongClick(libraryItem.libraryManga) }, + onClick = { onClick(libraryItem.libraryManga) }, + onClickContinueReading = if (onClickContinueReading != null) { + { onClickContinueReading(libraryItem.libraryManga) } + } else { + null + }, + ) + } } } } diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt b/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt index 6fec3b4ad5..a844a73725 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LibraryPager.kt @@ -48,11 +48,6 @@ fun LibraryPager( } val library = getLibraryForPage(page) - if (library.isEmpty()) { - LibraryPagerEmptyScreen(searchQuery, hasActiveFilters, contentPadding) - return@HorizontalPager - } - val displayMode = getDisplayModeForPage(page) val columns by if (displayMode != LibraryDisplayMode.List) { val configuration = LocalConfiguration.current @@ -74,6 +69,7 @@ fun LibraryPager( onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, + hasActiveFilters = hasActiveFilters, ) } LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> { @@ -88,6 +84,7 @@ fun LibraryPager( onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, + hasActiveFilters = hasActiveFilters, ) } LibraryDisplayMode.ComfortableGrid -> { @@ -101,6 +98,7 @@ fun LibraryPager( onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, + hasActiveFilters = hasActiveFilters, ) } } @@ -108,7 +106,7 @@ fun LibraryPager( } @Composable -private fun LibraryPagerEmptyScreen( +internal fun LibraryPagerEmptyScreen( searchQuery: String?, hasActiveFilters: Boolean, contentPadding: PaddingValues, @@ -119,6 +117,7 @@ private fun LibraryPagerEmptyScreen( else -> R.string.information_no_manga_category } + // TODO: vertically center this better EmptyScreen( textResource = msg, modifier = Modifier.padding(contentPadding), diff --git a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt index 846add570e..5fde035729 100644 --- a/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt +++ b/app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsSearchScreen.kt @@ -212,43 +212,43 @@ private fun SearchResult( } Crossfade(targetState = result) { - LazyColumn( - modifier = modifier.fillMaxSize(), - state = listState, - contentPadding = contentPadding, - horizontalAlignment = Alignment.CenterHorizontally, - ) { - when { - it == null -> { - /* Don't show anything just yet */ - } - // No result - it.isEmpty() -> item { EmptyScreen(stringResource(R.string.no_results_found)) } - // Show result list - else -> items( - items = it, - key = { i -> i.hashCode() }, - ) { item -> - Column( - modifier = Modifier - .fillMaxWidth() - .clickable { onItemClick(item) } - .padding(horizontal = 24.dp, vertical = 14.dp), - ) { - Text( - text = item.title, - overflow = TextOverflow.Ellipsis, - maxLines = 1, - fontWeight = FontWeight.Normal, - style = MaterialTheme.typography.titleMedium, - ) - Text( - text = item.breadcrumbs, - modifier = Modifier.paddingFromBaseline(top = 16.dp), - maxLines = 1, - color = MaterialTheme.colorScheme.onSurfaceVariant, - style = MaterialTheme.typography.bodySmall, - ) + when { + it == null -> {} + it.isEmpty() -> { + EmptyScreen(stringResource(R.string.no_results_found)) + } + else -> { + LazyColumn( + modifier = modifier.fillMaxSize(), + state = listState, + contentPadding = contentPadding, + horizontalAlignment = Alignment.CenterHorizontally, + ) { + items( + items = it, + key = { i -> i.hashCode() }, + ) { item -> + Column( + modifier = Modifier + .fillMaxWidth() + .clickable { onItemClick(item) } + .padding(horizontal = 24.dp, vertical = 14.dp), + ) { + Text( + text = item.title, + overflow = TextOverflow.Ellipsis, + maxLines = 1, + fontWeight = FontWeight.Normal, + style = MaterialTheme.typography.titleMedium, + ) + Text( + text = item.breadcrumbs, + modifier = Modifier.paddingFromBaseline(top = 16.dp), + maxLines = 1, + color = MaterialTheme.colorScheme.onSurfaceVariant, + style = MaterialTheme.typography.bodySmall, + ) + } } } }