diff --git a/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt b/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt index 5869174c3f..25699a6a5f 100644 --- a/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt +++ b/app/src/main/java/eu/kanade/presentation/components/PullRefresh.kt @@ -14,6 +14,12 @@ import androidx.compose.ui.draw.clipToBounds import androidx.compose.ui.unit.dp /** + * @param refreshing Whether the layout is currently refreshing + * @param onRefresh Lambda which is invoked when a swipe to refresh gesture is completed. + * @param enabled Whether the the layout should react to swipe gestures or not. + * @param indicatorPadding Content padding for the indicator, to inset the indicator in if required. + * @param content The content containing a vertically scrollable composable. + * * Code reference: [Accompanist SwipeRefresh](https://github.com/google/accompanist/blob/677bc4ca0ee74677a8ba73793d04d85fe4ab55fb/swiperefresh/src/main/java/com/google/accompanist/swiperefresh/SwipeRefresh.kt#L265-L283) */ @Composable diff --git a/app/src/main/java/eu/kanade/presentation/library/components/GlobalSearchItem.kt b/app/src/main/java/eu/kanade/presentation/library/components/GlobalSearchItem.kt new file mode 100644 index 0000000000..6055745ea3 --- /dev/null +++ b/app/src/main/java/eu/kanade/presentation/library/components/GlobalSearchItem.kt @@ -0,0 +1,26 @@ +package eu.kanade.presentation.library.components + +import androidx.compose.material3.Text +import androidx.compose.material3.TextButton +import androidx.compose.runtime.Composable +import androidx.compose.ui.Modifier +import androidx.compose.ui.res.stringResource +import androidx.compose.ui.zIndex +import eu.kanade.tachiyomi.R + +@Composable +fun GlobalSearchItem( + searchQuery: String, + onClick: () -> Unit, + modifier: Modifier = Modifier, +) { + TextButton( + modifier = modifier, + onClick = onClick, + ) { + Text( + text = stringResource(R.string.action_global_search_query, searchQuery), + modifier = Modifier.zIndex(99f), + ) + } +} diff --git a/app/src/main/java/eu/kanade/presentation/library/components/LazyLibraryGrid.kt b/app/src/main/java/eu/kanade/presentation/library/components/LazyLibraryGrid.kt index 6e7a109ec0..cd0601ac22 100644 --- a/app/src/main/java/eu/kanade/presentation/library/components/LazyLibraryGrid.kt +++ b/app/src/main/java/eu/kanade/presentation/library/components/LazyLibraryGrid.kt @@ -5,17 +5,12 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.lazy.grid.GridCells import androidx.compose.foundation.lazy.grid.GridItemSpan import androidx.compose.foundation.lazy.grid.LazyGridScope -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp -import androidx.compose.ui.zIndex import eu.kanade.presentation.components.CommonMangaItemDefaults import eu.kanade.presentation.components.FastScrollLazyVerticalGrid import eu.kanade.presentation.util.plus -import eu.kanade.tachiyomi.R @Composable fun LazyLibraryGrid( @@ -43,12 +38,10 @@ fun LazyGridScope.globalSearchItem( span = { GridItemSpan(maxLineSpan) }, contentType = { "library_global_search_item" }, ) { - TextButton(onClick = onGlobalSearchClicked) { - Text( - text = stringResource(R.string.action_global_search_query, searchQuery!!), - modifier = Modifier.zIndex(99f), - ) - } + GlobalSearchItem( + searchQuery = searchQuery, + onClick = onGlobalSearchClicked, + ) } } } 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 05aa6a88e9..ee39501461 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,7 +2,6 @@ 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,7 +22,6 @@ fun LibraryComfortableGrid( onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - hasActiveFilters: Boolean, ) { LazyLibraryGrid( modifier = Modifier.fillMaxSize(), @@ -32,48 +30,39 @@ fun LibraryComfortableGrid( ) { globalSearchItem(searchQuery, onGlobalSearchClicked) - 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 - }, - ) - } + 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 c36958bbe5..de3309325b 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,7 +2,6 @@ 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 @@ -24,7 +23,6 @@ fun LibraryCompactGrid( onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - hasActiveFilters: Boolean, ) { LazyLibraryGrid( modifier = Modifier.fillMaxSize(), @@ -33,48 +31,39 @@ fun LibraryCompactGrid( ) { globalSearchItem(searchQuery, onGlobalSearchClicked) - 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 - }, - ) - } + 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 6e7aab9e80..4be5ebaa52 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 @@ -4,20 +4,15 @@ import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.lazy.items -import androidx.compose.material3.Text -import androidx.compose.material3.TextButton import androidx.compose.runtime.Composable import androidx.compose.ui.Modifier -import androidx.compose.ui.res.stringResource import androidx.compose.ui.unit.dp import androidx.compose.ui.util.fastAny -import androidx.compose.ui.zIndex import eu.kanade.domain.library.model.LibraryManga import eu.kanade.domain.manga.model.MangaCover import eu.kanade.presentation.components.FastScrollLazyColumn import eu.kanade.presentation.components.MangaListItem import eu.kanade.presentation.util.plus -import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.library.LibraryItem @Composable @@ -30,7 +25,6 @@ fun LibraryList( onClickContinueReading: ((LibraryManga) -> Unit)?, searchQuery: String?, onGlobalSearchClicked: () -> Unit, - hasActiveFilters: Boolean, ) { FastScrollLazyColumn( modifier = Modifier.fillMaxSize(), @@ -38,57 +32,45 @@ fun LibraryList( ) { item { if (!searchQuery.isNullOrEmpty()) { - TextButton( + GlobalSearchItem( modifier = Modifier.fillMaxWidth(), + searchQuery = searchQuery, onClick = onGlobalSearchClicked, - ) { - Text( - text = stringResource(R.string.action_global_search_query, searchQuery), - modifier = Modifier.zIndex(99f), - ) - } - } - } - - 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 - }, ) } } + + 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 a844a73725..f121152fac 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 @@ -1,9 +1,13 @@ package eu.kanade.presentation.library.components import android.content.res.Configuration +import androidx.compose.foundation.layout.Column import androidx.compose.foundation.layout.PaddingValues import androidx.compose.foundation.layout.fillMaxSize +import androidx.compose.foundation.layout.fillMaxWidth import androidx.compose.foundation.layout.padding +import androidx.compose.foundation.rememberScrollState +import androidx.compose.foundation.verticalScroll import androidx.compose.runtime.Composable import androidx.compose.runtime.getValue import androidx.compose.runtime.mutableStateOf @@ -11,12 +15,14 @@ import androidx.compose.runtime.remember import androidx.compose.ui.Alignment import androidx.compose.ui.Modifier import androidx.compose.ui.platform.LocalConfiguration +import androidx.compose.ui.unit.dp import eu.kanade.core.prefs.PreferenceMutableState import eu.kanade.domain.library.model.LibraryDisplayMode import eu.kanade.domain.library.model.LibraryManga import eu.kanade.presentation.components.EmptyScreen import eu.kanade.presentation.components.HorizontalPager import eu.kanade.presentation.components.PagerState +import eu.kanade.presentation.util.plus import eu.kanade.tachiyomi.R import eu.kanade.tachiyomi.ui.library.LibraryItem @@ -48,6 +54,16 @@ fun LibraryPager( } val library = getLibraryForPage(page) + if (library.isEmpty()) { + LibraryPagerEmptyScreen( + searchQuery = searchQuery, + hasActiveFilters = hasActiveFilters, + contentPadding = contentPadding, + onGlobalSearchClicked = onGlobalSearchClicked, + ) + return@HorizontalPager + } + val displayMode = getDisplayModeForPage(page) val columns by if (displayMode != LibraryDisplayMode.List) { val configuration = LocalConfiguration.current @@ -69,7 +85,6 @@ fun LibraryPager( onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - hasActiveFilters = hasActiveFilters, ) } LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> { @@ -84,7 +99,6 @@ fun LibraryPager( onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - hasActiveFilters = hasActiveFilters, ) } LibraryDisplayMode.ComfortableGrid -> { @@ -98,7 +112,6 @@ fun LibraryPager( onClickContinueReading = onClickContinueReading, searchQuery = searchQuery, onGlobalSearchClicked = onGlobalSearchClicked, - hasActiveFilters = hasActiveFilters, ) } } @@ -106,10 +119,11 @@ fun LibraryPager( } @Composable -internal fun LibraryPagerEmptyScreen( +private fun LibraryPagerEmptyScreen( searchQuery: String?, hasActiveFilters: Boolean, contentPadding: PaddingValues, + onGlobalSearchClicked: () -> Unit, ) { val msg = when { !searchQuery.isNullOrEmpty() -> R.string.no_results_found @@ -117,9 +131,25 @@ internal fun LibraryPagerEmptyScreen( else -> R.string.information_no_manga_category } - // TODO: vertically center this better - EmptyScreen( - textResource = msg, - modifier = Modifier.padding(contentPadding), - ) + Column( + modifier = Modifier + .padding(contentPadding + PaddingValues(8.dp)) + .fillMaxSize() + .verticalScroll(rememberScrollState()), + ) { + if (!searchQuery.isNullOrEmpty()) { + GlobalSearchItem( + modifier = Modifier + .fillMaxWidth() + .align(Alignment.CenterHorizontally), + searchQuery = searchQuery, + onClick = onGlobalSearchClicked, + ) + } + + EmptyScreen( + textResource = msg, + modifier = Modifier.weight(1f), + ) + } }