2022-05-07 23:34:55 -04:00
|
|
|
package eu.kanade.presentation.browse
|
|
|
|
|
2022-05-19 17:31:07 -04:00
|
|
|
import android.util.DisplayMetrics
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.annotation.StringRes
|
|
|
|
import androidx.compose.foundation.background
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.foundation.clickable
|
|
|
|
import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
|
|
import androidx.compose.foundation.layout.Arrangement
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.foundation.layout.Box
|
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
|
import androidx.compose.foundation.layout.Row
|
|
|
|
import androidx.compose.foundation.layout.Spacer
|
|
|
|
import androidx.compose.foundation.layout.WindowInsets
|
|
|
|
import androidx.compose.foundation.layout.asPaddingValues
|
|
|
|
import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
|
import androidx.compose.foundation.layout.height
|
|
|
|
import androidx.compose.foundation.layout.navigationBars
|
|
|
|
import androidx.compose.foundation.layout.padding
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.foundation.layout.size
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.foundation.layout.width
|
|
|
|
import androidx.compose.foundation.lazy.items
|
|
|
|
import androidx.compose.material.icons.Icons
|
|
|
|
import androidx.compose.material.icons.outlined.Settings
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.material3.AlertDialog
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.material3.Button
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.material3.Divider
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.material3.Icon
|
|
|
|
import androidx.compose.material3.IconButton
|
|
|
|
import androidx.compose.material3.MaterialTheme
|
|
|
|
import androidx.compose.material3.OutlinedButton
|
|
|
|
import androidx.compose.material3.Switch
|
|
|
|
import androidx.compose.material3.Text
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.material3.TextButton
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.runtime.Composable
|
|
|
|
import androidx.compose.runtime.collectAsState
|
|
|
|
import androidx.compose.runtime.getValue
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.runtime.mutableStateOf
|
|
|
|
import androidx.compose.runtime.remember
|
2022-05-19 17:43:27 -04:00
|
|
|
import androidx.compose.runtime.setValue
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.ui.Alignment
|
|
|
|
import androidx.compose.ui.Modifier
|
|
|
|
import androidx.compose.ui.input.nestedscroll.NestedScrollConnection
|
|
|
|
import androidx.compose.ui.input.nestedscroll.nestedScroll
|
|
|
|
import androidx.compose.ui.platform.LocalContext
|
|
|
|
import androidx.compose.ui.res.stringResource
|
2022-05-19 17:31:07 -04:00
|
|
|
import androidx.compose.ui.text.TextStyle
|
|
|
|
import androidx.compose.ui.text.font.FontWeight
|
2022-06-07 17:47:46 -04:00
|
|
|
import androidx.compose.ui.text.style.TextAlign
|
2022-05-07 23:34:55 -04:00
|
|
|
import androidx.compose.ui.unit.dp
|
|
|
|
import eu.kanade.presentation.browse.components.ExtensionIcon
|
2022-05-19 17:43:27 -04:00
|
|
|
import eu.kanade.presentation.components.DIVIDER_ALPHA
|
2022-05-07 23:34:55 -04:00
|
|
|
import eu.kanade.presentation.components.Divider
|
|
|
|
import eu.kanade.presentation.components.EmptyScreen
|
|
|
|
import eu.kanade.presentation.components.PreferenceRow
|
2022-05-23 18:03:46 -04:00
|
|
|
import eu.kanade.presentation.components.ScrollbarLazyColumn
|
2022-05-07 23:34:55 -04:00
|
|
|
import eu.kanade.presentation.util.horizontalPadding
|
|
|
|
import eu.kanade.tachiyomi.R
|
|
|
|
import eu.kanade.tachiyomi.extension.model.Extension
|
|
|
|
import eu.kanade.tachiyomi.source.ConfigurableSource
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionDetailsPresenter
|
|
|
|
import eu.kanade.tachiyomi.ui.browse.extension.details.ExtensionSourceItem
|
|
|
|
import eu.kanade.tachiyomi.util.system.LocaleHelper
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
fun ExtensionDetailsScreen(
|
|
|
|
nestedScrollInterop: NestedScrollConnection,
|
|
|
|
presenter: ExtensionDetailsPresenter,
|
|
|
|
onClickUninstall: () -> Unit,
|
|
|
|
onClickAppInfo: () -> Unit,
|
|
|
|
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
|
|
|
onClickSource: (sourceId: Long) -> Unit,
|
|
|
|
) {
|
|
|
|
val extension = presenter.extension
|
|
|
|
|
|
|
|
if (extension == null) {
|
|
|
|
EmptyScreen(textResource = R.string.empty_screen)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
val sources by presenter.sourcesState.collectAsState()
|
|
|
|
|
2022-05-19 17:43:27 -04:00
|
|
|
var showNsfwWarning by remember { mutableStateOf(false) }
|
2022-05-19 17:31:07 -04:00
|
|
|
|
2022-05-23 18:03:46 -04:00
|
|
|
ScrollbarLazyColumn(
|
2022-05-07 23:34:55 -04:00
|
|
|
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
|
|
|
contentPadding = WindowInsets.navigationBars.asPaddingValues(),
|
|
|
|
) {
|
2022-05-16 12:04:54 -04:00
|
|
|
when {
|
|
|
|
extension.isUnofficial ->
|
|
|
|
item {
|
|
|
|
WarningBanner(R.string.unofficial_extension_message)
|
|
|
|
}
|
|
|
|
extension.isObsolete ->
|
|
|
|
item {
|
|
|
|
WarningBanner(R.string.obsolete_extension_message)
|
|
|
|
}
|
2022-05-07 23:34:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
item {
|
2022-05-19 17:31:07 -04:00
|
|
|
DetailsHeader(
|
|
|
|
extension = extension,
|
|
|
|
onClickUninstall = onClickUninstall,
|
|
|
|
onClickAppInfo = onClickAppInfo,
|
|
|
|
onClickAgeRating = {
|
2022-05-19 17:43:27 -04:00
|
|
|
showNsfwWarning = true
|
2022-05-19 17:31:07 -04:00
|
|
|
},
|
|
|
|
)
|
2022-05-07 23:34:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
items(
|
|
|
|
items = sources,
|
|
|
|
key = { it.source.id },
|
|
|
|
) { source ->
|
|
|
|
SourceSwitchPreference(
|
|
|
|
modifier = Modifier.animateItemPlacement(),
|
|
|
|
source = source,
|
|
|
|
onClickSourcePreferences = onClickSourcePreferences,
|
|
|
|
onClickSource = onClickSource,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
2022-05-19 17:31:07 -04:00
|
|
|
if (showNsfwWarning) {
|
|
|
|
NsfwWarningDialog(
|
|
|
|
onClickConfirm = {
|
2022-05-19 17:43:27 -04:00
|
|
|
showNsfwWarning = false
|
2022-05-19 17:31:07 -04:00
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2022-05-07 23:34:55 -04:00
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
private fun WarningBanner(@StringRes textRes: Int) {
|
|
|
|
Box(
|
|
|
|
modifier = Modifier
|
|
|
|
.fillMaxWidth()
|
|
|
|
.background(MaterialTheme.colorScheme.error)
|
|
|
|
.padding(16.dp),
|
|
|
|
contentAlignment = Alignment.Center,
|
|
|
|
) {
|
|
|
|
Text(
|
|
|
|
text = stringResource(textRes),
|
|
|
|
color = MaterialTheme.colorScheme.onError,
|
2022-06-07 17:47:46 -04:00
|
|
|
style = MaterialTheme.typography.bodyMedium,
|
2022-05-07 23:34:55 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
private fun DetailsHeader(
|
|
|
|
extension: Extension,
|
2022-05-19 17:31:07 -04:00
|
|
|
onClickAgeRating: () -> Unit,
|
2022-05-07 23:34:55 -04:00
|
|
|
onClickUninstall: () -> Unit,
|
|
|
|
onClickAppInfo: () -> Unit,
|
|
|
|
) {
|
|
|
|
val context = LocalContext.current
|
|
|
|
|
|
|
|
Column {
|
2022-05-19 17:31:07 -04:00
|
|
|
Column(
|
|
|
|
modifier = Modifier
|
|
|
|
.fillMaxWidth()
|
|
|
|
.padding(
|
|
|
|
start = horizontalPadding,
|
|
|
|
end = horizontalPadding,
|
|
|
|
top = 16.dp,
|
|
|
|
bottom = 8.dp,
|
|
|
|
),
|
|
|
|
horizontalAlignment = Alignment.CenterHorizontally,
|
2022-05-07 23:34:55 -04:00
|
|
|
) {
|
|
|
|
ExtensionIcon(
|
|
|
|
modifier = Modifier
|
2022-05-19 17:31:07 -04:00
|
|
|
.size(112.dp),
|
2022-05-07 23:34:55 -04:00
|
|
|
extension = extension,
|
2022-05-19 17:31:07 -04:00
|
|
|
density = DisplayMetrics.DENSITY_XXXHIGH,
|
2022-05-07 23:34:55 -04:00
|
|
|
)
|
|
|
|
|
2022-05-19 17:31:07 -04:00
|
|
|
Text(
|
|
|
|
text = extension.name,
|
|
|
|
style = MaterialTheme.typography.headlineSmall,
|
|
|
|
)
|
|
|
|
|
|
|
|
val strippedPkgName = extension.pkgName.substringAfter("eu.kanade.tachiyomi.extension.")
|
|
|
|
|
|
|
|
Text(
|
|
|
|
text = strippedPkgName,
|
|
|
|
style = MaterialTheme.typography.bodySmall,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
|
|
|
|
Row(
|
|
|
|
modifier = Modifier
|
|
|
|
.fillMaxWidth()
|
|
|
|
.padding(
|
|
|
|
horizontal = horizontalPadding * 2,
|
|
|
|
vertical = 8.dp,
|
|
|
|
),
|
|
|
|
horizontalArrangement = Arrangement.SpaceEvenly,
|
|
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
|
|
) {
|
|
|
|
InfoText(
|
2022-06-07 17:47:46 -04:00
|
|
|
modifier = Modifier.weight(1f),
|
2022-05-19 17:31:07 -04:00
|
|
|
primaryText = extension.versionName,
|
|
|
|
secondaryText = stringResource(R.string.ext_info_version),
|
|
|
|
)
|
|
|
|
|
|
|
|
InfoDivider()
|
|
|
|
|
|
|
|
InfoText(
|
2022-06-07 17:47:46 -04:00
|
|
|
modifier = Modifier.weight(if (extension.isNsfw) 1.5f else 1f),
|
2022-05-19 17:31:07 -04:00
|
|
|
primaryText = LocaleHelper.getSourceDisplayName(extension.lang, context),
|
|
|
|
secondaryText = stringResource(R.string.ext_info_language),
|
|
|
|
)
|
|
|
|
|
|
|
|
if (extension.isNsfw) {
|
|
|
|
InfoDivider()
|
|
|
|
|
|
|
|
InfoText(
|
2022-06-07 17:47:46 -04:00
|
|
|
modifier = Modifier.weight(1f),
|
2022-05-19 17:31:07 -04:00
|
|
|
primaryText = stringResource(R.string.ext_nsfw_short),
|
|
|
|
primaryTextStyle = MaterialTheme.typography.bodyLarge.copy(
|
2022-05-07 23:34:55 -04:00
|
|
|
color = MaterialTheme.colorScheme.error,
|
2022-05-19 17:31:07 -04:00
|
|
|
fontWeight = FontWeight.Medium,
|
|
|
|
),
|
|
|
|
secondaryText = stringResource(R.string.ext_info_age_rating),
|
2022-05-19 17:43:27 -04:00
|
|
|
onClick = onClickAgeRating,
|
2022-05-07 23:34:55 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Row(
|
|
|
|
modifier = Modifier.padding(
|
|
|
|
start = horizontalPadding,
|
|
|
|
end = horizontalPadding,
|
|
|
|
top = 8.dp,
|
|
|
|
bottom = 16.dp,
|
|
|
|
),
|
|
|
|
) {
|
|
|
|
OutlinedButton(
|
|
|
|
modifier = Modifier.weight(1f),
|
|
|
|
onClick = onClickUninstall,
|
|
|
|
) {
|
|
|
|
Text(stringResource(R.string.ext_uninstall))
|
|
|
|
}
|
|
|
|
|
|
|
|
Spacer(Modifier.width(16.dp))
|
|
|
|
|
|
|
|
Button(
|
|
|
|
modifier = Modifier.weight(1f),
|
|
|
|
onClick = onClickAppInfo,
|
|
|
|
) {
|
|
|
|
Text(
|
|
|
|
text = stringResource(R.string.ext_app_info),
|
|
|
|
color = MaterialTheme.colorScheme.onPrimary,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Divider()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2022-05-19 17:31:07 -04:00
|
|
|
@Composable
|
|
|
|
private fun InfoText(
|
2022-06-07 17:47:46 -04:00
|
|
|
modifier: Modifier,
|
2022-05-19 17:31:07 -04:00
|
|
|
primaryText: String,
|
|
|
|
primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge,
|
|
|
|
secondaryText: String,
|
2022-05-19 17:43:27 -04:00
|
|
|
onClick: (() -> Unit)? = null,
|
2022-05-19 17:31:07 -04:00
|
|
|
) {
|
|
|
|
val interactionSource = remember { MutableInteractionSource() }
|
|
|
|
|
2022-06-07 17:47:46 -04:00
|
|
|
val clickableModifier = if (onClick != null) {
|
2022-05-19 17:43:27 -04:00
|
|
|
Modifier.clickable(interactionSource, indication = null) { onClick() }
|
2022-05-19 17:31:07 -04:00
|
|
|
} else Modifier
|
|
|
|
|
|
|
|
Column(
|
2022-06-07 17:47:46 -04:00
|
|
|
modifier = modifier.then(clickableModifier),
|
2022-05-19 17:31:07 -04:00
|
|
|
horizontalAlignment = Alignment.CenterHorizontally,
|
|
|
|
verticalArrangement = Arrangement.Center,
|
|
|
|
) {
|
|
|
|
Text(
|
|
|
|
text = primaryText,
|
2022-06-07 17:47:46 -04:00
|
|
|
textAlign = TextAlign.Center,
|
2022-05-19 17:31:07 -04:00
|
|
|
style = primaryTextStyle,
|
|
|
|
)
|
|
|
|
|
|
|
|
Text(
|
2022-05-19 17:43:27 -04:00
|
|
|
text = secondaryText + if (onClick != null) " ⓘ" else "",
|
2022-06-07 17:47:46 -04:00
|
|
|
textAlign = TextAlign.Center,
|
2022-05-19 17:31:07 -04:00
|
|
|
style = MaterialTheme.typography.bodyMedium,
|
2022-05-19 17:43:27 -04:00
|
|
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5f),
|
2022-05-19 17:31:07 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
private fun InfoDivider() {
|
|
|
|
Divider(
|
|
|
|
modifier = Modifier
|
|
|
|
.height(20.dp)
|
|
|
|
.width(1.dp),
|
2022-05-19 17:43:27 -04:00
|
|
|
color = MaterialTheme.colorScheme.onSurface.copy(alpha = DIVIDER_ALPHA),
|
2022-05-19 17:31:07 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
|
2022-05-07 23:34:55 -04:00
|
|
|
@Composable
|
|
|
|
private fun SourceSwitchPreference(
|
|
|
|
modifier: Modifier = Modifier,
|
|
|
|
source: ExtensionSourceItem,
|
|
|
|
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
|
|
|
onClickSource: (sourceId: Long) -> Unit,
|
|
|
|
) {
|
|
|
|
val context = LocalContext.current
|
|
|
|
|
|
|
|
PreferenceRow(
|
|
|
|
modifier = modifier,
|
|
|
|
title = if (source.labelAsName) {
|
|
|
|
source.source.toString()
|
|
|
|
} else {
|
|
|
|
LocaleHelper.getSourceDisplayName(source.source.lang, context)
|
|
|
|
},
|
|
|
|
onClick = { onClickSource(source.source.id) },
|
|
|
|
action = {
|
|
|
|
Row(
|
|
|
|
verticalAlignment = Alignment.CenterVertically,
|
|
|
|
) {
|
|
|
|
if (source.source is ConfigurableSource) {
|
|
|
|
IconButton(onClick = { onClickSourcePreferences(source.source.id) }) {
|
|
|
|
Icon(
|
|
|
|
imageVector = Icons.Outlined.Settings,
|
|
|
|
contentDescription = stringResource(R.string.label_settings),
|
|
|
|
tint = MaterialTheme.colorScheme.onSurface,
|
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Switch(checked = source.enabled, onCheckedChange = null)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
2022-05-19 17:31:07 -04:00
|
|
|
|
|
|
|
@Composable
|
|
|
|
fun NsfwWarningDialog(
|
|
|
|
onClickConfirm: () -> Unit,
|
|
|
|
) {
|
|
|
|
AlertDialog(
|
|
|
|
text = {
|
2022-05-19 17:43:27 -04:00
|
|
|
Text(text = stringResource(R.string.ext_nsfw_warning))
|
2022-05-19 17:31:07 -04:00
|
|
|
},
|
|
|
|
confirmButton = {
|
|
|
|
TextButton(onClick = onClickConfirm) {
|
2022-05-19 17:43:27 -04:00
|
|
|
Text(text = stringResource(android.R.string.ok))
|
2022-05-19 17:31:07 -04:00
|
|
|
}
|
|
|
|
},
|
|
|
|
onDismissRequest = onClickConfirm,
|
|
|
|
)
|
|
|
|
}
|