2022-05-07 23:34:55 -04:00
|
|
|
package eu.kanade.presentation.browse
|
|
|
|
|
2022-07-16 14:44:37 -04:00
|
|
|
import android.content.Intent
|
|
|
|
import android.net.Uri
|
|
|
|
import android.provider.Settings
|
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
|
2022-08-29 16:10:55 -04:00
|
|
|
import androidx.compose.foundation.layout.PaddingValues
|
2022-05-07 23:34:55 -04:00
|
|
|
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
|
2022-08-29 16:10:55 -04:00
|
|
|
import androidx.compose.material.icons.outlined.HelpOutline
|
|
|
|
import androidx.compose.material.icons.outlined.History
|
2022-05-07 23:34:55 -04:00
|
|
|
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.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.platform.LocalContext
|
2022-08-29 16:10:55 -04:00
|
|
|
import androidx.compose.ui.platform.LocalUriHandler
|
2022-05-07 23:34:55 -04:00
|
|
|
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-08-29 16:10:55 -04:00
|
|
|
import eu.kanade.presentation.components.AppBar
|
|
|
|
import eu.kanade.presentation.components.AppBarActions
|
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
|
2022-07-16 14:44:37 -04:00
|
|
|
import eu.kanade.presentation.components.LoadingScreen
|
2022-05-07 23:34:55 -04:00
|
|
|
import eu.kanade.presentation.components.PreferenceRow
|
2022-08-29 16:10:55 -04:00
|
|
|
import eu.kanade.presentation.components.Scaffold
|
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
|
2022-08-29 16:10:55 -04:00
|
|
|
import eu.kanade.presentation.util.plus
|
2022-05-07 23:34:55 -04:00
|
|
|
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(
|
2022-08-29 16:10:55 -04:00
|
|
|
navigateUp: () -> Unit,
|
|
|
|
presenter: ExtensionDetailsPresenter,
|
|
|
|
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
|
|
|
) {
|
|
|
|
val uriHandler = LocalUriHandler.current
|
|
|
|
|
|
|
|
Scaffold(
|
2022-08-31 16:31:08 -04:00
|
|
|
topBar = { scrollBehavior ->
|
2022-08-29 16:10:55 -04:00
|
|
|
AppBar(
|
|
|
|
title = stringResource(R.string.label_extension_info),
|
|
|
|
navigateUp = navigateUp,
|
|
|
|
actions = {
|
|
|
|
AppBarActions(
|
|
|
|
actions = buildList {
|
|
|
|
if (presenter.extension?.isUnofficial == false) {
|
|
|
|
add(
|
|
|
|
AppBar.Action(
|
|
|
|
title = stringResource(R.string.whats_new),
|
|
|
|
icon = Icons.Outlined.History,
|
|
|
|
onClick = { uriHandler.openUri(presenter.getChangelogUrl()) },
|
|
|
|
),
|
|
|
|
)
|
|
|
|
add(
|
|
|
|
AppBar.Action(
|
|
|
|
title = stringResource(R.string.action_faq_and_guides),
|
|
|
|
icon = Icons.Outlined.HelpOutline,
|
|
|
|
onClick = { uriHandler.openUri(presenter.getReadmeUrl()) },
|
|
|
|
),
|
|
|
|
)
|
|
|
|
}
|
|
|
|
addAll(
|
|
|
|
listOf(
|
|
|
|
AppBar.OverflowAction(
|
|
|
|
title = stringResource(R.string.action_enable_all),
|
|
|
|
onClick = { presenter.toggleSources(true) },
|
|
|
|
),
|
|
|
|
AppBar.OverflowAction(
|
|
|
|
title = stringResource(R.string.action_disable_all),
|
|
|
|
onClick = { presenter.toggleSources(false) },
|
|
|
|
),
|
|
|
|
AppBar.OverflowAction(
|
|
|
|
title = stringResource(R.string.pref_clear_cookies),
|
|
|
|
onClick = { presenter.clearCookies() },
|
|
|
|
),
|
|
|
|
),
|
|
|
|
)
|
|
|
|
},
|
|
|
|
)
|
|
|
|
},
|
2022-08-31 16:31:08 -04:00
|
|
|
scrollBehavior = scrollBehavior,
|
2022-08-29 16:10:55 -04:00
|
|
|
)
|
|
|
|
},
|
|
|
|
) { paddingValues ->
|
|
|
|
ExtensionDetails(paddingValues, presenter, onClickSourcePreferences)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Composable
|
|
|
|
private fun ExtensionDetails(
|
|
|
|
paddingValues: PaddingValues,
|
2022-05-07 23:34:55 -04:00
|
|
|
presenter: ExtensionDetailsPresenter,
|
|
|
|
onClickSourcePreferences: (sourceId: Long) -> Unit,
|
|
|
|
) {
|
2022-07-16 14:44:37 -04:00
|
|
|
when {
|
|
|
|
presenter.isLoading -> LoadingScreen()
|
|
|
|
presenter.extension == null -> EmptyScreen(textResource = R.string.empty_screen)
|
|
|
|
else -> {
|
|
|
|
val context = LocalContext.current
|
|
|
|
val extension = presenter.extension
|
|
|
|
var showNsfwWarning by remember { mutableStateOf(false) }
|
2022-05-07 23:34:55 -04:00
|
|
|
|
2022-07-16 14:44:37 -04:00
|
|
|
ScrollbarLazyColumn(
|
2022-08-29 16:10:55 -04:00
|
|
|
contentPadding = paddingValues + WindowInsets.navigationBars.asPaddingValues(),
|
2022-07-16 14:44:37 -04:00
|
|
|
) {
|
|
|
|
when {
|
|
|
|
extension.isUnofficial ->
|
|
|
|
item {
|
|
|
|
WarningBanner(R.string.unofficial_extension_message)
|
|
|
|
}
|
|
|
|
extension.isObsolete ->
|
|
|
|
item {
|
|
|
|
WarningBanner(R.string.obsolete_extension_message)
|
|
|
|
}
|
2022-05-16 12:04:54 -04:00
|
|
|
}
|
2022-07-16 14:44:37 -04:00
|
|
|
|
2022-05-16 12:04:54 -04:00
|
|
|
item {
|
2022-07-16 14:44:37 -04:00
|
|
|
DetailsHeader(
|
|
|
|
extension = extension,
|
2022-08-29 16:10:55 -04:00
|
|
|
onClickUninstall = { presenter.uninstallExtension() },
|
2022-07-16 14:44:37 -04:00
|
|
|
onClickAppInfo = {
|
|
|
|
Intent(Settings.ACTION_APPLICATION_DETAILS_SETTINGS).apply {
|
|
|
|
data = Uri.fromParts("package", extension.pkgName, null)
|
|
|
|
context.startActivity(this)
|
|
|
|
}
|
|
|
|
},
|
|
|
|
onClickAgeRating = {
|
|
|
|
showNsfwWarning = true
|
|
|
|
},
|
|
|
|
)
|
2022-05-16 12:04:54 -04:00
|
|
|
}
|
2022-05-07 23:34:55 -04:00
|
|
|
|
2022-07-16 14:44:37 -04:00
|
|
|
items(
|
|
|
|
items = presenter.sources,
|
|
|
|
key = { it.source.id },
|
|
|
|
) { source ->
|
|
|
|
SourceSwitchPreference(
|
|
|
|
modifier = Modifier.animateItemPlacement(),
|
|
|
|
source = source,
|
|
|
|
onClickSourcePreferences = onClickSourcePreferences,
|
2022-08-29 16:10:55 -04:00
|
|
|
onClickSource = { presenter.toggleSource(it) },
|
2022-07-16 14:44:37 -04:00
|
|
|
)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (showNsfwWarning) {
|
|
|
|
NsfwWarningDialog(
|
|
|
|
onClickConfirm = {
|
|
|
|
showNsfwWarning = false
|
|
|
|
},
|
|
|
|
)
|
|
|
|
}
|
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-09-10 23:57:03 -04:00
|
|
|
} else {
|
|
|
|
Modifier
|
|
|
|
}
|
2022-05-19 17:31:07 -04:00
|
|
|
|
|
|
|
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,
|
|
|
|
)
|
|
|
|
}
|