|
@@ -1,7 +1,11 @@
|
|
|
package eu.kanade.presentation.browse
|
|
|
|
|
|
+import android.util.DisplayMetrics
|
|
|
import androidx.annotation.StringRes
|
|
|
import androidx.compose.foundation.background
|
|
|
+import androidx.compose.foundation.clickable
|
|
|
+import androidx.compose.foundation.interaction.MutableInteractionSource
|
|
|
+import androidx.compose.foundation.layout.Arrangement
|
|
|
import androidx.compose.foundation.layout.Box
|
|
|
import androidx.compose.foundation.layout.Column
|
|
|
import androidx.compose.foundation.layout.Row
|
|
@@ -12,27 +16,35 @@ import androidx.compose.foundation.layout.fillMaxWidth
|
|
|
import androidx.compose.foundation.layout.height
|
|
|
import androidx.compose.foundation.layout.navigationBars
|
|
|
import androidx.compose.foundation.layout.padding
|
|
|
+import androidx.compose.foundation.layout.size
|
|
|
import androidx.compose.foundation.layout.width
|
|
|
import androidx.compose.foundation.lazy.LazyColumn
|
|
|
import androidx.compose.foundation.lazy.items
|
|
|
import androidx.compose.material.icons.Icons
|
|
|
import androidx.compose.material.icons.outlined.Settings
|
|
|
+import androidx.compose.material3.AlertDialog
|
|
|
import androidx.compose.material3.Button
|
|
|
+import androidx.compose.material3.Divider
|
|
|
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
|
|
|
+import androidx.compose.material3.TextButton
|
|
|
import androidx.compose.runtime.Composable
|
|
|
import androidx.compose.runtime.collectAsState
|
|
|
import androidx.compose.runtime.getValue
|
|
|
+import androidx.compose.runtime.mutableStateOf
|
|
|
+import androidx.compose.runtime.remember
|
|
|
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
|
|
|
+import androidx.compose.ui.text.TextStyle
|
|
|
+import androidx.compose.ui.text.font.FontWeight
|
|
|
import androidx.compose.ui.unit.dp
|
|
|
import eu.kanade.presentation.browse.components.ExtensionIcon
|
|
|
import eu.kanade.presentation.components.Divider
|
|
@@ -64,6 +76,8 @@ fun ExtensionDetailsScreen(
|
|
|
|
|
|
val sources by presenter.sourcesState.collectAsState()
|
|
|
|
|
|
+ val (showNsfwWarning, setShowNsfwWarning) = remember { mutableStateOf(false) }
|
|
|
+
|
|
|
LazyColumn(
|
|
|
modifier = Modifier.nestedScroll(nestedScrollInterop),
|
|
|
contentPadding = WindowInsets.navigationBars.asPaddingValues(),
|
|
@@ -80,7 +94,14 @@ fun ExtensionDetailsScreen(
|
|
|
}
|
|
|
|
|
|
item {
|
|
|
- DetailsHeader(extension, onClickUninstall, onClickAppInfo)
|
|
|
+ DetailsHeader(
|
|
|
+ extension = extension,
|
|
|
+ onClickUninstall = onClickUninstall,
|
|
|
+ onClickAppInfo = onClickAppInfo,
|
|
|
+ onClickAgeRating = {
|
|
|
+ setShowNsfwWarning(true)
|
|
|
+ },
|
|
|
+ )
|
|
|
}
|
|
|
|
|
|
items(
|
|
@@ -95,6 +116,13 @@ fun ExtensionDetailsScreen(
|
|
|
)
|
|
|
}
|
|
|
}
|
|
|
+ if (showNsfwWarning) {
|
|
|
+ NsfwWarningDialog(
|
|
|
+ onClickConfirm = {
|
|
|
+ setShowNsfwWarning(false)
|
|
|
+ },
|
|
|
+ )
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
@Composable
|
|
@@ -116,52 +144,77 @@ private fun WarningBanner(@StringRes textRes: Int) {
|
|
|
@Composable
|
|
|
private fun DetailsHeader(
|
|
|
extension: Extension,
|
|
|
+ onClickAgeRating: () -> Unit,
|
|
|
onClickUninstall: () -> Unit,
|
|
|
onClickAppInfo: () -> Unit,
|
|
|
) {
|
|
|
val context = LocalContext.current
|
|
|
|
|
|
Column {
|
|
|
- Row(
|
|
|
- modifier = Modifier.padding(
|
|
|
- start = horizontalPadding,
|
|
|
- end = horizontalPadding,
|
|
|
- top = 16.dp,
|
|
|
- bottom = 8.dp,
|
|
|
- ),
|
|
|
+ Column(
|
|
|
+ modifier = Modifier
|
|
|
+ .fillMaxWidth()
|
|
|
+ .padding(
|
|
|
+ start = horizontalPadding,
|
|
|
+ end = horizontalPadding,
|
|
|
+ top = 16.dp,
|
|
|
+ bottom = 8.dp,
|
|
|
+ ),
|
|
|
+ horizontalAlignment = Alignment.CenterHorizontally,
|
|
|
) {
|
|
|
ExtensionIcon(
|
|
|
modifier = Modifier
|
|
|
- .height(56.dp)
|
|
|
- .width(56.dp),
|
|
|
+ .size(112.dp),
|
|
|
extension = extension,
|
|
|
+ density = DisplayMetrics.DENSITY_XXXHIGH,
|
|
|
)
|
|
|
|
|
|
- Column(
|
|
|
- modifier = Modifier.padding(start = 16.dp),
|
|
|
- ) {
|
|
|
- Text(
|
|
|
- text = extension.name,
|
|
|
- style = MaterialTheme.typography.titleMedium,
|
|
|
- )
|
|
|
- Text(
|
|
|
- text = stringResource(R.string.ext_version_info, extension.versionName),
|
|
|
- style = MaterialTheme.typography.bodySmall,
|
|
|
- )
|
|
|
- Text(
|
|
|
- text = stringResource(R.string.ext_language_info, LocaleHelper.getSourceDisplayName(extension.lang, context)),
|
|
|
- style = MaterialTheme.typography.bodySmall,
|
|
|
- )
|
|
|
- if (extension.isNsfw) {
|
|
|
- Text(
|
|
|
- text = stringResource(R.string.ext_nsfw_warning),
|
|
|
+ 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(
|
|
|
+ primaryText = extension.versionName,
|
|
|
+ secondaryText = stringResource(R.string.ext_info_version),
|
|
|
+ )
|
|
|
+
|
|
|
+ InfoDivider()
|
|
|
+
|
|
|
+ InfoText(
|
|
|
+ primaryText = LocaleHelper.getSourceDisplayName(extension.lang, context),
|
|
|
+ secondaryText = stringResource(R.string.ext_info_language),
|
|
|
+ )
|
|
|
+
|
|
|
+ if (extension.isNsfw) {
|
|
|
+ InfoDivider()
|
|
|
+
|
|
|
+ InfoText(
|
|
|
+ primaryText = stringResource(R.string.ext_nsfw_short),
|
|
|
+ primaryTextStyle = MaterialTheme.typography.bodyLarge.copy(
|
|
|
color = MaterialTheme.colorScheme.error,
|
|
|
- style = MaterialTheme.typography.bodySmall,
|
|
|
- )
|
|
|
- }
|
|
|
- Text(
|
|
|
- text = extension.pkgName,
|
|
|
- style = MaterialTheme.typography.bodySmall,
|
|
|
+ fontWeight = FontWeight.Medium,
|
|
|
+ ),
|
|
|
+ secondaryText = stringResource(R.string.ext_info_age_rating),
|
|
|
+ onCLick = onClickAgeRating,
|
|
|
)
|
|
|
}
|
|
|
}
|
|
@@ -198,6 +251,47 @@ private fun DetailsHeader(
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+@Composable
|
|
|
+private fun InfoText(
|
|
|
+ primaryText: String,
|
|
|
+ primaryTextStyle: TextStyle = MaterialTheme.typography.bodyLarge,
|
|
|
+ secondaryText: String,
|
|
|
+ onCLick: (() -> Unit)? = null,
|
|
|
+) {
|
|
|
+ val interactionSource = remember { MutableInteractionSource() }
|
|
|
+
|
|
|
+ val modifier = if (onCLick != null) {
|
|
|
+ Modifier.clickable(interactionSource, indication = null) { onCLick() }
|
|
|
+ } else Modifier
|
|
|
+
|
|
|
+ Column(
|
|
|
+ modifier = modifier,
|
|
|
+ horizontalAlignment = Alignment.CenterHorizontally,
|
|
|
+ verticalArrangement = Arrangement.Center,
|
|
|
+ ) {
|
|
|
+ Text(
|
|
|
+ text = primaryText,
|
|
|
+ style = primaryTextStyle,
|
|
|
+ )
|
|
|
+
|
|
|
+ Text(
|
|
|
+ text = secondaryText + if (onCLick != null) " ⓘ" else "",
|
|
|
+ style = MaterialTheme.typography.bodyMedium,
|
|
|
+ color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5F),
|
|
|
+ )
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+@Composable
|
|
|
+private fun InfoDivider() {
|
|
|
+ Divider(
|
|
|
+ modifier = Modifier
|
|
|
+ .height(20.dp)
|
|
|
+ .width(1.dp),
|
|
|
+ color = MaterialTheme.colorScheme.onSurface.copy(alpha = 0.5F),
|
|
|
+ )
|
|
|
+}
|
|
|
+
|
|
|
@Composable
|
|
|
private fun SourceSwitchPreference(
|
|
|
modifier: Modifier = Modifier,
|
|
@@ -234,3 +328,20 @@ private fun SourceSwitchPreference(
|
|
|
},
|
|
|
)
|
|
|
}
|
|
|
+
|
|
|
+@Composable
|
|
|
+fun NsfwWarningDialog(
|
|
|
+ onClickConfirm: () -> Unit,
|
|
|
+) {
|
|
|
+ AlertDialog(
|
|
|
+ text = {
|
|
|
+ Text(text = stringResource(id = R.string.ext_nsfw_warning))
|
|
|
+ },
|
|
|
+ confirmButton = {
|
|
|
+ TextButton(onClick = onClickConfirm) {
|
|
|
+ Text(text = stringResource(id = R.string.ext_nsfw_warning_dismiss))
|
|
|
+ }
|
|
|
+ },
|
|
|
+ onDismissRequest = onClickConfirm,
|
|
|
+ )
|
|
|
+}
|