Эх сурвалжийг харах

Update extension details screen design (#7158)

* Update extension details screen design

* Review Changes

Co-Authored-By: Andreas <[email protected]>

* Review Changes 2

Co-authored-by: Andreas <[email protected]>
FourTOne5 2 жил өмнө
parent
commit
64da16f58f

+ 145 - 34
app/src/main/java/eu/kanade/presentation/browse/ExtensionDetailsScreen.kt

@@ -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,
+    )
+}

+ 8 - 3
app/src/main/java/eu/kanade/presentation/browse/components/BrowseIcons.kt

@@ -1,5 +1,7 @@
 package eu.kanade.presentation.browse.components
 
+import android.content.pm.PackageManager
+import android.util.DisplayMetrics
 import androidx.compose.foundation.Image
 import androidx.compose.foundation.layout.Box
 import androidx.compose.foundation.layout.aspectRatio
@@ -57,6 +59,7 @@ fun SourceIcon(
 fun ExtensionIcon(
     extension: Extension,
     modifier: Modifier = Modifier,
+    density: Int = DisplayMetrics.DENSITY_DEFAULT,
 ) {
     when (extension) {
         is Extension.Available -> {
@@ -71,7 +74,7 @@ fun ExtensionIcon(
             )
         }
         is Extension.Installed -> {
-            val icon by extension.getIcon()
+            val icon by extension.getIcon(density)
             when (icon) {
                 Result.Error -> Image(
                     bitmap = ImageBitmap.imageResource(id = R.mipmap.ic_local_source),
@@ -95,13 +98,15 @@ fun ExtensionIcon(
 }
 
 @Composable
-private fun Extension.getIcon(): State<Result<ImageBitmap>> {
+private fun Extension.getIcon(density: Int = DisplayMetrics.DENSITY_DEFAULT): State<Result<ImageBitmap>> {
     val context = LocalContext.current
     return produceState<Result<ImageBitmap>>(initialValue = Result.Loading, this) {
         withIOContext {
             value = try {
+                val appInfo = context.packageManager.getApplicationInfo(pkgName, PackageManager.GET_META_DATA)
+                val appResources = context.packageManager.getResourcesForApplication(appInfo)
                 Result.Success(
-                    context.packageManager.getApplicationIcon(pkgName)
+                    appResources.getDrawableForDensity(appInfo.icon, density, null)!!
                         .toBitmap()
                         .asImageBitmap(),
                 )

+ 4 - 2
app/src/main/res/values/strings.xml

@@ -269,10 +269,12 @@
     <string name="obsolete_extension_message">This extension is no longer available.</string>
     <string name="unofficial_extension_message">This extension is not from the official Tachiyomi extensions list.</string>
     <string name="extension_api_error">Failed to get extensions list</string>
-    <string name="ext_version_info">Version: %1$s</string>
-    <string name="ext_language_info">Language: %1$s</string>
+    <string name="ext_info_version">Version</string>
+    <string name="ext_info_language">Language</string>
+    <string name="ext_info_age_rating">Age rating</string>
     <string name="ext_nsfw_short">18+</string>
     <string name="ext_nsfw_warning">May contain NSFW (18+) content</string>
+    <string name="ext_nsfw_warning_dismiss">Got it</string>
     <string name="ext_install_service_notif">Installing extension…</string>
     <string name="ext_installer_pref">Installer</string>
     <string name="ext_installer_legacy">Legacy</string>