
(cherry picked from commit aa498360db90350f2642e6320dc55e7d474df1fd) # Conflicts: # app/build.gradle.kts # app/src/main/java/eu/kanade/domain/base/BasePreferences.kt # app/src/main/java/eu/kanade/domain/chapter/interactor/SetReadStatus.kt # app/src/main/java/eu/kanade/presentation/library/LibrarySettingsDialog.kt # app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsAdvancedScreen.kt # app/src/main/java/eu/kanade/presentation/more/settings/screen/SettingsBrowseScreen.kt # app/src/main/java/eu/kanade/tachiyomi/App.kt # app/src/main/java/eu/kanade/tachiyomi/Migrations.kt # app/src/main/java/eu/kanade/tachiyomi/data/backup/create/BackupCreator.kt # app/src/main/java/eu/kanade/tachiyomi/data/library/LibraryUpdateJob.kt # app/src/main/java/eu/kanade/tachiyomi/data/updater/AppUpdateChecker.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/MigrateDialog.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/migration/search/SourceSearchScreen.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/SourcesScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/BrowseSourceScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/browse/source/browse/SourceFilterDialog.kt # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/library/LibraryTab.kt # app/src/main/java/eu/kanade/tachiyomi/ui/main/MainActivity.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreen.kt # app/src/main/java/eu/kanade/tachiyomi/ui/manga/MangaScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderActivity.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/ReaderViewModel.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ChapterLoader.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/RarPageLoader.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/loader/ZipPageLoader.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/setting/ReaderPreferences.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerPageHolder.kt # app/src/main/java/eu/kanade/tachiyomi/ui/reader/viewer/pager/PagerViewerAdapter.kt # app/src/main/java/eu/kanade/tachiyomi/ui/stats/StatsScreenModel.kt # app/src/main/java/eu/kanade/tachiyomi/util/CrashLogUtil.kt # core/common/src/main/kotlin/eu/kanade/tachiyomi/util/storage/CbzCrypto.kt # data/src/main/java/tachiyomi/data/manga/MangaRepositoryImpl.kt # data/src/main/java/tachiyomi/data/source/SourcePagingSource.kt # domain/src/main/java/tachiyomi/domain/library/service/LibraryPreferences.kt # domain/src/main/java/tachiyomi/domain/manga/model/Manga.kt # settings.gradle.kts # source-api/src/commonMain/kotlin/eu/kanade/tachiyomi/source/online/HttpSource.kt # source-local/src/androidMain/kotlin/tachiyomi/source/local/image/LocalCoverManager.kt
200 lines
7.3 KiB
Kotlin
200 lines
7.3 KiB
Kotlin
package eu.kanade.presentation.browse
|
|
|
|
import androidx.compose.foundation.layout.PaddingValues
|
|
import androidx.compose.foundation.layout.padding
|
|
import androidx.compose.foundation.lazy.grid.GridCells
|
|
import androidx.compose.material.icons.Icons
|
|
import androidx.compose.material.icons.automirrored.outlined.HelpOutline
|
|
import androidx.compose.material.icons.outlined.Public
|
|
import androidx.compose.material.icons.outlined.Refresh
|
|
import androidx.compose.material3.SnackbarDuration
|
|
import androidx.compose.material3.SnackbarHostState
|
|
import androidx.compose.material3.SnackbarResult
|
|
import androidx.compose.runtime.Composable
|
|
import androidx.compose.runtime.LaunchedEffect
|
|
import androidx.compose.ui.Modifier
|
|
import androidx.compose.ui.platform.LocalContext
|
|
import androidx.paging.LoadState
|
|
import androidx.paging.compose.LazyPagingItems
|
|
import eu.kanade.presentation.browse.components.BrowseSourceComfortableGrid
|
|
import eu.kanade.presentation.browse.components.BrowseSourceCompactGrid
|
|
import eu.kanade.presentation.browse.components.BrowseSourceEHentaiList
|
|
import eu.kanade.presentation.browse.components.BrowseSourceList
|
|
import eu.kanade.presentation.components.AppBar
|
|
import eu.kanade.presentation.util.formattedMessage
|
|
import eu.kanade.tachiyomi.source.Source
|
|
import exh.metadata.metadata.RaisedSearchMetadata
|
|
import exh.source.isEhBasedSource
|
|
import kotlinx.collections.immutable.persistentListOf
|
|
import kotlinx.collections.immutable.toImmutableList
|
|
import kotlinx.coroutines.flow.StateFlow
|
|
import tachiyomi.core.common.i18n.stringResource
|
|
import tachiyomi.domain.library.model.LibraryDisplayMode
|
|
import tachiyomi.domain.manga.model.Manga
|
|
import tachiyomi.domain.source.model.StubSource
|
|
import tachiyomi.i18n.MR
|
|
import tachiyomi.presentation.core.components.material.Scaffold
|
|
import tachiyomi.presentation.core.i18n.stringResource
|
|
import tachiyomi.presentation.core.screens.EmptyScreen
|
|
import tachiyomi.presentation.core.screens.EmptyScreenAction
|
|
import tachiyomi.presentation.core.screens.LoadingScreen
|
|
import tachiyomi.source.local.LocalSource
|
|
|
|
@Composable
|
|
fun BrowseSourceContent(
|
|
source: Source?,
|
|
mangaList: LazyPagingItems<StateFlow</* SY --> */Pair<Manga, RaisedSearchMetadata?>/* SY <-- */>>,
|
|
columns: GridCells,
|
|
// SY -->
|
|
ehentaiBrowseDisplayMode: Boolean,
|
|
// SY <--
|
|
displayMode: LibraryDisplayMode,
|
|
snackbarHostState: SnackbarHostState,
|
|
contentPadding: PaddingValues,
|
|
// SY -->
|
|
onWebViewClick: (() -> Unit)?,
|
|
onHelpClick: (() -> Unit)?,
|
|
onLocalSourceHelpClick: (() -> Unit)?,
|
|
// SY <--
|
|
onMangaClick: (Manga) -> Unit,
|
|
onMangaLongClick: (Manga) -> Unit,
|
|
) {
|
|
val context = LocalContext.current
|
|
|
|
val errorState = mangaList.loadState.refresh.takeIf { it is LoadState.Error }
|
|
?: mangaList.loadState.append.takeIf { it is LoadState.Error }
|
|
|
|
val getErrorMessage: (LoadState.Error) -> String = { state ->
|
|
with(context) { state.error.formattedMessage }
|
|
}
|
|
|
|
LaunchedEffect(errorState) {
|
|
if (mangaList.itemCount > 0 && errorState != null && errorState is LoadState.Error) {
|
|
val result = snackbarHostState.showSnackbar(
|
|
message = getErrorMessage(errorState),
|
|
actionLabel = context.stringResource(MR.strings.action_retry),
|
|
duration = SnackbarDuration.Indefinite,
|
|
)
|
|
when (result) {
|
|
SnackbarResult.Dismissed -> snackbarHostState.currentSnackbarData?.dismiss()
|
|
SnackbarResult.ActionPerformed -> mangaList.retry()
|
|
}
|
|
}
|
|
}
|
|
|
|
if (mangaList.itemCount <= 0 && errorState != null && errorState is LoadState.Error) {
|
|
EmptyScreen(
|
|
modifier = Modifier.padding(contentPadding),
|
|
message = getErrorMessage(errorState),
|
|
actions = if (source is LocalSource /* SY --> */ && onLocalSourceHelpClick != null /* SY <-- */) {
|
|
persistentListOf(
|
|
EmptyScreenAction(
|
|
stringRes = MR.strings.local_source_help_guide,
|
|
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
|
onClick = onLocalSourceHelpClick,
|
|
),
|
|
)
|
|
} else {
|
|
listOfNotNull(
|
|
EmptyScreenAction(
|
|
stringRes = MR.strings.action_retry,
|
|
icon = Icons.Outlined.Refresh,
|
|
onClick = mangaList::refresh,
|
|
),
|
|
// SY -->
|
|
if (onWebViewClick != null) {
|
|
EmptyScreenAction(
|
|
MR.strings.action_open_in_web_view,
|
|
icon = Icons.Outlined.Public,
|
|
onClick = onWebViewClick,
|
|
)
|
|
} else {
|
|
null
|
|
},
|
|
if (onHelpClick != null) {
|
|
EmptyScreenAction(
|
|
MR.strings.label_help,
|
|
icon = Icons.AutoMirrored.Outlined.HelpOutline,
|
|
onClick = onHelpClick,
|
|
)
|
|
} else {
|
|
null
|
|
},
|
|
// SY <--
|
|
).toImmutableList()
|
|
},
|
|
)
|
|
|
|
return
|
|
}
|
|
|
|
if (mangaList.itemCount == 0 && mangaList.loadState.refresh is LoadState.Loading) {
|
|
LoadingScreen(
|
|
modifier = Modifier.padding(contentPadding),
|
|
)
|
|
return
|
|
}
|
|
|
|
// SY -->
|
|
if (source?.isEhBasedSource() == true && ehentaiBrowseDisplayMode) {
|
|
BrowseSourceEHentaiList(
|
|
mangaList = mangaList,
|
|
contentPadding = contentPadding,
|
|
onMangaClick = onMangaClick,
|
|
onMangaLongClick = onMangaLongClick,
|
|
)
|
|
return
|
|
}
|
|
// SY <--
|
|
|
|
when (displayMode) {
|
|
LibraryDisplayMode.ComfortableGrid -> {
|
|
BrowseSourceComfortableGrid(
|
|
mangaList = mangaList,
|
|
columns = columns,
|
|
contentPadding = contentPadding,
|
|
onMangaClick = onMangaClick,
|
|
onMangaLongClick = onMangaLongClick,
|
|
)
|
|
}
|
|
LibraryDisplayMode.List -> {
|
|
BrowseSourceList(
|
|
mangaList = mangaList,
|
|
contentPadding = contentPadding,
|
|
onMangaClick = onMangaClick,
|
|
onMangaLongClick = onMangaLongClick,
|
|
)
|
|
}
|
|
LibraryDisplayMode.CompactGrid, LibraryDisplayMode.CoverOnlyGrid -> {
|
|
BrowseSourceCompactGrid(
|
|
mangaList = mangaList,
|
|
columns = columns,
|
|
contentPadding = contentPadding,
|
|
onMangaClick = onMangaClick,
|
|
onMangaLongClick = onMangaLongClick,
|
|
)
|
|
}
|
|
}
|
|
}
|
|
|
|
@Composable
|
|
internal fun MissingSourceScreen(
|
|
source: StubSource,
|
|
navigateUp: () -> Unit,
|
|
) {
|
|
Scaffold(
|
|
topBar = { scrollBehavior ->
|
|
AppBar(
|
|
title = source.name,
|
|
navigateUp = navigateUp,
|
|
scrollBehavior = scrollBehavior,
|
|
)
|
|
},
|
|
) { paddingValues ->
|
|
EmptyScreen(
|
|
message = stringResource(MR.strings.source_not_installed, source.toString()),
|
|
modifier = Modifier.padding(paddingValues),
|
|
)
|
|
}
|
|
}
|