123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197 |
- package eu.kanade.presentation.browse
- import androidx.compose.foundation.clickable
- import androidx.compose.foundation.layout.Column
- import androidx.compose.foundation.layout.PaddingValues
- import androidx.compose.foundation.layout.fillMaxWidth
- import androidx.compose.foundation.layout.padding
- import androidx.compose.foundation.lazy.items
- import androidx.compose.material.icons.Icons
- import androidx.compose.material.icons.filled.PushPin
- import androidx.compose.material.icons.outlined.PushPin
- import androidx.compose.material3.AlertDialog
- import androidx.compose.material3.Icon
- import androidx.compose.material3.IconButton
- import androidx.compose.material3.LocalTextStyle
- import androidx.compose.material3.MaterialTheme
- import androidx.compose.material3.Text
- import androidx.compose.material3.TextButton
- import androidx.compose.runtime.Composable
- import androidx.compose.ui.Modifier
- import androidx.compose.ui.platform.LocalContext
- import androidx.compose.ui.res.stringResource
- import androidx.compose.ui.unit.dp
- import eu.kanade.presentation.browse.components.BaseSourceItem
- import eu.kanade.presentation.components.EmptyScreen
- import eu.kanade.presentation.theme.header
- import eu.kanade.tachiyomi.R
- import eu.kanade.tachiyomi.source.LocalSource
- import eu.kanade.tachiyomi.ui.browse.source.SourcesState
- import eu.kanade.tachiyomi.ui.browse.source.browse.BrowseSourceScreenModel.Listing
- import eu.kanade.tachiyomi.util.system.LocaleHelper
- import tachiyomi.domain.source.model.Pin
- import tachiyomi.domain.source.model.Source
- import tachiyomi.presentation.core.components.LoadingScreen
- import tachiyomi.presentation.core.components.ScrollbarLazyColumn
- import tachiyomi.presentation.core.components.material.padding
- import tachiyomi.presentation.core.components.material.topSmallPaddingValues
- import tachiyomi.presentation.core.util.plus
- @Composable
- fun SourcesScreen(
- state: SourcesState,
- contentPadding: PaddingValues,
- onClickItem: (Source, Listing) -> Unit,
- onClickPin: (Source) -> Unit,
- onLongClickItem: (Source) -> Unit,
- ) {
- when {
- state.isLoading -> LoadingScreen(modifier = Modifier.padding(contentPadding))
- state.isEmpty -> EmptyScreen(
- textResource = R.string.source_empty_screen,
- modifier = Modifier.padding(contentPadding),
- )
- else -> {
- ScrollbarLazyColumn(
- contentPadding = contentPadding + topSmallPaddingValues,
- ) {
- items(
- items = state.items,
- contentType = {
- when (it) {
- is SourceUiModel.Header -> "header"
- is SourceUiModel.Item -> "item"
- }
- },
- key = {
- when (it) {
- is SourceUiModel.Header -> it.hashCode()
- is SourceUiModel.Item -> "source-${it.source.key()}"
- }
- },
- ) { model ->
- when (model) {
- is SourceUiModel.Header -> {
- SourceHeader(
- modifier = Modifier.animateItemPlacement(),
- language = model.language,
- )
- }
- is SourceUiModel.Item -> SourceItem(
- modifier = Modifier.animateItemPlacement(),
- source = model.source,
- onClickItem = onClickItem,
- onLongClickItem = onLongClickItem,
- onClickPin = onClickPin,
- )
- }
- }
- }
- }
- }
- }
- @Composable
- private fun SourceHeader(
- modifier: Modifier = Modifier,
- language: String,
- ) {
- val context = LocalContext.current
- Text(
- text = LocaleHelper.getSourceDisplayName(language, context),
- modifier = modifier
- .padding(horizontal = MaterialTheme.padding.medium, vertical = MaterialTheme.padding.small),
- style = MaterialTheme.typography.header,
- )
- }
- @Composable
- private fun SourceItem(
- modifier: Modifier = Modifier,
- source: Source,
- onClickItem: (Source, Listing) -> Unit,
- onLongClickItem: (Source) -> Unit,
- onClickPin: (Source) -> Unit,
- ) {
- BaseSourceItem(
- modifier = modifier,
- source = source,
- onClickItem = { onClickItem(source, Listing.Popular) },
- onLongClickItem = { onLongClickItem(source) },
- action = {
- if (source.supportsLatest) {
- TextButton(onClick = { onClickItem(source, Listing.Latest) }) {
- Text(
- text = stringResource(R.string.latest),
- style = LocalTextStyle.current.copy(
- color = MaterialTheme.colorScheme.primary,
- ),
- )
- }
- }
- SourcePinButton(
- isPinned = Pin.Pinned in source.pin,
- onClick = { onClickPin(source) },
- )
- },
- )
- }
- @Composable
- private fun SourcePinButton(
- isPinned: Boolean,
- onClick: () -> Unit,
- ) {
- val icon = if (isPinned) Icons.Filled.PushPin else Icons.Outlined.PushPin
- val tint = if (isPinned) MaterialTheme.colorScheme.primary else MaterialTheme.colorScheme.onBackground
- val description = if (isPinned) R.string.action_unpin else R.string.action_pin
- IconButton(onClick = onClick) {
- Icon(
- imageVector = icon,
- tint = tint,
- contentDescription = stringResource(description),
- )
- }
- }
- @Composable
- fun SourceOptionsDialog(
- source: Source,
- onClickPin: () -> Unit,
- onClickDisable: () -> Unit,
- onDismiss: () -> Unit,
- ) {
- AlertDialog(
- title = {
- Text(text = source.visualName)
- },
- text = {
- Column {
- val textId = if (Pin.Pinned in source.pin) R.string.action_unpin else R.string.action_pin
- Text(
- text = stringResource(textId),
- modifier = Modifier
- .clickable(onClick = onClickPin)
- .fillMaxWidth()
- .padding(vertical = 16.dp),
- )
- if (source.id != LocalSource.ID) {
- Text(
- text = stringResource(R.string.action_disable),
- modifier = Modifier
- .clickable(onClick = onClickDisable)
- .fillMaxWidth()
- .padding(vertical = 16.dp),
- )
- }
- }
- },
- onDismissRequest = onDismiss,
- confirmButton = {},
- )
- }
- sealed class SourceUiModel {
- data class Item(val source: Source) : SourceUiModel()
- data class Header(val language: String) : SourceUiModel()
- }
|